Commit 662921cd authored by Jon Paul Maloy's avatar Jon Paul Maloy Committed by David S. Miller

tipc: merge link->exec_mode and link->state into one FSM

Until now, we have been handling link failover and synchronization
by using an additional link state variable, "exec_mode". This variable
is not independent of the link FSM state, something causing a risk of
inconsistencies, apart from the fact that it clutters the code.

The conditions are now in place to define a new link FSM that covers
all existing use cases, including failover and synchronization, and
eliminate the "exec_mode" field altogether. The FSM must also support
non-atomic resetting of links, which will be introduced later.

The new link FSM is shown below, with 7 states and 8 events.
Only events leading to state change are shown as edges.

+------------------------------------+
|RESET_EVT                           |
|                                    |
|                             +--------------+
|           +-----------------|   SYNCHING   |-----------------+
|           |FAILURE_EVT      +--------------+   PEER_RESET_EVT|
|           |                  A            |                  |
|           |                  |            |                  |
|           |                  |            |                  |
|           |                  |SYNCH_      |SYNCH_            |
|           |                  |BEGIN_EVT   |END_EVT           |
|           |                  |            |                  |
|           V                  |            V                  V
|    +-------------+          +--------------+          +------------+
|    |  RESETTING  |<---------|  ESTABLISHED |--------->| PEER_RESET |
|    +-------------+ FAILURE_ +--------------+ PEER_    +------------+
|           |        EVT        |    A         RESET_EVT       |
|           |                   |    |                         |
|           |                   |    |                         |
|           |    +--------------+    |                         |
|  RESET_EVT|    |RESET_EVT          |ESTABLISH_EVT            |
|           |    |                   |                         |
|           |    |                   |                         |
|           V    V                   |                         |
|    +-------------+          +--------------+        RESET_EVT|
+--->|    RESET    |--------->| ESTABLISHING |<----------------+
     +-------------+ PEER_    +--------------+
      |           A  RESET_EVT       |
      |           |                  |
      |           |                  |
      |FAILOVER_  |FAILOVER_         |FAILOVER_
      |BEGIN_EVT  |END_EVT           |BEGIN_EVT
      |           |                  |
      V           |                  |
     +-------------+                 |
     | FAILINGOVER |<----------------+
     +-------------+

These changes are fully backwards compatible.
Tested-by: default avatarYing Xue <ying.xue@windriver.com>
Signed-off-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5045f7b9
This diff is collapsed.
......@@ -49,13 +49,17 @@
*/
#define INVALID_LINK_SEQ 0x10000
/* Link endpoint receive states
/* Link FSM events:
*/
enum {
TIPC_LINK_OPEN,
TIPC_LINK_BLOCKED,
TIPC_LINK_TUNNEL
LINK_ESTABLISH_EVT = 0xec1ab1e,
LINK_PEER_RESET_EVT = 0x9eed0e,
LINK_FAILURE_EVT = 0xfa110e,
LINK_RESET_EVT = 0x10ca1d0e,
LINK_FAILOVER_BEGIN_EVT = 0xfa110bee,
LINK_FAILOVER_END_EVT = 0xfa110ede,
LINK_SYNCH_BEGIN_EVT = 0xc1ccbee,
LINK_SYNCH_END_EVT = 0xc1ccede
};
/* Events returned from link at packet reception or at timeout
......@@ -120,7 +124,6 @@ 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
......@@ -155,7 +158,7 @@ struct tipc_link {
u32 tolerance;
unsigned long keepalive_intv;
u32 abort_limit;
int state;
u32 state;
u32 silent_intv_cnt;
struct {
unchar hdr[INT_H_SIZE];
......@@ -166,7 +169,6 @@ struct tipc_link {
char net_plane;
/* Failover/synch */
u8 exec_mode;
u16 drop_point;
struct sk_buff *failover_reasm_skb;
......@@ -214,8 +216,13 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
int mtyp, struct sk_buff_head *xmitq);
void tipc_link_build_bcast_sync_msg(struct tipc_link *l,
struct sk_buff_head *xmitq);
int tipc_link_fsm_evt(struct tipc_link *l, int evt);
void tipc_link_reset_fragments(struct tipc_link *l_ptr);
int tipc_link_is_up(struct tipc_link *l_ptr);
bool tipc_link_is_up(struct tipc_link *l);
bool tipc_link_is_reset(struct tipc_link *l);
bool tipc_link_is_synching(struct tipc_link *l);
bool tipc_link_is_failingover(struct tipc_link *l);
bool tipc_link_is_blocked(struct tipc_link *l);
int tipc_link_is_active(struct tipc_link *l_ptr);
void tipc_link_purge_queues(struct tipc_link *l_ptr);
void tipc_link_purge_backlog(struct tipc_link *l);
......
......@@ -334,7 +334,6 @@ static void tipc_node_link_up(struct tipc_node *n, int bearer_id,
if (!ol) {
*slot0 = bearer_id;
*slot1 = bearer_id;
nl->exec_mode = TIPC_LINK_OPEN;
tipc_link_build_bcast_sync_msg(nl, xmitq);
node_established_contact(n);
return;
......@@ -368,7 +367,7 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id)
struct sk_buff_head xmitq;
l = n->links[bearer_id].link;
if (!l || !tipc_link_is_up(l))
if (!l || tipc_link_is_reset(l))
return;
__skb_queue_head_init(&xmitq);
......@@ -414,6 +413,7 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id)
n->sync_point = tnl->rcv_nxt + (U16_MAX / 2 - 1);
tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, &xmitq);
tipc_link_reset(l);
tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT);
tipc_bearer_xmit(n->net, tnl->bearer_id, &xmitq, maddr);
}
......@@ -749,7 +749,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
struct tipc_link *l_ptr = n_ptr->links[i].link;
if (!l_ptr)
continue;
l_ptr->exec_mode = TIPC_LINK_OPEN;
tipc_link_fsm_evt(l_ptr, LINK_FAILOVER_END_EVT);
kfree_skb(l_ptr->failover_reasm_skb);
l_ptr->failover_reasm_skb = NULL;
tipc_link_reset_fragments(l_ptr);
......@@ -989,7 +989,7 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
* Returns true if state is ok, otherwise consumes buffer and returns false
*/
static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
int bearer_id)
int bearer_id, struct sk_buff_head *xmitq)
{
struct tipc_msg *hdr = buf_msg(skb);
int usr = msg_user(hdr);
......@@ -1042,42 +1042,47 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
/* Initiate or update failover mode if applicable */
if ((usr == TUNNEL_PROTOCOL) && (mtyp == FAILOVER_MSG)) {
syncpt = oseqno + exp_pkts - 1;
if (pl && tipc_link_is_up(pl)) {
if (pl && tipc_link_is_up(pl))
tipc_node_link_down(n, pl->bearer_id);
pl->exec_mode = TIPC_LINK_BLOCKED;
}
/* If pkts arrive out of order, use lowest calculated syncpt */
if (less(syncpt, n->sync_point))
n->sync_point = syncpt;
}
/* Open parallel link when tunnel link reaches synch point */
if ((n->state == NODE_FAILINGOVER) && (more(rcv_nxt, n->sync_point))) {
if ((n->state == NODE_FAILINGOVER) && !tipc_link_is_failingover(l)) {
if (!more(rcv_nxt, n->sync_point))
return true;
tipc_node_fsm_evt(n, NODE_FAILOVER_END_EVT);
if (pl)
pl->exec_mode = TIPC_LINK_OPEN;
tipc_link_fsm_evt(pl, LINK_FAILOVER_END_EVT);
return true;
}
/* Initiate or update synch mode if applicable */
if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) {
syncpt = iseqno + exp_pkts - 1;
if (!tipc_link_is_up(l)) {
tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT);
tipc_node_link_up(n, bearer_id, xmitq);
}
if (n->state == SELF_UP_PEER_UP) {
n->sync_point = syncpt;
tipc_link_fsm_evt(l, LINK_SYNCH_BEGIN_EVT);
tipc_node_fsm_evt(n, NODE_SYNCH_BEGIN_EVT);
}
l->exec_mode = TIPC_LINK_TUNNEL;
if (less(syncpt, n->sync_point))
n->sync_point = syncpt;
}
/* Open tunnel link when parallel link reaches synch point */
if ((n->state == NODE_SYNCHING) && (l->exec_mode == TIPC_LINK_TUNNEL)) {
if ((n->state == NODE_SYNCHING) && tipc_link_is_synching(l)) {
if (pl)
dlv_nxt = mod(pl->rcv_nxt - skb_queue_len(pl->inputq));
if (!pl || more(dlv_nxt, n->sync_point)) {
tipc_link_fsm_evt(l, LINK_SYNCH_END_EVT);
tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT);
l->exec_mode = TIPC_LINK_OPEN;
return true;
}
if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG))
......@@ -1143,7 +1148,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)
tipc_bclink_acknowledge(n, msg_bcast_ack(hdr));
/* Check and if necessary update node state */
if (likely(tipc_node_check_state(n, skb, bearer_id))) {
if (likely(tipc_node_check_state(n, skb, bearer_id, &xmitq))) {
rc = tipc_link_rcv(le->link, skb, &xmitq);
skb = NULL;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment