mirror of
https://github.com/torvalds/linux.git
synced 2024-12-20 10:01:56 +00:00
Merge branch 'tipc-separate-link-and-aggregation'
Jon Maloy says: ==================== tipc: separate link and link aggregation layer This is the first batch of a longer series that has two main objectives: o Finer lock granularity during message sending and reception, especially regarding usage of the node spinlock. o Better separation between the link layer implementation and the link aggregation layer, represented by node.c::struct tipc_node. Hopefully these changes also make this part of code somewhat easier to comprehend and maintain. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7781e5d10a
@ -316,6 +316,29 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
void tipc_bclink_sync_state(struct tipc_node *n, struct tipc_msg *hdr)
|
||||
{
|
||||
u16 last = msg_last_bcast(hdr);
|
||||
int mtyp = msg_type(hdr);
|
||||
|
||||
if (unlikely(msg_user(hdr) != LINK_PROTOCOL))
|
||||
return;
|
||||
if (mtyp == STATE_MSG) {
|
||||
tipc_bclink_update_link_state(n, last);
|
||||
return;
|
||||
}
|
||||
/* Compatibility: older nodes don't know BCAST_PROTOCOL synchronization,
|
||||
* and transfer synch info in LINK_PROTOCOL messages.
|
||||
*/
|
||||
if (tipc_node_is_up(n))
|
||||
return;
|
||||
if ((mtyp != RESET_MSG) && (mtyp != ACTIVATE_MSG))
|
||||
return;
|
||||
n->bclink.last_sent = last;
|
||||
n->bclink.last_in = last;
|
||||
n->bclink.oos_state = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bclink_peek_nack - monitor retransmission requests sent by other nodes
|
||||
*
|
||||
@ -358,10 +381,9 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list)
|
||||
|
||||
/* Prepare clone of message for local node */
|
||||
skb = tipc_msg_reassemble(list);
|
||||
if (unlikely(!skb)) {
|
||||
__skb_queue_purge(list);
|
||||
if (unlikely(!skb))
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
|
||||
/* Broadcast to all nodes */
|
||||
if (likely(bclink)) {
|
||||
tipc_bclink_lock(net);
|
||||
@ -413,7 +435,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
|
||||
* all nodes in the cluster don't ACK at the same time
|
||||
*/
|
||||
if (((seqno - tn->own_addr) % TIPC_MIN_LINK_WIN) == 0) {
|
||||
tipc_link_proto_xmit(node->active_links[node->addr & 1],
|
||||
tipc_link_proto_xmit(node_active_link(node, node->addr),
|
||||
STATE_MSG, 0, 0, 0, 0);
|
||||
tn->bcl->stats.sent_acks++;
|
||||
}
|
||||
@ -925,7 +947,6 @@ int tipc_bclink_init(struct net *net)
|
||||
tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
|
||||
bcl->bearer_id = MAX_BEARERS;
|
||||
rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer);
|
||||
bcl->state = WORKING_WORKING;
|
||||
bcl->pmsg = (struct tipc_msg *)&bcl->proto_msg;
|
||||
msg_set_prevnode(bcl->pmsg, tn->own_addr);
|
||||
strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
|
||||
|
@ -133,5 +133,6 @@ void tipc_bclink_wakeup_users(struct net *net);
|
||||
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg);
|
||||
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);
|
||||
void tipc_bclink_input(struct net *net);
|
||||
void tipc_bclink_sync_state(struct tipc_node *n, struct tipc_msg *msg);
|
||||
|
||||
#endif
|
||||
|
@ -470,6 +470,32 @@ void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf,
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* tipc_bearer_xmit() -send buffer to destination over bearer
|
||||
*/
|
||||
void tipc_bearer_xmit(struct net *net, u32 bearer_id,
|
||||
struct sk_buff_head *xmitq,
|
||||
struct tipc_media_addr *dst)
|
||||
{
|
||||
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
||||
struct tipc_bearer *b;
|
||||
struct sk_buff *skb, *tmp;
|
||||
|
||||
if (skb_queue_empty(xmitq))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
|
||||
if (likely(b)) {
|
||||
skb_queue_walk_safe(xmitq, skb, tmp) {
|
||||
__skb_dequeue(xmitq);
|
||||
b->media->send_msg(net, skb, b, dst);
|
||||
/* Until we remove cloning in tipc_l2_send_msg(): */
|
||||
kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_l2_rcv_msg - handle incoming TIPC message from an interface
|
||||
* @buf: the received packet
|
||||
|
@ -217,5 +217,8 @@ void tipc_bearer_cleanup(void);
|
||||
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);
|
||||
void tipc_bearer_xmit(struct net *net, u32 bearer_id,
|
||||
struct sk_buff_head *xmitq,
|
||||
struct tipc_media_addr *dst);
|
||||
|
||||
#endif /* _TIPC_BEARER_H */
|
||||
|
@ -129,6 +129,11 @@ static inline int less(u16 left, u16 right)
|
||||
return less_eq(left, right) && (mod(right) != mod(left));
|
||||
}
|
||||
|
||||
static inline int in_range(u16 val, u16 min, u16 max)
|
||||
{
|
||||
return !less(val, min) && !more(val, max);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
int tipc_register_sysctl(void);
|
||||
void tipc_unregister_sysctl(void);
|
||||
|
@ -35,7 +35,7 @@
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "link.h"
|
||||
#include "node.h"
|
||||
#include "discover.h"
|
||||
|
||||
/* min delay during bearer start up */
|
||||
@ -125,7 +125,6 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
|
||||
{
|
||||
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
||||
struct tipc_node *node;
|
||||
struct tipc_link *link;
|
||||
struct tipc_media_addr maddr;
|
||||
struct sk_buff *rbuf;
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
@ -170,13 +169,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
|
||||
return;
|
||||
tipc_node_lock(node);
|
||||
node->capabilities = caps;
|
||||
link = node->links[bearer->identity];
|
||||
|
||||
/* Prepare to validate requesting node's signature and media address */
|
||||
sign_match = (signature == node->signature);
|
||||
addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr));
|
||||
link_up = link && tipc_link_is_up(link);
|
||||
|
||||
tipc_node_check_dest(node, bearer, &link_up, &addr_match, &maddr);
|
||||
|
||||
/* These three flags give us eight permutations: */
|
||||
|
||||
@ -239,16 +235,8 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
|
||||
if (accept_sign)
|
||||
node->signature = signature;
|
||||
|
||||
if (accept_addr) {
|
||||
if (!link)
|
||||
link = tipc_link_create(node, bearer, &maddr);
|
||||
if (link) {
|
||||
memcpy(&link->media_addr, &maddr, sizeof(maddr));
|
||||
tipc_link_reset(link);
|
||||
} else {
|
||||
respond = false;
|
||||
}
|
||||
}
|
||||
if (accept_addr && !tipc_node_update_dest(node, bearer, &maddr))
|
||||
respond = false;
|
||||
|
||||
/* Send response, if necessary */
|
||||
if (respond && (mtyp == DSC_REQ_MSG)) {
|
||||
|
1517
net/tipc/link.c
1517
net/tipc/link.c
File diff suppressed because it is too large
Load Diff
@ -49,19 +49,21 @@
|
||||
*/
|
||||
#define INVALID_LINK_SEQ 0x10000
|
||||
|
||||
/* Link working states
|
||||
*/
|
||||
#define WORKING_WORKING 560810u
|
||||
#define WORKING_UNKNOWN 560811u
|
||||
#define RESET_UNKNOWN 560812u
|
||||
#define RESET_RESET 560813u
|
||||
|
||||
/* Link endpoint execution states
|
||||
/* Link endpoint receive states
|
||||
*/
|
||||
#define LINK_STARTED 0x0001
|
||||
#define LINK_STOPPED 0x0002
|
||||
#define LINK_SYNCHING 0x0004
|
||||
#define LINK_FAILINGOVER 0x0008
|
||||
enum {
|
||||
TIPC_LINK_OPEN,
|
||||
TIPC_LINK_BLOCKED,
|
||||
TIPC_LINK_TUNNEL
|
||||
};
|
||||
|
||||
/* Events returned from link at packet reception or at timeout
|
||||
*/
|
||||
enum {
|
||||
TIPC_LINK_UP_EVT = 1,
|
||||
TIPC_LINK_DOWN_EVT = (1 << 1)
|
||||
};
|
||||
|
||||
/* Starting value for maximum packet size negotiation on unicast links
|
||||
* (unless bearer MTU is less)
|
||||
@ -106,7 +108,6 @@ struct tipc_stats {
|
||||
* @timer: link timer
|
||||
* @owner: pointer to peer node
|
||||
* @refcnt: reference counter for permanent references (owner node & timer)
|
||||
* @flags: execution state flags for link endpoint instance
|
||||
* @peer_session: link session # being used by peer end of link
|
||||
* @peer_bearer_id: bearer id used by link's peer endpoint
|
||||
* @bearer_id: local bearer id used by link
|
||||
@ -119,6 +120,7 @@ struct tipc_stats {
|
||||
* @pmsg: convenience pointer to "proto_msg" field
|
||||
* @priority: current link priority
|
||||
* @net_plane: current link network plane ('A' through 'H')
|
||||
* @exec_mode: transmit/receive mode for link endpoint instance
|
||||
* @backlog_limit: backlog queue congestion thresholds (indexed by importance)
|
||||
* @exp_msg_count: # of tunnelled messages expected during link changeover
|
||||
* @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset
|
||||
@ -144,12 +146,9 @@ struct tipc_link {
|
||||
u32 addr;
|
||||
char name[TIPC_MAX_LINK_NAME];
|
||||
struct tipc_media_addr media_addr;
|
||||
struct timer_list timer;
|
||||
struct tipc_node *owner;
|
||||
struct kref ref;
|
||||
|
||||
/* Management and link supervision data */
|
||||
unsigned int flags;
|
||||
u32 peer_session;
|
||||
u32 peer_bearer_id;
|
||||
u32 bearer_id;
|
||||
@ -165,6 +164,7 @@ struct tipc_link {
|
||||
struct tipc_msg *pmsg;
|
||||
u32 priority;
|
||||
char net_plane;
|
||||
u8 exec_mode;
|
||||
u16 synch_point;
|
||||
|
||||
/* Failover */
|
||||
@ -192,8 +192,8 @@ struct tipc_link {
|
||||
u16 rcv_nxt;
|
||||
u32 rcv_unacked;
|
||||
struct sk_buff_head deferdq;
|
||||
struct sk_buff_head inputq;
|
||||
struct sk_buff_head namedq;
|
||||
struct sk_buff_head *inputq;
|
||||
struct sk_buff_head *namedq;
|
||||
|
||||
/* Congestion handling */
|
||||
struct sk_buff_head wakeupq;
|
||||
@ -207,9 +207,11 @@ struct tipc_link {
|
||||
|
||||
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);
|
||||
struct tipc_link *tipc_link_create(struct tipc_node *n,
|
||||
struct tipc_bearer *b,
|
||||
const struct tipc_media_addr *maddr,
|
||||
struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *namedq);
|
||||
void tipc_link_delete(struct tipc_link *link);
|
||||
void tipc_link_delete_list(struct net *net, unsigned int bearer_id);
|
||||
void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
|
||||
@ -221,12 +223,11 @@ void tipc_link_purge_queues(struct tipc_link *l_ptr);
|
||||
void tipc_link_purge_backlog(struct tipc_link *l);
|
||||
void tipc_link_reset_all(struct tipc_node *node);
|
||||
void tipc_link_reset(struct tipc_link *l_ptr);
|
||||
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);
|
||||
void tipc_link_activate(struct tipc_link *link);
|
||||
int __tipc_link_xmit(struct net *net, struct tipc_link *link,
|
||||
struct sk_buff_head *list);
|
||||
int tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list,
|
||||
struct sk_buff_head *xmitq);
|
||||
void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
|
||||
u32 gap, u32 tolerance, u32 priority);
|
||||
void tipc_link_push_packets(struct tipc_link *l_ptr);
|
||||
@ -243,33 +244,12 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info);
|
||||
int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]);
|
||||
void link_prepare_wakeup(struct tipc_link *l);
|
||||
|
||||
int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq);
|
||||
int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
|
||||
struct sk_buff_head *xmitq);
|
||||
static inline u32 link_own_addr(struct tipc_link *l)
|
||||
{
|
||||
return msg_prevnode(l->pmsg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link status checking routines
|
||||
*/
|
||||
static inline int link_working_working(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == WORKING_WORKING;
|
||||
}
|
||||
|
||||
static inline int link_working_unknown(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == WORKING_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline int link_reset_unknown(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == RESET_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline int link_reset_reset(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == RESET_RESET;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define _TIPC_MSG_H
|
||||
|
||||
#include <linux/tipc.h>
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* Constants and routines used to read and write TIPC payload message headers
|
||||
@ -658,12 +659,12 @@ static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
|
||||
/*
|
||||
* Word 5
|
||||
*/
|
||||
static inline u32 msg_session(struct tipc_msg *m)
|
||||
static inline u16 msg_session(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 5, 16, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_session(struct tipc_msg *m, u32 n)
|
||||
static inline void msg_set_session(struct tipc_msg *m, u16 n)
|
||||
{
|
||||
msg_set_bits(m, 5, 16, 0xffff, n);
|
||||
}
|
||||
@ -766,6 +767,22 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
|
||||
msg_set_bits(m, 9, 0, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline bool msg_is_traffic(struct tipc_msg *m)
|
||||
{
|
||||
if (likely(msg_user(m) != LINK_PROTOCOL))
|
||||
return true;
|
||||
if ((msg_type(m) == RESET_MSG) || (msg_type(m) == ACTIVATE_MSG))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool msg_peer_is_up(struct tipc_msg *m)
|
||||
{
|
||||
if (likely(msg_is_traffic(m)))
|
||||
return false;
|
||||
return msg_redundant_link(m);
|
||||
}
|
||||
|
||||
struct sk_buff *tipc_buf_acquire(u32 size);
|
||||
bool tipc_msg_validate(struct sk_buff *skb);
|
||||
bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode,
|
||||
@ -879,4 +896,36 @@ static inline bool tipc_skb_queue_tail(struct sk_buff_head *list,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* tipc_skb_queue_sorted(); sort pkt into list according to sequence number
|
||||
* @list: list to be appended to
|
||||
* @skb: buffer to add
|
||||
* Returns true if queue should treated further, otherwise false
|
||||
*/
|
||||
static inline bool __tipc_skb_queue_sorted(struct sk_buff_head *list,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *_skb, *tmp;
|
||||
struct tipc_msg *hdr = buf_msg(skb);
|
||||
u16 seqno = msg_seqno(hdr);
|
||||
|
||||
if (skb_queue_empty(list) || (msg_user(hdr) == LINK_PROTOCOL)) {
|
||||
__skb_queue_head(list, skb);
|
||||
return true;
|
||||
}
|
||||
if (likely(less(seqno, buf_seqno(skb_peek(list))))) {
|
||||
__skb_queue_head(list, skb);
|
||||
return true;
|
||||
}
|
||||
if (!more(seqno, buf_seqno(skb_peek_tail(list)))) {
|
||||
skb_queue_walk_safe(list, _skb, tmp) {
|
||||
if (likely(less(seqno, buf_seqno(_skb)))) {
|
||||
__skb_queue_before(list, _skb, skb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
__skb_queue_tail(list, skb);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -96,13 +96,13 @@ void named_cluster_distribute(struct net *net, struct sk_buff *skb)
|
||||
dnode = node->addr;
|
||||
if (in_own_node(net, dnode))
|
||||
continue;
|
||||
if (!tipc_node_active_links(node))
|
||||
if (!tipc_node_is_up(node))
|
||||
continue;
|
||||
oskb = pskb_copy(skb, GFP_ATOMIC);
|
||||
if (!oskb)
|
||||
break;
|
||||
msg_set_destnode(buf_msg(oskb), dnode);
|
||||
tipc_link_xmit_skb(net, oskb, dnode, dnode);
|
||||
tipc_node_xmit_skb(net, oskb, dnode, dnode);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -223,7 +223,7 @@ void tipc_named_node_up(struct net *net, u32 dnode)
|
||||
&tn->nametbl->publ_list[TIPC_ZONE_SCOPE]);
|
||||
rcu_read_unlock();
|
||||
|
||||
tipc_link_xmit(net, &head, dnode, dnode);
|
||||
tipc_node_xmit(net, &head, dnode, dnode);
|
||||
}
|
||||
|
||||
static void tipc_publ_subscribe(struct net *net, struct publication *publ,
|
||||
|
553
net/tipc/node.c
553
net/tipc/node.c
@ -40,10 +40,13 @@
|
||||
#include "name_distr.h"
|
||||
#include "socket.h"
|
||||
#include "bcast.h"
|
||||
#include "discover.h"
|
||||
|
||||
static void node_lost_contact(struct tipc_node *n_ptr);
|
||||
static void node_established_contact(struct tipc_node *n_ptr);
|
||||
static void tipc_node_delete(struct tipc_node *node);
|
||||
static void tipc_node_timeout(unsigned long data);
|
||||
static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
|
||||
|
||||
struct tipc_sock_conn {
|
||||
u32 port;
|
||||
@ -132,6 +135,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
|
||||
INIT_LIST_HEAD(&n_ptr->list);
|
||||
INIT_LIST_HEAD(&n_ptr->publ_list);
|
||||
INIT_LIST_HEAD(&n_ptr->conn_sks);
|
||||
skb_queue_head_init(&n_ptr->bclink.namedq);
|
||||
__skb_queue_head_init(&n_ptr->bclink.deferdq);
|
||||
hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
|
||||
list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
|
||||
@ -139,14 +143,32 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
|
||||
break;
|
||||
}
|
||||
list_add_tail_rcu(&n_ptr->list, &temp_node->list);
|
||||
n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
|
||||
n_ptr->state = SELF_DOWN_PEER_LEAVING;
|
||||
n_ptr->signature = INVALID_NODE_SIG;
|
||||
n_ptr->active_links[0] = INVALID_BEARER_ID;
|
||||
n_ptr->active_links[1] = INVALID_BEARER_ID;
|
||||
tipc_node_get(n_ptr);
|
||||
setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr);
|
||||
n_ptr->keepalive_intv = U32_MAX;
|
||||
exit:
|
||||
spin_unlock_bh(&tn->node_list_lock);
|
||||
return n_ptr;
|
||||
}
|
||||
|
||||
static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l)
|
||||
{
|
||||
unsigned long tol = l->tolerance;
|
||||
unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4;
|
||||
unsigned long keepalive_intv = msecs_to_jiffies(intv);
|
||||
|
||||
/* Link with lowest tolerance determines timer interval */
|
||||
if (keepalive_intv < n->keepalive_intv)
|
||||
n->keepalive_intv = keepalive_intv;
|
||||
|
||||
/* Ensure link's abort limit corresponds to current interval */
|
||||
l->abort_limit = l->tolerance / jiffies_to_msecs(n->keepalive_intv);
|
||||
}
|
||||
|
||||
static void tipc_node_delete(struct tipc_node *node)
|
||||
{
|
||||
list_del_rcu(&node->list);
|
||||
@ -160,8 +182,11 @@ void tipc_node_stop(struct net *net)
|
||||
struct tipc_node *node, *t_node;
|
||||
|
||||
spin_lock_bh(&tn->node_list_lock);
|
||||
list_for_each_entry_safe(node, t_node, &tn->node_list, list)
|
||||
list_for_each_entry_safe(node, t_node, &tn->node_list, list) {
|
||||
if (del_timer(&node->timer))
|
||||
tipc_node_put(node);
|
||||
tipc_node_put(node);
|
||||
}
|
||||
spin_unlock_bh(&tn->node_list_lock);
|
||||
}
|
||||
|
||||
@ -219,131 +244,170 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
|
||||
tipc_node_put(node);
|
||||
}
|
||||
|
||||
/* tipc_node_timeout - handle expiration of node timer
|
||||
*/
|
||||
static void tipc_node_timeout(unsigned long data)
|
||||
{
|
||||
struct tipc_node *n = (struct tipc_node *)data;
|
||||
struct sk_buff_head xmitq;
|
||||
struct tipc_link *l;
|
||||
struct tipc_media_addr *maddr;
|
||||
int bearer_id;
|
||||
int rc = 0;
|
||||
|
||||
__skb_queue_head_init(&xmitq);
|
||||
|
||||
for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
|
||||
tipc_node_lock(n);
|
||||
l = n->links[bearer_id].link;
|
||||
if (l) {
|
||||
/* Link tolerance may change asynchronously: */
|
||||
tipc_node_calculate_timer(n, l);
|
||||
rc = tipc_link_timeout(l, &xmitq);
|
||||
if (rc & TIPC_LINK_DOWN_EVT)
|
||||
tipc_link_reset(l);
|
||||
}
|
||||
tipc_node_unlock(n);
|
||||
maddr = &n->links[bearer_id].maddr;
|
||||
tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr);
|
||||
}
|
||||
if (!mod_timer(&n->timer, jiffies + n->keepalive_intv))
|
||||
tipc_node_get(n);
|
||||
tipc_node_put(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_node_link_up - handle addition of link
|
||||
*
|
||||
* Link becomes active (alone or shared) or standby, depending on its priority.
|
||||
*/
|
||||
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
void tipc_node_link_up(struct tipc_node *n, int bearer_id)
|
||||
{
|
||||
struct tipc_link **active = &n_ptr->active_links[0];
|
||||
int *slot0 = &n->active_links[0];
|
||||
int *slot1 = &n->active_links[1];
|
||||
struct tipc_link_entry *links = n->links;
|
||||
struct tipc_link *l = n->links[bearer_id].link;
|
||||
|
||||
n_ptr->working_links++;
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
|
||||
n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
|
||||
/* Leave room for tunnel header when returning 'mtu' to users: */
|
||||
links[bearer_id].mtu = l->mtu - INT_H_SIZE;
|
||||
|
||||
n->working_links++;
|
||||
n->action_flags |= TIPC_NOTIFY_LINK_UP;
|
||||
n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
|
||||
|
||||
pr_debug("Established link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_ptr->net_plane);
|
||||
l->name, l->net_plane);
|
||||
|
||||
if (!active[0]) {
|
||||
active[0] = active[1] = l_ptr;
|
||||
node_established_contact(n_ptr);
|
||||
goto exit;
|
||||
/* No active links ? => take both active slots */
|
||||
if (*slot0 < 0) {
|
||||
*slot0 = bearer_id;
|
||||
*slot1 = bearer_id;
|
||||
node_established_contact(n);
|
||||
return;
|
||||
}
|
||||
if (l_ptr->priority < active[0]->priority) {
|
||||
pr_debug("New link <%s> becomes standby\n", l_ptr->name);
|
||||
goto exit;
|
||||
|
||||
/* Lower prio than current active ? => no slot */
|
||||
if (l->priority < links[*slot0].link->priority) {
|
||||
pr_debug("New link <%s> becomes standby\n", l->name);
|
||||
return;
|
||||
}
|
||||
tipc_link_dup_queue_xmit(active[0], l_ptr);
|
||||
if (l_ptr->priority == active[0]->priority) {
|
||||
active[0] = l_ptr;
|
||||
goto exit;
|
||||
tipc_link_dup_queue_xmit(links[*slot0].link, l);
|
||||
|
||||
/* Same prio as current active ? => take one slot */
|
||||
if (l->priority == links[*slot0].link->priority) {
|
||||
*slot0 = bearer_id;
|
||||
return;
|
||||
}
|
||||
pr_debug("Old link <%s> becomes standby\n", active[0]->name);
|
||||
if (active[1] != active[0])
|
||||
pr_debug("Old link <%s> becomes standby\n", active[1]->name);
|
||||
active[0] = active[1] = l_ptr;
|
||||
exit:
|
||||
/* Leave room for changeover header when returning 'mtu' to users: */
|
||||
n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
|
||||
n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* node_select_active_links - select active link
|
||||
*/
|
||||
static void node_select_active_links(struct tipc_node *n_ptr)
|
||||
{
|
||||
struct tipc_link **active = &n_ptr->active_links[0];
|
||||
u32 i;
|
||||
u32 highest_prio = 0;
|
||||
|
||||
active[0] = active[1] = NULL;
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
struct tipc_link *l_ptr = n_ptr->links[i];
|
||||
|
||||
if (!l_ptr || !tipc_link_is_up(l_ptr) ||
|
||||
(l_ptr->priority < highest_prio))
|
||||
continue;
|
||||
|
||||
if (l_ptr->priority > highest_prio) {
|
||||
highest_prio = l_ptr->priority;
|
||||
active[0] = active[1] = l_ptr;
|
||||
} else {
|
||||
active[1] = l_ptr;
|
||||
}
|
||||
}
|
||||
/* Higher prio than current active => take both active slots */
|
||||
pr_debug("Old link <%s> now standby\n", links[*slot0].link->name);
|
||||
*slot0 = bearer_id;
|
||||
*slot1 = bearer_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_node_link_down - handle loss of link
|
||||
*/
|
||||
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
void tipc_node_link_down(struct tipc_node *n, int bearer_id)
|
||||
{
|
||||
struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
|
||||
struct tipc_link **active;
|
||||
int *slot0 = &n->active_links[0];
|
||||
int *slot1 = &n->active_links[1];
|
||||
int i, highest = 0;
|
||||
struct tipc_link *l, *_l;
|
||||
|
||||
n_ptr->working_links--;
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
|
||||
n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
|
||||
l = n->links[bearer_id].link;
|
||||
n->working_links--;
|
||||
n->action_flags |= TIPC_NOTIFY_LINK_DOWN;
|
||||
n->link_id = l->peer_bearer_id << 16 | l->bearer_id;
|
||||
|
||||
if (!tipc_link_is_active(l_ptr)) {
|
||||
pr_debug("Lost standby link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_ptr->net_plane);
|
||||
return;
|
||||
}
|
||||
pr_debug("Lost link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_ptr->net_plane);
|
||||
l->name, l->net_plane);
|
||||
|
||||
active = &n_ptr->active_links[0];
|
||||
if (active[0] == l_ptr)
|
||||
active[0] = active[1];
|
||||
if (active[1] == l_ptr)
|
||||
active[1] = active[0];
|
||||
if (active[0] == l_ptr)
|
||||
node_select_active_links(n_ptr);
|
||||
if (tipc_node_is_up(n_ptr))
|
||||
tipc_link_failover_send_queue(l_ptr);
|
||||
/* Select new active link if any available */
|
||||
*slot0 = INVALID_BEARER_ID;
|
||||
*slot1 = INVALID_BEARER_ID;
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
_l = n->links[i].link;
|
||||
if (!_l || !tipc_link_is_up(_l))
|
||||
continue;
|
||||
if (_l->priority < highest)
|
||||
continue;
|
||||
if (_l->priority > highest) {
|
||||
highest = _l->priority;
|
||||
*slot0 = i;
|
||||
*slot1 = i;
|
||||
continue;
|
||||
}
|
||||
*slot1 = i;
|
||||
}
|
||||
if (tipc_node_is_up(n))
|
||||
tipc_link_failover_send_queue(l);
|
||||
else
|
||||
node_lost_contact(n_ptr);
|
||||
|
||||
/* Leave room for changeover header when returning 'mtu' to users: */
|
||||
if (active[0]) {
|
||||
n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE;
|
||||
n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE;
|
||||
return;
|
||||
}
|
||||
/* Loopback link went down? No fragmentation needed from now on. */
|
||||
if (n_ptr->addr == tn->own_addr) {
|
||||
n_ptr->act_mtus[0] = MAX_MSG_SIZE;
|
||||
n_ptr->act_mtus[1] = MAX_MSG_SIZE;
|
||||
}
|
||||
node_lost_contact(n);
|
||||
}
|
||||
|
||||
int tipc_node_active_links(struct tipc_node *n_ptr)
|
||||
bool tipc_node_is_up(struct tipc_node *n)
|
||||
{
|
||||
return n_ptr->active_links[0] != NULL;
|
||||
return n->active_links[0] != INVALID_BEARER_ID;
|
||||
}
|
||||
|
||||
int tipc_node_is_up(struct tipc_node *n_ptr)
|
||||
void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b,
|
||||
bool *link_up, bool *addr_match,
|
||||
struct tipc_media_addr *maddr)
|
||||
{
|
||||
return tipc_node_active_links(n_ptr);
|
||||
struct tipc_link *l = n->links[b->identity].link;
|
||||
struct tipc_media_addr *curr = &n->links[b->identity].maddr;
|
||||
|
||||
*link_up = l && tipc_link_is_up(l);
|
||||
*addr_match = l && !memcmp(curr, maddr, sizeof(*maddr));
|
||||
}
|
||||
|
||||
bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b,
|
||||
struct tipc_media_addr *maddr)
|
||||
{
|
||||
struct tipc_link *l = n->links[b->identity].link;
|
||||
struct tipc_media_addr *curr = &n->links[b->identity].maddr;
|
||||
struct sk_buff_head *inputq = &n->links[b->identity].inputq;
|
||||
|
||||
if (!l) {
|
||||
l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq);
|
||||
if (!l)
|
||||
return false;
|
||||
tipc_node_calculate_timer(n, l);
|
||||
if (n->link_cnt == 1) {
|
||||
if (!mod_timer(&n->timer, jiffies + n->keepalive_intv))
|
||||
tipc_node_get(n);
|
||||
}
|
||||
}
|
||||
memcpy(&l->media_addr, maddr, sizeof(*maddr));
|
||||
memcpy(curr, maddr, sizeof(*maddr));
|
||||
tipc_link_reset(l);
|
||||
return true;
|
||||
}
|
||||
|
||||
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
{
|
||||
n_ptr->links[l_ptr->bearer_id] = l_ptr;
|
||||
n_ptr->links[l_ptr->bearer_id].link = l_ptr;
|
||||
n_ptr->link_cnt++;
|
||||
}
|
||||
|
||||
@ -352,15 +416,151 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
if (l_ptr != n_ptr->links[i])
|
||||
if (l_ptr != n_ptr->links[i].link)
|
||||
continue;
|
||||
n_ptr->links[i] = NULL;
|
||||
n_ptr->links[i].link = NULL;
|
||||
n_ptr->link_cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
/* tipc_node_fsm_evt - node finite state machine
|
||||
* Determines when contact is allowed with peer node
|
||||
*/
|
||||
static void tipc_node_fsm_evt(struct tipc_node *n, int evt)
|
||||
{
|
||||
int state = n->state;
|
||||
|
||||
switch (state) {
|
||||
case SELF_DOWN_PEER_DOWN:
|
||||
switch (evt) {
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
state = SELF_UP_PEER_COMING;
|
||||
break;
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
state = SELF_COMING_PEER_UP;
|
||||
break;
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
case SELF_UP_PEER_UP:
|
||||
switch (evt) {
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
state = SELF_DOWN_PEER_LEAVING;
|
||||
break;
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
state = SELF_LEAVING_PEER_DOWN;
|
||||
break;
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
case SELF_DOWN_PEER_LEAVING:
|
||||
switch (evt) {
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
state = SELF_DOWN_PEER_DOWN;
|
||||
break;
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
case SELF_UP_PEER_COMING:
|
||||
switch (evt) {
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
state = SELF_UP_PEER_UP;
|
||||
break;
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
state = SELF_DOWN_PEER_LEAVING;
|
||||
break;
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
case SELF_COMING_PEER_UP:
|
||||
switch (evt) {
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
state = SELF_UP_PEER_UP;
|
||||
break;
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
state = SELF_LEAVING_PEER_DOWN;
|
||||
break;
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
case SELF_LEAVING_PEER_DOWN:
|
||||
switch (evt) {
|
||||
case SELF_LOST_CONTACT_EVT:
|
||||
state = SELF_DOWN_PEER_DOWN;
|
||||
break;
|
||||
case SELF_ESTABL_CONTACT_EVT:
|
||||
case PEER_ESTABL_CONTACT_EVT:
|
||||
case PEER_LOST_CONTACT_EVT:
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm evt %x/%x\n", state, evt);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown node fsm state %x\n", state);
|
||||
break;
|
||||
}
|
||||
|
||||
n->state = state;
|
||||
}
|
||||
|
||||
bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_link *l,
|
||||
struct tipc_msg *hdr)
|
||||
{
|
||||
int state = n->state;
|
||||
|
||||
if (likely(state == SELF_UP_PEER_UP))
|
||||
return true;
|
||||
|
||||
if (state == SELF_DOWN_PEER_DOWN)
|
||||
return true;
|
||||
|
||||
if (state == SELF_UP_PEER_COMING) {
|
||||
/* If not traffic msg, peer may still be ESTABLISHING */
|
||||
if (tipc_link_is_up(l) && msg_is_traffic(hdr))
|
||||
tipc_node_fsm_evt(n, PEER_ESTABL_CONTACT_EVT);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state == SELF_COMING_PEER_UP)
|
||||
return true;
|
||||
|
||||
if (state == SELF_LEAVING_PEER_DOWN)
|
||||
return false;
|
||||
|
||||
if (state == SELF_DOWN_PEER_LEAVING) {
|
||||
if (msg_peer_is_up(hdr))
|
||||
return false;
|
||||
tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void node_established_contact(struct tipc_node *n_ptr)
|
||||
{
|
||||
tipc_node_fsm_evt(n_ptr, SELF_ESTABL_CONTACT_EVT);
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
|
||||
n_ptr->bclink.oos_state = 0;
|
||||
n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net);
|
||||
@ -396,21 +596,18 @@ static void node_lost_contact(struct tipc_node *n_ptr)
|
||||
|
||||
/* Abort any ongoing link failover */
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
struct tipc_link *l_ptr = n_ptr->links[i];
|
||||
struct tipc_link *l_ptr = n_ptr->links[i].link;
|
||||
if (!l_ptr)
|
||||
continue;
|
||||
l_ptr->flags &= ~LINK_FAILINGOVER;
|
||||
l_ptr->exec_mode = TIPC_LINK_OPEN;
|
||||
l_ptr->failover_checkpt = 0;
|
||||
l_ptr->failover_pkts = 0;
|
||||
kfree_skb(l_ptr->failover_skb);
|
||||
l_ptr->failover_skb = NULL;
|
||||
tipc_link_reset_fragments(l_ptr);
|
||||
}
|
||||
|
||||
n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;
|
||||
|
||||
/* Prevent re-contact with node until cleanup is done */
|
||||
n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN;
|
||||
tipc_node_fsm_evt(n_ptr, SELF_LOST_CONTACT_EVT);
|
||||
|
||||
/* Notify publications from this node */
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN;
|
||||
@ -453,7 +650,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
|
||||
goto exit;
|
||||
|
||||
tipc_node_lock(node);
|
||||
link = node->links[bearer_id];
|
||||
link = node->links[bearer_id].link;
|
||||
if (link) {
|
||||
strncpy(linkname, link->name, len);
|
||||
err = 0;
|
||||
@ -559,6 +756,160 @@ msg_full:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static struct tipc_link *tipc_node_select_link(struct tipc_node *n, int sel,
|
||||
int *bearer_id,
|
||||
struct tipc_media_addr **maddr)
|
||||
{
|
||||
int id = n->active_links[sel & 1];
|
||||
|
||||
if (unlikely(id < 0))
|
||||
return NULL;
|
||||
|
||||
*bearer_id = id;
|
||||
*maddr = &n->links[id].maddr;
|
||||
return n->links[id].link;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_node_xmit() is the general link level function for message sending
|
||||
* @net: the applicable net namespace
|
||||
* @list: chain of buffers containing message
|
||||
* @dnode: address of destination node
|
||||
* @selector: a number used for deterministic link selection
|
||||
* Consumes the buffer chain, except when returning -ELINKCONG
|
||||
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
|
||||
*/
|
||||
int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
|
||||
u32 dnode, int selector)
|
||||
{
|
||||
struct tipc_link *l = NULL;
|
||||
struct tipc_node *n;
|
||||
struct sk_buff_head xmitq;
|
||||
struct tipc_media_addr *maddr;
|
||||
int bearer_id;
|
||||
int rc = -EHOSTUNREACH;
|
||||
|
||||
__skb_queue_head_init(&xmitq);
|
||||
n = tipc_node_find(net, dnode);
|
||||
if (likely(n)) {
|
||||
tipc_node_lock(n);
|
||||
l = tipc_node_select_link(n, selector, &bearer_id, &maddr);
|
||||
if (likely(l))
|
||||
rc = tipc_link_xmit(l, list, &xmitq);
|
||||
if (unlikely(rc == -ENOBUFS))
|
||||
tipc_link_reset(l);
|
||||
tipc_node_unlock(n);
|
||||
tipc_node_put(n);
|
||||
}
|
||||
if (likely(!rc)) {
|
||||
tipc_bearer_xmit(net, bearer_id, &xmitq, maddr);
|
||||
return 0;
|
||||
}
|
||||
if (likely(in_own_node(net, dnode))) {
|
||||
tipc_sk_rcv(net, list);
|
||||
return 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* tipc_node_xmit_skb(): send single buffer to destination
|
||||
* Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE
|
||||
* messages, which will not be rejected
|
||||
* The only exception is datagram messages rerouted after secondary
|
||||
* lookup, which are rare and safe to dispose of anyway.
|
||||
* TODO: Return real return value, and let callers use
|
||||
* tipc_wait_for_sendpkt() where applicable
|
||||
*/
|
||||
int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
|
||||
u32 selector)
|
||||
{
|
||||
struct sk_buff_head head;
|
||||
int rc;
|
||||
|
||||
skb_queue_head_init(&head);
|
||||
__skb_queue_tail(&head, skb);
|
||||
rc = tipc_node_xmit(net, &head, dnode, selector);
|
||||
if (rc == -ELINKCONG)
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_rcv - process TIPC packets/messages arriving from off-node
|
||||
* @net: the applicable net namespace
|
||||
* @skb: TIPC packet
|
||||
* @bearer: 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 net *net, struct sk_buff *skb, struct tipc_bearer *b)
|
||||
{
|
||||
struct sk_buff_head xmitq;
|
||||
struct tipc_node *n;
|
||||
struct tipc_link *l;
|
||||
struct tipc_msg *hdr;
|
||||
struct tipc_media_addr *maddr;
|
||||
int bearer_id = b->identity;
|
||||
int rc = 0;
|
||||
|
||||
__skb_queue_head_init(&xmitq);
|
||||
|
||||
/* Ensure message is well-formed */
|
||||
if (unlikely(!tipc_msg_validate(skb)))
|
||||
goto discard;
|
||||
|
||||
/* Handle arrival of a non-unicast link packet */
|
||||
hdr = buf_msg(skb);
|
||||
if (unlikely(msg_non_seq(hdr))) {
|
||||
if (msg_user(hdr) == LINK_CONFIG)
|
||||
tipc_disc_rcv(net, skb, b);
|
||||
else
|
||||
tipc_bclink_rcv(net, skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Locate neighboring node that sent packet */
|
||||
n = tipc_node_find(net, msg_prevnode(hdr));
|
||||
if (unlikely(!n))
|
||||
goto discard;
|
||||
tipc_node_lock(n);
|
||||
|
||||
/* Locate link endpoint that should handle packet */
|
||||
l = n->links[bearer_id].link;
|
||||
if (unlikely(!l))
|
||||
goto unlock;
|
||||
|
||||
/* Is reception of this packet permitted at the moment ? */
|
||||
if (unlikely(n->state != SELF_UP_PEER_UP))
|
||||
if (!tipc_node_filter_skb(n, l, hdr))
|
||||
goto unlock;
|
||||
|
||||
if (unlikely(msg_user(hdr) == LINK_PROTOCOL))
|
||||
tipc_bclink_sync_state(n, hdr);
|
||||
|
||||
/* Release acked broadcast messages */
|
||||
if (unlikely(n->bclink.acked != msg_bcast_ack(hdr)))
|
||||
tipc_bclink_acknowledge(n, msg_bcast_ack(hdr));
|
||||
|
||||
/* Check protocol and update link state */
|
||||
rc = tipc_link_rcv(l, skb, &xmitq);
|
||||
|
||||
if (unlikely(rc & TIPC_LINK_UP_EVT))
|
||||
tipc_link_activate(l);
|
||||
if (unlikely(rc & TIPC_LINK_DOWN_EVT))
|
||||
tipc_link_reset(l);
|
||||
skb = NULL;
|
||||
unlock:
|
||||
tipc_node_unlock(n);
|
||||
tipc_sk_rcv(net, &n->links[bearer_id].inputq);
|
||||
maddr = &n->links[bearer_id].maddr;
|
||||
tipc_bearer_xmit(net, bearer_id, &xmitq, maddr);
|
||||
tipc_node_put(n);
|
||||
discard:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
int err;
|
||||
|
@ -45,6 +45,26 @@
|
||||
/* Out-of-range value for node signature */
|
||||
#define INVALID_NODE_SIG 0x10000
|
||||
|
||||
#define INVALID_BEARER_ID -1
|
||||
|
||||
/* Node FSM states and events:
|
||||
*/
|
||||
enum {
|
||||
SELF_DOWN_PEER_DOWN = 0xdd,
|
||||
SELF_UP_PEER_UP = 0xaa,
|
||||
SELF_DOWN_PEER_LEAVING = 0xd1,
|
||||
SELF_UP_PEER_COMING = 0xac,
|
||||
SELF_COMING_PEER_UP = 0xca,
|
||||
SELF_LEAVING_PEER_DOWN = 0x1d,
|
||||
};
|
||||
|
||||
enum {
|
||||
SELF_ESTABL_CONTACT_EVT = 0xec,
|
||||
SELF_LOST_CONTACT_EVT = 0x1c,
|
||||
PEER_ESTABL_CONTACT_EVT = 0xfec,
|
||||
PEER_LOST_CONTACT_EVT = 0xf1c
|
||||
};
|
||||
|
||||
/* Flags used to take different actions according to flag type
|
||||
* TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down
|
||||
* TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down
|
||||
@ -54,8 +74,6 @@
|
||||
*/
|
||||
enum {
|
||||
TIPC_MSG_EVT = 1,
|
||||
TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1),
|
||||
TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2),
|
||||
TIPC_NOTIFY_NODE_DOWN = (1 << 3),
|
||||
TIPC_NOTIFY_NODE_UP = (1 << 4),
|
||||
TIPC_WAKEUP_BCAST_USERS = (1 << 5),
|
||||
@ -85,10 +103,17 @@ struct tipc_node_bclink {
|
||||
u32 deferred_size;
|
||||
struct sk_buff_head deferdq;
|
||||
struct sk_buff *reasm_buf;
|
||||
int inputq_map;
|
||||
struct sk_buff_head namedq;
|
||||
bool recv_permitted;
|
||||
};
|
||||
|
||||
struct tipc_link_entry {
|
||||
struct tipc_link *link;
|
||||
u32 mtu;
|
||||
struct sk_buff_head inputq;
|
||||
struct tipc_media_addr maddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_node - TIPC node structure
|
||||
* @addr: network address of node
|
||||
@ -98,9 +123,8 @@ struct tipc_node_bclink {
|
||||
* @hash: links to adjacent nodes in unsorted hash chain
|
||||
* @inputq: pointer to input queue containing messages for msg event
|
||||
* @namedq: pointer to name table input queue with name table messages
|
||||
* @curr_link: the link holding the node lock, if any
|
||||
* @active_links: pointers to active links to node
|
||||
* @links: pointers to all links to node
|
||||
* @active_links: bearer ids of active links, used as index into links[] array
|
||||
* @links: array containing references to all links to node
|
||||
* @action_flags: bit mask of different types of node actions
|
||||
* @bclink: broadcast-related info
|
||||
* @list: links to adjacent nodes in sorted list of cluster's nodes
|
||||
@ -120,12 +144,12 @@ struct tipc_node {
|
||||
struct hlist_node hash;
|
||||
struct sk_buff_head *inputq;
|
||||
struct sk_buff_head *namedq;
|
||||
struct tipc_link *active_links[2];
|
||||
u32 act_mtus[2];
|
||||
struct tipc_link *links[MAX_BEARERS];
|
||||
int active_links[2];
|
||||
struct tipc_link_entry links[MAX_BEARERS];
|
||||
int action_flags;
|
||||
struct tipc_node_bclink bclink;
|
||||
struct list_head list;
|
||||
int state;
|
||||
int link_cnt;
|
||||
u16 working_links;
|
||||
u16 capabilities;
|
||||
@ -133,6 +157,8 @@ struct tipc_node {
|
||||
u32 link_id;
|
||||
struct list_head publ_list;
|
||||
struct list_head conn_sks;
|
||||
unsigned long keepalive_intv;
|
||||
struct timer_list timer;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
@ -140,18 +166,25 @@ struct tipc_node *tipc_node_find(struct net *net, u32 addr);
|
||||
void tipc_node_put(struct tipc_node *node);
|
||||
struct tipc_node *tipc_node_create(struct net *net, u32 addr);
|
||||
void tipc_node_stop(struct net *net);
|
||||
void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *bearer,
|
||||
bool *link_up, bool *addr_match,
|
||||
struct tipc_media_addr *maddr);
|
||||
bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *bearer,
|
||||
struct tipc_media_addr *maddr);
|
||||
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);
|
||||
void tipc_node_link_down(struct tipc_node *n_ptr, int bearer_id);
|
||||
void tipc_node_link_up(struct tipc_node *n_ptr, int bearer_id);
|
||||
bool tipc_node_is_up(struct tipc_node *n);
|
||||
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_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
|
||||
int selector);
|
||||
int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,
|
||||
u32 selector);
|
||||
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);
|
||||
|
||||
static inline void tipc_node_lock(struct tipc_node *node)
|
||||
@ -159,26 +192,30 @@ static inline void tipc_node_lock(struct tipc_node *node)
|
||||
spin_lock_bh(&node->lock);
|
||||
}
|
||||
|
||||
static inline bool tipc_node_blocked(struct tipc_node *node)
|
||||
static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel)
|
||||
{
|
||||
return (node->action_flags & (TIPC_WAIT_PEER_LINKS_DOWN |
|
||||
TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN));
|
||||
int bearer_id = n->active_links[sel & 1];
|
||||
|
||||
if (unlikely(bearer_id == INVALID_BEARER_ID))
|
||||
return NULL;
|
||||
|
||||
return n->links[bearer_id].link;
|
||||
}
|
||||
|
||||
static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector)
|
||||
static inline unsigned int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
u32 mtu;
|
||||
struct tipc_node *n;
|
||||
int bearer_id;
|
||||
unsigned int mtu = MAX_MSG_SIZE;
|
||||
|
||||
node = tipc_node_find(net, addr);
|
||||
|
||||
if (likely(node)) {
|
||||
mtu = node->act_mtus[selector & 1];
|
||||
tipc_node_put(node);
|
||||
} else {
|
||||
mtu = MAX_MSG_SIZE;
|
||||
}
|
||||
n = tipc_node_find(net, addr);
|
||||
if (unlikely(!n))
|
||||
return mtu;
|
||||
|
||||
bearer_id = n->active_links[sel & 1];
|
||||
if (likely(bearer_id != INVALID_BEARER_ID))
|
||||
mtu = n->links[bearer_id].mtu;
|
||||
tipc_node_put(n);
|
||||
return mtu;
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ static void tsk_rej_rx_queue(struct sock *sk)
|
||||
|
||||
while ((skb = __skb_dequeue(&sk->sk_receive_queue))) {
|
||||
if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_ERR_NO_PORT))
|
||||
tipc_link_xmit_skb(sock_net(sk), skb, dnode, 0);
|
||||
tipc_node_xmit_skb(sock_net(sk), skb, dnode, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +443,7 @@ static int tipc_release(struct socket *sock)
|
||||
}
|
||||
if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
|
||||
TIPC_ERR_NO_PORT))
|
||||
tipc_link_xmit_skb(net, skb, dnode, 0);
|
||||
tipc_node_xmit_skb(net, skb, dnode, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ static int tipc_release(struct socket *sock)
|
||||
tsk_own_node(tsk), tsk_peer_port(tsk),
|
||||
tsk->portid, TIPC_ERR_NO_PORT);
|
||||
if (skb)
|
||||
tipc_link_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
tipc_node_remove_conn(net, dnode, tsk->portid);
|
||||
}
|
||||
|
||||
@ -686,21 +686,22 @@ new_mtu:
|
||||
|
||||
do {
|
||||
rc = tipc_bclink_xmit(net, pktchain);
|
||||
if (likely(rc >= 0)) {
|
||||
rc = dsz;
|
||||
break;
|
||||
if (likely(!rc))
|
||||
return dsz;
|
||||
|
||||
if (rc == -ELINKCONG) {
|
||||
tsk->link_cong = 1;
|
||||
rc = tipc_wait_for_sndmsg(sock, &timeo);
|
||||
if (!rc)
|
||||
continue;
|
||||
}
|
||||
__skb_queue_purge(pktchain);
|
||||
if (rc == -EMSGSIZE) {
|
||||
msg->msg_iter = save;
|
||||
goto new_mtu;
|
||||
}
|
||||
if (rc != -ELINKCONG)
|
||||
break;
|
||||
tipc_sk(sk)->link_cong = 1;
|
||||
rc = tipc_wait_for_sndmsg(sock, &timeo);
|
||||
if (rc)
|
||||
__skb_queue_purge(pktchain);
|
||||
} while (!rc);
|
||||
break;
|
||||
} while (1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -924,24 +925,25 @@ new_mtu:
|
||||
do {
|
||||
skb = skb_peek(pktchain);
|
||||
TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
|
||||
rc = tipc_link_xmit(net, pktchain, dnode, tsk->portid);
|
||||
if (likely(rc >= 0)) {
|
||||
rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid);
|
||||
if (likely(!rc)) {
|
||||
if (sock->state != SS_READY)
|
||||
sock->state = SS_CONNECTING;
|
||||
rc = dsz;
|
||||
break;
|
||||
return dsz;
|
||||
}
|
||||
if (rc == -ELINKCONG) {
|
||||
tsk->link_cong = 1;
|
||||
rc = tipc_wait_for_sndmsg(sock, &timeo);
|
||||
if (!rc)
|
||||
continue;
|
||||
}
|
||||
__skb_queue_purge(pktchain);
|
||||
if (rc == -EMSGSIZE) {
|
||||
m->msg_iter = save;
|
||||
goto new_mtu;
|
||||
}
|
||||
if (rc != -ELINKCONG)
|
||||
break;
|
||||
tsk->link_cong = 1;
|
||||
rc = tipc_wait_for_sndmsg(sock, &timeo);
|
||||
if (rc)
|
||||
__skb_queue_purge(pktchain);
|
||||
} while (!rc);
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -1043,15 +1045,16 @@ next:
|
||||
return rc;
|
||||
do {
|
||||
if (likely(!tsk_conn_cong(tsk))) {
|
||||
rc = tipc_link_xmit(net, pktchain, dnode, portid);
|
||||
rc = tipc_node_xmit(net, pktchain, dnode, portid);
|
||||
if (likely(!rc)) {
|
||||
tsk->sent_unacked++;
|
||||
sent += send;
|
||||
if (sent == dsz)
|
||||
break;
|
||||
return dsz;
|
||||
goto next;
|
||||
}
|
||||
if (rc == -EMSGSIZE) {
|
||||
__skb_queue_purge(pktchain);
|
||||
tsk->max_pkt = tipc_node_get_mtu(net, dnode,
|
||||
portid);
|
||||
m->msg_iter = save;
|
||||
@ -1059,13 +1062,13 @@ next:
|
||||
}
|
||||
if (rc != -ELINKCONG)
|
||||
break;
|
||||
|
||||
tsk->link_cong = 1;
|
||||
}
|
||||
rc = tipc_wait_for_sndpkt(sock, &timeo);
|
||||
if (rc)
|
||||
__skb_queue_purge(pktchain);
|
||||
} while (!rc);
|
||||
|
||||
__skb_queue_purge(pktchain);
|
||||
return sent ? sent : rc;
|
||||
}
|
||||
|
||||
@ -1221,7 +1224,7 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
|
||||
return;
|
||||
msg = buf_msg(skb);
|
||||
msg_set_msgcnt(msg, ack);
|
||||
tipc_link_xmit_skb(net, skb, dnode, msg_link_selector(msg));
|
||||
tipc_node_xmit_skb(net, skb, dnode, msg_link_selector(msg));
|
||||
}
|
||||
|
||||
static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
|
||||
@ -1700,7 +1703,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
if (!err || tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, -err))
|
||||
tipc_link_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1796,7 +1799,7 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
|
||||
if (!tipc_msg_reverse(tn->own_addr, skb, &dnode, -err))
|
||||
continue;
|
||||
xmit:
|
||||
tipc_link_xmit_skb(net, skb, dnode, dport);
|
||||
tipc_node_xmit_skb(net, skb, dnode, dport);
|
||||
}
|
||||
return err ? -EHOSTUNREACH : 0;
|
||||
}
|
||||
@ -2089,7 +2092,7 @@ restart:
|
||||
}
|
||||
if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
|
||||
TIPC_CONN_SHUTDOWN))
|
||||
tipc_link_xmit_skb(net, skb, dnode,
|
||||
tipc_node_xmit_skb(net, skb, dnode,
|
||||
tsk->portid);
|
||||
} else {
|
||||
dnode = tsk_peer_node(tsk);
|
||||
@ -2099,7 +2102,7 @@ restart:
|
||||
0, dnode, tsk_own_node(tsk),
|
||||
tsk_peer_port(tsk),
|
||||
tsk->portid, TIPC_CONN_SHUTDOWN);
|
||||
tipc_link_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
tipc_node_xmit_skb(net, skb, dnode, tsk->portid);
|
||||
}
|
||||
tsk->connected = 0;
|
||||
sock->state = SS_DISCONNECTING;
|
||||
@ -2161,7 +2164,7 @@ static void tipc_sk_timeout(unsigned long data)
|
||||
}
|
||||
bh_unlock_sock(sk);
|
||||
if (skb)
|
||||
tipc_link_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid);
|
||||
tipc_node_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid);
|
||||
exit:
|
||||
sock_put(sk);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user