summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netgraph/ng_pptpgre.c129
1 files changed, 89 insertions, 40 deletions
diff --git a/sys/netgraph/ng_pptpgre.c b/sys/netgraph/ng_pptpgre.c
index 6059406ddab6..11febadc1c2a 100644
--- a/sys/netgraph/ng_pptpgre.c
+++ b/sys/netgraph/ng_pptpgre.c
@@ -117,14 +117,21 @@ struct greheader {
/* All times are scaled by this (PPTP_TIME_SCALE time units = 1 sec.) */
#define PPTP_TIME_SCALE 1000 /* milliseconds */
-typedef u_int32_t pptptime_t;
+typedef u_int64_t pptptime_t;
/* Acknowledgment timeout parameters and functions */
#define PPTP_XMIT_WIN 16 /* max xmit window */
#define PPTP_MIN_RTT (PPTP_TIME_SCALE / 10) /* 100 milliseconds */
-#define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 100) /* 10 milliseconds */
+#define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
#define PPTP_MAX_TIMEOUT (10 * PPTP_TIME_SCALE) /* 10 seconds */
+/* When we recieve a packet, we wait to see if there's an outgoing packet
+ we can piggy-back the ACK off of. These parameters determine the mimimum
+ and maxmimum length of time we're willing to wait in order to do that.
+ These have no effect unless "enableDelayedAck" is turned on. */
+#define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500) /* 2 milliseconds */
+#define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2) /* 500 milliseconds */
+
/* See RFC 2637 section 4.4 */
#define PPTP_ACK_ALPHA(x) ((x) >> 3) /* alpha = 0.125 */
#define PPTP_ACK_BETA(x) ((x) >> 2) /* beta = 0.25 */
@@ -145,13 +152,12 @@ struct ng_pptpgre_ackp {
node_p *rackTimerPtr; /* recv ack timer pointer */
u_int32_t winAck; /* seq when xmitWin will grow */
pptptime_t timeSent[PPTP_XMIT_WIN];
+#ifdef DEBUG_RAT
+ pptptime_t timerStart; /* when rackTimer started */
+ pptptime_t timerLength; /* rackTimer duration */
+#endif
};
-/* When we recieve a packet, we wait to see if there's an outgoing packet
- we can piggy-back the ACK off of. These parameters determine the mimimum
- and maxmimum length of time we're willing to wait in order to do that. */
-#define PPTP_MAX_ACK_DELAY ((int) (0.25 * PPTP_TIME_SCALE))
-
/* Node private data */
struct ng_pptpgre_private {
hook_p upper; /* hook to upper layers */
@@ -178,7 +184,7 @@ static ng_disconnect_t ng_pptpgre_disconnect;
/* Helper functions */
static int ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta);
static int ng_pptpgre_recv(node_p node, struct mbuf *m, meta_p meta);
-static void ng_pptpgre_start_send_ack_timer(node_p node, long ackTimeout);
+static void ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout);
static void ng_pptpgre_start_recv_ack_timer(node_p node);
static void ng_pptpgre_recv_ack_timeout(void *arg);
static void ng_pptpgre_send_ack_timeout(void *arg);
@@ -493,7 +499,7 @@ ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
priv->stats.xmitLoneAcks++;
/* Build GRE header */
- ((u_int32_t *) gre)[0] = htonl(PPTP_INIT_VALUE);
+ ((u_int32_t *)gre)[0] = htonl(PPTP_INIT_VALUE);
gre->length = (m != NULL) ? htons((u_short)m->m_pkthdr.len) : 0;
gre->cid = htons(priv->conf.peerCid);
@@ -504,16 +510,18 @@ ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
= ng_pptpgre_time(node);
priv->xmitSeq++;
gre->data[0] = htonl(priv->xmitSeq);
- if (priv->xmitSeq == priv->recvAck + 1)
- ng_pptpgre_start_recv_ack_timer(node);
}
/* Include acknowledgement (and stop send ack timer) if needed */
- if (PPTP_SEQ_DIFF(priv->xmitAck, priv->recvSeq) < 0) {
+ if (priv->conf.enableAlwaysAck || priv->xmitAck != priv->recvSeq) {
gre->hasAck = 1;
+ gre->data[gre->hasSeq] = htonl(priv->recvSeq);
priv->xmitAck = priv->recvSeq;
- gre->data[gre->hasSeq] = htonl(priv->xmitAck);
- a->sackTimerPtr = NULL;
+ if (a->sackTimerPtr != NULL) {
+ untimeout(ng_pptpgre_send_ack_timeout,
+ a->sackTimerPtr, a->sackTimer);
+ a->sackTimerPtr = NULL;
+ }
}
/* Prepend GRE header to outgoing frame */
@@ -521,6 +529,7 @@ ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
if (m == NULL) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
+ priv->stats.memoryFailures++;
NG_FREE_META(meta);
return (ENOBUFS);
}
@@ -530,6 +539,7 @@ ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
M_PREPEND(m, grelen, M_NOWAIT);
if (m == NULL || (m->m_len < grelen
&& (m = m_pullup(m, grelen)) == NULL)) {
+ priv->stats.memoryFailures++;
NG_FREE_META(meta);
return (ENOBUFS);
}
@@ -542,6 +552,10 @@ ng_pptpgre_xmit(node_p node, struct mbuf *m, meta_p meta)
/* Deliver packet */
NG_SEND_DATA(error, priv->lower, m, meta);
+
+ /* Start receive ACK timer if data was sent and not already running */
+ if (error == 0 && gre->hasSeq && priv->xmitSeq == priv->recvAck + 1)
+ ng_pptpgre_start_recv_ack_timer(node);
return (error);
}
@@ -572,6 +586,7 @@ bad:
/* Safely pull up the complete IP+GRE headers */
if (m->m_len < sizeof(*ip) + sizeof(*gre)
&& (m = m_pullup(m, sizeof(*ip) + sizeof(*gre))) == NULL) {
+ priv->stats.memoryFailures++;
NG_FREE_META(meta);
return (ENOBUFS);
}
@@ -579,6 +594,7 @@ bad:
iphlen = ip->ip_hl << 2;
if (m->m_len < iphlen + sizeof(*gre)) {
if ((m = m_pullup(m, iphlen + sizeof(*gre))) == NULL) {
+ priv->stats.memoryFailures++;
NG_FREE_META(meta);
return (ENOBUFS);
}
@@ -592,6 +608,7 @@ bad:
}
if (m->m_len < iphlen + grelen) {
if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
+ priv->stats.memoryFailures++;
NG_FREE_META(meta);
return (ENOBUFS);
}
@@ -656,7 +673,13 @@ bad:
}
/* Stop/(re)start receive ACK timer as necessary */
- ng_pptpgre_start_recv_ack_timer(node);
+ if (a->rackTimerPtr != NULL) {
+ untimeout(ng_pptpgre_recv_ack_timeout,
+ a->rackTimerPtr, a->rackTimer);
+ a->rackTimerPtr = NULL;
+ }
+ if (priv->recvAck != priv->xmitSeq)
+ ng_pptpgre_start_recv_ack_timer(node);
}
badAck:
@@ -677,13 +700,14 @@ badAck:
/* We need to acknowledge this packet; do it soon... */
if (a->sackTimerPtr == NULL) {
- long maxWait;
+ int maxWait;
- /* Take half of the estimated round trip time */
- maxWait = (a->rtt >> 1);
+ /* Take 1/4 of the estimated round trip time */
+ maxWait = (a->rtt >> 2);
- /* If too soon, just send one right now */
- if (!priv->conf.enableDelayedAck)
+ /* If delayed ACK is disabled, send it now */
+ if (!priv->conf.enableDelayedAck
+ || maxWait < PPTP_MIN_ACK_DELAY)
ng_pptpgre_xmit(node, NULL, NULL);
else { /* send the ack later */
if (maxWait > PPTP_MAX_ACK_DELAY)
@@ -721,29 +745,32 @@ ng_pptpgre_start_recv_ack_timer(node_p node)
{
const priv_p priv = node->private;
struct ng_pptpgre_ackp *const a = &priv->ackp;
- int remain;
-
- /* "Stop" current recv ack timer, if any */
- a->rackTimerPtr = NULL;
-
- /* Are we waiting for an acknowlegement? */
- if (priv->recvAck == priv->xmitSeq)
- return;
+ int remain, ticks;
/* Compute how long until oldest unack'd packet times out,
and reset the timer to that time. */
+ KASSERT(a->rackTimerPtr == NULL, ("%s: rackTimer", __FUNCTION__));
remain = (a->timeSent[0] + a->ato) - ng_pptpgre_time(node);
if (remain < 0)
remain = 0;
+#ifdef DEBUG_RAT
+ a->timerLength = remain;
+ a->timerStart = ng_pptpgre_time(node);
+#endif
/* Start new timer */
MALLOC(a->rackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
- if (a->rackTimerPtr == NULL)
+ if (a->rackTimerPtr == NULL) {
+ priv->stats.memoryFailures++;
return; /* XXX potential hang here */
+ }
*a->rackTimerPtr = node; /* insures the correct timeout event */
node->refs++;
+
+ /* Be conservative: timeout() can return up to 1 tick early */
+ ticks = (((remain * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE) + 1;
a->rackTimer = timeout(ng_pptpgre_recv_ack_timeout,
- a->rackTimerPtr, remain * hz / PPTP_TIME_SCALE);
+ a->rackTimerPtr, ticks);
}
/*
@@ -783,6 +810,13 @@ ng_pptpgre_recv_ack_timeout(void *arg)
if (a->ato < PPTP_MIN_TIMEOUT)
a->ato = PPTP_MIN_TIMEOUT;
+#ifdef DEBUG_RAT
+ log(LOG_DEBUG,
+ "RAT now=%d seq=0x%x sent=%d tstart=%d tlen=%d ato=%d\n",
+ (int)ng_pptpgre_time(node), priv->recvAck + 1,
+ (int)a->timeSent[0], (int)a->timerStart, (int)a->timerLength, a->ato);
+#endif
+
/* Reset ack and sliding window */
priv->recvAck = priv->xmitSeq; /* pretend we got the ack */
a->xmitWin = (a->xmitWin + 1) / 2; /* shrink transmit window */
@@ -795,20 +829,26 @@ ng_pptpgre_recv_ack_timeout(void *arg)
* already running.
*/
static void
-ng_pptpgre_start_send_ack_timer(node_p node, long ackTimeout)
+ng_pptpgre_start_send_ack_timer(node_p node, int ackTimeout)
{
const priv_p priv = node->private;
struct ng_pptpgre_ackp *const a = &priv->ackp;
+ int ticks;
/* Start new timer */
KASSERT(a->sackTimerPtr == NULL, ("%s: sackTimer", __FUNCTION__));
MALLOC(a->sackTimerPtr, node_p *, sizeof(node_p), M_NETGRAPH, M_NOWAIT);
- if (a->sackTimerPtr == NULL)
+ if (a->sackTimerPtr == NULL) {
+ priv->stats.memoryFailures++;
return; /* XXX potential hang here */
+ }
*a->sackTimerPtr = node;
node->refs++;
+
+ /* Be conservative: timeout() can return up to 1 tick early */
+ ticks = (((ackTimeout * hz) + PPTP_TIME_SCALE - 1) / PPTP_TIME_SCALE);
a->sackTimer = timeout(ng_pptpgre_send_ack_timeout,
- a->sackTimerPtr, ackTimeout * hz / PPTP_TIME_SCALE);
+ a->sackTimerPtr, ticks);
}
/*
@@ -883,9 +923,17 @@ ng_pptpgre_reset(node_p node)
/* Reset stats */
bzero(&priv->stats, sizeof(priv->stats));
- /* "Stop" timers */
- a->sackTimerPtr = NULL;
- a->rackTimerPtr = NULL;
+ /* Stop timers */
+ if (a->sackTimerPtr != NULL) {
+ untimeout(ng_pptpgre_send_ack_timeout,
+ a->sackTimerPtr, a->sackTimer);
+ a->sackTimerPtr = NULL;
+ }
+ if (a->rackTimerPtr != NULL) {
+ untimeout(ng_pptpgre_recv_ack_timeout,
+ a->rackTimerPtr, a->rackTimer);
+ a->rackTimerPtr = NULL;
+ }
}
/*
@@ -896,15 +944,16 @@ ng_pptpgre_time(node_p node)
{
const priv_p priv = node->private;
struct timeval tv;
+ pptptime_t t;
- getmicrouptime(&tv);
+ microuptime(&tv);
if (tv.tv_sec < priv->startTime.tv_sec
|| (tv.tv_sec == priv->startTime.tv_sec
&& tv.tv_usec < priv->startTime.tv_usec))
return (0);
timevalsub(&tv, &priv->startTime);
- tv.tv_sec *= PPTP_TIME_SCALE;
- tv.tv_usec /= 1000000 / PPTP_TIME_SCALE;
- return(tv.tv_sec + tv.tv_usec);
+ t = (pptptime_t)tv.tv_sec * PPTP_TIME_SCALE;
+ t += (pptptime_t)tv.tv_usec / (1000000 / PPTP_TIME_SCALE);
+ return(t);
}