aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2013-07-02 15:29:00 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-02 19:33:25 -0400
commita0dbd822273ce7660bf35525d61d7a8ac5e679a3 (patch)
tree3f5187519c078bfa265654239854ab0a41597719 /net
parent8a1631d588a39e826f4248e60310498d5266c6fa (diff)
l2tp: make datapath resilient to packet loss when sequence numbers enabled
If L2TP data sequence numbers are enabled and reordering is not enabled, data reception stops if a packet is lost since the kernel waits for a sequence number that is never resent. (When reordering is enabled, data reception restarts when the reorder timeout expires.) If no reorder timeout is set, we should count the number of in-sequence packets after the out-of-sequence (OOS) condition is detected, and reset sequence number state after a number of such packets are received. For now, the number of in-sequence packets while in OOS state which cause the sequence number state to be reset is hard-coded to 5. This could be configurable later. Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/l2tp/l2tp_core.c36
-rw-r--r--net/l2tp/l2tp_core.h3
2 files changed, 34 insertions, 5 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 735cc06971ef..feae495a0a30 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -572,12 +572,33 @@ static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb)
572 * reorder queue, in order of ns. 572 * reorder queue, in order of ns.
573 */ 573 */
574 l2tp_recv_queue_skb(session, skb); 574 l2tp_recv_queue_skb(session, skb);
575 goto out;
576 }
577
578 /* Packet reordering disabled. Discard out-of-sequence packets, while
579 * tracking the number if in-sequence packets after the first OOS packet
580 * is seen. After nr_oos_count_max in-sequence packets, reset the
581 * sequence number to re-enable packet reception.
582 */
583 if (L2TP_SKB_CB(skb)->ns == session->nr) {
584 skb_queue_tail(&session->reorder_q, skb);
575 } else { 585 } else {
576 /* Packet reordering disabled. Discard out-of-sequence 586 u32 nr_oos = L2TP_SKB_CB(skb)->ns;
577 * packets 587 u32 nr_next = (session->nr_oos + 1) & session->nr_max;
578 */ 588
579 if ((L2TP_SKB_CB(skb)->ns != session->nr) && 589 if (nr_oos == nr_next)
580 (!session->reorder_skip)) { 590 session->nr_oos_count++;
591 else
592 session->nr_oos_count = 0;
593
594 session->nr_oos = nr_oos;
595 if (session->nr_oos_count > session->nr_oos_count_max) {
596 session->reorder_skip = 1;
597 l2tp_dbg(session, L2TP_MSG_SEQ,
598 "%s: %d oos packets received. Resetting sequence numbers\n",
599 session->name, session->nr_oos_count);
600 }
601 if (!session->reorder_skip) {
581 atomic_long_inc(&session->stats.rx_seq_discards); 602 atomic_long_inc(&session->stats.rx_seq_discards);
582 l2tp_dbg(session, L2TP_MSG_SEQ, 603 l2tp_dbg(session, L2TP_MSG_SEQ,
583 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n", 604 "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n",
@@ -589,6 +610,7 @@ static int l2tp_recv_data_seq(struct l2tp_session *session, struct sk_buff *skb)
589 skb_queue_tail(&session->reorder_q, skb); 610 skb_queue_tail(&session->reorder_q, skb);
590 } 611 }
591 612
613out:
592 return 0; 614 return 0;
593 615
594discard: 616discard:
@@ -1852,6 +1874,10 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
1852 else 1874 else
1853 session->nr_max = 0xffffff; 1875 session->nr_max = 0xffffff;
1854 session->nr_window_size = session->nr_max / 2; 1876 session->nr_window_size = session->nr_max / 2;
1877 session->nr_oos_count_max = 4;
1878
1879 /* Use NR of first received packet */
1880 session->reorder_skip = 1;
1855 1881
1856 sprintf(&session->name[0], "sess %u/%u", 1882 sprintf(&session->name[0], "sess %u/%u",
1857 tunnel->tunnel_id, session->session_id); 1883 tunnel->tunnel_id, session->session_id);
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 4b9a3b724423..66a559b104b6 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -104,6 +104,9 @@ struct l2tp_session {
104 struct sk_buff_head reorder_q; /* receive reorder queue */ 104 struct sk_buff_head reorder_q; /* receive reorder queue */
105 u32 nr_max; /* max NR. Depends on tunnel */ 105 u32 nr_max; /* max NR. Depends on tunnel */
106 u32 nr_window_size; /* NR window size */ 106 u32 nr_window_size; /* NR window size */
107 u32 nr_oos; /* NR of last OOS packet */
108 int nr_oos_count; /* For OOS recovery */
109 int nr_oos_count_max;
107 struct hlist_node hlist; /* Hash list node */ 110 struct hlist_node hlist; /* Hash list node */
108 atomic_t ref_count; 111 atomic_t ref_count;
109 112