提交 7781e5d1 编写于 作者: D David S. Miller

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: NDavid S. Miller <davem@davemloft.net>
...@@ -316,6 +316,29 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, ...@@ -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 * 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) ...@@ -358,10 +381,9 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list)
/* Prepare clone of message for local node */ /* Prepare clone of message for local node */
skb = tipc_msg_reassemble(list); skb = tipc_msg_reassemble(list);
if (unlikely(!skb)) { if (unlikely(!skb))
__skb_queue_purge(list);
return -EHOSTUNREACH; return -EHOSTUNREACH;
}
/* Broadcast to all nodes */ /* Broadcast to all nodes */
if (likely(bclink)) { if (likely(bclink)) {
tipc_bclink_lock(net); tipc_bclink_lock(net);
...@@ -413,7 +435,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) ...@@ -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 * all nodes in the cluster don't ACK at the same time
*/ */
if (((seqno - tn->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], tipc_link_proto_xmit(node_active_link(node, node->addr),
STATE_MSG, 0, 0, 0, 0); STATE_MSG, 0, 0, 0, 0);
tn->bcl->stats.sent_acks++; tn->bcl->stats.sent_acks++;
} }
...@@ -925,7 +947,6 @@ int tipc_bclink_init(struct net *net) ...@@ -925,7 +947,6 @@ int tipc_bclink_init(struct net *net)
tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
bcl->bearer_id = MAX_BEARERS; bcl->bearer_id = MAX_BEARERS;
rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer); rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer);
bcl->state = WORKING_WORKING;
bcl->pmsg = (struct tipc_msg *)&bcl->proto_msg; bcl->pmsg = (struct tipc_msg *)&bcl->proto_msg;
msg_set_prevnode(bcl->pmsg, tn->own_addr); msg_set_prevnode(bcl->pmsg, tn->own_addr);
strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME); strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
......
...@@ -133,5 +133,6 @@ void tipc_bclink_wakeup_users(struct net *net); ...@@ -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_add_bc_link(struct net *net, struct tipc_nl_msg *msg);
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]); int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);
void tipc_bclink_input(struct net *net); void tipc_bclink_input(struct net *net);
void tipc_bclink_sync_state(struct tipc_node *n, struct tipc_msg *msg);
#endif #endif
...@@ -470,6 +470,32 @@ void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf, ...@@ -470,6 +470,32 @@ void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf,
rcu_read_unlock(); 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 * tipc_l2_rcv_msg - handle incoming TIPC message from an interface
* @buf: the received packet * @buf: the received packet
......
...@@ -217,5 +217,8 @@ void tipc_bearer_cleanup(void); ...@@ -217,5 +217,8 @@ void tipc_bearer_cleanup(void);
void tipc_bearer_stop(struct net *net); void tipc_bearer_stop(struct net *net);
void tipc_bearer_send(struct net *net, 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_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 */ #endif /* _TIPC_BEARER_H */
...@@ -129,6 +129,11 @@ static inline int less(u16 left, u16 right) ...@@ -129,6 +129,11 @@ static inline int less(u16 left, u16 right)
return less_eq(left, right) && (mod(right) != mod(left)); 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 #ifdef CONFIG_SYSCTL
int tipc_register_sysctl(void); int tipc_register_sysctl(void);
void tipc_unregister_sysctl(void); void tipc_unregister_sysctl(void);
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
*/ */
#include "core.h" #include "core.h"
#include "link.h" #include "node.h"
#include "discover.h" #include "discover.h"
/* min delay during bearer start up */ /* min delay during bearer start up */
...@@ -125,7 +125,6 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, ...@@ -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_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *node; struct tipc_node *node;
struct tipc_link *link;
struct tipc_media_addr maddr; struct tipc_media_addr maddr;
struct sk_buff *rbuf; struct sk_buff *rbuf;
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
...@@ -170,13 +169,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, ...@@ -170,13 +169,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
return; return;
tipc_node_lock(node); tipc_node_lock(node);
node->capabilities = caps; node->capabilities = caps;
link = node->links[bearer->identity];
/* Prepare to validate requesting node's signature and media address */ /* Prepare to validate requesting node's signature and media address */
sign_match = (signature == node->signature); sign_match = (signature == node->signature);
addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr)); tipc_node_check_dest(node, bearer, &link_up, &addr_match, &maddr);
link_up = link && tipc_link_is_up(link);
/* These three flags give us eight permutations: */ /* These three flags give us eight permutations: */
...@@ -239,16 +235,8 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, ...@@ -239,16 +235,8 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
if (accept_sign) if (accept_sign)
node->signature = signature; node->signature = signature;
if (accept_addr) { if (accept_addr && !tipc_node_update_dest(node, bearer, &maddr))
if (!link) respond = false;
link = tipc_link_create(node, bearer, &maddr);
if (link) {
memcpy(&link->media_addr, &maddr, sizeof(maddr));
tipc_link_reset(link);
} else {
respond = false;
}
}
/* Send response, if necessary */ /* Send response, if necessary */
if (respond && (mtyp == DSC_REQ_MSG)) { if (respond && (mtyp == DSC_REQ_MSG)) {
......
此差异已折叠。
...@@ -49,19 +49,21 @@ ...@@ -49,19 +49,21 @@
*/ */
#define INVALID_LINK_SEQ 0x10000 #define INVALID_LINK_SEQ 0x10000
/* Link working states
/* Link endpoint receive states
*/ */
#define WORKING_WORKING 560810u enum {
#define WORKING_UNKNOWN 560811u TIPC_LINK_OPEN,
#define RESET_UNKNOWN 560812u TIPC_LINK_BLOCKED,
#define RESET_RESET 560813u TIPC_LINK_TUNNEL
};
/* Link endpoint execution states /* Events returned from link at packet reception or at timeout
*/ */
#define LINK_STARTED 0x0001 enum {
#define LINK_STOPPED 0x0002 TIPC_LINK_UP_EVT = 1,
#define LINK_SYNCHING 0x0004 TIPC_LINK_DOWN_EVT = (1 << 1)
#define LINK_FAILINGOVER 0x0008 };
/* Starting value for maximum packet size negotiation on unicast links /* Starting value for maximum packet size negotiation on unicast links
* (unless bearer MTU is less) * (unless bearer MTU is less)
...@@ -106,7 +108,6 @@ struct tipc_stats { ...@@ -106,7 +108,6 @@ struct tipc_stats {
* @timer: link timer * @timer: link timer
* @owner: pointer to peer node * @owner: pointer to peer node
* @refcnt: reference counter for permanent references (owner node & timer) * @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_session: link session # being used by peer end of link
* @peer_bearer_id: bearer id used by link's peer endpoint * @peer_bearer_id: bearer id used by link's peer endpoint
* @bearer_id: local bearer id used by link * @bearer_id: local bearer id used by link
...@@ -119,6 +120,7 @@ struct tipc_stats { ...@@ -119,6 +120,7 @@ struct tipc_stats {
* @pmsg: convenience pointer to "proto_msg" field * @pmsg: convenience pointer to "proto_msg" field
* @priority: current link priority * @priority: current link priority
* @net_plane: current link network plane ('A' through 'H') * @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) * @backlog_limit: backlog queue congestion thresholds (indexed by importance)
* @exp_msg_count: # of tunnelled messages expected during link changeover * @exp_msg_count: # of tunnelled messages expected during link changeover
* @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset
...@@ -144,12 +146,9 @@ struct tipc_link { ...@@ -144,12 +146,9 @@ struct tipc_link {
u32 addr; u32 addr;
char name[TIPC_MAX_LINK_NAME]; char name[TIPC_MAX_LINK_NAME];
struct tipc_media_addr media_addr; struct tipc_media_addr media_addr;
struct timer_list timer;
struct tipc_node *owner; struct tipc_node *owner;
struct kref ref;
/* Management and link supervision data */ /* Management and link supervision data */
unsigned int flags;
u32 peer_session; u32 peer_session;
u32 peer_bearer_id; u32 peer_bearer_id;
u32 bearer_id; u32 bearer_id;
...@@ -165,6 +164,7 @@ struct tipc_link { ...@@ -165,6 +164,7 @@ struct tipc_link {
struct tipc_msg *pmsg; struct tipc_msg *pmsg;
u32 priority; u32 priority;
char net_plane; char net_plane;
u8 exec_mode;
u16 synch_point; u16 synch_point;
/* Failover */ /* Failover */
...@@ -192,8 +192,8 @@ struct tipc_link { ...@@ -192,8 +192,8 @@ struct tipc_link {
u16 rcv_nxt; u16 rcv_nxt;
u32 rcv_unacked; u32 rcv_unacked;
struct sk_buff_head deferdq; struct sk_buff_head deferdq;
struct sk_buff_head inputq; struct sk_buff_head *inputq;
struct sk_buff_head namedq; struct sk_buff_head *namedq;
/* Congestion handling */ /* Congestion handling */
struct sk_buff_head wakeupq; struct sk_buff_head wakeupq;
...@@ -207,9 +207,11 @@ struct tipc_link { ...@@ -207,9 +207,11 @@ struct tipc_link {
struct tipc_port; struct tipc_port;
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, struct tipc_link *tipc_link_create(struct tipc_node *n,
struct tipc_bearer *b_ptr, struct tipc_bearer *b,
const struct tipc_media_addr *media_addr); 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(struct tipc_link *link);
void tipc_link_delete_list(struct net *net, unsigned int bearer_id); void tipc_link_delete_list(struct net *net, unsigned int bearer_id);
void tipc_link_failover_send_queue(struct tipc_link *l_ptr); 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); ...@@ -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_purge_backlog(struct tipc_link *l);
void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset_all(struct tipc_node *node);
void tipc_link_reset(struct tipc_link *l_ptr); void tipc_link_reset(struct tipc_link *l_ptr);
int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, void tipc_link_activate(struct tipc_link *link);
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, int __tipc_link_xmit(struct net *net, struct tipc_link *link,
struct sk_buff_head *list); 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, void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
u32 gap, u32 tolerance, u32 priority); u32 gap, u32 tolerance, u32 priority);
void tipc_link_push_packets(struct tipc_link *l_ptr); 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); ...@@ -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_link_reset_stats(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]); int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]);
void link_prepare_wakeup(struct tipc_link *l); 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) static inline u32 link_own_addr(struct tipc_link *l)
{ {
return msg_prevnode(l->pmsg); 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 #endif
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define _TIPC_MSG_H #define _TIPC_MSG_H
#include <linux/tipc.h> #include <linux/tipc.h>
#include "core.h"
/* /*
* Constants and routines used to read and write TIPC payload message headers * 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) ...@@ -658,12 +659,12 @@ static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
/* /*
* Word 5 * 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); 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); 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) ...@@ -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); 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); struct sk_buff *tipc_buf_acquire(u32 size);
bool tipc_msg_validate(struct sk_buff *skb); bool tipc_msg_validate(struct sk_buff *skb);
bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, 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, ...@@ -879,4 +896,36 @@ static inline bool tipc_skb_queue_tail(struct sk_buff_head *list,
return rv; 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 #endif
...@@ -96,13 +96,13 @@ void named_cluster_distribute(struct net *net, struct sk_buff *skb) ...@@ -96,13 +96,13 @@ void named_cluster_distribute(struct net *net, struct sk_buff *skb)
dnode = node->addr; dnode = node->addr;
if (in_own_node(net, dnode)) if (in_own_node(net, dnode))
continue; continue;
if (!tipc_node_active_links(node)) if (!tipc_node_is_up(node))
continue; continue;
oskb = pskb_copy(skb, GFP_ATOMIC); oskb = pskb_copy(skb, GFP_ATOMIC);
if (!oskb) if (!oskb)
break; break;
msg_set_destnode(buf_msg(oskb), dnode); 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(); rcu_read_unlock();
...@@ -223,7 +223,7 @@ void tipc_named_node_up(struct net *net, u32 dnode) ...@@ -223,7 +223,7 @@ void tipc_named_node_up(struct net *net, u32 dnode)
&tn->nametbl->publ_list[TIPC_ZONE_SCOPE]); &tn->nametbl->publ_list[TIPC_ZONE_SCOPE]);
rcu_read_unlock(); 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, static void tipc_publ_subscribe(struct net *net, struct publication *publ,
......
...@@ -40,10 +40,13 @@ ...@@ -40,10 +40,13 @@
#include "name_distr.h" #include "name_distr.h"
#include "socket.h" #include "socket.h"
#include "bcast.h" #include "bcast.h"
#include "discover.h"
static void node_lost_contact(struct tipc_node *n_ptr); static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_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_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 { struct tipc_sock_conn {
u32 port; u32 port;
...@@ -132,6 +135,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) ...@@ -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->list);
INIT_LIST_HEAD(&n_ptr->publ_list); INIT_LIST_HEAD(&n_ptr->publ_list);
INIT_LIST_HEAD(&n_ptr->conn_sks); INIT_LIST_HEAD(&n_ptr->conn_sks);
skb_queue_head_init(&n_ptr->bclink.namedq);
__skb_queue_head_init(&n_ptr->bclink.deferdq); __skb_queue_head_init(&n_ptr->bclink.deferdq);
hlist_add_head_rcu(&n_ptr->hash, &tn->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, &tn->node_list, list) { 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) ...@@ -139,14 +143,32 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
break; break;
} }
list_add_tail_rcu(&n_ptr->list, &temp_node->list); 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->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); tipc_node_get(n_ptr);
setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr);
n_ptr->keepalive_intv = U32_MAX;
exit: exit:
spin_unlock_bh(&tn->node_list_lock); spin_unlock_bh(&tn->node_list_lock);
return n_ptr; 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) static void tipc_node_delete(struct tipc_node *node)
{ {
list_del_rcu(&node->list); list_del_rcu(&node->list);
...@@ -160,8 +182,11 @@ void tipc_node_stop(struct net *net) ...@@ -160,8 +182,11 @@ void tipc_node_stop(struct net *net)
struct tipc_node *node, *t_node; struct tipc_node *node, *t_node;
spin_lock_bh(&tn->node_list_lock); 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); tipc_node_put(node);
}
spin_unlock_bh(&tn->node_list_lock); spin_unlock_bh(&tn->node_list_lock);
} }
...@@ -219,131 +244,170 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) ...@@ -219,131 +244,170 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port)
tipc_node_put(node); 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 * tipc_node_link_up - handle addition of link
* *
* Link becomes active (alone or shared) or standby, depending on its priority. * 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++; /* Leave room for tunnel header when returning 'mtu' to users: */
n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP; links[bearer_id].mtu = l->mtu - INT_H_SIZE;
n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
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", 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]) { /* No active links ? => take both active slots */
active[0] = active[1] = l_ptr; if (*slot0 < 0) {
node_established_contact(n_ptr); *slot0 = bearer_id;
goto exit; *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); /* Lower prio than current active ? => no slot */
goto exit; 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); tipc_link_dup_queue_xmit(links[*slot0].link, l);
if (l_ptr->priority == active[0]->priority) {
active[0] = l_ptr; /* Same prio as current active ? => take one slot */
goto exit; 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]) /* Higher prio than current active => take both active slots */
pr_debug("Old link <%s> becomes standby\n", active[1]->name); pr_debug("Old link <%s> now standby\n", links[*slot0].link->name);
active[0] = active[1] = l_ptr; *slot0 = bearer_id;
exit: *slot1 = bearer_id;
/* 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 * tipc_node_link_down - handle loss of link
*/ */
static void node_select_active_links(struct tipc_node *n_ptr) void tipc_node_link_down(struct tipc_node *n, int bearer_id)
{ {
struct tipc_link **active = &n_ptr->active_links[0]; int *slot0 = &n->active_links[0];
u32 i; int *slot1 = &n->active_links[1];
u32 highest_prio = 0; int i, highest = 0;
struct tipc_link *l, *_l;
active[0] = active[1] = NULL; 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;
for (i = 0; i < MAX_BEARERS; i++) { pr_debug("Lost link <%s> on network plane %c\n",
struct tipc_link *l_ptr = n_ptr->links[i]; l->name, l->net_plane);
if (!l_ptr || !tipc_link_is_up(l_ptr) || /* Select new active link if any available */
(l_ptr->priority < highest_prio)) *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; continue;
if (l_ptr->priority > highest_prio) {
highest_prio = l_ptr->priority;
active[0] = active[1] = l_ptr;
} else {
active[1] = l_ptr;
} }
*slot1 = i;
} }
if (tipc_node_is_up(n))
tipc_link_failover_send_queue(l);
else
node_lost_contact(n);
} }
/** bool tipc_node_is_up(struct tipc_node *n)
* tipc_node_link_down - handle loss of link
*/
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); return n->active_links[0] != INVALID_BEARER_ID;
struct tipc_link **active;
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;
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);
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);
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;
}
} }
int tipc_node_active_links(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 n_ptr->active_links[0] != NULL; 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));
} }
int tipc_node_is_up(struct tipc_node *n_ptr) bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b,
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;
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) 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++; n_ptr->link_cnt++;
} }
...@@ -352,15 +416,151 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) ...@@ -352,15 +416,151 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
int i; int i;
for (i = 0; i < MAX_BEARERS; i++) { for (i = 0; i < MAX_BEARERS; i++) {
if (l_ptr != n_ptr->links[i]) if (l_ptr != n_ptr->links[i].link)
continue; continue;
n_ptr->links[i] = NULL; n_ptr->links[i].link = NULL;
n_ptr->link_cnt--; 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) 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->action_flags |= TIPC_NOTIFY_NODE_UP;
n_ptr->bclink.oos_state = 0; n_ptr->bclink.oos_state = 0;
n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net); 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) ...@@ -396,21 +596,18 @@ static void node_lost_contact(struct tipc_node *n_ptr)
/* Abort any ongoing link failover */ /* Abort any ongoing link failover */
for (i = 0; i < MAX_BEARERS; i++) { 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) if (!l_ptr)
continue; continue;
l_ptr->flags &= ~LINK_FAILINGOVER; l_ptr->exec_mode = TIPC_LINK_OPEN;
l_ptr->failover_checkpt = 0; l_ptr->failover_checkpt = 0;
l_ptr->failover_pkts = 0; l_ptr->failover_pkts = 0;
kfree_skb(l_ptr->failover_skb); kfree_skb(l_ptr->failover_skb);
l_ptr->failover_skb = NULL; l_ptr->failover_skb = NULL;
tipc_link_reset_fragments(l_ptr); tipc_link_reset_fragments(l_ptr);
} }
n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;
/* Prevent re-contact with node until cleanup is done */ /* 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 */ /* Notify publications from this node */
n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN; 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, ...@@ -453,7 +650,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,
goto exit; goto exit;
tipc_node_lock(node); tipc_node_lock(node);
link = node->links[bearer_id]; link = node->links[bearer_id].link;
if (link) { if (link) {
strncpy(linkname, link->name, len); strncpy(linkname, link->name, len);
err = 0; err = 0;
...@@ -559,6 +756,160 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) ...@@ -559,6 +756,160 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
return -EMSGSIZE; 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 tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ {
int err; int err;
......
...@@ -45,6 +45,26 @@ ...@@ -45,6 +45,26 @@
/* Out-of-range value for node signature */ /* Out-of-range value for node signature */
#define INVALID_NODE_SIG 0x10000 #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 /* 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_PEER_LINKS_DOWN: wait to see that peer's links are down
* TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down
...@@ -54,8 +74,6 @@ ...@@ -54,8 +74,6 @@
*/ */
enum { enum {
TIPC_MSG_EVT = 1, 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_DOWN = (1 << 3),
TIPC_NOTIFY_NODE_UP = (1 << 4), TIPC_NOTIFY_NODE_UP = (1 << 4),
TIPC_WAKEUP_BCAST_USERS = (1 << 5), TIPC_WAKEUP_BCAST_USERS = (1 << 5),
...@@ -85,10 +103,17 @@ struct tipc_node_bclink { ...@@ -85,10 +103,17 @@ struct tipc_node_bclink {
u32 deferred_size; u32 deferred_size;
struct sk_buff_head deferdq; struct sk_buff_head deferdq;
struct sk_buff *reasm_buf; struct sk_buff *reasm_buf;
int inputq_map; struct sk_buff_head namedq;
bool recv_permitted; 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 * struct tipc_node - TIPC node structure
* @addr: network address of node * @addr: network address of node
...@@ -98,9 +123,8 @@ struct tipc_node_bclink { ...@@ -98,9 +123,8 @@ struct tipc_node_bclink {
* @hash: links to adjacent nodes in unsorted hash chain * @hash: links to adjacent nodes in unsorted hash chain
* @inputq: pointer to input queue containing messages for msg event * @inputq: pointer to input queue containing messages for msg event
* @namedq: pointer to name table input queue with name table messages * @namedq: pointer to name table input queue with name table messages
* @curr_link: the link holding the node lock, if any * @active_links: bearer ids of active links, used as index into links[] array
* @active_links: pointers to active links to node * @links: array containing references to all links to node
* @links: pointers to all links to node
* @action_flags: bit mask of different types of node actions * @action_flags: bit mask of different types of node actions
* @bclink: broadcast-related info * @bclink: broadcast-related info
* @list: links to adjacent nodes in sorted list of cluster's nodes * @list: links to adjacent nodes in sorted list of cluster's nodes
...@@ -120,12 +144,12 @@ struct tipc_node { ...@@ -120,12 +144,12 @@ struct tipc_node {
struct hlist_node hash; struct hlist_node hash;
struct sk_buff_head *inputq; struct sk_buff_head *inputq;
struct sk_buff_head *namedq; struct sk_buff_head *namedq;
struct tipc_link *active_links[2]; int active_links[2];
u32 act_mtus[2]; struct tipc_link_entry links[MAX_BEARERS];
struct tipc_link *links[MAX_BEARERS];
int action_flags; int action_flags;
struct tipc_node_bclink bclink; struct tipc_node_bclink bclink;
struct list_head list; struct list_head list;
int state;
int link_cnt; int link_cnt;
u16 working_links; u16 working_links;
u16 capabilities; u16 capabilities;
...@@ -133,6 +157,8 @@ struct tipc_node { ...@@ -133,6 +157,8 @@ struct tipc_node {
u32 link_id; u32 link_id;
struct list_head publ_list; struct list_head publ_list;
struct list_head conn_sks; struct list_head conn_sks;
unsigned long keepalive_intv;
struct timer_list timer;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -140,18 +166,25 @@ struct tipc_node *tipc_node_find(struct net *net, u32 addr); ...@@ -140,18 +166,25 @@ struct tipc_node *tipc_node_find(struct net *net, u32 addr);
void tipc_node_put(struct tipc_node *node); void tipc_node_put(struct tipc_node *node);
struct tipc_node *tipc_node_create(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_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_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_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_down(struct tipc_node *n_ptr, int bearer_id);
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); void tipc_node_link_up(struct tipc_node *n_ptr, int bearer_id);
int tipc_node_active_links(struct tipc_node *n_ptr); bool tipc_node_is_up(struct tipc_node *n);
int tipc_node_is_up(struct tipc_node *n_ptr);
int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
char *linkname, size_t len); char *linkname, size_t len);
void tipc_node_unlock(struct tipc_node *node); 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); int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port);
void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port); void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);
int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb); int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb);
static inline void tipc_node_lock(struct tipc_node *node) static inline void tipc_node_lock(struct tipc_node *node)
...@@ -159,26 +192,30 @@ 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); 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 | int bearer_id = n->active_links[sel & 1];
TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN));
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; struct tipc_node *n;
u32 mtu; int bearer_id;
unsigned int mtu = MAX_MSG_SIZE;
node = tipc_node_find(net, addr);
if (likely(node)) { n = tipc_node_find(net, addr);
mtu = node->act_mtus[selector & 1]; if (unlikely(!n))
tipc_node_put(node); return mtu;
} else {
mtu = MAX_MSG_SIZE;
}
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; return mtu;
} }
......
...@@ -261,7 +261,7 @@ static void tsk_rej_rx_queue(struct sock *sk) ...@@ -261,7 +261,7 @@ static void tsk_rej_rx_queue(struct sock *sk)
while ((skb = __skb_dequeue(&sk->sk_receive_queue))) { while ((skb = __skb_dequeue(&sk->sk_receive_queue))) {
if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_ERR_NO_PORT)) 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) ...@@ -443,7 +443,7 @@ static int tipc_release(struct socket *sock)
} }
if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
TIPC_ERR_NO_PORT)) 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) ...@@ -456,7 +456,7 @@ static int tipc_release(struct socket *sock)
tsk_own_node(tsk), tsk_peer_port(tsk), tsk_own_node(tsk), tsk_peer_port(tsk),
tsk->portid, TIPC_ERR_NO_PORT); tsk->portid, TIPC_ERR_NO_PORT);
if (skb) 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); tipc_node_remove_conn(net, dnode, tsk->portid);
} }
...@@ -686,21 +686,22 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, ...@@ -686,21 +686,22 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
do { do {
rc = tipc_bclink_xmit(net, pktchain); rc = tipc_bclink_xmit(net, pktchain);
if (likely(rc >= 0)) { if (likely(!rc))
rc = dsz; return dsz;
break;
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
rc = tipc_wait_for_sndmsg(sock, &timeo);
if (!rc)
continue;
} }
__skb_queue_purge(pktchain);
if (rc == -EMSGSIZE) { if (rc == -EMSGSIZE) {
msg->msg_iter = save; msg->msg_iter = save;
goto new_mtu; goto new_mtu;
} }
if (rc != -ELINKCONG) break;
break; } while (1);
tipc_sk(sk)->link_cong = 1;
rc = tipc_wait_for_sndmsg(sock, &timeo);
if (rc)
__skb_queue_purge(pktchain);
} while (!rc);
return rc; return rc;
} }
...@@ -924,24 +925,25 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz) ...@@ -924,24 +925,25 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
do { do {
skb = skb_peek(pktchain); skb = skb_peek(pktchain);
TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
rc = tipc_link_xmit(net, pktchain, dnode, tsk->portid); rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid);
if (likely(rc >= 0)) { if (likely(!rc)) {
if (sock->state != SS_READY) if (sock->state != SS_READY)
sock->state = SS_CONNECTING; sock->state = SS_CONNECTING;
rc = dsz; return dsz;
break;
} }
if (rc == -ELINKCONG) {
tsk->link_cong = 1;
rc = tipc_wait_for_sndmsg(sock, &timeo);
if (!rc)
continue;
}
__skb_queue_purge(pktchain);
if (rc == -EMSGSIZE) { if (rc == -EMSGSIZE) {
m->msg_iter = save; m->msg_iter = save;
goto new_mtu; goto new_mtu;
} }
if (rc != -ELINKCONG) break;
break; } while (1);
tsk->link_cong = 1;
rc = tipc_wait_for_sndmsg(sock, &timeo);
if (rc)
__skb_queue_purge(pktchain);
} while (!rc);
return rc; return rc;
} }
...@@ -1043,15 +1045,16 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz) ...@@ -1043,15 +1045,16 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
return rc; return rc;
do { do {
if (likely(!tsk_conn_cong(tsk))) { 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)) { if (likely(!rc)) {
tsk->sent_unacked++; tsk->sent_unacked++;
sent += send; sent += send;
if (sent == dsz) if (sent == dsz)
break; return dsz;
goto next; goto next;
} }
if (rc == -EMSGSIZE) { if (rc == -EMSGSIZE) {
__skb_queue_purge(pktchain);
tsk->max_pkt = tipc_node_get_mtu(net, dnode, tsk->max_pkt = tipc_node_get_mtu(net, dnode,
portid); portid);
m->msg_iter = save; m->msg_iter = save;
...@@ -1059,13 +1062,13 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz) ...@@ -1059,13 +1062,13 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
} }
if (rc != -ELINKCONG) if (rc != -ELINKCONG)
break; break;
tsk->link_cong = 1; tsk->link_cong = 1;
} }
rc = tipc_wait_for_sndpkt(sock, &timeo); rc = tipc_wait_for_sndpkt(sock, &timeo);
if (rc)
__skb_queue_purge(pktchain);
} while (!rc); } while (!rc);
__skb_queue_purge(pktchain);
return sent ? sent : rc; return sent ? sent : rc;
} }
...@@ -1221,7 +1224,7 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack) ...@@ -1221,7 +1224,7 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
return; return;
msg = buf_msg(skb); msg = buf_msg(skb);
msg_set_msgcnt(msg, ack); 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) 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) ...@@ -1700,7 +1703,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
return 0; return 0;
} }
if (!err || tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, -err)) 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; return 0;
} }
...@@ -1796,7 +1799,7 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) ...@@ -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)) if (!tipc_msg_reverse(tn->own_addr, skb, &dnode, -err))
continue; continue;
xmit: xmit:
tipc_link_xmit_skb(net, skb, dnode, dport); tipc_node_xmit_skb(net, skb, dnode, dport);
} }
return err ? -EHOSTUNREACH : 0; return err ? -EHOSTUNREACH : 0;
} }
...@@ -2089,7 +2092,7 @@ static int tipc_shutdown(struct socket *sock, int how) ...@@ -2089,7 +2092,7 @@ static int tipc_shutdown(struct socket *sock, int how)
} }
if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode,
TIPC_CONN_SHUTDOWN)) TIPC_CONN_SHUTDOWN))
tipc_link_xmit_skb(net, skb, dnode, tipc_node_xmit_skb(net, skb, dnode,
tsk->portid); tsk->portid);
} else { } else {
dnode = tsk_peer_node(tsk); dnode = tsk_peer_node(tsk);
...@@ -2099,7 +2102,7 @@ static int tipc_shutdown(struct socket *sock, int how) ...@@ -2099,7 +2102,7 @@ static int tipc_shutdown(struct socket *sock, int how)
0, dnode, tsk_own_node(tsk), 0, dnode, tsk_own_node(tsk),
tsk_peer_port(tsk), tsk_peer_port(tsk),
tsk->portid, TIPC_CONN_SHUTDOWN); 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; tsk->connected = 0;
sock->state = SS_DISCONNECTING; sock->state = SS_DISCONNECTING;
...@@ -2161,7 +2164,7 @@ static void tipc_sk_timeout(unsigned long data) ...@@ -2161,7 +2164,7 @@ static void tipc_sk_timeout(unsigned long data)
} }
bh_unlock_sock(sk); bh_unlock_sock(sk);
if (skb) 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: exit:
sock_put(sk); sock_put(sk);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册