aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-01-12 16:24:39 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-12 16:24:39 -0500
commitd9fbfb94d07ff8feb1741c31a1dd80d4850b44cb (patch)
tree2c6016a7125322f3ce57402144ce7dc2c8e75c17
parentMerge branch 'cxgb4-next' (diff)
parenttipc: make netlink support net namespace (diff)
downloadlinux-dev-d9fbfb94d07ff8feb1741c31a1dd80d4850b44cb.tar.xz
linux-dev-d9fbfb94d07ff8feb1741c31a1dd80d4850b44cb.zip
Merge branch 'tipc-namespaces'
Ying Xue says: ==================== tipc: make tipc support namespace This patchset aims to add net namespace support for TIPC stack. Currently TIPC module declares the following global resources: - TIPC network idenfication number - TIPC node table - TIPC bearer list table - TIPC broadcast link - TIPC socket reference table - TIPC name service table - TIPC node address - TIPC service subscriber server - TIPC random value - TIPC netlink In order that TIPC is aware of namespace, above each resource must be allocated, initialized and destroyed inside per namespace. Therefore, the major works of this patchset are to isolate these global resources and make them private for each namespace. However, before these changes come true, some necessary preparation works must be first done: convert socket reference table with generic rhashtable, cleanup core.c and core.h files, remove unnecessary wrapper functions for kernel timer interfaces and so on. It should be noted that commit ##1 ("tipc: fix bug in broadcast retransmit code") was already submitted to 'net' tree, so please see below link: http://patchwork.ozlabs.org/patch/426717/ Since it is prerequisite for the rest of the series to apply, I prepend them to the series. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/addr.c45
-rw-r--r--net/tipc/addr.h45
-rw-r--r--net/tipc/bcast.c372
-rw-r--r--net/tipc/bcast.h113
-rw-r--r--net/tipc/bearer.c141
-rw-r--r--net/tipc/bearer.h46
-rw-r--r--net/tipc/config.c66
-rw-r--r--net/tipc/config.h6
-rw-r--r--net/tipc/core.c140
-rw-r--r--net/tipc/core.h167
-rw-r--r--net/tipc/discover.c84
-rw-r--r--net/tipc/discover.h8
-rw-r--r--net/tipc/link.c322
-rw-r--r--net/tipc/link.h36
-rw-r--r--net/tipc/msg.c71
-rw-r--r--net/tipc/msg.h60
-rw-r--r--net/tipc/name_distr.c115
-rw-r--r--net/tipc/name_distr.h16
-rw-r--r--net/tipc/name_table.c180
-rw-r--r--net/tipc/name_table.h33
-rw-r--r--net/tipc/net.c54
-rw-r--r--net/tipc/net.h4
-rw-r--r--net/tipc/netlink.c17
-rw-r--r--net/tipc/netlink.h3
-rw-r--r--net/tipc/node.c159
-rw-r--r--net/tipc/node.h35
-rw-r--r--net/tipc/server.c6
-rw-r--r--net/tipc/server.h17
-rw-r--r--net/tipc/socket.c255
-rw-r--r--net/tipc/socket.h19
-rw-r--r--net/tipc/subscr.c131
-rw-r--r--net/tipc/subscr.h14
32 files changed, 1503 insertions, 1277 deletions
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
index 357b74b26f9e..48fd3b5a73fb 100644
--- a/net/tipc/addr.c
+++ b/net/tipc/addr.c
@@ -34,8 +34,51 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "core.h"
+#include <linux/kernel.h>
#include "addr.h"
+#include "core.h"
+
+/**
+ * in_own_cluster - test for cluster inclusion; <0.0.0> always matches
+ */
+int in_own_cluster(struct net *net, u32 addr)
+{
+ return in_own_cluster_exact(net, addr) || !addr;
+}
+
+int in_own_cluster_exact(struct net *net, u32 addr)
+{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ return !((addr ^ tn->own_addr) >> 12);
+}
+
+/**
+ * in_own_node - test for node inclusion; <0.0.0> always matches
+ */
+int in_own_node(struct net *net, u32 addr)
+{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ return (addr == tn->own_addr) || !addr;
+}
+
+/**
+ * addr_domain - convert 2-bit scope value to equivalent message lookup domain
+ *
+ * Needed when address of a named message must be looked up a second time
+ * after a network hop.
+ */
+u32 addr_domain(struct net *net, u32 sc)
+{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ if (likely(sc == TIPC_NODE_SCOPE))
+ return tn->own_addr;
+ if (sc == TIPC_CLUSTER_SCOPE)
+ return tipc_cluster_mask(tn->own_addr);
+ return tipc_zone_mask(tn->own_addr);
+}
/**
* tipc_addr_domain_valid - validates a network domain address
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
index a74acf9ee804..c700c2d28e09 100644
--- a/net/tipc/addr.h
+++ b/net/tipc/addr.h
@@ -37,7 +37,10 @@
#ifndef _TIPC_ADDR_H
#define _TIPC_ADDR_H
-#include "core.h"
+#include <linux/types.h>
+#include <linux/tipc.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
#define TIPC_ZONE_MASK 0xff000000u
#define TIPC_CLUSTER_MASK 0xfffff000u
@@ -52,42 +55,10 @@ static inline u32 tipc_cluster_mask(u32 addr)
return addr & TIPC_CLUSTER_MASK;
}
-static inline int in_own_cluster_exact(u32 addr)
-{
- return !((addr ^ tipc_own_addr) >> 12);
-}
-
-/**
- * in_own_node - test for node inclusion; <0.0.0> always matches
- */
-static inline int in_own_node(u32 addr)
-{
- return (addr == tipc_own_addr) || !addr;
-}
-
-/**
- * in_own_cluster - test for cluster inclusion; <0.0.0> always matches
- */
-static inline int in_own_cluster(u32 addr)
-{
- return in_own_cluster_exact(addr) || !addr;
-}
-
-/**
- * addr_domain - convert 2-bit scope value to equivalent message lookup domain
- *
- * Needed when address of a named message must be looked up a second time
- * after a network hop.
- */
-static inline u32 addr_domain(u32 sc)
-{
- if (likely(sc == TIPC_NODE_SCOPE))
- return tipc_own_addr;
- if (sc == TIPC_CLUSTER_SCOPE)
- return tipc_cluster_mask(tipc_own_addr);
- return tipc_zone_mask(tipc_own_addr);
-}
-
+int in_own_cluster(struct net *net, u32 addr);
+int in_own_cluster_exact(struct net *net, u32 addr);
+int in_own_node(struct net *net, u32 addr);
+u32 addr_domain(struct net *net, u32 sc);
int tipc_addr_domain_valid(u32);
int tipc_addr_node_valid(u32 addr);
int tipc_in_scope(u32 domain, u32 addr);
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 96ceefeb9daf..53f8bf059fec 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -35,77 +35,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "core.h"
-#include "link.h"
#include "socket.h"
#include "msg.h"
#include "bcast.h"
#include "name_distr.h"
+#include "core.h"
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
-#define BCBEARER MAX_BEARERS
-
-/**
- * struct tipc_bcbearer_pair - a pair of bearers used by broadcast link
- * @primary: pointer to primary bearer
- * @secondary: pointer to secondary bearer
- *
- * Bearers must have same priority and same set of reachable destinations
- * to be paired.
- */
-
-struct tipc_bcbearer_pair {
- struct tipc_bearer *primary;
- struct tipc_bearer *secondary;
-};
-
-/**
- * struct tipc_bcbearer - bearer used by broadcast link
- * @bearer: (non-standard) broadcast bearer structure
- * @media: (non-standard) broadcast media structure
- * @bpairs: array of bearer pairs
- * @bpairs_temp: temporary array of bearer pairs used by tipc_bcbearer_sort()
- * @remains: temporary node map used by tipc_bcbearer_send()
- * @remains_new: temporary node map used tipc_bcbearer_send()
- *
- * Note: The fields labelled "temporary" are incorporated into the bearer
- * to avoid consuming potentially limited stack space through the use of
- * large local variables within multicast routines. Concurrent access is
- * prevented through use of the spinlock "bclink_lock".
- */
-struct tipc_bcbearer {
- struct tipc_bearer bearer;
- struct tipc_media media;
- struct tipc_bcbearer_pair bpairs[MAX_BEARERS];
- struct tipc_bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
- struct tipc_node_map remains;
- struct tipc_node_map remains_new;
-};
-
-/**
- * struct tipc_bclink - link used for broadcast messages
- * @lock: spinlock governing access to structure
- * @link: (non-standard) broadcast link structure
- * @node: (non-standard) node structure representing b'cast link's peer node
- * @flags: represent bclink states
- * @bcast_nodes: map of broadcast-capable nodes
- * @retransmit_to: node that most recently requested a retransmit
- *
- * Handles sequence numbering, fragmentation, bundling, etc.
- */
-struct tipc_bclink {
- spinlock_t lock;
- struct tipc_link link;
- struct tipc_node node;
- unsigned int flags;
- struct tipc_node_map bcast_nodes;
- struct tipc_node *retransmit_to;
-};
-
-static struct tipc_bcbearer *bcbearer;
-static struct tipc_bclink *bclink;
-static struct tipc_link *bcl;
const char tipc_bclink_name[] = "broadcast-link";
@@ -115,25 +52,28 @@ static void tipc_nmap_diff(struct tipc_node_map *nm_a,
static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node);
static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node);
-static void tipc_bclink_lock(void)
+static void tipc_bclink_lock(struct net *net)
{
- spin_lock_bh(&bclink->lock);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ spin_lock_bh(&tn->bclink->lock);
}
-static void tipc_bclink_unlock(void)
+static void tipc_bclink_unlock(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node = NULL;
- if (likely(!bclink->flags)) {
- spin_unlock_bh(&bclink->lock);
+ if (likely(!tn->bclink->flags)) {
+ spin_unlock_bh(&tn->bclink->lock);
return;
}
- if (bclink->flags & TIPC_BCLINK_RESET) {
- bclink->flags &= ~TIPC_BCLINK_RESET;
- node = tipc_bclink_retransmit_to();
+ if (tn->bclink->flags & TIPC_BCLINK_RESET) {
+ tn->bclink->flags &= ~TIPC_BCLINK_RESET;
+ node = tipc_bclink_retransmit_to(net);
}
- spin_unlock_bh(&bclink->lock);
+ spin_unlock_bh(&tn->bclink->lock);
if (node)
tipc_link_reset_all(node);
@@ -144,9 +84,11 @@ uint tipc_bclink_get_mtu(void)
return MAX_PKT_DEFAULT_MCAST;
}
-void tipc_bclink_set_flags(unsigned int flags)
+void tipc_bclink_set_flags(struct net *net, unsigned int flags)
{
- bclink->flags |= flags;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ tn->bclink->flags |= flags;
}
static u32 bcbuf_acks(struct sk_buff *buf)
@@ -164,31 +106,40 @@ static void bcbuf_decr_acks(struct sk_buff *buf)
bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
}
-void tipc_bclink_add_node(u32 addr)
+void tipc_bclink_add_node(struct net *net, u32 addr)
{
- tipc_bclink_lock();
- tipc_nmap_add(&bclink->bcast_nodes, addr);
- tipc_bclink_unlock();
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ tipc_bclink_lock(net);
+ tipc_nmap_add(&tn->bclink->bcast_nodes, addr);
+ tipc_bclink_unlock(net);
}
-void tipc_bclink_remove_node(u32 addr)
+void tipc_bclink_remove_node(struct net *net, u32 addr)
{
- tipc_bclink_lock();
- tipc_nmap_remove(&bclink->bcast_nodes, addr);
- tipc_bclink_unlock();
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ tipc_bclink_lock(net);
+ tipc_nmap_remove(&tn->bclink->bcast_nodes, addr);
+ tipc_bclink_unlock(net);
}
-static void bclink_set_last_sent(void)
+static void bclink_set_last_sent(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
+
if (bcl->next_out)
bcl->fsm_msg_cnt = mod(buf_seqno(bcl->next_out) - 1);
else
bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1);
}
-u32 tipc_bclink_get_last_sent(void)
+u32 tipc_bclink_get_last_sent(struct net *net)
{
- return bcl->fsm_msg_cnt;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ return tn->bcl->fsm_msg_cnt;
}
static void bclink_update_last_sent(struct tipc_node *node, u32 seqno)
@@ -203,9 +154,11 @@ static void bclink_update_last_sent(struct tipc_node *node, u32 seqno)
*
* Called with bclink_lock locked
*/
-struct tipc_node *tipc_bclink_retransmit_to(void)
+struct tipc_node *tipc_bclink_retransmit_to(struct net *net)
{
- return bclink->retransmit_to;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ return tn->bclink->retransmit_to;
}
/**
@@ -215,15 +168,17 @@ struct tipc_node *tipc_bclink_retransmit_to(void)
*
* Called with bclink_lock locked
*/
-static void bclink_retransmit_pkt(u32 after, u32 to)
+static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to)
{
struct sk_buff *skb;
+ struct tipc_link *bcl = tn->bcl;
skb_queue_walk(&bcl->outqueue, skb) {
- if (more(buf_seqno(skb), after))
+ if (more(buf_seqno(skb), after)) {
+ tipc_link_retransmit(bcl, skb, mod(to - after));
break;
+ }
}
- tipc_link_retransmit(bcl, skb, mod(to - after));
}
/**
@@ -231,13 +186,13 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
*
* Called with no locks taken
*/
-void tipc_bclink_wakeup_users(void)
+void tipc_bclink_wakeup_users(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *skb;
- while ((skb = skb_dequeue(&bclink->link.waiting_sks)))
- tipc_sk_rcv(skb);
-
+ while ((skb = skb_dequeue(&tn->bclink->link.waiting_sks)))
+ tipc_sk_rcv(net, skb);
}
/**
@@ -252,10 +207,12 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
struct sk_buff *skb, *tmp;
struct sk_buff *next;
unsigned int released = 0;
+ struct net *net = n_ptr->net;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
/* Bail out if tx queue is empty (no clean up is required) */
- skb = skb_peek(&bcl->outqueue);
+ skb = skb_peek(&tn->bcl->outqueue);
if (!skb)
goto exit;
@@ -266,43 +223,43 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
* acknowledge sent messages only (if other nodes still exist)
* or both sent and unsent messages (otherwise)
*/
- if (bclink->bcast_nodes.count)
- acked = bcl->fsm_msg_cnt;
+ if (tn->bclink->bcast_nodes.count)
+ acked = tn->bcl->fsm_msg_cnt;
else
- acked = bcl->next_out_no;
+ acked = tn->bcl->next_out_no;
} else {
/*
* Bail out if specified sequence number does not correspond
* to a message that has been sent and not yet acknowledged
*/
if (less(acked, buf_seqno(skb)) ||
- less(bcl->fsm_msg_cnt, acked) ||
+ less(tn->bcl->fsm_msg_cnt, acked) ||
less_eq(acked, n_ptr->bclink.acked))
goto exit;
}
/* Skip over packets that node has previously acknowledged */
- skb_queue_walk(&bcl->outqueue, skb) {
+ skb_queue_walk(&tn->bcl->outqueue, skb) {
if (more(buf_seqno(skb), n_ptr->bclink.acked))
break;
}
/* Update packets that node is now acknowledging */
- skb_queue_walk_from_safe(&bcl->outqueue, skb, tmp) {
+ skb_queue_walk_from_safe(&tn->bcl->outqueue, skb, tmp) {
if (more(buf_seqno(skb), acked))
break;
- next = tipc_skb_queue_next(&bcl->outqueue, skb);
- if (skb != bcl->next_out) {
+ next = tipc_skb_queue_next(&tn->bcl->outqueue, skb);
+ if (skb != tn->bcl->next_out) {
bcbuf_decr_acks(skb);
} else {
bcbuf_set_acks(skb, 0);
- bcl->next_out = next;
- bclink_set_last_sent();
+ tn->bcl->next_out = next;
+ bclink_set_last_sent(net);
}
if (bcbuf_acks(skb) == 0) {
- __skb_unlink(skb, &bcl->outqueue);
+ __skb_unlink(skb, &tn->bcl->outqueue);
kfree_skb(skb);
released = 1;
}
@@ -310,15 +267,15 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
n_ptr->bclink.acked = acked;
/* Try resolving broadcast link congestion, if necessary */
- if (unlikely(bcl->next_out)) {
- tipc_link_push_packets(bcl);
- bclink_set_last_sent();
+ if (unlikely(tn->bcl->next_out)) {
+ tipc_link_push_packets(tn->bcl);
+ bclink_set_last_sent(net);
}
- if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
+ if (unlikely(released && !skb_queue_empty(&tn->bcl->waiting_sks)))
n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS;
exit:
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
}
/**
@@ -326,9 +283,11 @@ exit:
*
* RCU and node lock set
*/
-void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
+void tipc_bclink_update_link_state(struct net *net, struct tipc_node *n_ptr,
+ u32 last_sent)
{
struct sk_buff *buf;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
/* Ignore "stale" link state info */
if (less_eq(last_sent, n_ptr->bclink.last_in))
@@ -358,18 +317,18 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferred_queue);
u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent;
- tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
+ tipc_msg_init(net, msg, BCAST_PROTOCOL, STATE_MSG,
INT_H_SIZE, n_ptr->addr);
msg_set_non_seq(msg, 1);
- msg_set_mc_netid(msg, tipc_net_id);
+ msg_set_mc_netid(msg, tn->net_id);
msg_set_bcast_ack(msg, n_ptr->bclink.last_in);
msg_set_bcgap_after(msg, n_ptr->bclink.last_in);
msg_set_bcgap_to(msg, to);
- tipc_bclink_lock();
- tipc_bearer_send(MAX_BEARERS, buf, NULL);
- bcl->stats.sent_nacks++;
- tipc_bclink_unlock();
+ tipc_bclink_lock(net);
+ tipc_bearer_send(net, MAX_BEARERS, buf, NULL);
+ tn->bcl->stats.sent_nacks++;
+ tipc_bclink_unlock(net);
kfree_skb(buf);
n_ptr->bclink.oos_state++;
@@ -382,9 +341,9 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
* Delay any upcoming NACK by this node if another node has already
* requested the first message this node is going to ask for.
*/
-static void bclink_peek_nack(struct tipc_msg *msg)
+static void bclink_peek_nack(struct net *net, struct tipc_msg *msg)
{
- struct tipc_node *n_ptr = tipc_node_find(msg_destnode(msg));
+ struct tipc_node *n_ptr = tipc_node_find(net, msg_destnode(msg));
if (unlikely(!n_ptr))
return;
@@ -401,12 +360,16 @@ static void bclink_peek_nack(struct tipc_msg *msg)
/* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster
* and to identified node local sockets
+ * @net: the applicable net namespace
* @list: chain of buffers containing message
* Consumes the buffer chain, except when returning -ELINKCONG
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
*/
-int tipc_bclink_xmit(struct sk_buff_head *list)
+int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
+ struct tipc_bclink *bclink = tn->bclink;
int rc = 0;
int bc = 0;
struct sk_buff *skb;
@@ -420,19 +383,19 @@ int tipc_bclink_xmit(struct sk_buff_head *list)
/* Broadcast to all other nodes */
if (likely(bclink)) {
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
if (likely(bclink->bcast_nodes.count)) {
- rc = __tipc_link_xmit(bcl, list);
+ rc = __tipc_link_xmit(net, bcl, list);
if (likely(!rc)) {
u32 len = skb_queue_len(&bcl->outqueue);
- bclink_set_last_sent();
+ bclink_set_last_sent(net);
bcl->stats.queue_sz_counts++;
bcl->stats.accu_queue_sz += len;
}
bc = 1;
}
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
}
if (unlikely(!bc))
@@ -440,7 +403,7 @@ int tipc_bclink_xmit(struct sk_buff_head *list)
/* Deliver message clone */
if (likely(!rc))
- tipc_sk_mcast_rcv(skb);
+ tipc_sk_mcast_rcv(net, skb);
else
kfree_skb(skb);
@@ -454,19 +417,21 @@ int tipc_bclink_xmit(struct sk_buff_head *list)
*/
static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
{
+ struct tipc_net *tn = net_generic(node->net, tipc_net_id);
+
bclink_update_last_sent(node, seqno);
node->bclink.last_in = seqno;
node->bclink.oos_state = 0;
- bcl->stats.recv_info++;
+ tn->bcl->stats.recv_info++;
/*
* Unicast an ACK periodically, ensuring that
* all nodes in the cluster don't ACK at the same time
*/
- if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) {
+ if (((seqno - tn->own_addr) % TIPC_MIN_LINK_WIN) == 0) {
tipc_link_proto_xmit(node->active_links[node->addr & 1],
STATE_MSG, 0, 0, 0, 0, 0);
- bcl->stats.sent_acks++;
+ tn->bcl->stats.sent_acks++;
}
}
@@ -475,8 +440,10 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
*
* RCU is locked, no other locks set
*/
-void tipc_bclink_rcv(struct sk_buff *buf)
+void tipc_bclink_rcv(struct net *net, struct sk_buff *buf)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
struct tipc_msg *msg = buf_msg(buf);
struct tipc_node *node;
u32 next_in;
@@ -484,10 +451,10 @@ void tipc_bclink_rcv(struct sk_buff *buf)
int deferred = 0;
/* Screen out unwanted broadcast messages */
- if (msg_mc_netid(msg) != tipc_net_id)
+ if (msg_mc_netid(msg) != tn->net_id)
goto exit;
- node = tipc_node_find(msg_prevnode(msg));
+ node = tipc_node_find(net, msg_prevnode(msg));
if (unlikely(!node))
goto exit;
@@ -499,18 +466,18 @@ void tipc_bclink_rcv(struct sk_buff *buf)
if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
if (msg_type(msg) != STATE_MSG)
goto unlock;
- if (msg_destnode(msg) == tipc_own_addr) {
+ if (msg_destnode(msg) == tn->own_addr) {
tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node);
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bcl->stats.recv_nacks++;
- bclink->retransmit_to = node;
- bclink_retransmit_pkt(msg_bcgap_after(msg),
+ tn->bclink->retransmit_to = node;
+ bclink_retransmit_pkt(tn, msg_bcgap_after(msg),
msg_bcgap_to(msg));
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
} else {
tipc_node_unlock(node);
- bclink_peek_nack(msg);
+ bclink_peek_nack(net, msg);
}
goto exit;
}
@@ -523,47 +490,47 @@ void tipc_bclink_rcv(struct sk_buff *buf)
receive:
/* Deliver message to destination */
if (likely(msg_isdata(msg))) {
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bclink_accept_pkt(node, seqno);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
tipc_node_unlock(node);
if (likely(msg_mcast(msg)))
- tipc_sk_mcast_rcv(buf);
+ tipc_sk_mcast_rcv(net, buf);
else
kfree_skb(buf);
} else if (msg_user(msg) == MSG_BUNDLER) {
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bclink_accept_pkt(node, seqno);
bcl->stats.recv_bundles++;
bcl->stats.recv_bundled += msg_msgcnt(msg);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
tipc_node_unlock(node);
- tipc_link_bundle_rcv(buf);
+ tipc_link_bundle_rcv(net, buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
tipc_buf_append(&node->bclink.reasm_buf, &buf);
if (unlikely(!buf && !node->bclink.reasm_buf))
goto unlock;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bclink_accept_pkt(node, seqno);
bcl->stats.recv_fragments++;
if (buf) {
bcl->stats.recv_fragmented++;
msg = buf_msg(buf);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
goto receive;
}
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
tipc_node_unlock(node);
} else if (msg_user(msg) == NAME_DISTRIBUTOR) {
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bclink_accept_pkt(node, seqno);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
tipc_node_unlock(node);
- tipc_named_rcv(buf);
+ tipc_named_rcv(net, buf);
} else {
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
bclink_accept_pkt(node, seqno);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
tipc_node_unlock(node);
kfree_skb(buf);
}
@@ -601,14 +568,14 @@ receive:
buf = NULL;
}
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
if (deferred)
bcl->stats.deferred_recv++;
else
bcl->stats.duplicates++;
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
unlock:
tipc_node_unlock(node);
@@ -619,7 +586,7 @@ exit:
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
{
return (n_ptr->bclink.recv_permitted &&
- (tipc_bclink_get_last_sent() != n_ptr->bclink.acked));
+ (tipc_bclink_get_last_sent(n_ptr->net) != n_ptr->bclink.acked));
}
@@ -632,11 +599,15 @@ u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
* Returns 0 (packet sent successfully) under all circumstances,
* since the broadcast link's pseudo-bearer never blocks
*/
-static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
+static int tipc_bcbearer_send(struct net *net, struct sk_buff *buf,
+ struct tipc_bearer *unused1,
struct tipc_media_addr *unused2)
{
int bp_index;
struct tipc_msg *msg = buf_msg(buf);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_bcbearer *bcbearer = tn->bcbearer;
+ struct tipc_bclink *bclink = tn->bclink;
/* Prepare broadcast link message for reliable transmission,
* if first time trying to send it;
@@ -646,8 +617,8 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
if (likely(!msg_non_seq(buf_msg(buf)))) {
bcbuf_set_acks(buf, bclink->bcast_nodes.count);
msg_set_non_seq(msg, 1);
- msg_set_mc_netid(msg, tipc_net_id);
- bcl->stats.sent_info++;
+ msg_set_mc_netid(msg, tn->net_id);
+ tn->bcl->stats.sent_info++;
if (WARN_ON(!bclink->bcast_nodes.count)) {
dump_stack();
@@ -676,13 +647,14 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
if (bp_index == 0) {
/* Use original buffer for first bearer */
- tipc_bearer_send(b->identity, buf, &b->bcast_addr);
+ tipc_bearer_send(net, b->identity, buf, &b->bcast_addr);
} else {
/* Avoid concurrent buffer access */
tbuf = pskb_copy_for_clone(buf, GFP_ATOMIC);
if (!tbuf)
break;
- tipc_bearer_send(b->identity, tbuf, &b->bcast_addr);
+ tipc_bearer_send(net, b->identity, tbuf,
+ &b->bcast_addr);
kfree_skb(tbuf); /* Bearer keeps a clone */
}
if (bcbearer->remains_new.count == 0)
@@ -697,15 +669,18 @@ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
/**
* tipc_bcbearer_sort - create sets of bearer pairs used by broadcast bearer
*/
-void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
+void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr,
+ u32 node, bool action)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_bcbearer *bcbearer = tn->bcbearer;
struct tipc_bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
struct tipc_bcbearer_pair *bp_curr;
struct tipc_bearer *b;
int b_index;
int pri;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
if (action)
tipc_nmap_add(nm_ptr, node);
@@ -717,7 +692,7 @@ void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
rcu_read_lock();
for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
- b = rcu_dereference_rtnl(bearer_list[b_index]);
+ b = rcu_dereference_rtnl(tn->bearer_list[b_index]);
if (!b || !b->nodes.count)
continue;
@@ -752,7 +727,7 @@ void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
bp_curr++;
}
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
}
static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb,
@@ -806,17 +781,19 @@ msg_full:
return -EMSGSIZE;
}
-int tipc_nl_add_bc_link(struct tipc_nl_msg *msg)
+int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)
{
int err;
void *hdr;
struct nlattr *attrs;
struct nlattr *prop;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
if (!bcl)
return 0;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
NLM_F_MULTI, TIPC_NL_LINK_GET);
@@ -851,7 +828,7 @@ int tipc_nl_add_bc_link(struct tipc_nl_msg *msg)
if (err)
goto attr_msg_full;
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr);
@@ -862,21 +839,23 @@ prop_msg_full:
attr_msg_full:
nla_nest_cancel(msg->skb, attrs);
msg_full:
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
genlmsg_cancel(msg->skb, hdr);
return -EMSGSIZE;
}
-int tipc_bclink_stats(char *buf, const u32 buf_size)
+int tipc_bclink_stats(struct net *net, char *buf, const u32 buf_size)
{
int ret;
struct tipc_stats *s;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
if (!bcl)
return 0;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
s = &bcl->stats;
@@ -905,36 +884,47 @@ int tipc_bclink_stats(char *buf, const u32 buf_size)
s->queue_sz_counts ?
(s->accu_queue_sz / s->queue_sz_counts) : 0);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
return ret;
}
-int tipc_bclink_reset_stats(void)
+int tipc_bclink_reset_stats(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
+
if (!bcl)
return -ENOPROTOOPT;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
memset(&bcl->stats, 0, sizeof(bcl->stats));
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
return 0;
}
-int tipc_bclink_set_queue_limits(u32 limit)
+int tipc_bclink_set_queue_limits(struct net *net, u32 limit)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_link *bcl = tn->bcl;
+
if (!bcl)
return -ENOPROTOOPT;
if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
return -EINVAL;
- tipc_bclink_lock();
+ tipc_bclink_lock(net);
tipc_link_set_queue_limits(bcl, limit);
- tipc_bclink_unlock();
+ tipc_bclink_unlock(net);
return 0;
}
-int tipc_bclink_init(void)
+int tipc_bclink_init(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_bcbearer *bcbearer;
+ struct tipc_bclink *bclink;
+ struct tipc_link *bcl;
+
bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC);
if (!bcbearer)
return -ENOMEM;
@@ -958,25 +948,31 @@ int tipc_bclink_init(void)
spin_lock_init(&bclink->node.lock);
__skb_queue_head_init(&bclink->node.waiting_sks);
bcl->owner = &bclink->node;
+ bcl->owner->net = net;
bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
bcl->bearer_id = MAX_BEARERS;
- rcu_assign_pointer(bearer_list[MAX_BEARERS], &bcbearer->bearer);
+ rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer);
bcl->state = WORKING_WORKING;
strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
+ tn->bcbearer = bcbearer;
+ tn->bclink = bclink;
+ tn->bcl = bcl;
return 0;
}
-void tipc_bclink_stop(void)
+void tipc_bclink_stop(struct net *net)
{
- tipc_bclink_lock();
- tipc_link_purge_queues(bcl);
- tipc_bclink_unlock();
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ tipc_bclink_lock(net);
+ tipc_link_purge_queues(tn->bcl);
+ tipc_bclink_unlock(net);
- RCU_INIT_POINTER(bearer_list[BCBEARER], NULL);
+ RCU_INIT_POINTER(tn->bearer_list[BCBEARER], NULL);
synchronize_net();
- kfree(bcbearer);
- kfree(bclink);
+ kfree(tn->bcbearer);
+ kfree(tn->bclink);
}
/**
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 644d79129fba..a4583a109486 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -37,23 +37,13 @@
#ifndef _TIPC_BCAST_H
#define _TIPC_BCAST_H
-#include "netlink.h"
+#include <linux/tipc_config.h>
+#include "link.h"
+#include "node.h"
-#define MAX_NODES 4096
-#define WSIZE 32
-#define TIPC_BCLINK_RESET 1
-
-/**
- * struct tipc_node_map - set of node identifiers
- * @count: # of nodes in set
- * @map: bitmap of node identifiers that are in the set
- */
-struct tipc_node_map {
- u32 count;
- u32 map[MAX_NODES / WSIZE];
-};
-
-#define PLSIZE 32
+#define TIPC_BCLINK_RESET 1
+#define PLSIZE 32
+#define BCBEARER MAX_BEARERS
/**
* struct tipc_port_list - set of node local destination ports
@@ -67,9 +57,64 @@ struct tipc_port_list {
u32 ports[PLSIZE];
};
+/**
+ * struct tipc_bcbearer_pair - a pair of bearers used by broadcast link
+ * @primary: pointer to primary bearer
+ * @secondary: pointer to secondary bearer
+ *
+ * Bearers must have same priority and same set of reachable destinations
+ * to be paired.
+ */
-struct tipc_node;
+struct tipc_bcbearer_pair {
+ struct tipc_bearer *primary;
+ struct tipc_bearer *secondary;
+};
+/**
+ * struct tipc_bcbearer - bearer used by broadcast link
+ * @bearer: (non-standard) broadcast bearer structure
+ * @media: (non-standard) broadcast media structure
+ * @bpairs: array of bearer pairs
+ * @bpairs_temp: temporary array of bearer pairs used by tipc_bcbearer_sort()
+ * @remains: temporary node map used by tipc_bcbearer_send()
+ * @remains_new: temporary node map used tipc_bcbearer_send()
+ *
+ * Note: The fields labelled "temporary" are incorporated into the bearer
+ * to avoid consuming potentially limited stack space through the use of
+ * large local variables within multicast routines. Concurrent access is
+ * prevented through use of the spinlock "bclink_lock".
+ */
+struct tipc_bcbearer {
+ struct tipc_bearer bearer;
+ struct tipc_media media;
+ struct tipc_bcbearer_pair bpairs[MAX_BEARERS];
+ struct tipc_bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
+ struct tipc_node_map remains;
+ struct tipc_node_map remains_new;
+};
+
+/**
+ * struct tipc_bclink - link used for broadcast messages
+ * @lock: spinlock governing access to structure
+ * @link: (non-standard) broadcast link structure
+ * @node: (non-standard) node structure representing b'cast link's peer node
+ * @flags: represent bclink states
+ * @bcast_nodes: map of broadcast-capable nodes
+ * @retransmit_to: node that most recently requested a retransmit
+ *
+ * Handles sequence numbering, fragmentation, bundling, etc.
+ */
+struct tipc_bclink {
+ spinlock_t lock;
+ struct tipc_link link;
+ struct tipc_node node;
+ unsigned int flags;
+ struct tipc_node_map bcast_nodes;
+ struct tipc_node *retransmit_to;
+};
+
+struct tipc_node;
extern const char tipc_bclink_name[];
/**
@@ -84,24 +129,26 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a,
void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port);
void tipc_port_list_free(struct tipc_port_list *pl_ptr);
-int tipc_bclink_init(void);
-void tipc_bclink_stop(void);
-void tipc_bclink_set_flags(unsigned int flags);
-void tipc_bclink_add_node(u32 addr);
-void tipc_bclink_remove_node(u32 addr);
-struct tipc_node *tipc_bclink_retransmit_to(void);
+int tipc_bclink_init(struct net *net);
+void tipc_bclink_stop(struct net *net);
+void tipc_bclink_set_flags(struct net *tn, unsigned int flags);
+void tipc_bclink_add_node(struct net *net, u32 addr);
+void tipc_bclink_remove_node(struct net *net, u32 addr);
+struct tipc_node *tipc_bclink_retransmit_to(struct net *tn);
void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
-void tipc_bclink_rcv(struct sk_buff *buf);
-u32 tipc_bclink_get_last_sent(void);
+void tipc_bclink_rcv(struct net *net, struct sk_buff *buf);
+u32 tipc_bclink_get_last_sent(struct net *net);
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
-void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent);
-int tipc_bclink_stats(char *stats_buf, const u32 buf_size);
-int tipc_bclink_reset_stats(void);
-int tipc_bclink_set_queue_limits(u32 limit);
-void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action);
+void tipc_bclink_update_link_state(struct net *net, struct tipc_node *n_ptr,
+ u32 last_sent);
+int tipc_bclink_stats(struct net *net, char *stats_buf, const u32 buf_size);
+int tipc_bclink_reset_stats(struct net *net);
+int tipc_bclink_set_queue_limits(struct net *net, u32 limit);
+void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr,
+ u32 node, bool action);
uint tipc_bclink_get_mtu(void);
-int tipc_bclink_xmit(struct sk_buff_head *list);
-void tipc_bclink_wakeup_users(void);
-int tipc_nl_add_bc_link(struct tipc_nl_msg *msg);
+int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list);
+void tipc_bclink_wakeup_users(struct net *net);
+int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg);
#endif
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 463db5b15b8b..33dc3486d16c 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -34,11 +34,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <net/sock.h>
#include "core.h"
#include "config.h"
#include "bearer.h"
#include "link.h"
#include "discover.h"
+#include "bcast.h"
#define MAX_ADDR_STR 60
@@ -67,9 +69,8 @@ static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = {
[TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED }
};
-struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
-
-static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
+static void bearer_disable(struct net *net, struct tipc_bearer *b_ptr,
+ bool shutting_down);
/**
* tipc_media_find - locates specified media object by name
@@ -190,13 +191,14 @@ static int bearer_name_validate(const char *name,
/**
* tipc_bearer_find - locates bearer object with matching bearer name
*/
-struct tipc_bearer *tipc_bearer_find(const char *name)
+struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
u32 i;
for (i = 0; i < MAX_BEARERS; i++) {
- b_ptr = rtnl_dereference(bearer_list[i]);
+ b_ptr = rtnl_dereference(tn->bearer_list[i]);
if (b_ptr && (!strcmp(b_ptr->name, name)))
return b_ptr;
}
@@ -206,8 +208,9 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
/**
* tipc_bearer_get_names - record names of bearers in buffer
*/
-struct sk_buff *tipc_bearer_get_names(void)
+struct sk_buff *tipc_bearer_get_names(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *buf;
struct tipc_bearer *b;
int i, j;
@@ -218,7 +221,7 @@ struct sk_buff *tipc_bearer_get_names(void)
for (i = 0; media_info_array[i] != NULL; i++) {
for (j = 0; j < MAX_BEARERS; j++) {
- b = rtnl_dereference(bearer_list[j]);
+ b = rtnl_dereference(tn->bearer_list[j]);
if (!b)
continue;
if (b->media == media_info_array[i]) {
@@ -231,27 +234,29 @@ struct sk_buff *tipc_bearer_get_names(void)
return buf;
}
-void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
+void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
rcu_read_lock();
- b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+ b_ptr = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (b_ptr) {
- tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
+ tipc_bcbearer_sort(net, &b_ptr->nodes, dest, true);
tipc_disc_add_dest(b_ptr->link_req);
}
rcu_read_unlock();
}
-void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
+void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
rcu_read_lock();
- b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+ b_ptr = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (b_ptr) {
- tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
+ tipc_bcbearer_sort(net, &b_ptr->nodes, dest, false);
tipc_disc_remove_dest(b_ptr->link_req);
}
rcu_read_unlock();
@@ -260,8 +265,10 @@ void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
/**
* tipc_enable_bearer - enable bearer with the given name
*/
-int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
+int tipc_enable_bearer(struct net *net, const char *name, u32 disc_domain,
+ u32 priority)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
struct tipc_media *m_ptr;
struct tipc_bearer_names b_names;
@@ -271,7 +278,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
u32 i;
int res = -EINVAL;
- if (!tipc_own_addr) {
+ if (!tn->own_addr) {
pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
name);
return -ENOPROTOOPT;
@@ -281,11 +288,11 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
return -EINVAL;
}
if (tipc_addr_domain_valid(disc_domain) &&
- (disc_domain != tipc_own_addr)) {
- if (tipc_in_scope(disc_domain, tipc_own_addr)) {
- disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
+ (disc_domain != tn->own_addr)) {
+ if (tipc_in_scope(disc_domain, tn->own_addr)) {
+ disc_domain = tn->own_addr & TIPC_CLUSTER_MASK;
res = 0; /* accept any node in own cluster */
- } else if (in_own_cluster_exact(disc_domain))
+ } else if (in_own_cluster_exact(net, disc_domain))
res = 0; /* accept specified node in own cluster */
}
if (res) {
@@ -313,7 +320,7 @@ restart:
bearer_id = MAX_BEARERS;
with_this_prio = 1;
for (i = MAX_BEARERS; i-- != 0; ) {
- b_ptr = rtnl_dereference(bearer_list[i]);
+ b_ptr = rtnl_dereference(tn->bearer_list[i]);
if (!b_ptr) {
bearer_id = i;
continue;
@@ -347,7 +354,7 @@ restart:
strcpy(b_ptr->name, name);
b_ptr->media = m_ptr;
- res = m_ptr->enable_media(b_ptr);
+ res = m_ptr->enable_media(net, b_ptr);
if (res) {
pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
name, -res);
@@ -361,15 +368,15 @@ restart:
b_ptr->net_plane = bearer_id + 'A';
b_ptr->priority = priority;
- res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
+ res = tipc_disc_create(net, b_ptr, &b_ptr->bcast_addr);
if (res) {
- bearer_disable(b_ptr, false);
+ bearer_disable(net, b_ptr, false);
pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
name);
return -EINVAL;
}
- rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
+ rcu_assign_pointer(tn->bearer_list[bearer_id], b_ptr);
pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
name,
@@ -380,11 +387,11 @@ restart:
/**
* tipc_reset_bearer - Reset all links established over this bearer
*/
-static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
+static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b_ptr)
{
pr_info("Resetting bearer <%s>\n", b_ptr->name);
- tipc_link_reset_list(b_ptr->identity);
- tipc_disc_reset(b_ptr);
+ tipc_link_reset_list(net, b_ptr->identity);
+ tipc_disc_reset(net, b_ptr);
return 0;
}
@@ -393,49 +400,51 @@ static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
*
* Note: This routine assumes caller holds RTNL lock.
*/
-static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
+static void bearer_disable(struct net *net, struct tipc_bearer *b_ptr,
+ bool shutting_down)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 i;
pr_info("Disabling bearer <%s>\n", b_ptr->name);
b_ptr->media->disable_media(b_ptr);
- tipc_link_delete_list(b_ptr->identity, shutting_down);
+ tipc_link_delete_list(net, b_ptr->identity, shutting_down);
if (b_ptr->link_req)
tipc_disc_delete(b_ptr->link_req);
for (i = 0; i < MAX_BEARERS; i++) {
- if (b_ptr == rtnl_dereference(bearer_list[i])) {
- RCU_INIT_POINTER(bearer_list[i], NULL);
+ if (b_ptr == rtnl_dereference(tn->bearer_list[i])) {
+ RCU_INIT_POINTER(tn->bearer_list[i], NULL);
break;
}
}
kfree_rcu(b_ptr, rcu);
}
-int tipc_disable_bearer(const char *name)
+int tipc_disable_bearer(struct net *net, const char *name)
{
struct tipc_bearer *b_ptr;
int res;
- b_ptr = tipc_bearer_find(name);
+ b_ptr = tipc_bearer_find(net, name);
if (b_ptr == NULL) {
pr_warn("Attempt to disable unknown bearer <%s>\n", name);
res = -EINVAL;
} else {
- bearer_disable(b_ptr, false);
+ bearer_disable(net, b_ptr, false);
res = 0;
}
return res;
}
-int tipc_enable_l2_media(struct tipc_bearer *b)
+int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b)
{
struct net_device *dev;
char *driver_name = strchr((const char *)b->name, ':') + 1;
/* Find device with specified name */
- dev = dev_get_by_name(&init_net, driver_name);
+ dev = dev_get_by_name(net, driver_name);
if (!dev)
return -ENODEV;
@@ -474,8 +483,8 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
* @b_ptr: the bearer through which the packet is to be sent
* @dest: peer destination address
*/
-int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
- struct tipc_media_addr *dest)
+int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
+ struct tipc_bearer *b, struct tipc_media_addr *dest)
{
struct sk_buff *clone;
struct net_device *dev;
@@ -511,15 +520,16 @@ int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
* The media send routine must not alter the buffer being passed in
* as it may be needed for later retransmission!
*/
-void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
+void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf,
struct tipc_media_addr *dest)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
rcu_read_lock();
- b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
+ b_ptr = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (likely(b_ptr))
- b_ptr->media->send_msg(buf, b_ptr, dest);
+ b_ptr->media->send_msg(net, buf, b_ptr, dest);
rcu_read_unlock();
}
@@ -539,17 +549,12 @@ static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
{
struct tipc_bearer *b_ptr;
- if (!net_eq(dev_net(dev), &init_net)) {
- kfree_skb(buf);
- return NET_RX_DROP;
- }
-
rcu_read_lock();
b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
if (likely(b_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
- tipc_rcv(buf, b_ptr);
+ tipc_rcv(dev_net(dev), buf, b_ptr);
rcu_read_unlock();
return NET_RX_SUCCESS;
}
@@ -572,11 +577,9 @@ static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
void *ptr)
{
- struct tipc_bearer *b_ptr;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
+ struct net *net = dev_net(dev);
+ struct tipc_bearer *b_ptr;
b_ptr = rtnl_dereference(dev->tipc_ptr);
if (!b_ptr)
@@ -590,16 +593,16 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
break;
case NETDEV_DOWN:
case NETDEV_CHANGEMTU:
- tipc_reset_bearer(b_ptr);
+ tipc_reset_bearer(net, b_ptr);
break;
case NETDEV_CHANGEADDR:
b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
(char *)dev->dev_addr);
- tipc_reset_bearer(b_ptr);
+ tipc_reset_bearer(net, b_ptr);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
- bearer_disable(b_ptr, false);
+ bearer_disable(dev_net(dev), b_ptr, false);
break;
}
return NOTIFY_OK;
@@ -632,16 +635,17 @@ void tipc_bearer_cleanup(void)
dev_remove_pack(&tipc_packet_type);
}
-void tipc_bearer_stop(void)
+void tipc_bearer_stop(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_bearer *b_ptr;
u32 i;
for (i = 0; i < MAX_BEARERS; i++) {
- b_ptr = rtnl_dereference(bearer_list[i]);
+ b_ptr = rtnl_dereference(tn->bearer_list[i]);
if (b_ptr) {
- bearer_disable(b_ptr, true);
- bearer_list[i] = NULL;
+ bearer_disable(net, b_ptr, true);
+ tn->bearer_list[i] = NULL;
}
}
}
@@ -698,6 +702,8 @@ int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb)
int i = cb->args[0];
struct tipc_bearer *bearer;
struct tipc_nl_msg msg;
+ struct net *net = sock_net(skb->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
if (i == MAX_BEARERS)
return 0;
@@ -708,7 +714,7 @@ int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb)
rtnl_lock();
for (i = 0; i < MAX_BEARERS; i++) {
- bearer = rtnl_dereference(bearer_list[i]);
+ bearer = rtnl_dereference(tn->bearer_list[i]);
if (!bearer)
continue;
@@ -730,6 +736,7 @@ int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
struct tipc_bearer *bearer;
struct tipc_nl_msg msg;
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+ struct net *net = genl_info_net(info);
if (!info->attrs[TIPC_NLA_BEARER])
return -EINVAL;
@@ -753,7 +760,7 @@ int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
msg.seq = info->snd_seq;
rtnl_lock();
- bearer = tipc_bearer_find(name);
+ bearer = tipc_bearer_find(net, name);
if (!bearer) {
err = -EINVAL;
goto err_out;
@@ -778,6 +785,7 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
char *name;
struct tipc_bearer *bearer;
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+ struct net *net = genl_info_net(info);
if (!info->attrs[TIPC_NLA_BEARER])
return -EINVAL;
@@ -794,13 +802,13 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
rtnl_lock();
- bearer = tipc_bearer_find(name);
+ bearer = tipc_bearer_find(net, name);
if (!bearer) {
rtnl_unlock();
return -EINVAL;
}
- bearer_disable(bearer, false);
+ bearer_disable(net, bearer, false);
rtnl_unlock();
return 0;
@@ -808,6 +816,8 @@ 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)
{
+ struct net *net = genl_info_net(info);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
int err;
char *bearer;
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
@@ -815,7 +825,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
u32 prio;
prio = TIPC_MEDIA_LINK_PRI;
- domain = tipc_own_addr & TIPC_CLUSTER_MASK;
+ domain = tn->own_addr & TIPC_CLUSTER_MASK;
if (!info->attrs[TIPC_NLA_BEARER])
return -EINVAL;
@@ -847,7 +857,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
}
rtnl_lock();
- err = tipc_enable_bearer(bearer, domain, prio);
+ err = tipc_enable_bearer(net, bearer, domain, prio);
if (err) {
rtnl_unlock();
return err;
@@ -863,6 +873,7 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
char *name;
struct tipc_bearer *b;
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+ struct net *net = genl_info_net(info);
if (!info->attrs[TIPC_NLA_BEARER])
return -EINVAL;
@@ -878,7 +889,7 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
rtnl_lock();
- b = tipc_bearer_find(name);
+ b = tipc_bearer_find(net, name);
if (!b) {
rtnl_unlock();
return -EINVAL;
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 2c1230ac5dfe..c035e3e24764 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -37,12 +37,13 @@
#ifndef _TIPC_BEARER_H
#define _TIPC_BEARER_H
-#include "bcast.h"
#include "netlink.h"
#include <net/genetlink.h>
#define MAX_BEARERS 2
#define MAX_MEDIA 2
+#define MAX_NODES 4096
+#define WSIZE 32
/* Identifiers associated with TIPC message header media address info
* - address info field is 32 bytes long
@@ -59,6 +60,16 @@
#define TIPC_MEDIA_TYPE_IB 2
/**
+ * struct tipc_node_map - set of node identifiers
+ * @count: # of nodes in set
+ * @map: bitmap of node identifiers that are in the set
+ */
+struct tipc_node_map {
+ u32 count;
+ u32 map[MAX_NODES / WSIZE];
+};
+
+/**
* struct tipc_media_addr - destination address used by TIPC bearers
* @value: address info (format defined by media)
* @media_id: TIPC media type identifier
@@ -89,10 +100,10 @@ struct tipc_bearer;
* @name: media name
*/
struct tipc_media {
- int (*send_msg)(struct sk_buff *buf,
+ int (*send_msg)(struct net *net, struct sk_buff *buf,
struct tipc_bearer *b_ptr,
struct tipc_media_addr *dest);
- int (*enable_media)(struct tipc_bearer *b_ptr);
+ int (*enable_media)(struct net *net, struct tipc_bearer *b_ptr);
void (*disable_media)(struct tipc_bearer *b_ptr);
int (*addr2str)(struct tipc_media_addr *addr,
char *strbuf,
@@ -157,17 +168,14 @@ struct tipc_bearer_names {
char if_name[TIPC_MAX_IF_NAME];
};
-struct tipc_link;
-
-extern struct tipc_bearer __rcu *bearer_list[];
-
/*
* TIPC routines available to supported media types
*/
-void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *tb_ptr);
-int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority);
-int tipc_disable_bearer(const char *name);
+void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr);
+int tipc_enable_bearer(struct net *net, const char *bearer_name,
+ u32 disc_domain, u32 priority);
+int tipc_disable_bearer(struct net *net, const char *name);
/*
* Routines made available to TIPC by supported media types
@@ -192,20 +200,20 @@ int tipc_media_set_priority(const char *name, u32 new_value);
int tipc_media_set_window(const char *name, u32 new_value);
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
struct sk_buff *tipc_media_get_names(void);
-int tipc_enable_l2_media(struct tipc_bearer *b);
+int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b);
void tipc_disable_l2_media(struct tipc_bearer *b);
-int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
- struct tipc_media_addr *dest);
+int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
+ struct tipc_bearer *b, struct tipc_media_addr *dest);
-struct sk_buff *tipc_bearer_get_names(void);
-void tipc_bearer_add_dest(u32 bearer_id, u32 dest);
-void tipc_bearer_remove_dest(u32 bearer_id, u32 dest);
-struct tipc_bearer *tipc_bearer_find(const char *name);
+struct sk_buff *tipc_bearer_get_names(struct net *net);
+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);
struct tipc_media *tipc_media_find(const char *name);
int tipc_bearer_setup(void);
void tipc_bearer_cleanup(void);
-void tipc_bearer_stop(void);
-void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
+void tipc_bearer_stop(struct net *net);
+void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf,
struct tipc_media_addr *dest);
#endif /* _TIPC_BEARER_H */
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 0b3a90ecab6d..6873360cda53 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -134,7 +134,7 @@ static struct sk_buff *tipc_show_stats(void)
return buf;
}
-static struct sk_buff *cfg_enable_bearer(void)
+static struct sk_buff *cfg_enable_bearer(struct net *net)
{
struct tipc_bearer_config *args;
@@ -142,7 +142,7 @@ static struct sk_buff *cfg_enable_bearer(void)
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
- if (tipc_enable_bearer(args->name,
+ if (tipc_enable_bearer(net, args->name,
ntohl(args->disc_domain),
ntohl(args->priority)))
return tipc_cfg_reply_error_string("unable to enable bearer");
@@ -150,62 +150,66 @@ static struct sk_buff *cfg_enable_bearer(void)
return tipc_cfg_reply_none();
}
-static struct sk_buff *cfg_disable_bearer(void)
+static struct sk_buff *cfg_disable_bearer(struct net *net)
{
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
- if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
+ if (tipc_disable_bearer(net, (char *)TLV_DATA(req_tlv_area)))
return tipc_cfg_reply_error_string("unable to disable bearer");
return tipc_cfg_reply_none();
}
-static struct sk_buff *cfg_set_own_addr(void)
+static struct sk_buff *cfg_set_own_addr(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 addr;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
- if (addr == tipc_own_addr)
+ if (addr == tn->own_addr)
return tipc_cfg_reply_none();
if (!tipc_addr_node_valid(addr))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (node address)");
- if (tipc_own_addr)
+ if (tn->own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- if (!tipc_net_start(addr))
+ if (!tipc_net_start(net, addr))
return tipc_cfg_reply_none();
return tipc_cfg_reply_error_string("cannot change to network mode");
}
-static struct sk_buff *cfg_set_netid(void)
+static struct sk_buff *cfg_set_netid(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
- if (value == tipc_net_id)
+ if (value == tn->net_id)
return tipc_cfg_reply_none();
if (value < 1 || value > 9999)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network id must be 1-9999)");
- if (tipc_own_addr)
+ if (tn->own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change network id once TIPC has joined a network)");
- tipc_net_id = value;
+ tn->net_id = value;
return tipc_cfg_reply_none();
}
-struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
- int request_space, int reply_headroom)
+struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
+ const void *request_area, int request_space,
+ int reply_headroom)
{
struct sk_buff *rep_tlv_buf;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
rtnl_lock();
@@ -215,7 +219,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
rep_headroom = reply_headroom;
/* Check command authorization */
- if (likely(in_own_node(orig_node))) {
+ if (likely(in_own_node(net, orig_node))) {
/* command is permitted */
} else {
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
@@ -229,28 +233,33 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
rep_tlv_buf = tipc_cfg_reply_none();
break;
case TIPC_CMD_GET_NODES:
- rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_node_get_nodes(net, req_tlv_area,
+ req_tlv_space);
break;
case TIPC_CMD_GET_LINKS:
- rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_node_get_links(net, req_tlv_area,
+ req_tlv_space);
break;
case TIPC_CMD_SHOW_LINK_STATS:
- rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_link_cmd_show_stats(net, req_tlv_area,
+ req_tlv_space);
break;
case TIPC_CMD_RESET_LINK_STATS:
- rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_link_cmd_reset_stats(net, req_tlv_area,
+ req_tlv_space);
break;
case TIPC_CMD_SHOW_NAME_TABLE:
- rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_nametbl_get(net, req_tlv_area,
+ req_tlv_space);
break;
case TIPC_CMD_GET_BEARER_NAMES:
- rep_tlv_buf = tipc_bearer_get_names();
+ rep_tlv_buf = tipc_bearer_get_names(net);
break;
case TIPC_CMD_GET_MEDIA_NAMES:
rep_tlv_buf = tipc_media_get_names();
break;
case TIPC_CMD_SHOW_PORTS:
- rep_tlv_buf = tipc_sk_socks_show();
+ rep_tlv_buf = tipc_sk_socks_show(net);
break;
case TIPC_CMD_SHOW_STATS:
rep_tlv_buf = tipc_show_stats();
@@ -258,22 +267,23 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
case TIPC_CMD_SET_LINK_TOL:
case TIPC_CMD_SET_LINK_PRI:
case TIPC_CMD_SET_LINK_WINDOW:
- rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
+ rep_tlv_buf = tipc_link_cmd_config(net, req_tlv_area,
+ req_tlv_space, cmd);
break;
case TIPC_CMD_ENABLE_BEARER:
- rep_tlv_buf = cfg_enable_bearer();
+ rep_tlv_buf = cfg_enable_bearer(net);
break;
case TIPC_CMD_DISABLE_BEARER:
- rep_tlv_buf = cfg_disable_bearer();
+ rep_tlv_buf = cfg_disable_bearer(net);
break;
case TIPC_CMD_SET_NODE_ADDR:
- rep_tlv_buf = cfg_set_own_addr();
+ rep_tlv_buf = cfg_set_own_addr(net);
break;
case TIPC_CMD_SET_NETID:
- rep_tlv_buf = cfg_set_netid();
+ rep_tlv_buf = cfg_set_netid(net);
break;
case TIPC_CMD_GET_NETID:
- rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
+ rep_tlv_buf = tipc_cfg_reply_unsigned(tn->net_id);
break;
case TIPC_CMD_NOT_NET_ADMIN:
rep_tlv_buf =
diff --git a/net/tipc/config.h b/net/tipc/config.h
index 47b1bf181612..9e9b575fc429 100644
--- a/net/tipc/config.h
+++ b/net/tipc/config.h
@@ -37,10 +37,10 @@
#ifndef _TIPC_CONFIG_H
#define _TIPC_CONFIG_H
-/* ---------------------------------------------------------------------- */
-
#include "link.h"
+#define ULTRA_STRING_MAX_LEN 32768
+
struct sk_buff *tipc_cfg_reply_alloc(int payload_size);
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
void *tlv_data, int tlv_data_size);
@@ -61,7 +61,7 @@ static inline struct sk_buff *tipc_cfg_reply_ultra_string(char *string)
return tipc_cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
}
-struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd,
+struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
const void *req_tlv_area, int req_tlv_space,
int headroom);
#endif
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 71b2ada0f5ab..674bd2698528 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -44,68 +44,68 @@
#include <linux/module.h>
-/* global variables used by multiple sub-systems within TIPC */
-int tipc_random __read_mostly;
-
/* configurable TIPC parameters */
-u32 tipc_own_addr __read_mostly;
int tipc_net_id __read_mostly;
int sysctl_tipc_rmem[3] __read_mostly; /* min/default/max */
-/**
- * tipc_buf_acquire - creates a TIPC message buffer
- * @size: message size (including TIPC header)
- *
- * Returns 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)
+static int __net_init tipc_init_net(struct net *net)
{
- struct sk_buff *skb;
- unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
-
- skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
- if (skb) {
- skb_reserve(skb, BUF_HEADROOM);
- skb_put(skb, size);
- skb->next = NULL;
- }
- return skb;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ int err;
+
+ tn->net_id = 4711;
+ tn->own_addr = 0;
+ get_random_bytes(&tn->random, sizeof(int));
+ INIT_LIST_HEAD(&tn->node_list);
+ spin_lock_init(&tn->node_list_lock);
+
+ err = tipc_sk_rht_init(net);
+ if (err)
+ goto out_sk_rht;
+
+ err = tipc_nametbl_init(net);
+ if (err)
+ goto out_nametbl;
+
+ err = tipc_subscr_start(net);
+ if (err)
+ goto out_subscr;
+ return 0;
+
+out_subscr:
+ tipc_nametbl_stop(net);
+out_nametbl:
+ tipc_sk_rht_destroy(net);
+out_sk_rht:
+ return err;
}
-/**
- * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
- */
-static void tipc_core_stop(void)
+static void __net_exit tipc_exit_net(struct net *net)
{
- tipc_net_stop();
- tipc_bearer_cleanup();
- tipc_netlink_stop();
- tipc_subscr_stop();
- tipc_nametbl_stop();
- tipc_socket_stop();
- tipc_unregister_sysctl();
- tipc_sk_rht_destroy();
+ tipc_subscr_stop(net);
+ tipc_net_stop(net);
+ tipc_nametbl_stop(net);
+ tipc_sk_rht_destroy(net);
}
-/**
- * tipc_core_start - switch TIPC from NOT RUNNING to SINGLE NODE mode
- */
-static int tipc_core_start(void)
+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 int __init tipc_init(void)
{
int err;
- get_random_bytes(&tipc_random, sizeof(tipc_random));
-
- err = tipc_sk_rht_init();
- if (err)
- goto out_reftbl;
+ pr_info("Activated (version " TIPC_MOD_VER ")\n");
- err = tipc_nametbl_init();
- if (err)
- goto out_nametbl;
+ sysctl_tipc_rmem[0] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
+ TIPC_LOW_IMPORTANCE;
+ sysctl_tipc_rmem[1] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
+ TIPC_CRITICAL_IMPORTANCE;
+ sysctl_tipc_rmem[2] = TIPC_CONN_OVERLOAD_LIMIT;
err = tipc_netlink_start();
if (err)
@@ -119,57 +119,37 @@ static int tipc_core_start(void)
if (err)
goto out_sysctl;
- err = tipc_subscr_start();
+ err = register_pernet_subsys(&tipc_net_ops);
if (err)
- goto out_subscr;
+ goto out_pernet;
err = tipc_bearer_setup();
if (err)
goto out_bearer;
+ pr_info("Started in single node mode\n");
return 0;
out_bearer:
- tipc_subscr_stop();
-out_subscr:
+ unregister_pernet_subsys(&tipc_net_ops);
+out_pernet:
tipc_unregister_sysctl();
out_sysctl:
tipc_socket_stop();
out_socket:
tipc_netlink_stop();
out_netlink:
- tipc_nametbl_stop();
-out_nametbl:
- tipc_sk_rht_destroy();
-out_reftbl:
+ pr_err("Unable to start in single node mode\n");
return err;
}
-static int __init tipc_init(void)
-{
- int res;
-
- pr_info("Activated (version " TIPC_MOD_VER ")\n");
-
- tipc_own_addr = 0;
- tipc_net_id = 4711;
-
- sysctl_tipc_rmem[0] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
- TIPC_LOW_IMPORTANCE;
- sysctl_tipc_rmem[1] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
- TIPC_CRITICAL_IMPORTANCE;
- sysctl_tipc_rmem[2] = TIPC_CONN_OVERLOAD_LIMIT;
-
- res = tipc_core_start();
- if (res)
- pr_err("Unable to start in single node mode\n");
- else
- pr_info("Started in single node mode\n");
- return res;
-}
-
static void __exit tipc_exit(void)
{
- tipc_core_stop();
+ tipc_bearer_cleanup();
+ tipc_netlink_stop();
+ tipc_socket_stop();
+ tipc_unregister_sysctl();
+ unregister_pernet_subsys(&tipc_net_ops);
+
pr_info("Deactivated\n");
}
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 56fe4229fc5e..817b2e9d4227 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -57,46 +57,56 @@
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
+#include <net/netns/generic.h>
+#include <linux/rhashtable.h>
-#define TIPC_MOD_VER "2.0.0"
-
-#define ULTRA_STRING_MAX_LEN 32768
-#define TIPC_MAX_SUBSCRIPTIONS 65535
-#define TIPC_MAX_PUBLICATIONS 65535
+#include "node.h"
+#include "bearer.h"
+#include "bcast.h"
+#include "netlink.h"
+#include "link.h"
+#include "node.h"
+#include "msg.h"
-struct tipc_msg; /* msg.h */
+#define TIPC_MOD_VER "2.0.0"
int tipc_snprintf(char *buf, int len, const char *fmt, ...);
-/*
- * TIPC-specific error codes
- */
-#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
-
-/*
- * Global configuration variables
- */
-extern u32 tipc_own_addr __read_mostly;
extern int tipc_net_id __read_mostly;
extern int sysctl_tipc_rmem[3] __read_mostly;
extern int sysctl_tipc_named_timeout __read_mostly;
-/*
- * Other global variables
- */
-extern int tipc_random __read_mostly;
+struct tipc_net {
+ u32 own_addr;
+ int net_id;
+ int random;
-/*
- * Routines available to privileged subsystems
- */
-int tipc_netlink_start(void);
-void tipc_netlink_stop(void);
-int tipc_socket_init(void);
-void tipc_socket_stop(void);
-int tipc_sock_create_local(int type, struct socket **res);
-void tipc_sock_release_local(struct socket *sock);
-int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
- int flags);
+ /* 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;
+
+ /* Bearer list */
+ struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
+
+ /* Broadcast link */
+ struct tipc_bcbearer *bcbearer;
+ struct tipc_bclink *bclink;
+ 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_server *topsrv;
+ atomic_t subscription_count;
+};
#ifdef CONFIG_SYSCTL
int tipc_register_sysctl(void);
@@ -106,101 +116,4 @@ void tipc_unregister_sysctl(void);
#define tipc_unregister_sysctl()
#endif
-/*
- * TIPC timer code
- */
-typedef void (*Handler) (unsigned long);
-
-/**
- * k_init_timer - initialize a timer
- * @timer: pointer to timer structure
- * @routine: pointer to routine to invoke when timer expires
- * @argument: value to pass to routine when timer expires
- *
- * Timer must be initialized before use (and terminated when no longer needed).
- */
-static inline void k_init_timer(struct timer_list *timer, Handler routine,
- unsigned long argument)
-{
- setup_timer(timer, routine, argument);
-}
-
-/**
- * k_start_timer - start a timer
- * @timer: pointer to timer structure
- * @msec: time to delay (in ms)
- *
- * Schedules a previously initialized timer for later execution.
- * If timer is already running, the new timeout overrides the previous request.
- *
- * To ensure the timer doesn't expire before the specified delay elapses,
- * the amount of delay is rounded up when converting to the jiffies
- * then an additional jiffy is added to account for the fact that
- * the starting time may be in the middle of the current jiffy.
- */
-static inline void k_start_timer(struct timer_list *timer, unsigned long msec)
-{
- mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1);
-}
-
-/**
- * k_cancel_timer - cancel a timer
- * @timer: pointer to timer structure
- *
- * Cancels a previously initialized timer.
- * Can be called safely even if the timer is already inactive.
- *
- * WARNING: Must not be called when holding locks required by the timer's
- * timeout routine, otherwise deadlock can occur on SMP systems!
- */
-static inline void k_cancel_timer(struct timer_list *timer)
-{
- del_timer_sync(timer);
-}
-
-/**
- * k_term_timer - terminate a timer
- * @timer: pointer to timer structure
- *
- * Prevents further use of a previously initialized timer.
- *
- * WARNING: Caller must ensure timer isn't currently running.
- *
- * (Do not "enhance" this routine to automatically cancel an active timer,
- * otherwise deadlock can arise when a timeout routine calls k_term_timer.)
- */
-static inline void k_term_timer(struct timer_list *timer)
-{
-}
-
-/*
- * TIPC message buffer code
- *
- * TIPC message buffer headroom reserves space for the worst-case
- * link-level device header (in case the message is sent off-node).
- *
- * Note: Headroom should be a multiple of 4 to ensure the TIPC header fields
- * are word aligned for quicker access
- */
-#define BUF_HEADROOM LL_MAX_HEADER
-
-struct tipc_skb_cb {
- void *handle;
- struct sk_buff *tail;
- bool deferred;
- bool wakeup_pending;
- bool bundling;
- u16 chain_sz;
- u16 chain_imp;
-};
-
-#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
-
-static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
-{
- return (struct tipc_msg *)skb->data;
-}
-
-struct sk_buff *tipc_buf_acquire(u32 size);
-
#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index aa722a42ef8b..5b40cb89ff0a 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -38,15 +38,20 @@
#include "link.h"
#include "discover.h"
-#define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */
-#define TIPC_LINK_REQ_FAST 1000 /* max delay if bearer has no links */
-#define TIPC_LINK_REQ_SLOW 60000 /* max delay if bearer has links */
-#define TIPC_LINK_REQ_INACTIVE 0xffffffff /* indicates no timer in use */
+/* min delay during bearer start up */
+#define TIPC_LINK_REQ_INIT msecs_to_jiffies(125)
+/* max delay if bearer has no links */
+#define TIPC_LINK_REQ_FAST msecs_to_jiffies(1000)
+/* max delay if bearer has links */
+#define TIPC_LINK_REQ_SLOW msecs_to_jiffies(60000)
+/* indicates no timer in use */
+#define TIPC_LINK_REQ_INACTIVE 0xffffffff
/**
* struct tipc_link_req - 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)
@@ -58,31 +63,34 @@
struct tipc_link_req {
u32 bearer_id;
struct tipc_media_addr dest;
+ struct net *net;
u32 domain;
int num_nodes;
spinlock_t lock;
struct sk_buff *buf;
struct timer_list timer;
- unsigned int timer_intv;
+ unsigned long timer_intv;
};
/**
* tipc_disc_init_msg - initialize a link setup message
+ * @net: the applicable net namespace
* @type: message type (request or response)
* @b_ptr: ptr to bearer issuing message
*/
-static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
+static void tipc_disc_init_msg(struct net *net, struct sk_buff *buf, u32 type,
struct tipc_bearer *b_ptr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_msg *msg;
u32 dest_domain = b_ptr->domain;
msg = buf_msg(buf);
- tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
+ tipc_msg_init(net, msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
msg_set_non_seq(msg, 1);
- msg_set_node_sig(msg, tipc_random);
+ msg_set_node_sig(msg, tn->random);
msg_set_dest_domain(msg, dest_domain);
- msg_set_bc_netid(msg, tipc_net_id);
+ msg_set_bc_netid(msg, tn->net_id);
b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
}
@@ -107,11 +115,14 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
/**
* tipc_disc_rcv - handle incoming discovery message (request or response)
+ * @net: the applicable net namespace
* @buf: buffer containing message
* @bearer: bearer that message arrived on
*/
-void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
+void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
+ struct tipc_bearer *bearer)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node;
struct tipc_link *link;
struct tipc_media_addr maddr;
@@ -133,7 +144,7 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
kfree_skb(buf);
/* Ensure message from node is valid and communication is permitted */
- if (net_id != tipc_net_id)
+ if (net_id != tn->net_id)
return;
if (maddr.broadcast)
return;
@@ -142,20 +153,20 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
if (!tipc_addr_node_valid(onode))
return;
- if (in_own_node(onode)) {
+ if (in_own_node(net, onode)) {
if (memcmp(&maddr, &bearer->addr, sizeof(maddr)))
- disc_dupl_alert(bearer, tipc_own_addr, &maddr);
+ disc_dupl_alert(bearer, tn->own_addr, &maddr);
return;
}
- if (!tipc_in_scope(ddom, tipc_own_addr))
+ if (!tipc_in_scope(ddom, tn->own_addr))
return;
if (!tipc_in_scope(bearer->domain, onode))
return;
/* Locate, or if necessary, create, node: */
- node = tipc_node_find(onode);
+ node = tipc_node_find(net, onode);
if (!node)
- node = tipc_node_create(onode);
+ node = tipc_node_create(net, onode);
if (!node)
return;
@@ -244,8 +255,8 @@ void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
if (respond && (mtyp == DSC_REQ_MSG)) {
rbuf = tipc_buf_acquire(INT_H_SIZE);
if (rbuf) {
- tipc_disc_init_msg(rbuf, DSC_RESP_MSG, bearer);
- tipc_bearer_send(bearer->identity, rbuf, &maddr);
+ tipc_disc_init_msg(net, rbuf, DSC_RESP_MSG, bearer);
+ tipc_bearer_send(net, bearer->identity, rbuf, &maddr);
kfree_skb(rbuf);
}
}
@@ -265,7 +276,7 @@ static void disc_update(struct tipc_link_req *req)
if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) ||
(req->timer_intv > TIPC_LINK_REQ_FAST)) {
req->timer_intv = TIPC_LINK_REQ_INIT;
- k_start_timer(&req->timer, req->timer_intv);
+ mod_timer(&req->timer, jiffies + req->timer_intv);
}
}
}
@@ -295,12 +306,13 @@ void tipc_disc_remove_dest(struct tipc_link_req *req)
/**
* disc_timeout - send a periodic link setup request
- * @req: ptr to link request structure
+ * @data: ptr to link request structure
*
* Called whenever a link setup request timer associated with a bearer expires.
*/
-static void disc_timeout(struct tipc_link_req *req)
+static void disc_timeout(unsigned long data)
{
+ struct tipc_link_req *req = (struct tipc_link_req *)data;
int max_delay;
spin_lock_bh(&req->lock);
@@ -318,7 +330,7 @@ static void disc_timeout(struct tipc_link_req *req)
* hold at fast polling rate if don't have any associated nodes,
* otherwise hold at slow polling rate
*/
- tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
+ tipc_bearer_send(req->net, req->bearer_id, req->buf, &req->dest);
req->timer_intv *= 2;
@@ -329,20 +341,22 @@ static void disc_timeout(struct tipc_link_req *req)
if (req->timer_intv > max_delay)
req->timer_intv = max_delay;
- k_start_timer(&req->timer, req->timer_intv);
+ mod_timer(&req->timer, jiffies + req->timer_intv);
exit:
spin_unlock_bh(&req->lock);
}
/**
* tipc_disc_create - create object to send periodic link setup requests
+ * @net: the applicable net namespace
* @b_ptr: ptr to bearer issuing requests
* @dest: destination address for request messages
* @dest_domain: network domain to which links can be established
*
* Returns 0 if successful, otherwise -errno.
*/
-int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
+int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
+ struct tipc_media_addr *dest)
{
struct tipc_link_req *req;
@@ -356,17 +370,18 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
return -ENOMEM;
}
- tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
+ tipc_disc_init_msg(net, req->buf, DSC_REQ_MSG, b_ptr);
memcpy(&req->dest, dest, sizeof(*dest));
+ req->net = net;
req->bearer_id = b_ptr->identity;
req->domain = b_ptr->domain;
req->num_nodes = 0;
req->timer_intv = TIPC_LINK_REQ_INIT;
spin_lock_init(&req->lock);
- k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
- k_start_timer(&req->timer, req->timer_intv);
+ setup_timer(&req->timer, disc_timeout, (unsigned long)req);
+ mod_timer(&req->timer, jiffies + req->timer_intv);
b_ptr->link_req = req;
- tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
+ tipc_bearer_send(net, req->bearer_id, req->buf, &req->dest);
return 0;
}
@@ -376,28 +391,29 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
*/
void tipc_disc_delete(struct tipc_link_req *req)
{
- k_cancel_timer(&req->timer);
- k_term_timer(&req->timer);
+ del_timer_sync(&req->timer);
kfree_skb(req->buf);
kfree(req);
}
/**
* tipc_disc_reset - reset object to send periodic link setup requests
+ * @net: the applicable net namespace
* @b_ptr: ptr to bearer issuing requests
* @dest_domain: network domain to which links can be established
*/
-void tipc_disc_reset(struct tipc_bearer *b_ptr)
+void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr)
{
struct tipc_link_req *req = b_ptr->link_req;
spin_lock_bh(&req->lock);
- tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
+ tipc_disc_init_msg(net, req->buf, DSC_REQ_MSG, b_ptr);
+ req->net = net;
req->bearer_id = b_ptr->identity;
req->domain = b_ptr->domain;
req->num_nodes = 0;
req->timer_intv = TIPC_LINK_REQ_INIT;
- k_start_timer(&req->timer, req->timer_intv);
- tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
+ mod_timer(&req->timer, jiffies + req->timer_intv);
+ tipc_bearer_send(net, req->bearer_id, req->buf, &req->dest);
spin_unlock_bh(&req->lock);
}
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
index 515b57392f4d..c9b12770c5ed 100644
--- a/net/tipc/discover.h
+++ b/net/tipc/discover.h
@@ -39,11 +39,13 @@
struct tipc_link_req;
-int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest);
+int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
+ struct tipc_media_addr *dest);
void tipc_disc_delete(struct tipc_link_req *req);
-void tipc_disc_reset(struct tipc_bearer *b_ptr);
+void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr);
void tipc_disc_add_dest(struct tipc_link_req *req);
void tipc_disc_remove_dest(struct tipc_link_req *req);
-void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr);
+void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
+ struct tipc_bearer *b_ptr);
#endif
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 082c3b5b32a1..193bc1560677 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -101,19 +101,23 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
*/
#define START_CHANGEOVER 100000u
-static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
+static void link_handle_out_of_seq_msg(struct net *net,
+ struct tipc_link *l_ptr,
struct sk_buff *buf);
-static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf);
-static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr,
+static void tipc_link_proto_rcv(struct net *net, struct tipc_link *l_ptr,
+ struct sk_buff *buf);
+static int tipc_link_tunnel_rcv(struct net *net, struct tipc_node *n_ptr,
struct sk_buff **buf);
-static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance);
+static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol);
static void link_state_event(struct tipc_link *l_ptr, u32 event);
static void link_reset_statistics(struct tipc_link *l_ptr);
static void link_print(struct tipc_link *l_ptr, const char *str);
static void tipc_link_sync_xmit(struct tipc_link *l);
static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf);
-static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf);
-static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf);
+static int tipc_link_input(struct net *net, struct tipc_link *l,
+ struct sk_buff *buf);
+static int tipc_link_prepare_input(struct net *net, struct tipc_link *l,
+ struct sk_buff **buf);
/*
* Simple link routines
@@ -125,11 +129,13 @@ static unsigned int align(unsigned int i)
static void link_init_max_pkt(struct tipc_link *l_ptr)
{
+ struct tipc_node *node = l_ptr->owner;
+ struct tipc_net *tn = net_generic(node->net, tipc_net_id);
struct tipc_bearer *b_ptr;
u32 max_pkt;
rcu_read_lock();
- b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]);
+ b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);
if (!b_ptr) {
rcu_read_unlock();
return;
@@ -169,8 +175,9 @@ int tipc_link_is_active(struct tipc_link *l_ptr)
* link_timeout - handle expiration of link timer
* @l_ptr: pointer to link
*/
-static void link_timeout(struct tipc_link *l_ptr)
+static void link_timeout(unsigned long data)
{
+ struct tipc_link *l_ptr = (struct tipc_link *)data;
struct sk_buff *skb;
tipc_node_lock(l_ptr->owner);
@@ -217,9 +224,9 @@ static void link_timeout(struct tipc_link *l_ptr)
tipc_node_unlock(l_ptr->owner);
}
-static void link_set_timer(struct tipc_link *l_ptr, u32 time)
+static void link_set_timer(struct tipc_link *link, unsigned long time)
{
- k_start_timer(&l_ptr->timer, time);
+ mod_timer(&link->timer, jiffies + time);
}
/**
@@ -234,6 +241,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
struct tipc_bearer *b_ptr,
const struct tipc_media_addr *media_addr)
{
+ struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
struct tipc_link *l_ptr;
struct tipc_msg *msg;
char *if_name;
@@ -263,8 +271,8 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
l_ptr->addr = peer;
if_name = strchr(b_ptr->name, ':') + 1;
sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
- tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
- tipc_node(tipc_own_addr),
+ tipc_zone(tn->own_addr), tipc_cluster(tn->own_addr),
+ tipc_node(tn->own_addr),
if_name,
tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
/* note: peer i/f name is updated by reset/activate message */
@@ -278,9 +286,10 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
msg = l_ptr->pmsg;
- tipc_msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
+ tipc_msg_init(n_ptr->net, msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE,
+ l_ptr->addr);
msg_set_size(msg, sizeof(l_ptr->proto_msg));
- msg_set_session(msg, (tipc_random & 0xffff));
+ msg_set_session(msg, (tn->random & 0xffff));
msg_set_bearer_id(msg, b_ptr->identity);
strcpy((char *)msg_data(msg), if_name);
@@ -299,21 +308,22 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
tipc_node_attach_link(n_ptr, l_ptr);
- k_init_timer(&l_ptr->timer, (Handler)link_timeout,
- (unsigned long)l_ptr);
+ setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr);
link_state_event(l_ptr, STARTING_EVT);
return l_ptr;
}
-void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
+void tipc_link_delete_list(struct net *net, unsigned int bearer_id,
+ bool shutting_down)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_link *l_ptr;
struct tipc_node *n_ptr;
rcu_read_lock();
- list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+ list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
tipc_node_lock(n_ptr);
l_ptr = n_ptr->links[bearer_id];
if (l_ptr) {
@@ -350,10 +360,12 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
static bool link_schedule_user(struct tipc_link *link, u32 oport,
uint chain_sz, uint imp)
{
+ struct net *net = link->owner->net;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *buf;
- buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr,
- tipc_own_addr, oport, 0, 0);
+ buf = tipc_msg_create(net, SOCK_WAKEUP, 0, INT_H_SIZE, 0, tn->own_addr,
+ tn->own_addr, oport, 0, 0);
if (!buf)
return false;
TIPC_SKB_CB(buf)->chain_sz = chain_sz;
@@ -425,7 +437,7 @@ void tipc_link_reset(struct tipc_link *l_ptr)
return;
tipc_node_link_down(l_ptr->owner, l_ptr);
- tipc_bearer_remove_dest(l_ptr->bearer_id, l_ptr->addr);
+ tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr);
if (was_active_link && tipc_node_active_links(l_ptr->owner)) {
l_ptr->reset_checkpoint = checkpoint;
@@ -448,13 +460,14 @@ void tipc_link_reset(struct tipc_link *l_ptr)
link_reset_statistics(l_ptr);
}
-void tipc_link_reset_list(unsigned int bearer_id)
+void tipc_link_reset_list(struct net *net, unsigned int bearer_id)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_link *l_ptr;
struct tipc_node *n_ptr;
rcu_read_lock();
- list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+ list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
tipc_node_lock(n_ptr);
l_ptr = n_ptr->links[bearer_id];
if (l_ptr)
@@ -464,11 +477,14 @@ void tipc_link_reset_list(unsigned int bearer_id)
rcu_read_unlock();
}
-static void link_activate(struct tipc_link *l_ptr)
+static void link_activate(struct tipc_link *link)
{
- l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
- tipc_node_link_up(l_ptr->owner, l_ptr);
- tipc_bearer_add_dest(l_ptr->bearer_id, l_ptr->addr);
+ struct tipc_node *node = link->owner;
+
+ link->next_in_no = 1;
+ link->stats.recv_info = 1;
+ tipc_node_link_up(node, link);
+ tipc_bearer_add_dest(node->net, link->bearer_id, link->addr);
}
/**
@@ -479,7 +495,7 @@ static void link_activate(struct tipc_link *l_ptr)
static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
{
struct tipc_link *other;
- u32 cont_intv = l_ptr->continuity_interval;
+ unsigned long cont_intv = l_ptr->cont_intv;
if (l_ptr->flags & LINK_STOPPED)
return;
@@ -700,7 +716,8 @@ drop:
* Only the socket functions tipc_send_stream() and tipc_send_packet() need
* to act on the return value, since they may need to do more send attempts.
*/
-int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list)
+int __tipc_link_xmit(struct net *net, struct tipc_link *link,
+ struct sk_buff_head *list)
{
struct tipc_msg *msg = buf_msg(skb_peek(list));
uint psz = msg_size(msg);
@@ -733,13 +750,14 @@ int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list)
if (skb_queue_len(outqueue) < sndlim) {
__skb_queue_tail(outqueue, skb);
- tipc_bearer_send(link->bearer_id, skb, addr);
+ tipc_bearer_send(net, link->bearer_id,
+ skb, addr);
link->next_out = NULL;
link->unacked_window = 0;
} else if (tipc_msg_bundle(outqueue, skb, mtu)) {
link->stats.sent_bundled++;
continue;
- } else if (tipc_msg_make_bundle(outqueue, skb, mtu,
+ } else if (tipc_msg_make_bundle(net, outqueue, skb, mtu,
link->addr)) {
link->stats.sent_bundled++;
link->stats.sent_bundles++;
@@ -767,19 +785,21 @@ static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb)
struct sk_buff_head head;
skb2list(skb, &head);
- return __tipc_link_xmit(link, &head);
+ return __tipc_link_xmit(link->owner->net, link, &head);
}
-int tipc_link_xmit_skb(struct sk_buff *skb, u32 dnode, u32 selector)
+int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
+ u32 selector)
{
struct sk_buff_head head;
skb2list(skb, &head);
- return tipc_link_xmit(&head, dnode, selector);
+ return tipc_link_xmit(net, &head, dnode, selector);
}
/**
* tipc_link_xmit() is the general link level function for message sending
+ * @net: the applicable net namespace
* @list: chain of buffers containing message
* @dsz: amount of user data to be sent
* @dnode: address of destination node
@@ -787,30 +807,31 @@ int tipc_link_xmit_skb(struct sk_buff *skb, u32 dnode, u32 selector)
* Consumes the buffer chain, except when returning -ELINKCONG
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
*/
-int tipc_link_xmit(struct sk_buff_head *list, u32 dnode, u32 selector)
+int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
+ u32 selector)
{
struct tipc_link *link = NULL;
struct tipc_node *node;
int rc = -EHOSTUNREACH;
- node = tipc_node_find(dnode);
+ node = tipc_node_find(net, dnode);
if (node) {
tipc_node_lock(node);
link = node->active_links[selector & 1];
if (link)
- rc = __tipc_link_xmit(link, list);
+ rc = __tipc_link_xmit(net, link, list);
tipc_node_unlock(node);
}
if (link)
return rc;
- if (likely(in_own_node(dnode))) {
+ if (likely(in_own_node(net, dnode))) {
/* As a node local message chain never contains more than one
* buffer, we just need to dequeue one SKB buffer from the
* head list.
*/
- return tipc_sk_rcv(__skb_dequeue(list));
+ return tipc_sk_rcv(net, __skb_dequeue(list));
}
__skb_queue_purge(list);
@@ -835,7 +856,8 @@ static void tipc_link_sync_xmit(struct tipc_link *link)
return;
msg = buf_msg(skb);
- tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr);
+ tipc_msg_init(link->owner->net, msg, BCAST_PROTOCOL, STATE_MSG,
+ INT_H_SIZE, link->addr);
msg_set_last_bcast(msg, link->owner->bclink.acked);
__tipc_link_xmit_skb(link, skb);
}
@@ -890,7 +912,8 @@ void tipc_link_push_packets(struct tipc_link *l_ptr)
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
if (msg_user(msg) == MSG_BUNDLER)
TIPC_SKB_CB(skb)->bundling = false;
- tipc_bearer_send(l_ptr->bearer_id, skb,
+ tipc_bearer_send(l_ptr->owner->net,
+ l_ptr->bearer_id, skb,
&l_ptr->media_addr);
l_ptr->next_out = tipc_skb_queue_next(outqueue, skb);
} else {
@@ -923,6 +946,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
+ struct net *net = l_ptr->owner->net;
pr_warn("Retransmission failure on link <%s>\n", l_ptr->name);
@@ -940,7 +964,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
pr_cont("Outstanding acks: %lu\n",
(unsigned long) TIPC_SKB_CB(buf)->handle);
- n_ptr = tipc_bclink_retransmit_to();
+ n_ptr = tipc_bclink_retransmit_to(net);
tipc_node_lock(n_ptr);
tipc_addr_string_fill(addr_string, n_ptr->addr);
@@ -955,7 +979,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,
tipc_node_unlock(n_ptr);
- tipc_bclink_set_flags(TIPC_BCLINK_RESET);
+ tipc_bclink_set_flags(net, TIPC_BCLINK_RESET);
l_ptr->stale_count = 0;
}
}
@@ -987,7 +1011,8 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *skb,
msg = buf_msg(skb);
msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
- tipc_bearer_send(l_ptr->bearer_id, skb, &l_ptr->media_addr);
+ tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, skb,
+ &l_ptr->media_addr);
retransmits--;
l_ptr->stats.retransmitted++;
}
@@ -1063,14 +1088,16 @@ static int link_recv_buf_validate(struct sk_buff *buf)
/**
* tipc_rcv - process TIPC packets/messages arriving from off-node
+ * @net: the applicable net namespace
* @skb: TIPC packet
* @b_ptr: pointer to bearer message arrived on
*
* Invoked with no locks held. Bearer pointer must point to a valid bearer
* structure (i.e. cannot be NULL), but bearer can be inactive.
*/
-void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)
+void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff_head head;
struct tipc_node *n_ptr;
struct tipc_link *l_ptr;
@@ -1096,19 +1123,19 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)
if (unlikely(msg_non_seq(msg))) {
if (msg_user(msg) == LINK_CONFIG)
- tipc_disc_rcv(skb, b_ptr);
+ tipc_disc_rcv(net, skb, b_ptr);
else
- tipc_bclink_rcv(skb);
+ tipc_bclink_rcv(net, skb);
continue;
}
/* Discard unicast link messages destined for another node */
if (unlikely(!msg_short(msg) &&
- (msg_destnode(msg) != tipc_own_addr)))
+ (msg_destnode(msg) != tn->own_addr)))
goto discard;
/* Locate neighboring node that sent message */
- n_ptr = tipc_node_find(msg_prevnode(msg));
+ n_ptr = tipc_node_find(net, msg_prevnode(msg));
if (unlikely(!n_ptr))
goto discard;
tipc_node_lock(n_ptr);
@@ -1159,7 +1186,7 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)
/* Process the incoming packet */
if (unlikely(!link_working_working(l_ptr))) {
if (msg_user(msg) == LINK_PROTOCOL) {
- tipc_link_proto_rcv(l_ptr, skb);
+ tipc_link_proto_rcv(net, l_ptr, skb);
link_retrieve_defq(l_ptr, &head);
tipc_node_unlock(n_ptr);
continue;
@@ -1179,7 +1206,7 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)
/* Link is now in state WORKING_WORKING */
if (unlikely(seq_no != mod(l_ptr->next_in_no))) {
- link_handle_out_of_seq_msg(l_ptr, skb);
+ link_handle_out_of_seq_msg(net, l_ptr, skb);
link_retrieve_defq(l_ptr, &head);
tipc_node_unlock(n_ptr);
continue;
@@ -1193,13 +1220,13 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)
tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
}
- if (tipc_link_prepare_input(l_ptr, &skb)) {
+ if (tipc_link_prepare_input(net, l_ptr, &skb)) {
tipc_node_unlock(n_ptr);
continue;
}
tipc_node_unlock(n_ptr);
- if (tipc_link_input(l_ptr, skb) != 0)
+ if (tipc_link_input(net, l_ptr, skb) != 0)
goto discard;
continue;
unlock_discard:
@@ -1216,7 +1243,8 @@ discard:
*
* Node lock must be held
*/
-static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf)
+static int tipc_link_prepare_input(struct net *net, struct tipc_link *l,
+ struct sk_buff **buf)
{
struct tipc_node *n;
struct tipc_msg *msg;
@@ -1226,7 +1254,7 @@ static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf)
msg = buf_msg(*buf);
switch (msg_user(msg)) {
case CHANGEOVER_PROTOCOL:
- if (tipc_link_tunnel_rcv(n, buf))
+ if (tipc_link_tunnel_rcv(net, n, buf))
res = 0;
break;
case MSG_FRAGMENTER:
@@ -1258,7 +1286,8 @@ static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf)
/**
* tipc_link_input - Deliver message too higher layers
*/
-static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf)
+static int tipc_link_input(struct net *net, struct tipc_link *l,
+ struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
int res = 0;
@@ -1269,13 +1298,13 @@ static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf)
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
case CONN_MANAGER:
- tipc_sk_rcv(buf);
+ tipc_sk_rcv(net, buf);
break;
case NAME_DISTRIBUTOR:
- tipc_named_rcv(buf);
+ tipc_named_rcv(net, buf);
break;
case MSG_BUNDLER:
- tipc_link_bundle_rcv(buf);
+ tipc_link_bundle_rcv(net, buf);
break;
default:
res = -EINVAL;
@@ -1325,13 +1354,14 @@ u32 tipc_link_defer_pkt(struct sk_buff_head *list, struct sk_buff *skb)
/*
* link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
*/
-static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
+static void link_handle_out_of_seq_msg(struct net *net,
+ struct tipc_link *l_ptr,
struct sk_buff *buf)
{
u32 seq_no = buf_seqno(buf);
if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
- tipc_link_proto_rcv(l_ptr, buf);
+ tipc_link_proto_rcv(net, l_ptr, buf);
return;
}
@@ -1381,7 +1411,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
msg_set_type(msg, msg_typ);
msg_set_net_plane(msg, l_ptr->net_plane);
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
- msg_set_last_bcast(msg, tipc_bclink_get_last_sent());
+ msg_set_last_bcast(msg, tipc_bclink_get_last_sent(l_ptr->owner->net));
if (msg_typ == STATE_MSG) {
u32 next_sent = mod(l_ptr->next_out_no);
@@ -1445,7 +1475,8 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
buf->priority = TC_PRIO_CONTROL;
- tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr);
+ tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, buf,
+ &l_ptr->media_addr);
l_ptr->unacked_window = 0;
kfree_skb(buf);
}
@@ -1455,8 +1486,10 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
* Note that network plane id propagates through the network, and may
* change at any time. The node with lowest address rules
*/
-static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
+static void tipc_link_proto_rcv(struct net *net, struct tipc_link *l_ptr,
+ struct sk_buff *buf)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 rec_gap = 0;
u32 max_pkt_info;
u32 max_pkt_ack;
@@ -1468,7 +1501,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
goto exit;
if (l_ptr->net_plane != msg_net_plane(msg))
- if (tipc_own_addr > msg_prevnode(msg))
+ if (tn->own_addr > msg_prevnode(msg))
l_ptr->net_plane = msg_net_plane(msg);
switch (msg_type(msg)) {
@@ -1571,7 +1604,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
/* Protocol message before retransmits, reduce loss risk */
if (l_ptr->owner->bclink.recv_permitted)
- tipc_bclink_update_link_state(l_ptr->owner,
+ tipc_bclink_update_link_state(net, l_ptr->owner,
msg_last_bcast(msg));
if (rec_gap || (msg_probe(msg))) {
@@ -1636,8 +1669,8 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr)
if (!tunnel)
return;
- tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
+ tipc_msg_init(l_ptr->owner->net, &tunnel_hdr, CHANGEOVER_PROTOCOL,
+ ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
msg_set_msgcnt(&tunnel_hdr, msgcount);
@@ -1694,8 +1727,8 @@ void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr,
struct sk_buff *skb;
struct tipc_msg tunnel_hdr;
- tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
+ tipc_msg_init(l_ptr->owner->net, &tunnel_hdr, CHANGEOVER_PROTOCOL,
+ DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_msgcnt(&tunnel_hdr, skb_queue_len(&l_ptr->outqueue));
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
skb_queue_walk(&l_ptr->outqueue, skb) {
@@ -1748,7 +1781,7 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
/* tipc_link_dup_rcv(): Receive a tunnelled DUPLICATE_MSG packet.
* Owner node is locked.
*/
-static void tipc_link_dup_rcv(struct tipc_link *l_ptr,
+static void tipc_link_dup_rcv(struct net *net, struct tipc_link *l_ptr,
struct sk_buff *t_buf)
{
struct sk_buff *buf;
@@ -1763,7 +1796,7 @@ static void tipc_link_dup_rcv(struct tipc_link *l_ptr,
}
/* Add buffer to deferred queue, if applicable: */
- link_handle_out_of_seq_msg(l_ptr, buf);
+ link_handle_out_of_seq_msg(net, l_ptr, buf);
}
/* tipc_link_failover_rcv(): Receive a tunnelled ORIGINAL_MSG packet
@@ -1817,7 +1850,7 @@ exit:
* returned to the active link for delivery upwards.
* Owner node is locked.
*/
-static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr,
+static int tipc_link_tunnel_rcv(struct net *net, struct tipc_node *n_ptr,
struct sk_buff **buf)
{
struct sk_buff *t_buf = *buf;
@@ -1835,7 +1868,7 @@ static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr,
goto exit;
if (msg_type(t_msg) == DUPLICATE_MSG)
- tipc_link_dup_rcv(l_ptr, t_buf);
+ tipc_link_dup_rcv(net, l_ptr, t_buf);
else if (msg_type(t_msg) == ORIGINAL_MSG)
*buf = tipc_link_failover_rcv(l_ptr, t_buf);
else
@@ -1848,7 +1881,7 @@ exit:
/*
* Bundler functionality:
*/
-void tipc_link_bundle_rcv(struct sk_buff *buf)
+void tipc_link_bundle_rcv(struct net *net, struct sk_buff *buf)
{
u32 msgcount = msg_msgcnt(buf_msg(buf));
u32 pos = INT_H_SIZE;
@@ -1865,13 +1898,13 @@ void tipc_link_bundle_rcv(struct sk_buff *buf)
pos += align(msg_size(omsg));
if (msg_isdata(omsg)) {
if (unlikely(msg_type(omsg) == TIPC_MCAST_MSG))
- tipc_sk_mcast_rcv(obuf);
+ tipc_sk_mcast_rcv(net, obuf);
else
- tipc_sk_rcv(obuf);
+ tipc_sk_rcv(net, obuf);
} else if (msg_user(omsg) == CONN_MANAGER) {
- tipc_sk_rcv(obuf);
+ tipc_sk_rcv(net, obuf);
} else if (msg_user(omsg) == NAME_DISTRIBUTOR) {
- tipc_named_rcv(obuf);
+ tipc_named_rcv(net, obuf);
} else {
pr_warn("Illegal bundled msg: %u\n", msg_user(omsg));
kfree_skb(obuf);
@@ -1880,15 +1913,16 @@ void tipc_link_bundle_rcv(struct sk_buff *buf)
kfree_skb(buf);
}
-static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance)
+static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol)
{
- if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL))
+ unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4;
+
+ if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL))
return;
- l_ptr->tolerance = tolerance;
- l_ptr->continuity_interval =
- ((tolerance / 4) > 500) ? 500 : tolerance / 4;
- l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
+ l_ptr->tolerance = tol;
+ l_ptr->cont_intv = msecs_to_jiffies(intv);
+ l_ptr->abort_limit = tol / (jiffies_to_msecs(l_ptr->cont_intv) / 4);
}
void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
@@ -1911,14 +1945,17 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
}
/* tipc_link_find_owner - locate owner node of link by link's name
+ * @net: the applicable net namespace
* @name: pointer to link name string
* @bearer_id: pointer to index in 'node->links' array where the link was found.
*
* Returns pointer to node owning the link, or 0 if no matching link is found.
*/
-static struct tipc_node *tipc_link_find_owner(const char *link_name,
+static struct tipc_node *tipc_link_find_owner(struct net *net,
+ const char *link_name,
unsigned int *bearer_id)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_link *l_ptr;
struct tipc_node *n_ptr;
struct tipc_node *found_node = NULL;
@@ -1926,7 +1963,7 @@ static struct tipc_node *tipc_link_find_owner(const char *link_name,
*bearer_id = 0;
rcu_read_lock();
- list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+ list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
tipc_node_lock(n_ptr);
for (i = 0; i < MAX_BEARERS; i++) {
l_ptr = n_ptr->links[i];
@@ -1970,6 +2007,7 @@ static int link_value_is_valid(u16 cmd, u32 new_value)
/**
* link_cmd_set_value - change priority/tolerance/window for link/bearer/media
+ * @net: the applicable net namespace
* @name: ptr to link, bearer, or media name
* @new_value: new value of link, bearer, or media setting
* @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*)
@@ -1978,7 +2016,8 @@ static int link_value_is_valid(u16 cmd, u32 new_value)
*
* Returns 0 if value updated and negative value on error.
*/
-static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
+static int link_cmd_set_value(struct net *net, const char *name, u32 new_value,
+ u16 cmd)
{
struct tipc_node *node;
struct tipc_link *l_ptr;
@@ -1987,7 +2026,7 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
int bearer_id;
int res = 0;
- node = tipc_link_find_owner(name, &bearer_id);
+ node = tipc_link_find_owner(net, name, &bearer_id);
if (node) {
tipc_node_lock(node);
l_ptr = node->links[bearer_id];
@@ -2016,7 +2055,7 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
return res;
}
- b_ptr = tipc_bearer_find(name);
+ b_ptr = tipc_bearer_find(net, name);
if (b_ptr) {
switch (cmd) {
case TIPC_CMD_SET_LINK_TOL:
@@ -2055,8 +2094,8 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
return res;
}
-struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space,
- u16 cmd)
+struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
+ int req_tlv_space, u16 cmd)
{
struct tipc_link_config *args;
u32 new_value;
@@ -2074,13 +2113,13 @@ struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space
if (!strcmp(args->name, tipc_bclink_name)) {
if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
- (tipc_bclink_set_queue_limits(new_value) == 0))
+ (tipc_bclink_set_queue_limits(net, new_value) == 0))
return tipc_cfg_reply_none();
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change setting on broadcast link)");
}
- res = link_cmd_set_value(args->name, new_value, cmd);
+ res = link_cmd_set_value(net, args->name, new_value, cmd);
if (res)
return tipc_cfg_reply_error_string("cannot change link setting");
@@ -2098,7 +2137,9 @@ static void link_reset_statistics(struct tipc_link *l_ptr)
l_ptr->stats.recv_info = l_ptr->next_in_no;
}
-struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
+ const void *req_tlv_area,
+ int req_tlv_space)
{
char *link_name;
struct tipc_link *l_ptr;
@@ -2110,11 +2151,11 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
link_name = (char *)TLV_DATA(req_tlv_area);
if (!strcmp(link_name, tipc_bclink_name)) {
- if (tipc_bclink_reset_stats())
+ if (tipc_bclink_reset_stats(net))
return tipc_cfg_reply_error_string("link not found");
return tipc_cfg_reply_none();
}
- node = tipc_link_find_owner(link_name, &bearer_id);
+ node = tipc_link_find_owner(net, link_name, &bearer_id);
if (!node)
return tipc_cfg_reply_error_string("link not found");
@@ -2139,13 +2180,15 @@ static u32 percent(u32 count, u32 total)
/**
* tipc_link_stats - print link statistics
+ * @net: the applicable net namespace
* @name: link name
* @buf: print buffer area
* @buf_size: size of print buffer area
*
* Returns length of print buffer data string (or 0 if error)
*/
-static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
+static int tipc_link_stats(struct net *net, const char *name, char *buf,
+ const u32 buf_size)
{
struct tipc_link *l;
struct tipc_stats *s;
@@ -2156,9 +2199,9 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
int ret;
if (!strcmp(name, tipc_bclink_name))
- return tipc_bclink_stats(buf, buf_size);
+ return tipc_bclink_stats(net, buf, buf_size);
- node = tipc_link_find_owner(name, &bearer_id);
+ node = tipc_link_find_owner(net, name, &bearer_id);
if (!node)
return 0;
@@ -2235,7 +2278,9 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
return ret;
}
-struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
+ const void *req_tlv_area,
+ int req_tlv_space)
{
struct sk_buff *buf;
struct tlv_desc *rep_tlv;
@@ -2253,7 +2298,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s
rep_tlv = (struct tlv_desc *)buf->data;
pb = TLV_DATA(rep_tlv);
pb_len = ULTRA_STRING_MAX_LEN;
- str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area),
+ str_len = tipc_link_stats(net, (char *)TLV_DATA(req_tlv_area),
pb, pb_len);
if (!str_len) {
kfree_skb(buf);
@@ -2266,39 +2311,13 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s
return buf;
}
-/**
- * tipc_link_get_max_pkt - get maximum packet size to use when sending to destination
- * @dest: network address of destination node
- * @selector: used to select from set of active links
- *
- * If no active link can be found, uses default maximum packet size.
- */
-u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
-{
- struct tipc_node *n_ptr;
- struct tipc_link *l_ptr;
- u32 res = MAX_PKT_DEFAULT;
-
- if (dest == tipc_own_addr)
- return MAX_MSG_SIZE;
-
- n_ptr = tipc_node_find(dest);
- if (n_ptr) {
- tipc_node_lock(n_ptr);
- l_ptr = n_ptr->active_links[selector & 1];
- if (l_ptr)
- res = l_ptr->max_pkt;
- tipc_node_unlock(n_ptr);
- }
- return res;
-}
-
static void link_print(struct tipc_link *l_ptr, const char *str)
{
+ struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);
struct tipc_bearer *b_ptr;
rcu_read_lock();
- b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]);
+ b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);
if (b_ptr)
pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name);
rcu_read_unlock();
@@ -2362,6 +2381,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)
struct tipc_link *link;
struct tipc_node *node;
struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
+ struct net *net = genl_info_net(info);
if (!info->attrs[TIPC_NLA_LINK])
return -EINVAL;
@@ -2377,7 +2397,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)
name = nla_data(attrs[TIPC_NLA_LINK_NAME]);
- node = tipc_link_find_owner(name, &bearer_id);
+ node = tipc_link_find_owner(net, name, &bearer_id);
if (!node)
return -EINVAL;
@@ -2493,12 +2513,14 @@ msg_full:
}
/* Caller should hold appropriate locks to protect the link */
-static int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link)
+static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
+ struct tipc_link *link)
{
int err;
void *hdr;
struct nlattr *attrs;
struct nlattr *prop;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
NLM_F_MULTI, TIPC_NL_LINK_GET);
@@ -2512,7 +2534,7 @@ static int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link)
if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, link->name))
goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST,
- tipc_cluster_mask(tipc_own_addr)))
+ tipc_cluster_mask(tn->own_addr)))
goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->max_pkt))
goto attr_msg_full;
@@ -2562,9 +2584,8 @@ msg_full:
}
/* Caller should hold node lock */
-static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,
- struct tipc_node *node,
- u32 *prev_link)
+static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
+ struct tipc_node *node, u32 *prev_link)
{
u32 i;
int err;
@@ -2575,7 +2596,7 @@ static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,
if (!node->links[i])
continue;
- err = __tipc_nl_add_link(msg, node->links[i]);
+ err = __tipc_nl_add_link(net, msg, node->links[i]);
if (err)
return err;
}
@@ -2586,6 +2607,8 @@ static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,
int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct net *net = sock_net(skb->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node;
struct tipc_nl_msg msg;
u32 prev_node = cb->args[0];
@@ -2603,7 +2626,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
if (prev_node) {
- node = tipc_node_find(prev_node);
+ node = tipc_node_find(net, prev_node);
if (!node) {
/* We never set seq or call nl_dump_check_consistent()
* this means that setting prev_seq here will cause the
@@ -2615,9 +2638,11 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
goto out;
}
- list_for_each_entry_continue_rcu(node, &tipc_node_list, list) {
+ list_for_each_entry_continue_rcu(node, &tn->node_list,
+ list) {
tipc_node_lock(node);
- err = __tipc_nl_add_node_links(&msg, node, &prev_link);
+ err = __tipc_nl_add_node_links(net, &msg, node,
+ &prev_link);
tipc_node_unlock(node);
if (err)
goto out;
@@ -2625,13 +2650,14 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
prev_node = node->addr;
}
} else {
- err = tipc_nl_add_bc_link(&msg);
+ err = tipc_nl_add_bc_link(net, &msg);
if (err)
goto out;
- list_for_each_entry_rcu(node, &tipc_node_list, list) {
+ list_for_each_entry_rcu(node, &tn->node_list, list) {
tipc_node_lock(node);
- err = __tipc_nl_add_node_links(&msg, node, &prev_link);
+ err = __tipc_nl_add_node_links(net, &msg, node,
+ &prev_link);
tipc_node_unlock(node);
if (err)
goto out;
@@ -2652,6 +2678,7 @@ out:
int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)
{
+ struct net *net = genl_info_net(info);
struct sk_buff *ans_skb;
struct tipc_nl_msg msg;
struct tipc_link *link;
@@ -2664,7 +2691,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]);
- node = tipc_link_find_owner(name, &bearer_id);
+ node = tipc_link_find_owner(net, name, &bearer_id);
if (!node)
return -EINVAL;
@@ -2683,7 +2710,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)
goto err_out;
}
- err = __tipc_nl_add_link(&msg, link);
+ err = __tipc_nl_add_link(net, &msg, link);
if (err)
goto err_out;
@@ -2706,6 +2733,7 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)
struct tipc_link *link;
struct tipc_node *node;
struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
+ struct net *net = genl_info_net(info);
if (!info->attrs[TIPC_NLA_LINK])
return -EINVAL;
@@ -2722,13 +2750,13 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)
link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]);
if (strcmp(link_name, tipc_bclink_name) == 0) {
- err = tipc_bclink_reset_stats();
+ err = tipc_bclink_reset_stats(net);
if (err)
return err;
return 0;
}
- node = tipc_link_find_owner(link_name, &bearer_id);
+ node = tipc_link_find_owner(net, link_name, &bearer_id);
if (!node)
return -EINVAL;
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 55812e87ca1e..9df7fa4d3bdd 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -41,6 +41,10 @@
#include "msg.h"
#include "node.h"
+/* TIPC-specific error codes
+*/
+#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
+
/* Out-of-range value for link sequence numbers
*/
#define INVALID_LINK_SEQ 0x10000
@@ -105,7 +109,7 @@ struct tipc_stats {
* @peer_bearer_id: bearer id used by link's peer endpoint
* @bearer_id: local bearer id used by link
* @tolerance: minimum link continuity loss needed to reset link [in ms]
- * @continuity_interval: link continuity testing interval [in ms]
+ * @cont_intv: link continuity testing interval
* @abort_limit: # of unacknowledged continuity probes needed to reset link
* @state: current state of link FSM
* @fsm_msg_cnt: # of protocol messages link FSM has sent in current state
@@ -146,7 +150,7 @@ struct tipc_link {
u32 peer_bearer_id;
u32 bearer_id;
u32 tolerance;
- u32 continuity_interval;
+ unsigned long cont_intv;
u32 abort_limit;
int state;
u32 fsm_msg_cnt;
@@ -196,28 +200,32 @@ struct tipc_port;
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
struct tipc_bearer *b_ptr,
const struct tipc_media_addr *media_addr);
-void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down);
+void tipc_link_delete_list(struct net *net, unsigned int bearer_id,
+ bool shutting_down);
void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr, struct tipc_link *dest);
void tipc_link_reset_fragments(struct tipc_link *l_ptr);
int tipc_link_is_up(struct tipc_link *l_ptr);
int tipc_link_is_active(struct tipc_link *l_ptr);
void tipc_link_purge_queues(struct tipc_link *l_ptr);
-struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area,
- int req_tlv_space,
- u16 cmd);
-struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area,
+struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
+ int req_tlv_space, u16 cmd);
+struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
+ const void *req_tlv_area,
int req_tlv_space);
-struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
+struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
+ const void *req_tlv_area,
int req_tlv_space);
void tipc_link_reset_all(struct tipc_node *node);
void tipc_link_reset(struct tipc_link *l_ptr);
-void tipc_link_reset_list(unsigned int bearer_id);
-int tipc_link_xmit_skb(struct sk_buff *skb, u32 dest, u32 selector);
-int tipc_link_xmit(struct sk_buff_head *list, u32 dest, u32 selector);
-int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list);
-u32 tipc_link_get_max_pkt(u32 dest, u32 selector);
-void tipc_link_bundle_rcv(struct sk_buff *buf);
+void tipc_link_reset_list(struct net *net, unsigned int bearer_id);
+int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,
+ u32 selector);
+int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dest,
+ u32 selector);
+int __tipc_link_xmit(struct net *net, struct tipc_link *link,
+ struct sk_buff_head *list);
+void tipc_link_bundle_rcv(struct net *net, struct sk_buff *buf);
void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
u32 gap, u32 tolerance, u32 priority, u32 acked_mtu);
void tipc_link_push_packets(struct tipc_link *l_ptr);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index a687b30a699c..18aba9e99345 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -34,6 +34,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <net/sock.h>
#include "core.h"
#include "msg.h"
#include "addr.h"
@@ -46,25 +47,50 @@ static unsigned int align(unsigned int i)
return (i + 3) & ~3u;
}
-void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
- u32 destnode)
+/**
+ * tipc_buf_acquire - creates a TIPC message buffer
+ * @size: message size (including TIPC header)
+ *
+ * Returns 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)
{
+ struct sk_buff *skb;
+ unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
+
+ skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
+ if (skb) {
+ skb_reserve(skb, BUF_HEADROOM);
+ skb_put(skb, size);
+ skb->next = NULL;
+ }
+ return skb;
+}
+
+void tipc_msg_init(struct net *net, struct tipc_msg *m, u32 user, u32 type,
+ u32 hsize, u32 destnode)
+{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
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, tipc_own_addr);
+ msg_set_prevnode(m, tn->own_addr);
msg_set_type(m, type);
if (hsize > SHORT_H_SIZE) {
- msg_set_orignode(m, tipc_own_addr);
+ msg_set_orignode(m, tn->own_addr);
msg_set_destnode(m, destnode);
}
}
-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 sk_buff *tipc_msg_create(struct net *net, 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;
@@ -74,7 +100,7 @@ struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
return NULL;
msg = buf_msg(buf);
- tipc_msg_init(msg, user, type, hdr_sz, dnode);
+ tipc_msg_init(net, msg, user, type, hdr_sz, dnode);
msg_set_size(msg, hdr_sz + data_sz);
msg_set_prevnode(msg, onode);
msg_set_origport(msg, oport);
@@ -170,8 +196,8 @@ err:
*
* Returns 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 tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,
+ int offset, int dsz, int pktmax, struct sk_buff_head *list)
{
int mhsz = msg_hdr_sz(mhdr);
int msz = mhsz + dsz;
@@ -191,6 +217,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
skb = tipc_buf_acquire(msz);
if (unlikely(!skb))
return -ENOMEM;
+ skb_orphan(skb);
__skb_queue_tail(list, skb);
skb_copy_to_linear_data(skb, mhdr, mhsz);
pktpos = skb->data + mhsz;
@@ -202,8 +229,8 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
}
/* Prepare reusable fragment header */
- tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
- INT_H_SIZE, msg_destnode(mhdr));
+ tipc_msg_init(net, &pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE,
+ msg_destnode(mhdr));
msg_set_size(&pkthdr, pktmax);
msg_set_fragm_no(&pkthdr, pktno);
@@ -211,6 +238,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
skb = tipc_buf_acquire(pktmax);
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);
@@ -244,6 +272,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
rc = -ENOMEM;
goto error;
}
+ skb_orphan(skb);
__skb_queue_tail(list, skb);
msg_set_type(&pkthdr, FRAGMENT);
msg_set_size(&pkthdr, pktsz);
@@ -312,8 +341,8 @@ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)
* Replaces buffer if successful
* Returns true if success, otherwise false
*/
-bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,
- u32 mtu, u32 dnode)
+bool tipc_msg_make_bundle(struct net *net, struct sk_buff_head *list,
+ struct sk_buff *skb, u32 mtu, u32 dnode)
{
struct sk_buff *bskb;
struct tipc_msg *bmsg;
@@ -336,7 +365,7 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,
skb_trim(bskb, INT_H_SIZE);
bmsg = buf_msg(bskb);
- tipc_msg_init(bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode);
+ tipc_msg_init(net, bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode);
msg_set_seqno(bmsg, msg_seqno(msg));
msg_set_ack(bmsg, msg_ack(msg));
msg_set_bcast_ack(bmsg, msg_bcast_ack(msg));
@@ -353,8 +382,10 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,
* Consumes buffer if failure
* Returns true if success, otherwise false
*/
-bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err)
+bool tipc_msg_reverse(struct net *net, struct sk_buff *buf, u32 *dnode,
+ int err)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_msg *msg = buf_msg(buf);
uint imp = msg_importance(msg);
struct tipc_msg ohdr;
@@ -374,7 +405,7 @@ bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err)
msg_set_errcode(msg, err);
msg_set_origport(msg, msg_destport(&ohdr));
msg_set_destport(msg, msg_origport(&ohdr));
- msg_set_prevnode(msg, tipc_own_addr);
+ msg_set_prevnode(msg, tn->own_addr);
if (!msg_short(msg)) {
msg_set_orignode(msg, msg_destnode(&ohdr));
msg_set_destnode(msg, msg_orignode(&ohdr));
@@ -399,7 +430,7 @@ exit:
* Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error
* code if message to be rejected
*/
-int tipc_msg_eval(struct sk_buff *buf, u32 *dnode)
+int tipc_msg_eval(struct net *net, struct sk_buff *buf, u32 *dnode)
{
struct tipc_msg *msg = buf_msg(buf);
u32 dport;
@@ -413,8 +444,8 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode)
if (msg_reroute_cnt(msg) > 0)
return -TIPC_ERR_NO_NAME;
- *dnode = addr_domain(msg_lookup_scope(msg));
- dport = tipc_nametbl_translate(msg_nametype(msg),
+ *dnode = addr_domain(net, msg_lookup_scope(msg));
+ dport = tipc_nametbl_translate(net, msg_nametype(msg),
msg_nameinst(msg),
dnode);
if (!dport)
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index d5c83d7ecb47..526ef345b70e 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -37,7 +37,7 @@
#ifndef _TIPC_MSG_H
#define _TIPC_MSG_H
-#include "bearer.h"
+#include <linux/tipc.h>
/*
* Constants and routines used to read and write TIPC payload message headers
@@ -77,11 +77,37 @@
#define TIPC_MEDIA_ADDR_OFFSET 5
+/**
+ * TIPC message buffer code
+ *
+ * TIPC message buffer headroom reserves space for the worst-case
+ * link-level device header (in case the message is sent off-node).
+ *
+ * Note: Headroom should be a multiple of 4 to ensure the TIPC header fields
+ * are word aligned for quicker access
+ */
+#define BUF_HEADROOM LL_MAX_HEADER
+
+struct tipc_skb_cb {
+ void *handle;
+ struct sk_buff *tail;
+ bool deferred;
+ bool wakeup_pending;
+ bool bundling;
+ u16 chain_sz;
+ u16 chain_imp;
+};
+
+#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
struct tipc_msg {
__be32 hdr[15];
};
+static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
+{
+ return (struct tipc_msg *)skb->data;
+}
static inline u32 msg_word(struct tipc_msg *m, u32 pos)
{
@@ -721,27 +747,21 @@ static inline u32 msg_tot_origport(struct tipc_msg *m)
return msg_origport(m);
}
-bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err);
-
-int tipc_msg_eval(struct sk_buff *buf, u32 *dnode);
-
-void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
- u32 destnode);
-
-struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
- uint data_sz, u32 dnode, u32 onode,
- u32 dport, u32 oport, int errcode);
-
+struct sk_buff *tipc_buf_acquire(u32 size);
+bool tipc_msg_reverse(struct net *net, struct sk_buff *buf, u32 *dnode,
+ int err);
+int tipc_msg_eval(struct net *net, struct sk_buff *buf, u32 *dnode);
+void tipc_msg_init(struct net *net, struct tipc_msg *m, u32 user, u32 type,
+ u32 hsize, u32 destnode);
+struct sk_buff *tipc_msg_create(struct net *net, uint user, uint type,
+ uint hdr_sz, uint data_sz, u32 dnode,
+ u32 onode, u32 dport, u32 oport, int errcode);
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
-
bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu);
-
-bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,
- u32 mtu, u32 dnode);
-
-int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
- int dsz, int mtu, struct sk_buff_head *list);
-
+bool tipc_msg_make_bundle(struct net *net, struct sk_buff_head *list,
+ struct sk_buff *skb, u32 mtu, u32 dnode);
+int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,
+ int offset, int dsz, int mtu, struct sk_buff_head *list);
struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list);
#endif
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index ba6083dca95b..7f31cd4badc4 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -68,29 +68,32 @@ static void publ_to_item(struct distr_item *i, struct publication *p)
/**
* named_prepare_buf - allocate & initialize a publication message
*/
-static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
+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);
struct tipc_msg *msg;
if (buf != NULL) {
msg = buf_msg(buf);
- tipc_msg_init(msg, NAME_DISTRIBUTOR, type, INT_H_SIZE, dest);
+ tipc_msg_init(net, msg, NAME_DISTRIBUTOR, type, INT_H_SIZE,
+ dest);
msg_set_size(msg, INT_H_SIZE + size);
}
return buf;
}
-void named_cluster_distribute(struct sk_buff *skb)
+void named_cluster_distribute(struct net *net, struct sk_buff *skb)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *oskb;
struct tipc_node *node;
u32 dnode;
rcu_read_lock();
- list_for_each_entry_rcu(node, &tipc_node_list, list) {
+ list_for_each_entry_rcu(node, &tn->node_list, list) {
dnode = node->addr;
- if (in_own_node(dnode))
+ if (in_own_node(net, dnode))
continue;
if (!tipc_node_active_links(node))
continue;
@@ -98,7 +101,7 @@ void named_cluster_distribute(struct sk_buff *skb)
if (!oskb)
break;
msg_set_destnode(buf_msg(oskb), dnode);
- tipc_link_xmit_skb(oskb, dnode, dnode);
+ tipc_link_xmit_skb(net, oskb, dnode, dnode);
}
rcu_read_unlock();
@@ -108,18 +111,19 @@ void named_cluster_distribute(struct sk_buff *skb)
/**
* tipc_named_publish - tell other nodes about a new publication by this node
*/
-struct sk_buff *tipc_named_publish(struct publication *publ)
+struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *buf;
struct distr_item *item;
list_add_tail_rcu(&publ->local_list,
- &tipc_nametbl->publ_list[publ->scope]);
+ &tn->nametbl->publ_list[publ->scope]);
if (publ->scope == TIPC_NODE_SCOPE)
return NULL;
- buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
+ buf = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);
if (!buf) {
pr_warn("Publication distribution failure\n");
return NULL;
@@ -133,7 +137,7 @@ struct sk_buff *tipc_named_publish(struct publication *publ)
/**
* tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
*/
-struct sk_buff *tipc_named_withdraw(struct publication *publ)
+struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ)
{
struct sk_buff *buf;
struct distr_item *item;
@@ -143,7 +147,7 @@ struct sk_buff *tipc_named_withdraw(struct publication *publ)
if (publ->scope == TIPC_NODE_SCOPE)
return NULL;
- buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
+ buf = named_prepare_buf(net, WITHDRAWAL, ITEM_SIZE, 0);
if (!buf) {
pr_warn("Withdrawal distribution failure\n");
return NULL;
@@ -160,19 +164,21 @@ struct sk_buff *tipc_named_withdraw(struct publication *publ)
* @dnode: node to be updated
* @pls: linked list of publication items to be packed into buffer chain
*/
-static void named_distribute(struct sk_buff_head *list, u32 dnode,
- struct list_head *pls)
+static void named_distribute(struct net *net, struct sk_buff_head *list,
+ u32 dnode, struct list_head *pls)
{
struct publication *publ;
struct sk_buff *skb = NULL;
struct distr_item *item = NULL;
- uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE;
+ uint msg_dsz = (tipc_node_get_mtu(net, dnode, 0) / ITEM_SIZE) *
+ ITEM_SIZE;
uint msg_rem = msg_dsz;
list_for_each_entry(publ, pls, local_list) {
/* Prepare next buffer: */
if (!skb) {
- skb = named_prepare_buf(PUBLICATION, msg_rem, dnode);
+ skb = named_prepare_buf(net, PUBLICATION, msg_rem,
+ dnode);
if (!skb) {
pr_warn("Bulk publication failure\n");
return;
@@ -202,30 +208,32 @@ static void named_distribute(struct sk_buff_head *list, u32 dnode,
/**
* tipc_named_node_up - tell specified node about all publications by this node
*/
-void tipc_named_node_up(u32 dnode)
+void tipc_named_node_up(struct net *net, u32 dnode)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff_head head;
__skb_queue_head_init(&head);
rcu_read_lock();
- named_distribute(&head, dnode,
- &tipc_nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
- named_distribute(&head, dnode,
- &tipc_nametbl->publ_list[TIPC_ZONE_SCOPE]);
+ named_distribute(net, &head, dnode,
+ &tn->nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
+ named_distribute(net, &head, dnode,
+ &tn->nametbl->publ_list[TIPC_ZONE_SCOPE]);
rcu_read_unlock();
- tipc_link_xmit(&head, dnode, dnode);
+ tipc_link_xmit(net, &head, dnode, dnode);
}
-static void tipc_publ_subscribe(struct publication *publ, u32 addr)
+static void tipc_publ_subscribe(struct net *net, struct publication *publ,
+ u32 addr)
{
struct tipc_node *node;
- if (in_own_node(addr))
+ if (in_own_node(net, addr))
return;
- node = tipc_node_find(addr);
+ node = tipc_node_find(net, addr);
if (!node) {
pr_warn("Node subscription rejected, unknown node 0x%x\n",
addr);
@@ -237,11 +245,12 @@ static void tipc_publ_subscribe(struct publication *publ, u32 addr)
tipc_node_unlock(node);
}
-static void tipc_publ_unsubscribe(struct publication *publ, u32 addr)
+static void tipc_publ_unsubscribe(struct net *net, struct publication *publ,
+ u32 addr)
{
struct tipc_node *node;
- node = tipc_node_find(addr);
+ node = tipc_node_find(net, addr);
if (!node)
return;
@@ -256,16 +265,17 @@ static void tipc_publ_unsubscribe(struct publication *publ, u32 addr)
* Invoked for each publication issued by a newly failed node.
* Removes publication structure from name table & deletes it.
*/
-static void tipc_publ_purge(struct publication *publ, u32 addr)
+static void tipc_publ_purge(struct net *net, struct publication *publ, u32 addr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct publication *p;
- spin_lock_bh(&tipc_nametbl_lock);
- p = tipc_nametbl_remove_publ(publ->type, publ->lower,
+ spin_lock_bh(&tn->nametbl_lock);
+ p = tipc_nametbl_remove_publ(net, publ->type, publ->lower,
publ->node, publ->ref, publ->key);
if (p)
- tipc_publ_unsubscribe(p, addr);
- spin_unlock_bh(&tipc_nametbl_lock);
+ tipc_publ_unsubscribe(net, p, addr);
+ spin_unlock_bh(&tn->nametbl_lock);
if (p != publ) {
pr_err("Unable to remove publication from failed node\n"
@@ -277,12 +287,12 @@ static void tipc_publ_purge(struct publication *publ, u32 addr)
kfree_rcu(p, rcu);
}
-void tipc_publ_notify(struct list_head *nsub_list, u32 addr)
+void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr)
{
struct publication *publ, *tmp;
list_for_each_entry_safe(publ, tmp, nsub_list, nodesub_list)
- tipc_publ_purge(publ, addr);
+ tipc_publ_purge(net, publ, addr);
}
/**
@@ -292,25 +302,28 @@ void tipc_publ_notify(struct list_head *nsub_list, u32 addr)
* tipc_nametbl_lock must be held.
* Returns the publication item if successful, otherwise NULL.
*/
-static bool tipc_update_nametbl(struct distr_item *i, u32 node, u32 dtype)
+static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
+ u32 node, u32 dtype)
{
struct publication *publ = NULL;
if (dtype == PUBLICATION) {
- publ = tipc_nametbl_insert_publ(ntohl(i->type), ntohl(i->lower),
+ publ = tipc_nametbl_insert_publ(net, ntohl(i->type),
+ ntohl(i->lower),
ntohl(i->upper),
TIPC_CLUSTER_SCOPE, node,
ntohl(i->ref), ntohl(i->key));
if (publ) {
- tipc_publ_subscribe(publ, node);
+ tipc_publ_subscribe(net, publ, node);
return true;
}
} else if (dtype == WITHDRAWAL) {
- publ = tipc_nametbl_remove_publ(ntohl(i->type), ntohl(i->lower),
+ publ = tipc_nametbl_remove_publ(net, ntohl(i->type),
+ ntohl(i->lower),
node, ntohl(i->ref),
ntohl(i->key));
if (publ) {
- tipc_publ_unsubscribe(publ, node);
+ tipc_publ_unsubscribe(net, publ, node);
kfree_rcu(publ, rcu);
return true;
}
@@ -343,7 +356,7 @@ static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
* tipc_named_process_backlog - try to process any pending name table updates
* from the network.
*/
-void tipc_named_process_backlog(void)
+void tipc_named_process_backlog(struct net *net)
{
struct distr_queue_item *e, *tmp;
char addr[16];
@@ -351,7 +364,7 @@ void tipc_named_process_backlog(void)
list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
if (time_after(e->expires, now)) {
- if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
+ if (!tipc_update_nametbl(net, &e->i, e->node, e->dtype))
continue;
} else {
tipc_addr_string_fill(addr, e->node);
@@ -369,21 +382,22 @@ void tipc_named_process_backlog(void)
/**
* tipc_named_rcv - process name table update message sent by another node
*/
-void tipc_named_rcv(struct sk_buff *buf)
+void tipc_named_rcv(struct net *net, struct sk_buff *buf)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_msg *msg = buf_msg(buf);
struct distr_item *item = (struct distr_item *)msg_data(msg);
u32 count = msg_data_sz(msg) / ITEM_SIZE;
u32 node = msg_orignode(msg);
- spin_lock_bh(&tipc_nametbl_lock);
+ spin_lock_bh(&tn->nametbl_lock);
while (count--) {
- if (!tipc_update_nametbl(item, node, msg_type(msg)))
+ if (!tipc_update_nametbl(net, item, node, msg_type(msg)))
tipc_named_add_backlog(item, msg_type(msg), node);
item++;
}
- tipc_named_process_backlog();
- spin_unlock_bh(&tipc_nametbl_lock);
+ tipc_named_process_backlog(net);
+ spin_unlock_bh(&tn->nametbl_lock);
kfree_skb(buf);
}
@@ -394,17 +408,18 @@ void tipc_named_rcv(struct sk_buff *buf)
* All name table entries published by this node are updated to reflect
* the node's new network address.
*/
-void tipc_named_reinit(void)
+void tipc_named_reinit(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct publication *publ;
int scope;
- spin_lock_bh(&tipc_nametbl_lock);
+ spin_lock_bh(&tn->nametbl_lock);
for (scope = TIPC_ZONE_SCOPE; scope <= TIPC_NODE_SCOPE; scope++)
- list_for_each_entry_rcu(publ, &tipc_nametbl->publ_list[scope],
+ list_for_each_entry_rcu(publ, &tn->nametbl->publ_list[scope],
local_list)
- publ->node = tipc_own_addr;
+ publ->node = tn->own_addr;
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
index cef55cedcfb2..5ec10b59527b 100644
--- a/net/tipc/name_distr.h
+++ b/net/tipc/name_distr.h
@@ -67,13 +67,13 @@ struct distr_item {
__be32 key;
};
-struct sk_buff *tipc_named_publish(struct publication *publ);
-struct sk_buff *tipc_named_withdraw(struct publication *publ);
-void named_cluster_distribute(struct sk_buff *buf);
-void tipc_named_node_up(u32 dnode);
-void tipc_named_rcv(struct sk_buff *buf);
-void tipc_named_reinit(void);
-void tipc_named_process_backlog(void);
-void tipc_publ_notify(struct list_head *nsub_list, u32 addr);
+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 named_cluster_distribute(struct net *net, struct sk_buff *buf);
+void tipc_named_node_up(struct net *net, u32 dnode);
+void tipc_named_rcv(struct net *net, struct sk_buff *buf);
+void tipc_named_reinit(struct net *net);
+void tipc_named_process_backlog(struct net *net);
+void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr);
#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index c8df0223371a..ce09b863528c 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -34,11 +34,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <net/sock.h>
#include "core.h"
#include "config.h"
#include "name_table.h"
#include "name_distr.h"
#include "subscr.h"
+#include "bcast.h"
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
@@ -105,9 +107,6 @@ struct name_seq {
struct rcu_head rcu;
};
-struct name_table *tipc_nametbl;
-DEFINE_SPINLOCK(tipc_nametbl_lock);
-
static int hash(int x)
{
return x & (TIPC_NAMETBL_SIZE - 1);
@@ -228,9 +227,11 @@ static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
/**
* tipc_nameseq_insert_publ
*/
-static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
- u32 type, u32 lower, u32 upper,
- u32 scope, u32 node, u32 port, u32 key)
+static struct publication *tipc_nameseq_insert_publ(struct net *net,
+ struct name_seq *nseq,
+ u32 type, u32 lower,
+ u32 upper, u32 scope,
+ u32 node, u32 port, u32 key)
{
struct tipc_subscription *s;
struct tipc_subscription *st;
@@ -315,12 +316,12 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
list_add(&publ->zone_list, &info->zone_list);
info->zone_list_size++;
- if (in_own_cluster(node)) {
+ if (in_own_cluster(net, node)) {
list_add(&publ->cluster_list, &info->cluster_list);
info->cluster_list_size++;
}
- if (in_own_node(node)) {
+ if (in_own_node(net, node)) {
list_add(&publ->node_list, &info->node_list);
info->node_list_size++;
}
@@ -349,8 +350,10 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
* A failed withdraw request simply returns a failure indication and lets the
* caller issue any error or warning messages associated with such a problem.
*/
-static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
- u32 node, u32 ref, u32 key)
+static struct publication *tipc_nameseq_remove_publ(struct net *net,
+ struct name_seq *nseq,
+ u32 inst, u32 node,
+ u32 ref, u32 key)
{
struct publication *publ;
struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
@@ -378,13 +381,13 @@ found:
info->zone_list_size--;
/* Remove publication from cluster scope list, if present */
- if (in_own_cluster(node)) {
+ if (in_own_cluster(net, node)) {
list_del(&publ->cluster_list);
info->cluster_list_size--;
}
/* Remove publication from node scope list, if present */
- if (in_own_node(node)) {
+ if (in_own_node(net, node)) {
list_del(&publ->node_list);
info->node_list_size--;
}
@@ -447,12 +450,13 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq,
}
}
-static struct name_seq *nametbl_find_seq(u32 type)
+static struct name_seq *nametbl_find_seq(struct net *net, u32 type)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct hlist_head *seq_head;
struct name_seq *ns;
- seq_head = &tipc_nametbl->seq_hlist[hash(type)];
+ seq_head = &tn->nametbl->seq_hlist[hash(type)];
hlist_for_each_entry_rcu(ns, seq_head, ns_list) {
if (ns->type == type)
return ns;
@@ -461,11 +465,13 @@ static struct name_seq *nametbl_find_seq(u32 type)
return NULL;
};
-struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
- u32 scope, u32 node, u32 port, u32 key)
+struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
+ u32 lower, u32 upper, u32 scope,
+ u32 node, u32 port, u32 key)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct publication *publ;
- struct name_seq *seq = nametbl_find_seq(type);
+ struct name_seq *seq = nametbl_find_seq(net, type);
int index = hash(type);
if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
@@ -476,29 +482,29 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
}
if (!seq)
- seq = tipc_nameseq_create(type,
- &tipc_nametbl->seq_hlist[index]);
+ seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
if (!seq)
return NULL;
spin_lock_bh(&seq->lock);
- publ = tipc_nameseq_insert_publ(seq, type, lower, upper,
+ publ = tipc_nameseq_insert_publ(net, seq, type, lower, upper,
scope, node, port, key);
spin_unlock_bh(&seq->lock);
return publ;
}
-struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
- u32 node, u32 ref, u32 key)
+struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
+ u32 lower, u32 node, u32 ref,
+ u32 key)
{
struct publication *publ;
- struct name_seq *seq = nametbl_find_seq(type);
+ struct name_seq *seq = nametbl_find_seq(net, type);
if (!seq)
return NULL;
spin_lock_bh(&seq->lock);
- publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
+ publ = tipc_nameseq_remove_publ(net, seq, lower, node, ref, key);
if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init_rcu(&seq->ns_list);
kfree(seq->sseqs);
@@ -523,8 +529,10 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
* - if name translation is attempted and fails, sets 'destnode' to 0
* and returns 0
*/
-u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
+u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
+ u32 *destnode)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sub_seq *sseq;
struct name_info *info;
struct publication *publ;
@@ -532,11 +540,11 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
u32 ref = 0;
u32 node = 0;
- if (!tipc_in_scope(*destnode, tipc_own_addr))
+ if (!tipc_in_scope(*destnode, tn->own_addr))
return 0;
rcu_read_lock();
- seq = nametbl_find_seq(type);
+ seq = nametbl_find_seq(net, type);
if (unlikely(!seq))
goto not_found;
spin_lock_bh(&seq->lock);
@@ -569,13 +577,13 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
}
/* Round-Robin Algorithm */
- else if (*destnode == tipc_own_addr) {
+ else if (*destnode == tn->own_addr) {
if (list_empty(&info->node_list))
goto no_match;
publ = list_first_entry(&info->node_list, struct publication,
node_list);
list_move_tail(&publ->node_list, &info->node_list);
- } else if (in_own_cluster_exact(*destnode)) {
+ } else if (in_own_cluster_exact(net, *destnode)) {
if (list_empty(&info->cluster_list))
goto no_match;
publ = list_first_entry(&info->cluster_list, struct publication,
@@ -609,8 +617,8 @@ not_found:
*
* Returns non-zero if any off-node ports overlap
*/
-int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
- struct tipc_port_list *dports)
+int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
+ u32 limit, struct tipc_port_list *dports)
{
struct name_seq *seq;
struct sub_seq *sseq;
@@ -619,7 +627,7 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
int res = 0;
rcu_read_lock();
- seq = nametbl_find_seq(type);
+ seq = nametbl_find_seq(net, type);
if (!seq)
goto exit;
@@ -650,50 +658,55 @@ exit:
/*
* tipc_nametbl_publish - add name publication to network name tables
*/
-struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
- u32 scope, u32 port_ref, u32 key)
+struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
+ u32 upper, u32 scope, u32 port_ref,
+ u32 key)
{
struct publication *publ;
struct sk_buff *buf = NULL;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
- spin_lock_bh(&tipc_nametbl_lock);
- if (tipc_nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
+ spin_lock_bh(&tn->nametbl_lock);
+ if (tn->nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
pr_warn("Publication failed, local publication limit reached (%u)\n",
TIPC_MAX_PUBLICATIONS);
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
return NULL;
}
- publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
- tipc_own_addr, port_ref, key);
+ publ = tipc_nametbl_insert_publ(net, type, lower, upper, scope,
+ tn->own_addr, port_ref, key);
if (likely(publ)) {
- tipc_nametbl->local_publ_count++;
- buf = tipc_named_publish(publ);
+ tn->nametbl->local_publ_count++;
+ buf = tipc_named_publish(net, publ);
/* Any pending external events? */
- tipc_named_process_backlog();
+ tipc_named_process_backlog(net);
}
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
if (buf)
- named_cluster_distribute(buf);
+ named_cluster_distribute(net, buf);
return publ;
}
/**
* tipc_nametbl_withdraw - withdraw name publication from network name tables
*/
-int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
+int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
+ u32 key)
{
struct publication *publ;
struct sk_buff *skb = NULL;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
- spin_lock_bh(&tipc_nametbl_lock);
- publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
+ spin_lock_bh(&tn->nametbl_lock);
+ publ = tipc_nametbl_remove_publ(net, type, lower, tn->own_addr,
+ ref, key);
if (likely(publ)) {
- tipc_nametbl->local_publ_count--;
- skb = tipc_named_withdraw(publ);
+ tn->nametbl->local_publ_count--;
+ skb = tipc_named_withdraw(net, publ);
/* Any pending external events? */
- tipc_named_process_backlog();
+ tipc_named_process_backlog(net);
list_del_init(&publ->pport_list);
kfree_rcu(publ, rcu);
} else {
@@ -701,10 +714,10 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
"(type=%u, lower=%u, ref=%u, key=%u)\n",
type, lower, ref, key);
}
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
if (skb) {
- named_cluster_distribute(skb);
+ named_cluster_distribute(net, skb);
return 1;
}
return 0;
@@ -715,15 +728,15 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
*/
void tipc_nametbl_subscribe(struct tipc_subscription *s)
{
+ struct tipc_net *tn = net_generic(s->net, tipc_net_id);
u32 type = s->seq.type;
int index = hash(type);
struct name_seq *seq;
- spin_lock_bh(&tipc_nametbl_lock);
- seq = nametbl_find_seq(type);
+ spin_lock_bh(&tn->nametbl_lock);
+ seq = nametbl_find_seq(s->net, type);
if (!seq)
- seq = tipc_nameseq_create(type,
- &tipc_nametbl->seq_hlist[index]);
+ seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
if (seq) {
spin_lock_bh(&seq->lock);
tipc_nameseq_subscribe(seq, s);
@@ -732,7 +745,7 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s)
pr_warn("Failed to create subscription for {%u,%u,%u}\n",
s->seq.type, s->seq.lower, s->seq.upper);
}
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
}
/**
@@ -740,10 +753,11 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s)
*/
void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
{
+ struct tipc_net *tn = net_generic(s->net, tipc_net_id);
struct name_seq *seq;
- spin_lock_bh(&tipc_nametbl_lock);
- seq = nametbl_find_seq(s->seq.type);
+ spin_lock_bh(&tn->nametbl_lock);
+ seq = nametbl_find_seq(s->net, s->seq.type);
if (seq != NULL) {
spin_lock_bh(&seq->lock);
list_del_init(&s->nameseq_list);
@@ -756,7 +770,7 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
spin_unlock_bh(&seq->lock);
}
}
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
}
/**
@@ -858,9 +872,10 @@ static int nametbl_header(char *buf, int len, u32 depth)
/**
* nametbl_list - print specified name table contents into the given buffer
*/
-static int nametbl_list(char *buf, int len, u32 depth_info,
+static int nametbl_list(struct net *net, char *buf, int len, u32 depth_info,
u32 type, u32 lowbound, u32 upbound)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct hlist_head *seq_head;
struct name_seq *seq;
int all_types;
@@ -880,7 +895,7 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
lowbound = 0;
upbound = ~0;
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
- seq_head = &tipc_nametbl->seq_hlist[i];
+ seq_head = &tn->nametbl->seq_hlist[i];
hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
ret += nameseq_list(seq, buf + ret, len - ret,
depth, seq->type,
@@ -896,7 +911,7 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
}
ret += nametbl_header(buf + ret, len - ret, depth);
i = hash(type);
- seq_head = &tipc_nametbl->seq_hlist[i];
+ seq_head = &tn->nametbl->seq_hlist[i];
hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
if (seq->type == type) {
ret += nameseq_list(seq, buf + ret, len - ret,
@@ -909,7 +924,8 @@ static int nametbl_list(char *buf, int len, u32 depth_info,
return ret;
}
-struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
+ int req_tlv_space)
{
struct sk_buff *buf;
struct tipc_name_table_query *argv;
@@ -930,7 +946,7 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
pb_len = ULTRA_STRING_MAX_LEN;
argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
rcu_read_lock();
- str_len = nametbl_list(pb, pb_len, ntohl(argv->depth),
+ str_len = nametbl_list(net, pb, pb_len, ntohl(argv->depth),
ntohl(argv->type),
ntohl(argv->lowbound), ntohl(argv->upbound));
rcu_read_unlock();
@@ -941,8 +957,10 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
return buf;
}
-int tipc_nametbl_init(void)
+int tipc_nametbl_init(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct name_table *tipc_nametbl;
int i;
tipc_nametbl = kzalloc(sizeof(*tipc_nametbl), GFP_ATOMIC);
@@ -955,6 +973,8 @@ int tipc_nametbl_init(void)
INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_ZONE_SCOPE]);
INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_NODE_SCOPE]);
+ tn->nametbl = tipc_nametbl;
+ spin_lock_init(&tn->nametbl_lock);
return 0;
}
@@ -963,7 +983,7 @@ int tipc_nametbl_init(void)
*
* tipc_nametbl_lock must be held when calling this function
*/
-static void tipc_purge_publications(struct name_seq *seq)
+static void tipc_purge_publications(struct net *net, struct name_seq *seq)
{
struct publication *publ, *safe;
struct sub_seq *sseq;
@@ -973,8 +993,8 @@ static void tipc_purge_publications(struct name_seq *seq)
sseq = seq->sseqs;
info = sseq->info;
list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
- tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
- publ->ref, publ->key);
+ tipc_nametbl_remove_publ(net, publ->type, publ->lower,
+ publ->node, publ->ref, publ->key);
kfree_rcu(publ, rcu);
}
hlist_del_init_rcu(&seq->ns_list);
@@ -984,25 +1004,27 @@ static void tipc_purge_publications(struct name_seq *seq)
kfree_rcu(seq, rcu);
}
-void tipc_nametbl_stop(void)
+void tipc_nametbl_stop(struct net *net)
{
u32 i;
struct name_seq *seq;
struct hlist_head *seq_head;
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct name_table *tipc_nametbl = tn->nametbl;
/* Verify name table is empty and purge any lingering
* publications, then release the name table
*/
- spin_lock_bh(&tipc_nametbl_lock);
+ spin_lock_bh(&tn->nametbl_lock);
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
if (hlist_empty(&tipc_nametbl->seq_hlist[i]))
continue;
seq_head = &tipc_nametbl->seq_hlist[i];
hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
- tipc_purge_publications(seq);
+ tipc_purge_publications(net, seq);
}
}
- spin_unlock_bh(&tipc_nametbl_lock);
+ spin_unlock_bh(&tn->nametbl_lock);
synchronize_net();
kfree(tipc_nametbl);
@@ -1106,9 +1128,10 @@ static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
return 0;
}
-static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
- u32 *last_lower, u32 *last_publ)
+static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg,
+ u32 *last_type, u32 *last_lower, u32 *last_publ)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct hlist_head *seq_head;
struct name_seq *seq = NULL;
int err;
@@ -1120,10 +1143,10 @@ static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
i = 0;
for (; i < TIPC_NAMETBL_SIZE; i++) {
- seq_head = &tipc_nametbl->seq_hlist[i];
+ seq_head = &tn->nametbl->seq_hlist[i];
if (*last_type) {
- seq = nametbl_find_seq(*last_type);
+ seq = nametbl_find_seq(net, *last_type);
if (!seq)
return -EPIPE;
} else {
@@ -1157,6 +1180,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
u32 last_type = cb->args[0];
u32 last_lower = cb->args[1];
u32 last_publ = cb->args[2];
+ struct net *net = sock_net(skb->sk);
struct tipc_nl_msg msg;
if (done)
@@ -1167,7 +1191,7 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
msg.seq = cb->nlh->nlmsg_seq;
rcu_read_lock();
- err = __tipc_nl_seq_list(&msg, &last_type, &last_lower, &last_publ);
+ err = tipc_nl_seq_list(net, &msg, &last_type, &last_lower, &last_publ);
if (!err) {
done = 1;
} else if (err != -EMSGSIZE) {
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 5f0dee92010d..f67b3d8d4b2f 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -95,26 +95,27 @@ struct name_table {
u32 local_publ_count;
};
-extern spinlock_t tipc_nametbl_lock;
-extern struct name_table *tipc_nametbl;
-
int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb);
-struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space);
-u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *node);
-int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
- struct tipc_port_list *dports);
-struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
- u32 scope, u32 port_ref, u32 key);
-int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key);
-struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
- u32 scope, u32 node, u32 ref,
+struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
+ int req_tlv_space);
+u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *node);
+int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
+ u32 limit, struct tipc_port_list *dports);
+struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
+ u32 upper, u32 scope, u32 port_ref,
+ u32 key);
+int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
+ u32 key);
+struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
+ u32 lower, u32 upper, u32 scope,
+ u32 node, u32 ref, u32 key);
+struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
+ u32 lower, u32 node, u32 ref,
u32 key);
-struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, u32 node,
- u32 ref, u32 key);
void tipc_nametbl_subscribe(struct tipc_subscription *s);
void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
-int tipc_nametbl_init(void);
-void tipc_nametbl_stop(void);
+int tipc_nametbl_init(struct net *net);
+void tipc_nametbl_stop(struct net *net);
#endif
diff --git a/net/tipc/net.c b/net/tipc/net.c
index cf13df3cde8f..263267e0e7fe 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -41,6 +41,7 @@
#include "socket.h"
#include "node.h"
#include "config.h"
+#include "bcast.h"
static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
[TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC },
@@ -108,44 +109,50 @@ static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
* - A local spin_lock protecting the queue of subscriber events.
*/
-int tipc_net_start(u32 addr)
+int tipc_net_start(struct net *net, u32 addr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
char addr_string[16];
int res;
- tipc_own_addr = addr;
- tipc_named_reinit();
- tipc_sk_reinit();
- res = tipc_bclink_init();
+ tn->own_addr = addr;
+ tipc_named_reinit(net);
+ tipc_sk_reinit(net);
+ res = tipc_bclink_init(net);
if (res)
return res;
- tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr,
- TIPC_ZONE_SCOPE, 0, tipc_own_addr);
+ tipc_nametbl_publish(net, TIPC_CFG_SRV, tn->own_addr, tn->own_addr,
+ TIPC_ZONE_SCOPE, 0, tn->own_addr);
pr_info("Started in network mode\n");
pr_info("Own node address %s, network identity %u\n",
- tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
+ tipc_addr_string_fill(addr_string, tn->own_addr),
+ tn->net_id);
return 0;
}
-void tipc_net_stop(void)
+void tipc_net_stop(struct net *net)
{
- if (!tipc_own_addr)
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
+ if (!tn->own_addr)
return;
- tipc_nametbl_withdraw(TIPC_CFG_SRV, tipc_own_addr, 0, tipc_own_addr);
+ tipc_nametbl_withdraw(net, TIPC_CFG_SRV, tn->own_addr, 0,
+ tn->own_addr);
rtnl_lock();
- tipc_bearer_stop();
- tipc_bclink_stop();
- tipc_node_stop();
+ tipc_bearer_stop(net);
+ tipc_bclink_stop(net);
+ tipc_node_stop(net);
rtnl_unlock();
pr_info("Left network mode\n");
}
-static int __tipc_nl_add_net(struct tipc_nl_msg *msg)
+static int __tipc_nl_add_net(struct net *net, struct tipc_nl_msg *msg)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
void *hdr;
struct nlattr *attrs;
@@ -158,7 +165,7 @@ static int __tipc_nl_add_net(struct tipc_nl_msg *msg)
if (!attrs)
goto msg_full;
- if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tipc_net_id))
+ if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tn->net_id))
goto attr_msg_full;
nla_nest_end(msg->skb, attrs);
@@ -176,6 +183,7 @@ msg_full:
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;
@@ -187,7 +195,7 @@ int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb)
msg.portid = NETLINK_CB(cb->skb).portid;
msg.seq = cb->nlh->nlmsg_seq;
- err = __tipc_nl_add_net(&msg);
+ err = __tipc_nl_add_net(net, &msg);
if (err)
goto out;
@@ -200,8 +208,10 @@ out:
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
{
- int err;
+ struct net *net = genl_info_net(info);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
+ int err;
if (!info->attrs[TIPC_NLA_NET])
return -EINVAL;
@@ -216,21 +226,21 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
u32 val;
/* Can't change net id once TIPC has joined a network */
- if (tipc_own_addr)
+ if (tn->own_addr)
return -EPERM;
val = nla_get_u32(attrs[TIPC_NLA_NET_ID]);
if (val < 1 || val > 9999)
return -EINVAL;
- tipc_net_id = val;
+ tn->net_id = val;
}
if (attrs[TIPC_NLA_NET_ADDR]) {
u32 addr;
/* Can't change net addr once TIPC has joined a network */
- if (tipc_own_addr)
+ if (tn->own_addr)
return -EPERM;
addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]);
@@ -238,7 +248,7 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
rtnl_lock();
- tipc_net_start(addr);
+ tipc_net_start(net, addr);
rtnl_unlock();
}
diff --git a/net/tipc/net.h b/net/tipc/net.h
index a81c1b9eb150..77a7a118911d 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -39,9 +39,9 @@
#include <net/genetlink.h>
-int tipc_net_start(u32 addr);
+int tipc_net_start(struct net *net, u32 addr);
-void tipc_net_stop(void);
+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);
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index b891e3905bc4..fe0f5134ce15 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -46,6 +46,7 @@
static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
{
+ struct net *net = genl_info_net(info);
struct sk_buff *rep_buf;
struct nlmsghdr *rep_nlh;
struct nlmsghdr *req_nlh = info->nlhdr;
@@ -53,22 +54,24 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
u16 cmd;
- if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, CAP_NET_ADMIN)))
+ if ((req_userhdr->cmd & 0xC000) &&
+ (!netlink_net_capable(skb, CAP_NET_ADMIN)))
cmd = TIPC_CMD_NOT_NET_ADMIN;
else
cmd = req_userhdr->cmd;
- rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
- nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
- nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
- hdr_space);
+ rep_buf = tipc_cfg_do_cmd(net, req_userhdr->dest, cmd,
+ nlmsg_data(req_nlh) + GENL_HDRLEN +
+ TIPC_GENL_HDRLEN,
+ nlmsg_attrlen(req_nlh, GENL_HDRLEN +
+ TIPC_GENL_HDRLEN), hdr_space);
if (rep_buf) {
skb_push(rep_buf, hdr_space);
rep_nlh = nlmsg_hdr(rep_buf);
memcpy(rep_nlh, req_nlh, hdr_space);
rep_nlh->nlmsg_len = rep_buf->len;
- genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).portid);
+ genlmsg_unicast(net, rep_buf, NETLINK_CB(skb).portid);
}
return 0;
@@ -93,6 +96,7 @@ static struct genl_family tipc_genl_family = {
.version = TIPC_GENL_VERSION,
.hdrsize = TIPC_GENL_HDRLEN,
.maxattr = 0,
+ .netnsok = true,
};
/* Legacy ASCII API */
@@ -112,6 +116,7 @@ struct genl_family tipc_genl_v2_family = {
.version = TIPC_GENL_V2_VERSION,
.hdrsize = 0,
.maxattr = TIPC_NLA_MAX,
+ .netnsok = true,
};
static const struct genl_ops tipc_genl_v2_ops[] = {
diff --git a/net/tipc/netlink.h b/net/tipc/netlink.h
index 1425c6869de0..ae2f2d923a15 100644
--- a/net/tipc/netlink.h
+++ b/net/tipc/netlink.h
@@ -45,4 +45,7 @@ struct tipc_nl_msg {
u32 seq;
};
+int tipc_netlink_start(void);
+void tipc_netlink_stop(void);
+
#endif
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 8d353ec77a66..b1eb0927bac8 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -40,17 +40,9 @@
#include "name_distr.h"
#include "socket.h"
-#define NODE_HTABLE_SIZE 512
-
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
-static struct hlist_head node_htable[NODE_HTABLE_SIZE];
-LIST_HEAD(tipc_node_list);
-static u32 tipc_num_nodes;
-static u32 tipc_num_links;
-static DEFINE_SPINLOCK(node_list_lock);
-
struct tipc_sock_conn {
u32 port;
u32 peer_port;
@@ -78,15 +70,17 @@ static unsigned int tipc_hashfn(u32 addr)
/*
* tipc_node_find - locate specified node object, if it exists
*/
-struct tipc_node *tipc_node_find(u32 addr)
+struct tipc_node *tipc_node_find(struct net *net, u32 addr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node;
- if (unlikely(!in_own_cluster_exact(addr)))
+ if (unlikely(!in_own_cluster_exact(net, addr)))
return NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(node, &node_htable[tipc_hashfn(addr)], hash) {
+ hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
+ hash) {
if (node->addr == addr) {
rcu_read_unlock();
return node;
@@ -96,20 +90,22 @@ struct tipc_node *tipc_node_find(u32 addr)
return NULL;
}
-struct tipc_node *tipc_node_create(u32 addr)
+struct tipc_node *tipc_node_create(struct net *net, u32 addr)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *n_ptr, *temp_node;
- spin_lock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
if (!n_ptr) {
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
pr_warn("Node creation failed, no memory\n");
return NULL;
}
n_ptr->addr = addr;
+ n_ptr->net = net;
spin_lock_init(&n_ptr->lock);
INIT_HLIST_NODE(&n_ptr->hash);
INIT_LIST_HEAD(&n_ptr->list);
@@ -118,9 +114,9 @@ struct tipc_node *tipc_node_create(u32 addr)
skb_queue_head_init(&n_ptr->waiting_sks);
__skb_queue_head_init(&n_ptr->bclink.deferred_queue);
- hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
+ hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
- list_for_each_entry_rcu(temp_node, &tipc_node_list, list) {
+ list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
if (n_ptr->addr < temp_node->addr)
break;
}
@@ -128,40 +124,41 @@ struct tipc_node *tipc_node_create(u32 addr)
n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
n_ptr->signature = INVALID_NODE_SIG;
- tipc_num_nodes++;
+ tn->num_nodes++;
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
return n_ptr;
}
-static void tipc_node_delete(struct tipc_node *n_ptr)
+static void tipc_node_delete(struct tipc_net *tn, struct tipc_node *n_ptr)
{
list_del_rcu(&n_ptr->list);
hlist_del_rcu(&n_ptr->hash);
kfree_rcu(n_ptr, rcu);
- tipc_num_nodes--;
+ tn->num_nodes--;
}
-void tipc_node_stop(void)
+void tipc_node_stop(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node, *t_node;
- spin_lock_bh(&node_list_lock);
- list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
- tipc_node_delete(node);
- spin_unlock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
+ list_for_each_entry_safe(node, t_node, &tn->node_list, list)
+ tipc_node_delete(tn, node);
+ spin_unlock_bh(&tn->node_list_lock);
}
-int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
+int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port)
{
struct tipc_node *node;
struct tipc_sock_conn *conn;
- if (in_own_node(dnode))
+ if (in_own_node(net, dnode))
return 0;
- node = tipc_node_find(dnode);
+ node = tipc_node_find(net, dnode);
if (!node) {
pr_warn("Connecting sock to node 0x%x failed\n", dnode);
return -EHOSTUNREACH;
@@ -179,15 +176,15 @@ int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
return 0;
}
-void tipc_node_remove_conn(u32 dnode, u32 port)
+void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
{
struct tipc_node *node;
struct tipc_sock_conn *conn, *safe;
- if (in_own_node(dnode))
+ if (in_own_node(net, dnode))
return;
- node = tipc_node_find(dnode);
+ node = tipc_node_find(net, dnode);
if (!node)
return;
@@ -201,18 +198,20 @@ void tipc_node_remove_conn(u32 dnode, u32 port)
tipc_node_unlock(node);
}
-void tipc_node_abort_sock_conns(struct list_head *conns)
+void tipc_node_abort_sock_conns(struct net *net, struct list_head *conns)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_sock_conn *conn, *safe;
struct sk_buff *buf;
list_for_each_entry_safe(conn, safe, conns, list) {
- buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
- SHORT_H_SIZE, 0, tipc_own_addr,
- conn->peer_node, conn->port,
- conn->peer_port, TIPC_ERR_NO_NODE);
+ buf = tipc_msg_create(net, TIPC_CRITICAL_IMPORTANCE,
+ TIPC_CONN_MSG, SHORT_H_SIZE, 0,
+ tn->own_addr, conn->peer_node,
+ conn->port, conn->peer_port,
+ TIPC_ERR_NO_NODE);
if (likely(buf))
- tipc_sk_rcv(buf);
+ tipc_sk_rcv(net, buf);
list_del(&conn->list);
kfree(conn);
}
@@ -290,6 +289,7 @@ static void node_select_active_links(struct tipc_node *n_ptr)
*/
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
{
+ struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
struct tipc_link **active;
n_ptr->working_links--;
@@ -324,7 +324,7 @@ void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
}
/* Loopback link went down? No fragmentation needed from now on. */
- if (n_ptr->addr == tipc_own_addr) {
+ if (n_ptr->addr == tn->own_addr) {
n_ptr->act_mtus[0] = MAX_MSG_SIZE;
n_ptr->act_mtus[1] = MAX_MSG_SIZE;
}
@@ -342,24 +342,27 @@ int tipc_node_is_up(struct tipc_node *n_ptr)
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
{
+ struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
+
n_ptr->links[l_ptr->bearer_id] = l_ptr;
- spin_lock_bh(&node_list_lock);
- tipc_num_links++;
- spin_unlock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
+ tn->num_links++;
+ spin_unlock_bh(&tn->node_list_lock);
n_ptr->link_cnt++;
}
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
{
+ struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
int i;
for (i = 0; i < MAX_BEARERS; i++) {
if (l_ptr != n_ptr->links[i])
continue;
n_ptr->links[i] = NULL;
- spin_lock_bh(&node_list_lock);
- tipc_num_links--;
- spin_unlock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
+ tn->num_links--;
+ spin_unlock_bh(&tn->node_list_lock);
n_ptr->link_cnt--;
}
}
@@ -368,8 +371,8 @@ static void node_established_contact(struct tipc_node *n_ptr)
{
n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
n_ptr->bclink.oos_state = 0;
- n_ptr->bclink.acked = tipc_bclink_get_last_sent();
- tipc_bclink_add_node(n_ptr->addr);
+ n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net);
+ tipc_bclink_add_node(n_ptr->net, n_ptr->addr);
}
static void node_lost_contact(struct tipc_node *n_ptr)
@@ -389,7 +392,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
n_ptr->bclink.reasm_buf = NULL;
}
- tipc_bclink_remove_node(n_ptr->addr);
+ tipc_bclink_remove_node(n_ptr->net, n_ptr->addr);
tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
n_ptr->bclink.recv_permitted = false;
@@ -414,8 +417,10 @@ static void node_lost_contact(struct tipc_node *n_ptr)
TIPC_NOTIFY_NODE_DOWN;
}
-struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
+ int req_tlv_space)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 domain;
struct sk_buff *buf;
struct tipc_node *n_ptr;
@@ -430,20 +435,20 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
- spin_lock_bh(&node_list_lock);
- if (!tipc_num_nodes) {
- spin_unlock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
+ if (!tn->num_nodes) {
+ spin_unlock_bh(&tn->node_list_lock);
return tipc_cfg_reply_none();
}
/* For now, get space for all other nodes */
- payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
+ payload_size = TLV_SPACE(sizeof(node_info)) * tn->num_nodes;
if (payload_size > 32768u) {
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (too many nodes)");
}
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
buf = tipc_cfg_reply_alloc(payload_size);
if (!buf)
@@ -451,7 +456,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
/* Add TLVs for all nodes in scope */
rcu_read_lock();
- list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+ list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
if (!tipc_in_scope(domain, n_ptr->addr))
continue;
node_info.addr = htonl(n_ptr->addr);
@@ -463,8 +468,10 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
return buf;
}
-struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
+ int req_tlv_space)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 domain;
struct sk_buff *buf;
struct tipc_node *n_ptr;
@@ -479,32 +486,32 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
- if (!tipc_own_addr)
+ if (!tn->own_addr)
return tipc_cfg_reply_none();
- spin_lock_bh(&node_list_lock);
+ spin_lock_bh(&tn->node_list_lock);
/* Get space for all unicast links + broadcast link */
- payload_size = TLV_SPACE((sizeof(link_info)) * (tipc_num_links + 1));
+ payload_size = TLV_SPACE((sizeof(link_info)) * (tn->num_links + 1));
if (payload_size > 32768u) {
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (too many links)");
}
- spin_unlock_bh(&node_list_lock);
+ spin_unlock_bh(&tn->node_list_lock);
buf = tipc_cfg_reply_alloc(payload_size);
if (!buf)
return NULL;
/* Add TLV for broadcast link */
- link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
+ link_info.dest = htonl(tipc_cluster_mask(tn->own_addr));
link_info.up = htonl(1);
strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
/* Add TLVs for any other links in scope */
rcu_read_lock();
- list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+ list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
u32 i;
if (!tipc_in_scope(domain, n_ptr->addr))
@@ -534,10 +541,11 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
*
* Returns 0 on success
*/
-int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
+int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
+ char *linkname, size_t len)
{
struct tipc_link *link;
- struct tipc_node *node = tipc_node_find(addr);
+ struct tipc_node *node = tipc_node_find(net, addr);
if ((bearer_id >= MAX_BEARERS) || !node)
return -EINVAL;
@@ -554,6 +562,7 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
void tipc_node_unlock(struct tipc_node *node)
{
+ struct net *net = node->net;
LIST_HEAD(nsub_list);
LIST_HEAD(conn_sks);
struct sk_buff_head waiting_sks;
@@ -585,26 +594,26 @@ void tipc_node_unlock(struct tipc_node *node)
spin_unlock_bh(&node->lock);
while (!skb_queue_empty(&waiting_sks))
- tipc_sk_rcv(__skb_dequeue(&waiting_sks));
+ tipc_sk_rcv(net, __skb_dequeue(&waiting_sks));
if (!list_empty(&conn_sks))
- tipc_node_abort_sock_conns(&conn_sks);
+ tipc_node_abort_sock_conns(net, &conn_sks);
if (!list_empty(&nsub_list))
- tipc_publ_notify(&nsub_list, addr);
+ tipc_publ_notify(net, &nsub_list, addr);
if (flags & TIPC_WAKEUP_BCAST_USERS)
- tipc_bclink_wakeup_users();
+ tipc_bclink_wakeup_users(net);
if (flags & TIPC_NOTIFY_NODE_UP)
- tipc_named_node_up(addr);
+ tipc_named_node_up(net, addr);
if (flags & TIPC_NOTIFY_LINK_UP)
- tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr,
+ tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr,
TIPC_NODE_SCOPE, link_id, addr);
if (flags & TIPC_NOTIFY_LINK_DOWN)
- tipc_nametbl_withdraw(TIPC_LINK_STATE, addr,
+ tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr,
link_id, addr);
}
@@ -645,6 +654,8 @@ msg_full:
int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
int err;
+ struct net *net = sock_net(skb->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
int done = cb->args[0];
int last_addr = cb->args[1];
struct tipc_node *node;
@@ -659,7 +670,7 @@ int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
- if (last_addr && !tipc_node_find(last_addr)) {
+ if (last_addr && !tipc_node_find(net, last_addr)) {
rcu_read_unlock();
/* We never set seq or call nl_dump_check_consistent() this
* means that setting prev_seq here will cause the consistence
@@ -671,7 +682,7 @@ int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
return -EPIPE;
}
- list_for_each_entry_rcu(node, &tipc_node_list, list) {
+ list_for_each_entry_rcu(node, &tn->node_list, list) {
if (last_addr) {
if (node->addr == last_addr)
last_addr = 0;
diff --git a/net/tipc/node.h b/net/tipc/node.h
index cbe0e950f1cc..43ef88ef3035 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -42,10 +42,10 @@
#include "bearer.h"
#include "msg.h"
-/*
- * Out-of-range value for node signature
- */
-#define INVALID_NODE_SIG 0x10000
+/* Out-of-range value for node signature */
+#define INVALID_NODE_SIG 0x10000
+
+#define NODE_HTABLE_SIZE 512
/* Flags used to take different actions according to flag type
* TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down
@@ -90,6 +90,7 @@ struct tipc_node_bclink {
* struct tipc_node - TIPC node structure
* @addr: network address of node
* @lock: spinlock governing access to structure
+ * @net: the applicable net namespace
* @hash: links to adjacent nodes in unsorted hash chain
* @active_links: pointers to active links to node
* @links: pointers to all links to node
@@ -106,6 +107,7 @@ struct tipc_node_bclink {
struct tipc_node {
u32 addr;
spinlock_t lock;
+ struct net *net;
struct hlist_node hash;
struct tipc_link *active_links[2];
u32 act_mtus[2];
@@ -123,23 +125,24 @@ struct tipc_node {
struct rcu_head rcu;
};
-extern struct list_head tipc_node_list;
-
-struct tipc_node *tipc_node_find(u32 addr);
-struct tipc_node *tipc_node_create(u32 addr);
-void tipc_node_stop(void);
+struct tipc_node *tipc_node_find(struct net *net, u32 addr);
+struct tipc_node *tipc_node_create(struct net *net, u32 addr);
+void tipc_node_stop(struct net *net);
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
int tipc_node_active_links(struct tipc_node *n_ptr);
int tipc_node_is_up(struct tipc_node *n_ptr);
-struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
-struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
-int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
+struct sk_buff *tipc_node_get_links(struct net *net, const void *req_tlv_area,
+ int req_tlv_space);
+struct sk_buff *tipc_node_get_nodes(struct net *net, const void *req_tlv_area,
+ int req_tlv_space);
+int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
+ char *linkname, size_t len);
void tipc_node_unlock(struct tipc_node *node);
-int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port);
-void tipc_node_remove_conn(u32 dnode, u32 port);
+int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port);
+void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);
int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb);
@@ -154,12 +157,12 @@ static inline bool tipc_node_blocked(struct tipc_node *node)
TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN));
}
-static inline uint tipc_node_get_mtu(u32 addr, u32 selector)
+static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector)
{
struct tipc_node *node;
u32 mtu;
- node = tipc_node_find(addr);
+ node = tipc_node_find(net, addr);
if (likely(node))
mtu = node->act_mtus[selector & 1];
diff --git a/net/tipc/server.c b/net/tipc/server.c
index a538a02f869b..eadd4ed45905 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -35,6 +35,7 @@
#include "server.h"
#include "core.h"
+#include "socket.h"
#include <net/sock.h>
/* Number of messages to send before rescheduling */
@@ -255,7 +256,8 @@ static int tipc_receive_from_sock(struct tipc_conn *con)
goto out_close;
}
- s->tipc_conn_recvmsg(con->conid, &addr, con->usr_data, buf, ret);
+ s->tipc_conn_recvmsg(sock_net(con->sock->sk), con->conid, &addr,
+ con->usr_data, buf, ret);
kmem_cache_free(s->rcvbuf_cache, buf);
@@ -307,7 +309,7 @@ static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
struct socket *sock = NULL;
int ret;
- ret = tipc_sock_create_local(s->type, &sock);
+ ret = tipc_sock_create_local(s->net, s->type, &sock);
if (ret < 0)
return NULL;
ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
diff --git a/net/tipc/server.h b/net/tipc/server.h
index be817b0b547e..9015faedb1b0 100644
--- a/net/tipc/server.h
+++ b/net/tipc/server.h
@@ -36,7 +36,9 @@
#ifndef _TIPC_SERVER_H
#define _TIPC_SERVER_H
-#include "core.h"
+#include <linux/idr.h>
+#include <linux/tipc.h>
+#include <net/net_namespace.h>
#define TIPC_SERVER_NAME_LEN 32
@@ -45,6 +47,7 @@
* @conn_idr: identifier set of connection
* @idr_lock: protect the connection identifier set
* @idr_in_use: amount of allocated identifier entry
+ * @net: network namspace instance
* @rcvbuf_cache: memory cache of server receive buffer
* @rcv_wq: receive workqueue
* @send_wq: send workqueue
@@ -61,16 +64,18 @@ struct tipc_server {
struct idr conn_idr;
spinlock_t idr_lock;
int idr_in_use;
+ struct net *net;
struct kmem_cache *rcvbuf_cache;
struct workqueue_struct *rcv_wq;
struct workqueue_struct *send_wq;
int max_rcvbuf_size;
- void *(*tipc_conn_new) (int conid);
- void (*tipc_conn_shutdown) (int conid, void *usr_data);
- void (*tipc_conn_recvmsg) (int conid, struct sockaddr_tipc *addr,
- void *usr_data, void *buf, size_t len);
+ void *(*tipc_conn_new)(int conid);
+ void (*tipc_conn_shutdown)(int conid, void *usr_data);
+ void (*tipc_conn_recvmsg)(struct net *net, int conid,
+ struct sockaddr_tipc *addr, void *usr_data,
+ void *buf, size_t len);
struct sockaddr_tipc *saddr;
- const char name[TIPC_SERVER_NAME_LEN];
+ char name[TIPC_SERVER_NAME_LEN];
int imp;
int type;
};
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 701f31bbbbfb..2cec496ba691 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -47,7 +47,7 @@
#define SS_READY -2 /* socket is connectionless */
#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */
-#define CONN_PROBING_INTERVAL 3600000 /* [ms] => 1 h */
+#define CONN_PROBING_INTERVAL msecs_to_jiffies(3600000) /* [ms] => 1 h */
#define TIPC_FWD_MSG 1
#define TIPC_CONN_OK 0
#define TIPC_CONN_PROBING 1
@@ -68,7 +68,7 @@
* @publications: list of publications for port
* @pub_count: total # of publications port has made during its lifetime
* @probing_state:
- * @probing_interval:
+ * @probing_intv:
* @timer:
* @port: port - interacts with 'sk' and with the rest of the TIPC stack
* @peer_name: the peer of the connection, if any
@@ -93,7 +93,7 @@ struct tipc_sock {
struct list_head publications;
u32 pub_count;
u32 probing_state;
- u32 probing_interval;
+ unsigned long probing_intv;
struct timer_list timer;
uint conn_timeout;
atomic_t dupl_rcvcnt;
@@ -110,12 +110,12 @@ static void tipc_write_space(struct sock *sk);
static int tipc_release(struct socket *sock);
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
-static void tipc_sk_timeout(unsigned long portid);
+static void tipc_sk_timeout(unsigned long data);
static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq);
static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq);
-static struct tipc_sock *tipc_sk_lookup(u32 portid);
+static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid);
static int tipc_sk_insert(struct tipc_sock *tsk);
static void tipc_sk_remove(struct tipc_sock *tsk);
@@ -179,9 +179,6 @@ static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
* - port reference
*/
-/* Protects tipc socket hash table mutations */
-static struct rhashtable tipc_sk_rht;
-
static u32 tsk_peer_node(struct tipc_sock *tsk)
{
return msg_destnode(&tsk->phdr);
@@ -254,10 +251,11 @@ static void tsk_rej_rx_queue(struct sock *sk)
{
struct sk_buff *skb;
u32 dnode;
+ struct net *net = sock_net(sk);
while ((skb = __skb_dequeue(&sk->sk_receive_queue))) {
- if (tipc_msg_reverse(skb, &dnode, TIPC_ERR_NO_PORT))
- tipc_link_xmit_skb(skb, dnode, 0);
+ if (tipc_msg_reverse(net, skb, &dnode, TIPC_ERR_NO_PORT))
+ tipc_link_xmit_skb(net, skb, dnode, 0);
}
}
@@ -268,6 +266,7 @@ static void tsk_rej_rx_queue(struct sock *sk)
*/
static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
{
+ struct tipc_net *tn = net_generic(sock_net(&tsk->sk), tipc_net_id);
u32 peer_port = tsk_peer_port(tsk);
u32 orig_node;
u32 peer_node;
@@ -284,10 +283,10 @@ static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
if (likely(orig_node == peer_node))
return true;
- if (!orig_node && (peer_node == tipc_own_addr))
+ if (!orig_node && (peer_node == tn->own_addr))
return true;
- if (!peer_node && (orig_node == tipc_own_addr))
+ if (!peer_node && (orig_node == tn->own_addr))
return true;
return false;
@@ -349,7 +348,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
tsk->max_pkt = MAX_PKT_DEFAULT;
INIT_LIST_HEAD(&tsk->publications);
msg = &tsk->phdr;
- tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
+ tipc_msg_init(net, msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
NAMED_H_SIZE, 0);
/* Finish initializing socket data structures */
@@ -361,7 +360,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
return -EINVAL;
}
msg_set_origport(msg, tsk->portid);
- k_init_timer(&tsk->timer, (Handler)tipc_sk_timeout, tsk->portid);
+ setup_timer(&tsk->timer, tipc_sk_timeout, (unsigned long)tsk);
sk->sk_backlog_rcv = tipc_backlog_rcv;
sk->sk_rcvbuf = sysctl_tipc_rmem[1];
sk->sk_data_ready = tipc_data_ready;
@@ -389,7 +388,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
*
* Returns 0 on success, errno otherwise
*/
-int tipc_sock_create_local(int type, struct socket **res)
+int tipc_sock_create_local(struct net *net, int type, struct socket **res)
{
int rc;
@@ -398,7 +397,7 @@ int tipc_sock_create_local(int type, struct socket **res)
pr_err("Failed to create kernel socket\n");
return rc;
}
- tipc_sk_create(&init_net, *res, 0, 1);
+ tipc_sk_create(net, *res, 0, 1);
return 0;
}
@@ -473,9 +472,11 @@ static void tipc_sk_callback(struct rcu_head *head)
static int tipc_release(struct socket *sock)
{
struct sock *sk = sock->sk;
+ struct net *net = sock_net(sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_sock *tsk;
struct sk_buff *skb;
- u32 dnode;
+ u32 dnode, probing_state;
/*
* Exit if socket isn't fully initialized (occurs when a failed accept()
@@ -503,26 +504,28 @@ static int tipc_release(struct socket *sock)
(sock->state == SS_CONNECTED)) {
sock->state = SS_DISCONNECTING;
tsk->connected = 0;
- tipc_node_remove_conn(dnode, tsk->portid);
+ tipc_node_remove_conn(net, dnode, tsk->portid);
}
- if (tipc_msg_reverse(skb, &dnode, TIPC_ERR_NO_PORT))
- tipc_link_xmit_skb(skb, dnode, 0);
+ if (tipc_msg_reverse(net, skb, &dnode,
+ TIPC_ERR_NO_PORT))
+ tipc_link_xmit_skb(net, skb, dnode, 0);
}
}
tipc_sk_withdraw(tsk, 0, NULL);
- k_cancel_timer(&tsk->timer);
+ probing_state = tsk->probing_state;
+ if (del_timer_sync(&tsk->timer) && probing_state != TIPC_CONN_PROBING)
+ sock_put(sk);
tipc_sk_remove(tsk);
if (tsk->connected) {
- skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
- SHORT_H_SIZE, 0, dnode, tipc_own_addr,
- tsk_peer_port(tsk),
+ skb = tipc_msg_create(net, TIPC_CRITICAL_IMPORTANCE,
+ TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode,
+ tn->own_addr, tsk_peer_port(tsk),
tsk->portid, TIPC_ERR_NO_PORT);
if (skb)
- tipc_link_xmit_skb(skb, dnode, tsk->portid);
- tipc_node_remove_conn(dnode, tsk->portid);
+ tipc_link_xmit_skb(net, skb, dnode, tsk->portid);
+ tipc_node_remove_conn(net, dnode, tsk->portid);
}
- k_term_timer(&tsk->timer);
/* Discard any remaining (connection-based) messages in receive queue */
__skb_queue_purge(&sk->sk_receive_queue);
@@ -615,6 +618,7 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
{
struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
struct tipc_sock *tsk = tipc_sk(sock->sk);
+ struct tipc_net *tn = net_generic(sock_net(sock->sk), tipc_net_id);
memset(addr, 0, sizeof(*addr));
if (peer) {
@@ -625,7 +629,7 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
addr->addr.id.node = tsk_peer_node(tsk);
} else {
addr->addr.id.ref = tsk->portid;
- addr->addr.id.node = tipc_own_addr;
+ addr->addr.id.node = tn->own_addr;
}
*uaddr_len = sizeof(*addr);
@@ -724,6 +728,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
struct msghdr *msg, size_t dsz, long timeo)
{
struct sock *sk = sock->sk;
+ struct net *net = sock_net(sk);
struct tipc_msg *mhdr = &tipc_sk(sk)->phdr;
struct sk_buff_head head;
uint mtu;
@@ -741,12 +746,12 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
new_mtu:
mtu = tipc_bclink_get_mtu();
__skb_queue_head_init(&head);
- rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &head);
+ rc = tipc_msg_build(net, mhdr, msg, 0, dsz, mtu, &head);
if (unlikely(rc < 0))
return rc;
do {
- rc = tipc_bclink_xmit(&head);
+ rc = tipc_bclink_xmit(net, &head);
if (likely(rc >= 0)) {
rc = dsz;
break;
@@ -765,7 +770,7 @@ new_mtu:
/* tipc_sk_mcast_rcv - Deliver multicast message to all destination sockets
*/
-void tipc_sk_mcast_rcv(struct sk_buff *buf)
+void tipc_sk_mcast_rcv(struct net *net, struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
struct tipc_port_list dports = {0, NULL, };
@@ -774,15 +779,12 @@ void tipc_sk_mcast_rcv(struct sk_buff *buf)
uint i, last, dst = 0;
u32 scope = TIPC_CLUSTER_SCOPE;
- if (in_own_node(msg_orignode(msg)))
+ if (in_own_node(net, msg_orignode(msg)))
scope = TIPC_NODE_SCOPE;
/* Create destination port list: */
- tipc_nametbl_mc_translate(msg_nametype(msg),
- msg_namelower(msg),
- msg_nameupper(msg),
- scope,
- &dports);
+ tipc_nametbl_mc_translate(net, msg_nametype(msg), msg_namelower(msg),
+ msg_nameupper(msg), scope, &dports);
last = dports.count;
if (!last) {
kfree_skb(buf);
@@ -797,7 +799,7 @@ void tipc_sk_mcast_rcv(struct sk_buff *buf)
continue;
}
msg_set_destport(msg, item->ports[i]);
- tipc_sk_rcv(b);
+ tipc_sk_rcv(net, b);
}
}
tipc_port_list_free(&dports);
@@ -829,7 +831,7 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode,
if (conn_cong)
tsk->sk.sk_write_space(&tsk->sk);
} else if (msg_type(msg) == CONN_PROBE) {
- if (!tipc_msg_reverse(buf, dnode, TIPC_OK))
+ if (!tipc_msg_reverse(sock_net(&tsk->sk), buf, dnode, TIPC_OK))
return TIPC_OK;
msg_set_type(msg, CONN_PROBE_REPLY);
return TIPC_FWD_MSG;
@@ -885,6 +887,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk);
+ struct net *net = sock_net(sk);
struct tipc_msg *mhdr = &tsk->phdr;
u32 dnode, dport;
struct sk_buff_head head;
@@ -942,7 +945,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
msg_set_nametype(mhdr, type);
msg_set_nameinst(mhdr, inst);
msg_set_lookup_scope(mhdr, tipc_addr_scope(domain));
- dport = tipc_nametbl_translate(type, inst, &dnode);
+ dport = tipc_nametbl_translate(net, type, inst, &dnode);
msg_set_destnode(mhdr, dnode);
msg_set_destport(mhdr, dport);
if (unlikely(!dport && !dnode)) {
@@ -959,16 +962,16 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
}
new_mtu:
- mtu = tipc_node_get_mtu(dnode, tsk->portid);
+ mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
__skb_queue_head_init(&head);
- rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &head);
+ rc = tipc_msg_build(net, mhdr, m, 0, dsz, mtu, &head);
if (rc < 0)
goto exit;
do {
skb = skb_peek(&head);
TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
- rc = tipc_link_xmit(&head, dnode, tsk->portid);
+ rc = tipc_link_xmit(net, &head, dnode, tsk->portid);
if (likely(rc >= 0)) {
if (sock->state != SS_READY)
sock->state = SS_CONNECTING;
@@ -1037,6 +1040,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t dsz)
{
struct sock *sk = sock->sk;
+ struct net *net = sock_net(sk);
struct tipc_sock *tsk = tipc_sk(sk);
struct tipc_msg *mhdr = &tsk->phdr;
struct sk_buff_head head;
@@ -1075,12 +1079,12 @@ next:
mtu = tsk->max_pkt;
send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
__skb_queue_head_init(&head);
- rc = tipc_msg_build(mhdr, m, sent, send, mtu, &head);
+ rc = tipc_msg_build(net, mhdr, m, sent, send, mtu, &head);
if (unlikely(rc < 0))
goto exit;
do {
if (likely(!tsk_conn_cong(tsk))) {
- rc = tipc_link_xmit(&head, dnode, portid);
+ rc = tipc_link_xmit(net, &head, dnode, portid);
if (likely(!rc)) {
tsk->sent_unacked++;
sent += send;
@@ -1089,7 +1093,8 @@ next:
goto next;
}
if (rc == -EMSGSIZE) {
- tsk->max_pkt = tipc_node_get_mtu(dnode, portid);
+ tsk->max_pkt = tipc_node_get_mtu(net, dnode,
+ portid);
goto next;
}
if (rc != -ELINKCONG)
@@ -1131,6 +1136,7 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
u32 peer_node)
{
+ struct net *net = sock_net(&tsk->sk);
struct tipc_msg *msg = &tsk->phdr;
msg_set_destnode(msg, peer_node);
@@ -1139,12 +1145,13 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
msg_set_lookup_scope(msg, 0);
msg_set_hdr_sz(msg, SHORT_H_SIZE);
- tsk->probing_interval = CONN_PROBING_INTERVAL;
+ tsk->probing_intv = CONN_PROBING_INTERVAL;
tsk->probing_state = TIPC_CONN_OK;
tsk->connected = 1;
- k_start_timer(&tsk->timer, tsk->probing_interval);
- tipc_node_add_conn(peer_node, tsk->portid, peer_port);
- tsk->max_pkt = tipc_node_get_mtu(peer_node, tsk->portid);
+ if (!mod_timer(&tsk->timer, jiffies + tsk->probing_intv))
+ sock_hold(&tsk->sk);
+ tipc_node_add_conn(net, peer_node, tsk->portid, peer_port);
+ tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid);
}
/**
@@ -1243,6 +1250,8 @@ static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
{
+ struct net *net = sock_net(&tsk->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *skb = NULL;
struct tipc_msg *msg;
u32 peer_port = tsk_peer_port(tsk);
@@ -1250,13 +1259,14 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
if (!tsk->connected)
return;
- skb = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0, dnode,
- tipc_own_addr, peer_port, tsk->portid, TIPC_OK);
+ skb = tipc_msg_create(net, CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0,
+ dnode, tn->own_addr, peer_port, tsk->portid,
+ TIPC_OK);
if (!skb)
return;
msg = buf_msg(skb);
msg_set_msgcnt(msg, ack);
- tipc_link_xmit_skb(skb, dnode, msg_link_selector(msg));
+ tipc_link_xmit_skb(net, skb, dnode, msg_link_selector(msg));
}
static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
@@ -1549,6 +1559,7 @@ static void tipc_data_ready(struct sock *sk)
static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
{
struct sock *sk = &tsk->sk;
+ struct net *net = sock_net(sk);
struct socket *sock = sk->sk_socket;
struct tipc_msg *msg = buf_msg(*buf);
int retval = -TIPC_ERR_NO_PORT;
@@ -1564,7 +1575,7 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
sock->state = SS_DISCONNECTING;
tsk->connected = 0;
/* let timer expire on it's own */
- tipc_node_remove_conn(tsk_peer_node(tsk),
+ tipc_node_remove_conn(net, tsk_peer_node(tsk),
tsk->portid);
}
retval = TIPC_OK;
@@ -1722,6 +1733,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
int rc;
u32 onode;
struct tipc_sock *tsk = tipc_sk(sk);
+ struct net *net = sock_net(sk);
uint truesize = skb->truesize;
rc = filter_rcv(sk, skb);
@@ -1732,10 +1744,10 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
return 0;
}
- if ((rc < 0) && !tipc_msg_reverse(skb, &onode, -rc))
+ if ((rc < 0) && !tipc_msg_reverse(net, skb, &onode, -rc))
return 0;
- tipc_link_xmit_skb(skb, onode, 0);
+ tipc_link_xmit_skb(net, skb, onode, 0);
return 0;
}
@@ -1746,7 +1758,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* Consumes buffer
* Returns 0 if success, or errno: -EHOSTUNREACH
*/
-int tipc_sk_rcv(struct sk_buff *skb)
+int tipc_sk_rcv(struct net *net, struct sk_buff *skb)
{
struct tipc_sock *tsk;
struct sock *sk;
@@ -1756,9 +1768,9 @@ int tipc_sk_rcv(struct sk_buff *skb)
u32 dnode;
/* Validate destination and message */
- tsk = tipc_sk_lookup(dport);
+ tsk = tipc_sk_lookup(net, dport);
if (unlikely(!tsk)) {
- rc = tipc_msg_eval(skb, &dnode);
+ rc = tipc_msg_eval(net, skb, &dnode);
goto exit;
}
sk = &tsk->sk;
@@ -1780,10 +1792,10 @@ int tipc_sk_rcv(struct sk_buff *skb)
if (likely(!rc))
return 0;
exit:
- if ((rc < 0) && !tipc_msg_reverse(skb, &dnode, -rc))
+ if ((rc < 0) && !tipc_msg_reverse(net, skb, &dnode, -rc))
return -EHOSTUNREACH;
- tipc_link_xmit_skb(skb, dnode, 0);
+ tipc_link_xmit_skb(net, skb, dnode, 0);
return (rc < 0) ? -EHOSTUNREACH : 0;
}
@@ -2040,6 +2052,8 @@ exit:
static int tipc_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
+ struct net *net = sock_net(sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_sock *tsk = tipc_sk(sk);
struct sk_buff *skb;
u32 dnode;
@@ -2062,21 +2076,23 @@ restart:
kfree_skb(skb);
goto restart;
}
- if (tipc_msg_reverse(skb, &dnode, TIPC_CONN_SHUTDOWN))
- tipc_link_xmit_skb(skb, dnode, tsk->portid);
- tipc_node_remove_conn(dnode, tsk->portid);
+ if (tipc_msg_reverse(net, skb, &dnode,
+ TIPC_CONN_SHUTDOWN))
+ tipc_link_xmit_skb(net, skb, dnode,
+ tsk->portid);
+ tipc_node_remove_conn(net, dnode, tsk->portid);
} else {
dnode = tsk_peer_node(tsk);
- skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
+ skb = tipc_msg_create(net, TIPC_CRITICAL_IMPORTANCE,
TIPC_CONN_MSG, SHORT_H_SIZE,
- 0, dnode, tipc_own_addr,
+ 0, dnode, tn->own_addr,
tsk_peer_port(tsk),
tsk->portid, TIPC_CONN_SHUTDOWN);
- tipc_link_xmit_skb(skb, dnode, tsk->portid);
+ tipc_link_xmit_skb(net, skb, dnode, tsk->portid);
}
tsk->connected = 0;
sock->state = SS_DISCONNECTING;
- tipc_node_remove_conn(dnode, tsk->portid);
+ tipc_node_remove_conn(net, dnode, tsk->portid);
/* fall through */
case SS_DISCONNECTING:
@@ -2097,18 +2113,15 @@ restart:
return res;
}
-static void tipc_sk_timeout(unsigned long portid)
+static void tipc_sk_timeout(unsigned long data)
{
- struct tipc_sock *tsk;
- struct sock *sk;
+ struct tipc_sock *tsk = (struct tipc_sock *)data;
+ struct sock *sk = &tsk->sk;
+ struct net *net = sock_net(sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct sk_buff *skb = NULL;
u32 peer_port, peer_node;
- tsk = tipc_sk_lookup(portid);
- if (!tsk)
- return;
-
- sk = &tsk->sk;
bh_lock_sock(sk);
if (!tsk->connected) {
bh_unlock_sock(sk);
@@ -2119,20 +2132,21 @@ static void tipc_sk_timeout(unsigned long portid)
if (tsk->probing_state == TIPC_CONN_PROBING) {
/* Previous probe not answered -> self abort */
- skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
- SHORT_H_SIZE, 0, tipc_own_addr,
- peer_node, portid, peer_port,
- TIPC_ERR_NO_PORT);
+ skb = tipc_msg_create(net, TIPC_CRITICAL_IMPORTANCE,
+ TIPC_CONN_MSG, SHORT_H_SIZE, 0,
+ tn->own_addr, peer_node, tsk->portid,
+ peer_port, TIPC_ERR_NO_PORT);
} else {
- skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE,
- 0, peer_node, tipc_own_addr,
- peer_port, portid, TIPC_OK);
+ skb = tipc_msg_create(net, CONN_MANAGER, CONN_PROBE, INT_H_SIZE,
+ 0, peer_node, tn->own_addr,
+ peer_port, tsk->portid, TIPC_OK);
tsk->probing_state = TIPC_CONN_PROBING;
- k_start_timer(&tsk->timer, tsk->probing_interval);
+ if (!mod_timer(&tsk->timer, jiffies + tsk->probing_intv))
+ sock_hold(sk);
}
bh_unlock_sock(sk);
if (skb)
- tipc_link_xmit_skb(skb, peer_node, portid);
+ tipc_link_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid);
exit:
sock_put(sk);
}
@@ -2140,6 +2154,7 @@ exit:
static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq)
{
+ struct net *net = sock_net(&tsk->sk);
struct publication *publ;
u32 key;
@@ -2149,7 +2164,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
if (key == tsk->portid)
return -EADDRINUSE;
- publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
+ publ = tipc_nametbl_publish(net, seq->type, seq->lower, seq->upper,
scope, tsk->portid, key);
if (unlikely(!publ))
return -EINVAL;
@@ -2163,6 +2178,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
struct tipc_name_seq const *seq)
{
+ struct net *net = sock_net(&tsk->sk);
struct publication *publ;
struct publication *safe;
int rc = -EINVAL;
@@ -2177,12 +2193,12 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
continue;
if (publ->upper != seq->upper)
break;
- tipc_nametbl_withdraw(publ->type, publ->lower,
+ tipc_nametbl_withdraw(net, publ->type, publ->lower,
publ->ref, publ->key);
rc = 0;
break;
}
- tipc_nametbl_withdraw(publ->type, publ->lower,
+ tipc_nametbl_withdraw(net, publ->type, publ->lower,
publ->ref, publ->key);
rc = 0;
}
@@ -2194,14 +2210,16 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
static int tipc_sk_show(struct tipc_sock *tsk, char *buf,
int len, int full_id)
{
+ struct net *net = sock_net(&tsk->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct publication *publ;
int ret;
if (full_id)
ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
- tipc_zone(tipc_own_addr),
- tipc_cluster(tipc_own_addr),
- tipc_node(tipc_own_addr), tsk->portid);
+ tipc_zone(tn->own_addr),
+ tipc_cluster(tn->own_addr),
+ tipc_node(tn->own_addr), tsk->portid);
else
ret = tipc_snprintf(buf, len, "%-10u:", tsk->portid);
@@ -2235,8 +2253,9 @@ static int tipc_sk_show(struct tipc_sock *tsk, char *buf,
return ret;
}
-struct sk_buff *tipc_sk_socks_show(void)
+struct sk_buff *tipc_sk_socks_show(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
const struct bucket_table *tbl;
struct rhash_head *pos;
struct sk_buff *buf;
@@ -2255,7 +2274,7 @@ struct sk_buff *tipc_sk_socks_show(void)
pb_len = ULTRA_STRING_MAX_LEN;
rcu_read_lock();
- tbl = rht_dereference_rcu((&tipc_sk_rht)->tbl, &tipc_sk_rht);
+ tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
for (i = 0; i < tbl->size; i++) {
rht_for_each_entry_rcu(tsk, pos, tbl, i, node) {
spin_lock_bh(&tsk->sk.sk_lock.slock);
@@ -2276,8 +2295,9 @@ struct sk_buff *tipc_sk_socks_show(void)
/* tipc_sk_reinit: set non-zero address in all existing sockets
* when we go from standalone to network mode.
*/
-void tipc_sk_reinit(void)
+void tipc_sk_reinit(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
const struct bucket_table *tbl;
struct rhash_head *pos;
struct tipc_sock *tsk;
@@ -2285,25 +2305,26 @@ void tipc_sk_reinit(void)
int i;
rcu_read_lock();
- tbl = rht_dereference_rcu((&tipc_sk_rht)->tbl, &tipc_sk_rht);
+ tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
for (i = 0; i < tbl->size; i++) {
rht_for_each_entry_rcu(tsk, pos, tbl, i, node) {
spin_lock_bh(&tsk->sk.sk_lock.slock);
msg = &tsk->phdr;
- msg_set_prevnode(msg, tipc_own_addr);
- msg_set_orignode(msg, tipc_own_addr);
+ msg_set_prevnode(msg, tn->own_addr);
+ msg_set_orignode(msg, tn->own_addr);
spin_unlock_bh(&tsk->sk.sk_lock.slock);
}
}
rcu_read_unlock();
}
-static struct tipc_sock *tipc_sk_lookup(u32 portid)
+static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_sock *tsk;
rcu_read_lock();
- tsk = rhashtable_lookup(&tipc_sk_rht, &portid);
+ tsk = rhashtable_lookup(&tn->sk_rht, &portid);
if (tsk)
sock_hold(&tsk->sk);
rcu_read_unlock();
@@ -2313,6 +2334,9 @@ static struct tipc_sock *tipc_sk_lookup(u32 portid)
static int tipc_sk_insert(struct tipc_sock *tsk)
{
+ struct sock *sk = &tsk->sk;
+ struct net *net = sock_net(sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
u32 remaining = (TIPC_MAX_PORT - TIPC_MIN_PORT) + 1;
u32 portid = prandom_u32() % remaining + TIPC_MIN_PORT;
@@ -2322,7 +2346,7 @@ static int tipc_sk_insert(struct tipc_sock *tsk)
portid = TIPC_MIN_PORT;
tsk->portid = portid;
sock_hold(&tsk->sk);
- if (rhashtable_lookup_insert(&tipc_sk_rht, &tsk->node))
+ if (rhashtable_lookup_insert(&tn->sk_rht, &tsk->node))
return 0;
sock_put(&tsk->sk);
}
@@ -2333,15 +2357,17 @@ static int tipc_sk_insert(struct tipc_sock *tsk)
static void tipc_sk_remove(struct tipc_sock *tsk)
{
struct sock *sk = &tsk->sk;
+ struct tipc_net *tn = net_generic(sock_net(sk), tipc_net_id);
- if (rhashtable_remove(&tipc_sk_rht, &tsk->node)) {
+ if (rhashtable_remove(&tn->sk_rht, &tsk->node)) {
WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
}
-int tipc_sk_rht_init(void)
+int tipc_sk_rht_init(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct rhashtable_params rht_params = {
.nelem_hint = 192,
.head_offset = offsetof(struct tipc_sock, node),
@@ -2354,15 +2380,17 @@ int tipc_sk_rht_init(void)
.shrink_decision = rht_shrink_below_30,
};
- return rhashtable_init(&tipc_sk_rht, &rht_params);
+ return rhashtable_init(&tn->sk_rht, &rht_params);
}
-void tipc_sk_rht_destroy(void)
+void tipc_sk_rht_destroy(struct net *net)
{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+
/* Wait for socket readers to complete */
synchronize_net();
- rhashtable_destroy(&tipc_sk_rht);
+ rhashtable_destroy(&tn->sk_rht);
}
/**
@@ -2494,8 +2522,9 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
return put_user(sizeof(value), ol);
}
-static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg)
+static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
+ struct sock *sk = sock->sk;
struct tipc_sioc_ln_req lnr;
void __user *argp = (void __user *)arg;
@@ -2503,7 +2532,8 @@ static int tipc_ioctl(struct socket *sk, unsigned int cmd, unsigned long arg)
case SIOCGETLINKNAME:
if (copy_from_user(&lnr, argp, sizeof(lnr)))
return -EFAULT;
- if (!tipc_node_get_linkname(lnr.bearer_id & 0xffff, lnr.peer,
+ if (!tipc_node_get_linkname(sock_net(sk),
+ lnr.bearer_id & 0xffff, lnr.peer,
lnr.linkname, TIPC_MAX_LINK_NAME)) {
if (copy_to_user(argp, &lnr, sizeof(lnr)))
return -EFAULT;
@@ -2675,6 +2705,8 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
int err;
void *hdr;
struct nlattr *attrs;
+ struct net *net = sock_net(skb->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
&tipc_genl_v2_family, NLM_F_MULTI, TIPC_NL_SOCK_GET);
@@ -2686,7 +2718,7 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,
goto genlmsg_cancel;
if (nla_put_u32(skb, TIPC_NLA_SOCK_REF, tsk->portid))
goto attr_msg_cancel;
- if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tipc_own_addr))
+ if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tn->own_addr))
goto attr_msg_cancel;
if (tsk->connected) {
@@ -2718,10 +2750,12 @@ int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb)
struct rhash_head *pos;
u32 prev_portid = cb->args[0];
u32 portid = prev_portid;
+ struct net *net = sock_net(skb->sk);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
int i;
rcu_read_lock();
- tbl = rht_dereference_rcu((&tipc_sk_rht)->tbl, &tipc_sk_rht);
+ tbl = rht_dereference_rcu((&tn->sk_rht)->tbl, &tn->sk_rht);
for (i = 0; i < tbl->size; i++) {
rht_for_each_entry_rcu(tsk, pos, tbl, i, node) {
spin_lock_bh(&tsk->sk.sk_lock.slock);
@@ -2827,6 +2861,7 @@ int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
u32 tsk_portid = cb->args[0];
u32 last_publ = cb->args[1];
u32 done = cb->args[2];
+ struct net *net = sock_net(skb->sk);
struct tipc_sock *tsk;
if (!tsk_portid) {
@@ -2852,7 +2887,7 @@ int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (done)
return 0;
- tsk = tipc_sk_lookup(tsk_portid);
+ tsk = tipc_sk_lookup(net, tsk_portid);
if (!tsk)
return -EINVAL;
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
index c7d46d069d89..f56c3fded51f 100644
--- a/net/tipc/socket.h
+++ b/net/tipc/socket.h
@@ -42,12 +42,19 @@
#define TIPC_FLOWCTRL_WIN (TIPC_CONNACK_INTV * 2)
#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
-int tipc_sk_rcv(struct sk_buff *buf);
-struct sk_buff *tipc_sk_socks_show(void);
-void tipc_sk_mcast_rcv(struct sk_buff *buf);
-void tipc_sk_reinit(void);
-int tipc_sk_rht_init(void);
-void tipc_sk_rht_destroy(void);
+
+int tipc_socket_init(void);
+void tipc_socket_stop(void);
+int tipc_sock_create_local(struct net *net, int type, struct socket **res);
+void tipc_sock_release_local(struct socket *sock);
+int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
+ int flags);
+int tipc_sk_rcv(struct net *net, struct sk_buff *buf);
+struct sk_buff *tipc_sk_socks_show(struct net *net);
+void tipc_sk_mcast_rcv(struct net *net, struct sk_buff *buf);
+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);
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 0344206b984f..72c339e432aa 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -50,33 +50,6 @@ struct tipc_subscriber {
struct list_head subscription_list;
};
-static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
- void *usr_data, void *buf, size_t len);
-static void *subscr_named_msg_event(int conid);
-static void subscr_conn_shutdown_event(int conid, void *usr_data);
-
-static atomic_t subscription_count = ATOMIC_INIT(0);
-
-static struct sockaddr_tipc topsrv_addr __read_mostly = {
- .family = AF_TIPC,
- .addrtype = TIPC_ADDR_NAMESEQ,
- .addr.nameseq.type = TIPC_TOP_SRV,
- .addr.nameseq.lower = TIPC_TOP_SRV,
- .addr.nameseq.upper = TIPC_TOP_SRV,
- .scope = TIPC_NODE_SCOPE
-};
-
-static struct tipc_server topsrv __read_mostly = {
- .saddr = &topsrv_addr,
- .imp = TIPC_CRITICAL_IMPORTANCE,
- .type = SOCK_SEQPACKET,
- .max_rcvbuf_size = sizeof(struct tipc_subscr),
- .name = "topology_server",
- .tipc_conn_recvmsg = subscr_conn_msg_event,
- .tipc_conn_new = subscr_named_msg_event,
- .tipc_conn_shutdown = subscr_conn_shutdown_event,
-};
-
/**
* htohl - convert value to endianness used by destination
* @in: value to convert
@@ -93,6 +66,7 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
u32 found_upper, u32 event, u32 port_ref,
u32 node)
{
+ struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
struct tipc_subscriber *subscriber = sub->subscriber;
struct kvec msg_sect;
@@ -103,8 +77,8 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
sub->evt.found_upper = htohl(found_upper, sub->swap);
sub->evt.port.ref = htohl(port_ref, sub->swap);
sub->evt.port.node = htohl(node, sub->swap);
- tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
- msg_sect.iov_len);
+ tipc_conn_sendmsg(tn->topsrv, subscriber->conid, NULL,
+ msg_sect.iov_base, msg_sect.iov_len);
}
/**
@@ -141,9 +115,11 @@ void tipc_subscr_report_overlap(struct tipc_subscription *sub, u32 found_lower,
subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
}
-static void subscr_timeout(struct tipc_subscription *sub)
+static void subscr_timeout(unsigned long data)
{
+ struct tipc_subscription *sub = (struct tipc_subscription *)data;
struct tipc_subscriber *subscriber = sub->subscriber;
+ struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
/* The spin lock per subscriber is used to protect its members */
spin_lock_bh(&subscriber->lock);
@@ -167,9 +143,8 @@ static void subscr_timeout(struct tipc_subscription *sub)
TIPC_SUBSCR_TIMEOUT, 0, 0);
/* Now destroy subscription */
- k_term_timer(&sub->timer);
kfree(sub);
- atomic_dec(&subscription_count);
+ atomic_dec(&tn->subscription_count);
}
/**
@@ -179,10 +154,12 @@ static void subscr_timeout(struct tipc_subscription *sub)
*/
static void subscr_del(struct tipc_subscription *sub)
{
+ struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
+
tipc_nametbl_unsubscribe(sub);
list_del(&sub->subscription_list);
kfree(sub);
- atomic_dec(&subscription_count);
+ atomic_dec(&tn->subscription_count);
}
/**
@@ -190,9 +167,12 @@ static void subscr_del(struct tipc_subscription *sub)
*
* Note: Must call it in process context since it might sleep.
*/
-static void subscr_terminate(struct tipc_subscriber *subscriber)
+static void subscr_terminate(struct tipc_subscription *sub)
{
- tipc_conn_terminate(&topsrv, subscriber->conid);
+ struct tipc_subscriber *subscriber = sub->subscriber;
+ struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
+
+ tipc_conn_terminate(tn->topsrv, subscriber->conid);
}
static void subscr_release(struct tipc_subscriber *subscriber)
@@ -207,8 +187,7 @@ static void subscr_release(struct tipc_subscriber *subscriber)
subscription_list) {
if (sub->timeout != TIPC_WAIT_FOREVER) {
spin_unlock_bh(&subscriber->lock);
- k_cancel_timer(&sub->timer);
- k_term_timer(&sub->timer);
+ del_timer_sync(&sub->timer);
spin_lock_bh(&subscriber->lock);
}
subscr_del(sub);
@@ -250,8 +229,7 @@ static void subscr_cancel(struct tipc_subscr *s,
if (sub->timeout != TIPC_WAIT_FOREVER) {
sub->timeout = TIPC_WAIT_FOREVER;
spin_unlock_bh(&subscriber->lock);
- k_cancel_timer(&sub->timer);
- k_term_timer(&sub->timer);
+ del_timer_sync(&sub->timer);
spin_lock_bh(&subscriber->lock);
}
subscr_del(sub);
@@ -262,9 +240,11 @@ static void subscr_cancel(struct tipc_subscr *s,
*
* Called with subscriber lock held.
*/
-static int subscr_subscribe(struct tipc_subscr *s,
+static int subscr_subscribe(struct net *net, struct tipc_subscr *s,
struct tipc_subscriber *subscriber,
- struct tipc_subscription **sub_p) {
+ struct tipc_subscription **sub_p)
+{
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_subscription *sub;
int swap;
@@ -279,7 +259,7 @@ static int subscr_subscribe(struct tipc_subscr *s,
}
/* Refuse subscription if global limit exceeded */
- if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
+ if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
pr_warn("Subscription rejected, limit reached (%u)\n",
TIPC_MAX_SUBSCRIPTIONS);
return -EINVAL;
@@ -293,10 +273,11 @@ static int subscr_subscribe(struct tipc_subscr *s,
}
/* Initialize subscription object */
+ sub->net = net;
sub->seq.type = htohl(s->seq.type, swap);
sub->seq.lower = htohl(s->seq.lower, swap);
sub->seq.upper = htohl(s->seq.upper, swap);
- sub->timeout = htohl(s->timeout, swap);
+ sub->timeout = msecs_to_jiffies(htohl(s->timeout, swap));
sub->filter = htohl(s->filter, swap);
if ((!(sub->filter & TIPC_SUB_PORTS) ==
!(sub->filter & TIPC_SUB_SERVICE)) ||
@@ -309,11 +290,10 @@ static int subscr_subscribe(struct tipc_subscr *s,
sub->subscriber = subscriber;
sub->swap = swap;
memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
- atomic_inc(&subscription_count);
+ atomic_inc(&tn->subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
- k_init_timer(&sub->timer,
- (Handler)subscr_timeout, (unsigned long)sub);
- k_start_timer(&sub->timer, sub->timeout);
+ setup_timer(&sub->timer, subscr_timeout, (unsigned long)sub);
+ mod_timer(&sub->timer, jiffies + sub->timeout);
}
*sub_p = sub;
return 0;
@@ -326,16 +306,18 @@ static void subscr_conn_shutdown_event(int conid, void *usr_data)
}
/* Handle one request to create a new subscription for the subscriber */
-static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
- void *usr_data, void *buf, size_t len)
+static void subscr_conn_msg_event(struct net *net, int conid,
+ struct sockaddr_tipc *addr, void *usr_data,
+ void *buf, size_t len)
{
struct tipc_subscriber *subscriber = usr_data;
struct tipc_subscription *sub = NULL;
spin_lock_bh(&subscriber->lock);
- if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) {
+ if (subscr_subscribe(net, (struct tipc_subscr *)buf, subscriber,
+ &sub) < 0) {
spin_unlock_bh(&subscriber->lock);
- subscr_terminate(subscriber);
+ subscr_terminate(sub);
return;
}
if (sub)
@@ -343,7 +325,6 @@ static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
spin_unlock_bh(&subscriber->lock);
}
-
/* Handle one request to establish a new subscriber */
static void *subscr_named_msg_event(int conid)
{
@@ -362,12 +343,50 @@ static void *subscr_named_msg_event(int conid)
return (void *)subscriber;
}
-int tipc_subscr_start(void)
+int tipc_subscr_start(struct net *net)
{
- return tipc_server_start(&topsrv);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ const char name[] = "topology_server";
+ struct tipc_server *topsrv;
+ struct sockaddr_tipc *saddr;
+
+ saddr = kzalloc(sizeof(*saddr), GFP_ATOMIC);
+ if (!saddr)
+ return -ENOMEM;
+ saddr->family = AF_TIPC;
+ saddr->addrtype = TIPC_ADDR_NAMESEQ;
+ 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;
+
+ topsrv = kzalloc(sizeof(*topsrv), GFP_ATOMIC);
+ if (!topsrv) {
+ kfree(saddr);
+ return -ENOMEM;
+ }
+ topsrv->net = net;
+ topsrv->saddr = saddr;
+ topsrv->imp = TIPC_CRITICAL_IMPORTANCE;
+ topsrv->type = SOCK_SEQPACKET;
+ topsrv->max_rcvbuf_size = sizeof(struct tipc_subscr);
+ topsrv->tipc_conn_recvmsg = subscr_conn_msg_event;
+ topsrv->tipc_conn_new = subscr_named_msg_event;
+ topsrv->tipc_conn_shutdown = subscr_conn_shutdown_event;
+
+ strncpy(topsrv->name, name, strlen(name) + 1);
+ tn->topsrv = topsrv;
+ atomic_set(&tn->subscription_count, 0);
+
+ return tipc_server_start(topsrv);
}
-void tipc_subscr_stop(void)
+void tipc_subscr_stop(struct net *net)
{
- tipc_server_stop(&topsrv);
+ struct tipc_net *tn = net_generic(net, tipc_net_id);
+ struct tipc_server *topsrv = tn->topsrv;
+
+ tipc_server_stop(topsrv);
+ kfree(topsrv->saddr);
+ kfree(topsrv);
}
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index 393e417bee3f..33488bd9fe3c 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -39,6 +39,9 @@
#include "server.h"
+#define TIPC_MAX_SUBSCRIPTIONS 65535
+#define TIPC_MAX_PUBLICATIONS 65535
+
struct tipc_subscription;
struct tipc_subscriber;
@@ -46,6 +49,7 @@ struct tipc_subscriber;
* struct tipc_subscription - TIPC network topology subscription object
* @subscriber: pointer to its subscriber
* @seq: name sequence associated with subscription
+ * @net: point to network namespace
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
* @timer: timer governing subscription duration (optional)
@@ -58,7 +62,8 @@ struct tipc_subscriber;
struct tipc_subscription {
struct tipc_subscriber *subscriber;
struct tipc_name_seq seq;
- u32 timeout;
+ struct net *net;
+ unsigned long timeout;
u32 filter;
struct timer_list timer;
struct list_head nameseq_list;
@@ -69,13 +74,10 @@ struct tipc_subscription {
int tipc_subscr_overlap(struct tipc_subscription *sub, u32 found_lower,
u32 found_upper);
-
void tipc_subscr_report_overlap(struct tipc_subscription *sub, u32 found_lower,
u32 found_upper, u32 event, u32 port_ref,
u32 node, int must);
-
-int tipc_subscr_start(void);
-
-void tipc_subscr_stop(void);
+int tipc_subscr_start(struct net *net);
+void tipc_subscr_stop(struct net *net);
#endif