tipc: check session number before accepting link protocol messages
authorJon Maloy <jon.maloy@ericsson.com>
Mon, 9 Jul 2018 23:07:36 +0000 (01:07 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 12 Jul 2018 06:06:14 +0000 (23:06 -0700)
In some virtual environments we observe a significant higher number of
packet reordering and delays than we have been used to traditionally.

This makes it necessary with stricter checks on incoming link protocol
messages' session number, which until now only has been validated for
RESET messages.

Since the other two message types, ACTIVATE and STATE messages also
carry this number, it is easy to extend the validation check to those
messages.

We also introduce a flag indicating if a link has a valid peer session
number or not. This eliminates the mixing of 32- and 16-bit arithmethics
we are currently using to achieve this.

Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/link.c
net/tipc/link.h
net/tipc/node.c

index 065e9e67da5d9d3609d78b9314f7fa6695365cc6..df763be38541040406d2bd8a6712856947232e81 100644 (file)
@@ -128,8 +128,8 @@ struct tipc_link {
        struct net *net;
 
        /* Management and link supervision data */
-       u32 peer_session;
-       u32 session;
+       u16 peer_session;
+       u16 session;
        u16 snd_nxt_state;
        u16 rcv_nxt_state;
        u32 peer_bearer_id;
@@ -138,6 +138,7 @@ struct tipc_link {
        u32 abort_limit;
        u32 state;
        u16 peer_caps;
+       bool in_session;
        bool active;
        u32 silent_intv_cnt;
        char if_name[TIPC_MAX_IF_NAME];
@@ -216,11 +217,6 @@ enum {
  */
 #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:
  */
 enum {
@@ -478,7 +474,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
        l->addr = peer;
        l->peer_caps = peer_caps;
        l->net = net;
-       l->peer_session = ANY_SESSION;
+       l->in_session = false;
        l->bearer_id = bearer_id;
        l->tolerance = tolerance;
        l->net_plane = net_plane;
@@ -847,7 +843,7 @@ void link_prepare_wakeup(struct tipc_link *l)
 
 void tipc_link_reset(struct tipc_link *l)
 {
-       l->peer_session = ANY_SESSION;
+       l->in_session = false;
        l->session++;
        l->mtu = l->advertised_mtu;
        __skb_queue_purge(&l->transmq);
@@ -1455,6 +1451,44 @@ 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 :
  * Note that network plane id propagates through the network, and may
  * change at any time. The node with lowest numerical id determines
@@ -1488,17 +1522,12 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        hdr = buf_msg(skb);
        data = msg_data(hdr);
 
+       if (!tipc_link_validate_msg(l, hdr))
+               goto exit;
+
        switch (mtyp) {
        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:
-
                /* Complete own link name with peer's interface name */
                if_name =  strrchr(l->name, ':') + 1;
                if (sizeof(l->name) - (if_name - l->name) <= TIPC_MAX_IF_NAME)
@@ -1526,16 +1555,13 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
                        rc = TIPC_LINK_UP_EVT;
 
                l->peer_session = msg_session(hdr);
+               l->in_session = true;
                l->peer_bearer_id = msg_bearer_id(hdr);
                if (l->mtu > msg_max_pkt(hdr))
                        l->mtu = msg_max_pkt(hdr);
                break;
 
        case STATE_MSG:
-
-               if (l->peer_caps & TIPC_LINK_PROTO_SEQNO &&
-                   less(msg_seqno(hdr), l->rcv_nxt_state))
-                       break;
                l->rcv_nxt_state = msg_seqno(hdr) + 1;
 
                /* Update own tolerance if peer indicates a non-zero value */
index d56f9c9e500007e083fc7e453ba1f83fde333ee0..7bc494a33fdf1c3cdf8feb04b44db7e6e04a349c 100644 (file)
@@ -111,6 +111,7 @@ char tipc_link_plane(struct tipc_link *l);
 int tipc_link_prio(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);
 void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
                             struct sk_buff_head *xmitq);
index 1cdb176798f7613806284d418c4b41e8a3379012..52fd80b0e7287568778deea89626c8bc3850cfc9 100644 (file)
@@ -1540,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
  * @skb: TIPC 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,
                                  int bearer_id, struct sk_buff_head *xmitq)
@@ -1574,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 */
        if (state == SELF_UP_PEER_COMING) {
                if (!tipc_link_is_up(l))