Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e97c4fb authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tipc-make-link-protocol-more-resilient'



Jon Maloy says:

====================
tipc: make link protocol more resilient

These two commits make the link ptotocol more resilient to
infrastructures with frequent packet duplication and long delays.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e32f55f3 7ea817f4
Loading
Loading
Loading
Loading
+59 −17
Original line number Original line Diff line number Diff line
@@ -128,14 +128,17 @@ struct tipc_link {
	struct net *net;
	struct net *net;


	/* Management and link supervision data */
	/* Management and link supervision data */
	u32 peer_session;
	u16 peer_session;
	u32 session;
	u16 session;
	u16 snd_nxt_state;
	u16 rcv_nxt_state;
	u32 peer_bearer_id;
	u32 peer_bearer_id;
	u32 bearer_id;
	u32 bearer_id;
	u32 tolerance;
	u32 tolerance;
	u32 abort_limit;
	u32 abort_limit;
	u32 state;
	u32 state;
	u16 peer_caps;
	u16 peer_caps;
	bool in_session;
	bool active;
	bool active;
	u32 silent_intv_cnt;
	u32 silent_intv_cnt;
	char if_name[TIPC_MAX_IF_NAME];
	char if_name[TIPC_MAX_IF_NAME];
@@ -214,11 +217,6 @@ enum {
 */
 */
#define TIPC_NACK_INTV (TIPC_MIN_LINK_WIN * 2)
#define TIPC_NACK_INTV (TIPC_MIN_LINK_WIN * 2)


/* Wildcard value for link session numbers. When it is known that
 * peer endpoint is down, any session number must be accepted.
 */
#define ANY_SESSION 0x10000

/* Link FSM states:
/* Link FSM states:
 */
 */
enum {
enum {
@@ -339,6 +337,11 @@ char tipc_link_plane(struct tipc_link *l)
	return l->net_plane;
	return l->net_plane;
}
}


void tipc_link_update_caps(struct tipc_link *l, u16 capabilities)
{
	l->peer_caps = capabilities;
}

void tipc_link_add_bc_peer(struct tipc_link *snd_l,
void tipc_link_add_bc_peer(struct tipc_link *snd_l,
			   struct tipc_link *uc_l,
			   struct tipc_link *uc_l,
			   struct sk_buff_head *xmitq)
			   struct sk_buff_head *xmitq)
@@ -471,7 +474,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
	l->addr = peer;
	l->addr = peer;
	l->peer_caps = peer_caps;
	l->peer_caps = peer_caps;
	l->net = net;
	l->net = net;
	l->peer_session = ANY_SESSION;
	l->in_session = false;
	l->bearer_id = bearer_id;
	l->bearer_id = bearer_id;
	l->tolerance = tolerance;
	l->tolerance = tolerance;
	l->net_plane = net_plane;
	l->net_plane = net_plane;
@@ -840,7 +843,7 @@ void link_prepare_wakeup(struct tipc_link *l)


void tipc_link_reset(struct tipc_link *l)
void tipc_link_reset(struct tipc_link *l)
{
{
	l->peer_session = ANY_SESSION;
	l->in_session = false;
	l->session++;
	l->session++;
	l->mtu = l->advertised_mtu;
	l->mtu = l->advertised_mtu;
	__skb_queue_purge(&l->transmq);
	__skb_queue_purge(&l->transmq);
@@ -859,6 +862,8 @@ void tipc_link_reset(struct tipc_link *l)
	l->rcv_unacked = 0;
	l->rcv_unacked = 0;
	l->snd_nxt = 1;
	l->snd_nxt = 1;
	l->rcv_nxt = 1;
	l->rcv_nxt = 1;
	l->snd_nxt_state = 1;
	l->rcv_nxt_state = 1;
	l->acked = 0;
	l->acked = 0;
	l->silent_intv_cnt = 0;
	l->silent_intv_cnt = 0;
	l->rst_cnt = 0;
	l->rst_cnt = 0;
@@ -1353,6 +1358,8 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
	msg_set_seqno(hdr, l->snd_nxt + U16_MAX / 2);
	msg_set_seqno(hdr, l->snd_nxt + U16_MAX / 2);


	if (mtyp == STATE_MSG) {
	if (mtyp == STATE_MSG) {
		if (l->peer_caps & TIPC_LINK_PROTO_SEQNO)
			msg_set_seqno(hdr, l->snd_nxt_state++);
		msg_set_seq_gap(hdr, rcvgap);
		msg_set_seq_gap(hdr, rcvgap);
		msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl));
		msg_set_bc_gap(hdr, link_bc_rcv_gap(bcl));
		msg_set_probe(hdr, probe);
		msg_set_probe(hdr, probe);
@@ -1444,6 +1451,44 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
	}
	}
}
}


/* tipc_link_validate_msg(): validate message against current link state
 * Returns true if message should be accepted, otherwise false
 */
bool tipc_link_validate_msg(struct tipc_link *l, struct tipc_msg *hdr)
{
	u16 curr_session = l->peer_session;
	u16 session = msg_session(hdr);
	int mtyp = msg_type(hdr);

	if (msg_user(hdr) != LINK_PROTOCOL)
		return true;

	switch (mtyp) {
	case RESET_MSG:
		if (!l->in_session)
			return true;
		/* Accept only RESET with new session number */
		return more(session, curr_session);
	case ACTIVATE_MSG:
		if (!l->in_session)
			return true;
		/* Accept only ACTIVATE with new or current session number */
		return !less(session, curr_session);
	case STATE_MSG:
		/* Accept only STATE with current session number */
		if (!l->in_session)
			return false;
		if (session != curr_session)
			return false;
		if (!(l->peer_caps & TIPC_LINK_PROTO_SEQNO))
			return true;
		/* Accept only STATE with new sequence number */
		return !less(msg_seqno(hdr), l->rcv_nxt_state);
	default:
		return false;
	}
}

/* tipc_link_proto_rcv(): receive link level protocol message :
/* tipc_link_proto_rcv(): receive link level protocol message :
 * Note that network plane id propagates through the network, and may
 * Note that network plane id propagates through the network, and may
 * change at any time. The node with lowest numerical id determines
 * change at any time. The node with lowest numerical id determines
@@ -1477,17 +1522,12 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
	hdr = buf_msg(skb);
	hdr = buf_msg(skb);
	data = msg_data(hdr);
	data = msg_data(hdr);


	if (!tipc_link_validate_msg(l, hdr))
		goto exit;

	switch (mtyp) {
	switch (mtyp) {
	case RESET_MSG:
	case RESET_MSG:

		/* Ignore duplicate RESET with old session number */
		if ((less_eq(msg_session(hdr), l->peer_session)) &&
		    (l->peer_session != ANY_SESSION))
			break;
		/* fall thru' */

	case ACTIVATE_MSG:
	case ACTIVATE_MSG:

		/* Complete own link name with peer's interface name */
		/* Complete own link name with peer's interface name */
		if_name =  strrchr(l->name, ':') + 1;
		if_name =  strrchr(l->name, ':') + 1;
		if (sizeof(l->name) - (if_name - l->name) <= TIPC_MAX_IF_NAME)
		if (sizeof(l->name) - (if_name - l->name) <= TIPC_MAX_IF_NAME)
@@ -1515,12 +1555,14 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
			rc = TIPC_LINK_UP_EVT;
			rc = TIPC_LINK_UP_EVT;


		l->peer_session = msg_session(hdr);
		l->peer_session = msg_session(hdr);
		l->in_session = true;
		l->peer_bearer_id = msg_bearer_id(hdr);
		l->peer_bearer_id = msg_bearer_id(hdr);
		if (l->mtu > msg_max_pkt(hdr))
		if (l->mtu > msg_max_pkt(hdr))
			l->mtu = msg_max_pkt(hdr);
			l->mtu = msg_max_pkt(hdr);
		break;
		break;


	case STATE_MSG:
	case STATE_MSG:
		l->rcv_nxt_state = msg_seqno(hdr) + 1;


		/* Update own tolerance if peer indicates a non-zero value */
		/* Update own tolerance if peer indicates a non-zero value */
		if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
		if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))
+2 −0
Original line number Original line Diff line number Diff line
@@ -110,6 +110,8 @@ char *tipc_link_name(struct tipc_link *l);
char tipc_link_plane(struct tipc_link *l);
char tipc_link_plane(struct tipc_link *l);
int tipc_link_prio(struct tipc_link *l);
int tipc_link_prio(struct tipc_link *l);
int tipc_link_window(struct tipc_link *l);
int tipc_link_window(struct tipc_link *l);
void tipc_link_update_caps(struct tipc_link *l, u16 capabilities);
bool tipc_link_validate_msg(struct tipc_link *l, struct tipc_msg *hdr);
unsigned long tipc_link_tolerance(struct tipc_link *l);
unsigned long tipc_link_tolerance(struct tipc_link *l);
void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
			     struct sk_buff_head *xmitq);
			     struct sk_buff_head *xmitq);
+11 −1
Original line number Original line Diff line number Diff line
@@ -363,6 +363,8 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
{
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_node *n, *temp_node;
	struct tipc_node *n, *temp_node;
	struct tipc_link *l;
	int bearer_id;
	int i;
	int i;


	spin_lock_bh(&tn->node_list_lock);
	spin_lock_bh(&tn->node_list_lock);
@@ -370,6 +372,11 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
	if (n) {
	if (n) {
		/* Same node may come back with new capabilities */
		/* Same node may come back with new capabilities */
		n->capabilities = capabilities;
		n->capabilities = capabilities;
		for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
			l = n->links[bearer_id].link;
			if (l)
				tipc_link_update_caps(l, capabilities);
		}
		goto exit;
		goto exit;
	}
	}
	n = kzalloc(sizeof(*n), GFP_ATOMIC);
	n = kzalloc(sizeof(*n), GFP_ATOMIC);
@@ -1533,7 +1540,7 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id
 * tipc_node_check_state - check and if necessary update node state
 * tipc_node_check_state - check and if necessary update node state
 * @skb: TIPC packet
 * @skb: TIPC packet
 * @bearer_id: identity of bearer delivering the packet
 * @bearer_id: identity of bearer delivering the packet
 * Returns true if state is ok, otherwise consumes buffer and returns false
 * Returns true if state and msg are ok, otherwise false
 */
 */
static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
				  int bearer_id, struct sk_buff_head *xmitq)
				  int bearer_id, struct sk_buff_head *xmitq)
@@ -1567,6 +1574,9 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,
		}
		}
	}
	}


	if (!tipc_link_validate_msg(l, hdr))
		return false;

	/* Check and update node accesibility if applicable */
	/* Check and update node accesibility if applicable */
	if (state == SELF_UP_PEER_COMING) {
	if (state == SELF_UP_PEER_COMING) {
		if (!tipc_link_is_up(l))
		if (!tipc_link_is_up(l))
+8 −6
Original line number Original line Diff line number Diff line
@@ -49,14 +49,16 @@ enum {
	TIPC_BCAST_STATE_NACK = (1 << 2),
	TIPC_BCAST_STATE_NACK = (1 << 2),
	TIPC_BLOCK_FLOWCTL    = (1 << 3),
	TIPC_BLOCK_FLOWCTL    = (1 << 3),
	TIPC_BCAST_RCAST      = (1 << 4),
	TIPC_BCAST_RCAST      = (1 << 4),
	TIPC_NODE_ID128       = (1 << 5)
	TIPC_NODE_ID128       = (1 << 5),
	TIPC_LINK_PROTO_SEQNO = (1 << 6)
};
};


#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH       |  \
#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH       |  \
				TIPC_BCAST_STATE_NACK  |  \
				TIPC_BCAST_STATE_NACK  |  \
				TIPC_BCAST_RCAST       |  \
				TIPC_BCAST_RCAST       |  \
				TIPC_BLOCK_FLOWCTL     |  \
				TIPC_BLOCK_FLOWCTL     |  \
				TIPC_NODE_ID128)
				TIPC_NODE_ID128        |  \
				TIPC_LINK_PROTO_SEQNO)
#define INVALID_BEARER_ID -1
#define INVALID_BEARER_ID -1


void tipc_node_stop(struct net *net);
void tipc_node_stop(struct net *net);