[PATCH 1/3]: ACKVEC: Split long ack vectors across multiple options

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ack vectors grow proportional to the window size.  If an ack vector does not fit
into a single option, it must be spread across multiple options.  This patch
will allow for windows to grow larger.

Signed-off-by: Andrea Bittau <a.bittau@xxxxxxxxxxxx>

---

diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 4d176d3..35308cf 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -72,11 +72,18 @@ #ifdef CONFIG_IP_DCCP_DEBUG
 				"CLIENT tx: " : "server tx: ";
 #endif
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
-	int len = av->dccpav_vec_len + 2;
+	int len;
 	struct timeval now;
 	u32 elapsed_time;
 	unsigned char *to, *from;
 	struct dccp_ackvec_record *avr;
+	int optc, i;
+
+	/* Figure out how many options do we need to represent the ackvec */
+	optc = av->dccpav_vec_len / DCCP_MAX_ACKVEC_OPT_LEN;
+	if (av->dccpav_vec_len % DCCP_MAX_ACKVEC_OPT_LEN)
+		optc++;
+	len = optc*2 + av->dccpav_vec_len;
 
 	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
 		return -1;
@@ -94,24 +101,42 @@ #endif
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
-	to    = skb_push(skb, len);
-	*to++ = DCCPO_ACK_VECTOR_0;
-	*to++ = len;
-
-	len  = av->dccpav_vec_len;
+	to   = skb_push(skb, len);
 	from = av->dccpav_buf + av->dccpav_buf_head;
+	len  = av->dccpav_vec_len;
 
-	/* Check if buf_head wraps */
-	if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) {
-		const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head;
+	/* write the vectors */
+	for (i = 0; i < optc; i++) {
+		int copylen = len;
+		if (copylen > DCCP_MAX_ACKVEC_OPT_LEN)
+			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
 
-		memcpy(to, from, tailsize);
-		to   += tailsize;
-		len  -= tailsize;
-		from = av->dccpav_buf;
+		*to++ = DCCPO_ACK_VECTOR_0;
+		*to++ = copylen+2;
+
+		/* Check if buf_head wraps */
+		if ((from + copylen) > &av->dccpav_buf[DCCP_MAX_ACKVEC_LEN]) {
+			u32 tailsize = &av->dccpav_buf[DCCP_MAX_ACKVEC_LEN] -
+				       from;
+
+			memcpy(to, from, tailsize);
+			to	+= tailsize;
+			from     = av->dccpav_buf;
+			copylen	-= tailsize;
+			len     -= tailsize;
+
+			BUG_ON((from + copylen) >
+			       &av->dccpav_buf[DCCP_MAX_ACKVEC_LEN]);
+		}
+
+		memcpy(to, from, copylen);
+		to   += copylen;
+		from += copylen;
+
+		len -= copylen;
 	}
+	BUG_ON(len != 0);
 
-	memcpy(to, from, len);
 	/*
 	 *	From draft-ietf-dccp-spec-11.txt:
 	 *
@@ -145,7 +170,6 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
 		av->dccpav_buf_head	= DCCP_MAX_ACKVEC_LEN - 1;
 		av->dccpav_buf_ackno	= DCCP_MAX_SEQNO + 1;
 		av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
-		av->dccpav_ack_ptr	= 0;
 		av->dccpav_time.tv_sec	= 0;
 		av->dccpav_time.tv_usec	= 0;
 		av->dccpav_vec_len	= 0;
@@ -174,13 +198,13 @@ void dccp_ackvec_free(struct dccp_ackvec
 }
 
 static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av,
-				   const u8 index)
+				   const int index)
 {
 	return av->dccpav_buf[index] & DCCP_ACKVEC_STATE_MASK;
 }
 
 static inline u8 dccp_ackvec_len(const struct dccp_ackvec *av,
-				 const u8 index)
+				 const int index)
 {
 	return av->dccpav_buf[index] & DCCP_ACKVEC_LEN_MASK;
 }
@@ -280,7 +304,7 @@ int dccp_ackvec_add(struct dccp_ackvec *
 		 *	could reduce the complexity of this scan.)
 		 */
 		u64 delta = dccp_delta_seqno(ackno, av->dccpav_buf_ackno);
-		u8 index = av->dccpav_buf_head;
+		int index = av->dccpav_buf_head;
 
 		while (1) {
 			const u8 len = dccp_ackvec_len(av, index);
@@ -396,17 +420,17 @@ #endif
 	}
 }
 
-static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
-					    struct sock *sk, u64 ackno,
-					    const unsigned char len,
-					    const unsigned char *vector)
+static u64 dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
+					   struct sock *sk, u64 ackno,
+					   const unsigned char len,
+					   const unsigned char *vector)
 {
 	unsigned char i;
 	struct dccp_ackvec_record *avr;
 
 	/* Check if we actually sent an ACK vector */
 	if (list_empty(&av->dccpav_records))
-		return;
+		return ackno; /* It's OK, because we will always return */
 
 	i = len;
 	/*
@@ -432,7 +456,10 @@ static void dccp_ackvec_check_rcv_ackvec
 				goto found;
 		}
 		/* End of the dccpav_records list, not found, exit */
-		break;
+		break; /* Do not need to return a correct ackno because the next
+		        * batch of ackvectors will not make situation better
+			* (their acknos will be lower)
+			*/
 found:
 		if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
 			const u8 state = *vector & DCCP_ACKVEC_STATE_MASK;
@@ -452,7 +479,9 @@ #endif
 					      (unsigned long long)
 					      avr->dccpavr_ack_ackno);
 				dccp_ackvec_throw_record(av, avr);
-				break;
+				break; /* Don't care about other ACKs because we
+				        * released the most possible state
+					*/
 			}
 			/*
 			 * If it wasn't received, continue scanning... we might
@@ -463,19 +492,16 @@ #endif
 		dccp_set_seqno(&ackno, ackno_end_rl - 1);
 		++vector;
 	}
+
+	return ackno;
 }
 
-int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
+u64 dccp_ackvec_parse(struct sock *sk, u64 ackno,
 		      const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_LEN)
-		return -1;
-
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
-	dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec, sk,
-					DCCP_SKB_CB(skb)->dccpd_ack_seq,
-				        len, value);
-	return 0;
+	return dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec,
+					       sk, ackno, len, value);
 }
 
 static char dccp_ackvec_slab_msg[] __initdata =
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index ec9a988..691a7f4 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -18,7 +18,9 @@ #include <linux/time.h>
 #include <linux/types.h>
 
 /* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_LEN 253
+#define DCCP_MAX_ACKVEC_OPT_LEN 253
+/* We can spread an ack vector across multiple options */
+#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN*2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
@@ -54,9 +56,8 @@ struct dccp_ackvec {
 	u64		dccpav_buf_ackno;
 	struct list_head dccpav_records;
 	struct timeval	dccpav_time;
-	u8		dccpav_buf_head;
-	u8		dccpav_ack_ptr;
-	u8		dccpav_vec_len;
+	int		dccpav_buf_head;
+	int		dccpav_vec_len;
 	u8		dccpav_buf_nonce;
 	u8		dccpav_ack_nonce;
 	u8		dccpav_buf[DCCP_MAX_ACKVEC_LEN];
@@ -79,9 +80,9 @@ struct dccp_ackvec_record {
 	struct list_head dccpavr_node;
 	u64		 dccpavr_ack_seqno;
 	u64		 dccpavr_ack_ackno;
-	u8		 dccpavr_ack_ptr;
+	int		 dccpavr_ack_ptr;
 	u8		 dccpavr_ack_nonce;
-	u8		 dccpavr_sent_len;
+	int		 dccpavr_sent_len;
 };
 
 struct sock;
@@ -99,7 +100,7 @@ extern int dccp_ackvec_add(struct dccp_a
 
 extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av,
 					struct sock *sk, const u64 ackno);
-extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
+extern u64 dccp_ackvec_parse(struct sock *sk, u64 ackno,
 			     const u8 opt, const u8 *value, const u8 len);
 
 extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb);
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index d208657..5f3e1c8 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -70,7 +70,7 @@ struct ccid2_txprofile {
 	unsigned long		ccid2txp_packets_last;
 };
 
-#define CCID2_SEQBUF_LEN 256
+#define CCID2_SEQBUF_LEN 1024
 #define CCID2_SEQBUF_MAX 128
 
 /** struct ccid2_hc_tx_sock - CCID2 TX half connection
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 1fe5091..303a75a 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,7 +42,7 @@ extern void dccp_tw_deschedule(struct in
 extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 
 /* FIXME: Right size this */
-#define DCCP_MAX_OPT_LEN 128
+#define DCCP_MAX_OPT_LEN 1024
 
 #define DCCP_MAX_PACKET_HDR 32
 
diff --git a/net/dccp/options.c b/net/dccp/options.c
index e9feb2a..7817313 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -75,6 +75,7 @@ #endif
 	u32 elapsed_time;
 	int rc;
 	int mandatory = 0;
+	u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
 
 	memset(opt_recv, 0, sizeof(*opt_recv));
 
@@ -151,9 +152,9 @@ #endif
 			if (pkt_type == DCCP_PKT_DATA)
 				break;
 
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
-			    dccp_ackvec_parse(sk, skb, opt, value, len))
-				goto out_invalid_option;
+			if (dccp_msk(sk)->dccpms_send_ack_vector)
+				ackno = dccp_ackvec_parse(sk, ackno, opt,
+							  value, len);
 			break;
 		case DCCPO_TIMESTAMP:
 			if (len != 4)
-
: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux