PERFORCE change 164426 for review

Fang Wang fangwang at FreeBSD.org
Mon Jun 15 13:42:59 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=164426

Change 164426 by fangwang at fangwang_utobsd on 2009/06/15 13:42:34

	Finish basic function. Hope it can work. There still are many details needs to modify according to RFC5482.

Affected files ...

.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_input.c#4 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_output.c#6 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_subr.c#4 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_syncache.c#4 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_syncache.h#4 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_timer.c#3 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_timer.h#4 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_usrreq.c#2 edit
.. //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_var.h#9 edit

Differences ...

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_input.c#4 (text+ko) ====

@@ -1187,6 +1187,16 @@
 	    (thflags & TH_SYN) ? TO_SYN : 0);
 
 	/*
+	 * If TCP user timeout option is received, because it's an
+	 * optional option, we do nothing at this moment. And we will
+	 * process when we need retransmission in synchronized states.
+	 */	 
+	if (to.to_flags & TOF_UTO) {
+		tp->uto_flags |= TCPUTO_RCVD;
+		tp->rcv_uto = to.to_uto;
+	}
+	
+	/*
 	 * If echoed timestamp is later than the current time,
 	 * fall back to non RFC1323 RTT calculation.  Normalize
 	 * timestamp if syncookies were used when this connection
@@ -1197,6 +1207,12 @@
 		if (TSTMP_GT(to.to_tsecr, ticks))
 			to.to_tsecr = 0;
 	}
+	if (tp->uto_flags & TCPUTO_SENDING)
+		if (th->th_ack > tp->uto_carrier) {
+			tp->uto_flags &= ~TCPUTO_SENDING;
+			tp->uto_flags |= TCPUTO_SENT;
+		}
+	
 
 	/*
 	 * Process options only when we get SYN/ACK back. The SYN case
@@ -1226,10 +1242,6 @@
 		if ((tp->t_flags & TF_SACK_PERMIT) &&
 		    (to.to_flags & TOF_SACKPERM) == 0)
 			tp->t_flags &= ~TF_SACK_PERMIT;
-		if (to.to_flags & TOF_UTO) {
-			tp->t_flags |= TF_RCVD_UTO;
-			tp->rcv_uto = to.to_uto;
-		}
 	}
 
 	/*
@@ -2952,7 +2964,7 @@
 				continue;
 			to->to_flags |= TOF_UTO;
 			bcopy((char *)cp + 2,
-			    (char *)&to->to_uto, sizeof(uto_load));			
+			    (char *)&to->to_uto, sizeof(to->to_uto));			
 			to->to_uto = ntohs(to->to_uto);
 			break;
 		default:

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_output.c#6 (text+ko) ====

@@ -696,9 +696,27 @@
 		if (tp->t_flags & TF_SIGNATURE)
 			to.to_flags |= TOF_SIGNATURE;
 #endif /* TCP_SIGNATURE */
+		/*
+		 * We put UTO option in tcp header in two case: the segment
+		 * is a SYN or SYN | ACK segment, or the segment is a normal
+		 * data segment.
+		 */
+		if (flags & TH_SYN || (len && (tp->t_flags & ~TF_FORCEDATA) == 0))
+			if (tp->uto_flags & (TCPUTO_NEED | TCPUTO_SENDING)) {
+				to.to_uto = tp->snd_uto;
+				to.to_flags |= TOF_UTO;
+			}
 
 		/* Processing the options. */
 		hdrlen += optlen = tcp_addoptions(&to, opt);
+
+		/* Check whether we place UTO in TCP header successfully */
+		if (tp->uto_flags & (TCPUTO_NEED | TCPUTO_SENDING) &&
+		    (to.to_flags & TOF_UTO) == 0) {
+			tp->uto_flags &= ~(TCPUTO_NEED | TCPUTO_SENDING);
+			tp->uto_flags |= TCPUTO_SENDING;
+			tp->uto_carrier = tp->snd_nxt + len;
+		}
 	}
 
 #ifdef INET6
@@ -1327,8 +1345,11 @@
  * we only have 10 bytes for SACK options (40 - (12 + 18)).
  * 
  * There is a new tcp option UTO (user timeout, defined in RFC 5482), the
- * UTO option is a optional option. So we attach the UTO option only when
- * there are enough free space in the TCP header.
+ * UTO option is an optional option. So we attach the UTO option only when
+ * there are enough free space in the TCP header. Although UTO is optional,
+ * we still should try our best to transmit it, so we need some way to
+ * notify whether UTO was placed into TCP header. We do this through remove
+ * TOF_UTO bit from to_flags.
  */
 int
 tcp_addoptions(struct tcpopt *to, u_char *optp)
@@ -1453,6 +1474,7 @@
 			optlen += TCPOLEN_UTO;
 			bcopy((u_char *)&to->to_uto, optp, sizeof(to->to_uto));
 			optp += sizeof(to->to_uto);
+			to->to_flags &= ~TOF_UTO;
 			break;
 			}
 		default:

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_subr.c#4 (text+ko) ====

@@ -741,11 +741,12 @@
 	tp->t_rcvtime = ticks;
 	tp->t_bw_rtttime = ticks;
 	/*
-	 * Init TCP user timeout (RFC5482) variables. We don't use UTO by default,
-	 * but we make it available if a UTO request received or set it through
+	 * Init TCP user timeout (RFC5482) variables. We don't enable UTO by default,
+	 * but we make it available if a UTO request is received or set through
 	 * setsockopt system call.
 	 */
-	tp->uto_flag = UTO_ENABLE | UTO_CHANGEABLE
+	tp->uto_flags = TCPUTO_ENABLE | TCPUTO_CHANGEABLE;
+	tp->t_uto_adv = 64 * 4;
 	/*
 	 * IPv4 TTL initialization is necessary for an IPv6 socket as well,
 	 * because the socket may be bound to an IPv6 wildcard address,

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_syncache.c#4 (text+ko) ====

@@ -772,9 +772,13 @@
 #endif
 		if (sc->sc_flags & SCF_SACK)
 			tp->t_flags |= TF_SACK_PERMIT;
-		if (sc->sc_flags & SCF_UTO) {
-			tp->t_flags |= TF_RCVD_UTO;
-			tp->rcv_uto = sc->sc_uto;
+		if (sc->sc_flags & SCF_RCVD_UTO) {
+			tp->uto_flags |= TCPUTO_RCVD;
+			tp->rcv_uto = sc->sc_peer_uto;
+		}
+		if (sc->sc_flags & SCF_SENT_UTO) {
+			tp->uto_flags |= TCPUTO_SENT;
+			tp->snd_uto = sc->sc_uto;
 		}
 	}
 
@@ -1214,8 +1218,12 @@
 	if ((th->th_flags & (TH_ECE|TH_CWR)) && V_tcp_do_ecn)
 		sc->sc_flags |= SCF_ECN;
 	if (to->to_flags & TOF_UTO) {
-		sc->sc_uto = to->to_uto;
-		sc->sc_flags |= SCF_UTO;
+		sc->sc_peer_uto = to->to_uto;
+		sc->sc_flags |= SCF_RCVD_UTO;
+	}
+	if (tp->uto_flags & TCPUTO_NEED) {
+		sc->sc_uto = tp->snd_uto;
+		sc->sc_flags = SCF_UTO;
 	}
 
 	if (V_tcp_syncookies) {
@@ -1390,6 +1398,11 @@
 		}
 		
 		optlen = tcp_addoptions(&to, (u_char *)(th + 1));
+		if ((to->to_flags & TOF_UTO) == 0 &&
+		    (sc->sc_flags & SCF_UTO) == 1) {
+			sc->sc_flags &= ~SCF_UTO;
+			sc->sc_flags |= SCF_SENT_UTO;
+		}
 
 		/* Adjust headers by option size. */
 		th->th_off = (sizeof(struct tcphdr) + optlen) >> 2;

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_syncache.h#4 (text+ko) ====

@@ -69,7 +69,8 @@
 	u_int8_t	sc_ip_tos;		/* IPv4 TOS */
 	u_int8_t	sc_requested_s_scale:4,
 			sc_requested_r_scale:4;
-	u_int16_t	sc_uto;			/* user timeout */
+	u_int16_t	sc_peer_uto;		/* peer's user timeout */
+	u_int16_t	sc_uto;			/* our user timeout to send */
 	u_int16_t	sc_flags;
 #ifndef TCP_OFFLOAD_DISABLE
 	struct toe_usrreqs *sc_tu;		/* TOE operations */
@@ -93,6 +94,8 @@
 #define SCF_SACK	0x80			/* send SACK option */
 #define SCF_ECN		0x100			/* send ECN setup packet */
 #define	SCF_UTO		0x200			/* send UTO option */
+#define	SCF_RCVD_UTO	0x400			/* received UTO option */
+#define	SCF_SENT_UTO	0x800			/* send UTO option successfully */
 
 #define	SYNCOOKIE_SECRET_SIZE	8	/* dwords */
 #define	SYNCOOKIE_LIFETIME	16	/* seconds */

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_timer.c#3 (text+ko) ====

@@ -159,6 +159,8 @@
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race,
     0, "Count of t_inpcb races on tcp_discardcb");
 
+static int	tcp_timer_uto_interval(struct tcpcb *);
+
 /*
  * TCP timer processing.
  */
@@ -445,7 +447,25 @@
 	INP_INFO_WUNLOCK(&V_tcbinfo);
 	CURVNET_RESTORE();
 }
+static int
+tcp_timer_uto_interval(struct tcpcb *tp)
+{
+	int rxtcur;
+	int rxttimes;
+	int rexmt;
+	int interval;
+
+	rxttimes = min(TCP_MAXRXTSHIFT, tp->t_rxtshift);
+	rexmt = TCP_REXMTVAL(tp) * tcp_backoff[rxttimes];
+	TCPT_RANGESET(rxtcur, rexmt, tp->t_rttmin, TCPTV_REXMTMAX);
+	interval = rxtcur / TCP_REXMTVAL(tp);
 
+	if (tp->t_uto_left - interval < 0)
+		interval = tp->t_uto_left;
+	tp->t_uto_left -= interval;
+	
+	return (interval);
+}
 void
 tcp_timer_rexmt(void * xtp)
 {
@@ -491,7 +511,8 @@
 	 * been acked within retransmit interval.  Back off
 	 * to a longer retransmit interval and retransmit one segment.
 	 */
-	if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
+	if ((++tp->t_rxtshift > TCP_MAXRXTSHIFT && (tp->uto_flags & TCPUTO_IMPL) == 0) || 
+	    (tp->t_uto_left == 0 && tp->uto_flags & TCPUTO_IMPL) {
 		tp->t_rxtshift = TCP_MAXRXTSHIFT;
 		TCPSTAT_INC(tcps_timeoutdrop);
 		tp = tcp_drop(tp, tp->t_softerror ?
@@ -518,12 +539,31 @@
 		else
 		  tp->t_flags &= ~TF_WASFRECOVERY;
 		tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1));
+
+		if (tp->uto_flags & TCPUTO_ENABLE && (tp->uto_flags & TCPUTO_SET ||
+		    (tp->uto_flags & TCPUTO_PEER_SET) == TCPUTO_PEER_SET)) {
+			u_int utoval;
+			if (tp->uto_flags & TCPUTO_SET) {
+				TCP_UTOVAL(utoval, tp->snd_uto);
+				tp->t_uto_impl = min(tcp_uto_min, max(utoval, tcp_uto_max));
+			} else {
+				TCP_UTOVAL(utoval, tp->rcv_uto);
+				tp->t_uto_impl = min(tcp_uto_max,
+				    max(tp->t_uto_adv, max(utoval, tcp_uto_min)));
+			}
+			tp->uto_flags |= TCPUTO_IMPL;
+		}
+		tp->t_uto_left = tp->t_uto_impl;
 	}
 	TCPSTAT_INC(tcps_rexmttimeo);
 	if (tp->t_state == TCPS_SYN_SENT)
 		rexmt = TCP_REXMTVAL(tp) * tcp_syn_backoff[tp->t_rxtshift];
 	else
-		rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+		if ((tp->uto_flags & TCPUTO_IMPL) == 0)
+			rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
+		else
+			rexmt = TCP_REXMTVAL(tp) * tcp_timer_uto_interval(tp);
+
 	TCPT_RANGESET(tp->t_rxtcur, rexmt,
 		      tp->t_rttmin, TCPTV_REXMTMAX);
 	/*

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_timer.h#4 (text+ko) ====

@@ -171,6 +171,8 @@
 
 extern int tcp_finwait2_timeout;
 extern int tcp_fast_finwait2_recycle;
+extern int tcp_uto_min;
+extern int tcp_uto_max;
 
 void	tcp_timer_init(void);
 void	tcp_timer_2msl(void *xtp);

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_usrreq.c#2 (text+ko) ====

@@ -1365,6 +1365,33 @@
 			error = EINVAL;
 			break;
 
+		case TCP_UTO:
+			INP_WUNLOCK(inp);
+			error = sooptcopyin(sopt, &optval, sizeof optval,
+			    sizeof optval);
+			if (error)
+				return (error);
+
+			INP_WLOCK_RECHECK(inp);
+			if (optval > 0 && optval <= 0x8FFF * 60) {
+				if (optval > 0x8FFF) {
+					tp->snd_uto = optval / 60;
+					tp->snd_uto <<= 1;
+					tp->snd_uto |= 1;
+				} else {
+					tp->snd_uto = optval;
+					tp->snd_uto <<= 1;
+				}
+				tp->t_uto_adv = optval;
+				tp->uto_flags |= TCPUTO_NEED;
+				tp->uto_flags |= TCPUTO_ENABLE;
+				tp->uto_flags &= ~TCPUTO_CHANGEABLE;
+			}
+			else
+				error = EINVAL;
+			INP_WUNLOCK(inp);
+			break;
+
 		default:
 			INP_WUNLOCK(inp);
 			error = ENOPROTOOPT;

==== //depot/projects/soc2009/tcputo/src/sys/netinet/tcp_var.h#9 (text+ko) ====

@@ -194,11 +194,11 @@
 /* user timeout variables (RFC 5482) */
 	uint16_t rcv_uto;		/* received user timeout */
 	uint16_t snd_uto;		/* send user timeout */
-	uint8_t	uto_flag;
-#define	UTO_ENABLE	0x01
-#define	UTO_CHANGEABLE	0x02
-#define	UTO_IMPL	0x04
-	u_int  t_impl_uto;		/* implemented user timeout */
+	uint8_t	uto_flags;
+	u_int	t_uto_adv;
+	u_int	t_uto_impl;		/* implemented user timeout */
+	u_int	t_uto_left;		/* remained user timeout value */
+	tcp_seq	uto_carrier;		/* max sequence number that carry user timeout */
 };
 
 /*
@@ -230,8 +230,6 @@
 #define	TF_ECN_PERMIT	0x4000000	/* connection ECN-ready */
 #define	TF_ECN_SND_CWR	0x8000000	/* ECN CWR in queue */
 #define	TF_ECN_SND_ECE	0x10000000	/* ECN ECE in queue */
-#define	TF_RCVD_UTO	0x20000000	/* a user timeout was received */
-#define	TF_NEEDUTO	0x40000000	/* send user timeout */
 
 #define IN_FASTRECOVERY(tp)	(tp->t_flags & TF_FASTRECOVERY)
 #define ENTER_FASTRECOVERY(tp)	tp->t_flags |= TF_FASTRECOVERY
@@ -243,6 +241,25 @@
 #define	TCPOOB_HAVEDATA	0x01
 #define	TCPOOB_HADDATA	0x02
 
+/*
+ * Flags for the uto_flags field.
+ */
+#define	TCPUTO_ENABLE	0x01	/* enable tcp user timeout */
+#define	TCPUTO_CHANGEABLE 0x02	/* user timeout can be changed by other side */
+#define	TCPUTO_IMPL	0x04	/* implement user timeout */
+#define	TCPUTO_RCVD	0x08	/* other side has requested user timeout */
+#define	TCPUTO_NEED	0x10	/* user timeout need to be sent */
+#define	TCPUTO_SENDING	0x20	/* user timeout is in the process of sending */
+#define	TCPUTO_SENT	0x40	/* user timeout is sent successfully */
+#define	TCPUTO_SET	(TCPUTO_NEED | TCPUTO_SENDING | TCPUTO_SENT)
+#define	TCPUTO_PEER_SET	(TCPUTO_CHANGEABLE | TCPUTO_RCVD)
+
+#define	TCP_UTOVAL(utoval, uto) do { \
+	(utoval) = (uto) >> 1; \
+	if ((uto) & 1) \
+		(utoval) *= 60; \
+} while(0)
+
 #ifdef TCP_SIGNATURE
 /*
  * Defines which are needed by the xform_tcp module and tcp_[in|out]put


More information about the p4-projects mailing list