Source-Changes-HG archive

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

[src/trunk]: src/sys/netinet Use callouts for SYN cache timers, rather than t...



details:   https://anonhg.NetBSD.org/src/rev/1787f9729bb4
branches:  trunk
changeset: 514860:1787f9729bb4
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Tue Sep 11 21:03:20 2001 +0000

description:
Use callouts for SYN cache timers, rather than traversing time queues
in tcp_slowtimo().

diffstat:

 sys/netinet/tcp_input.c |  184 ++++++++++++++++++++---------------------------
 sys/netinet/tcp_subr.c  |    3 +-
 sys/netinet/tcp_timer.c |    7 +-
 sys/netinet/tcp_var.h   |   18 ++--
 4 files changed, 89 insertions(+), 123 deletions(-)

diffs (truncated from 426 to 300 lines):

diff -r 51af528ec431 -r 1787f9729bb4 sys/netinet/tcp_input.c
--- a/sys/netinet/tcp_input.c   Tue Sep 11 20:37:12 2001 +0000
+++ b/sys/netinet/tcp_input.c   Tue Sep 11 21:03:20 2001 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tcp_input.c,v 1.129 2001/09/10 22:14:26 thorpej Exp $  */
+/*     $NetBSD: tcp_input.c,v 1.130 2001/09/11 21:03:20 thorpej Exp $  */
 
 /*
 %%% portions-copyright-nrl-95
@@ -2578,18 +2578,19 @@
        default:                                                        \
                hash = 0;                                               \
        }                                                               \
-} while (0)
+} while (/*CONSTCOND*/0)
 #endif /* INET6 */
 
 #define        SYN_CACHE_RM(sc)                                                \
 do {                                                                   \
-       LIST_REMOVE((sc), sc_bucketq);                                  \
+       TAILQ_REMOVE(&tcp_syn_cache[(sc)->sc_bucketidx].sch_bucket,     \
+           (sc), sc_bucketq);                                          \
        (sc)->sc_tp = NULL;                                             \
        LIST_REMOVE((sc), sc_tpq);                                      \
        tcp_syn_cache[(sc)->sc_bucketidx].sch_length--;                 \
-       TAILQ_REMOVE(&tcp_syn_cache_timeq[(sc)->sc_rxtshift], (sc), sc_timeq); \
+       callout_stop(&(sc)->sc_timer);                                  \
        syn_cache_count--;                                              \
-} while (0)
+} while (/*CONSTCOND*/0)
 
 #define        SYN_CACHE_PUT(sc)                                               \
 do {                                                                   \
@@ -2598,24 +2599,22 @@
        if ((sc)->sc_route4.ro_rt != NULL)                              \
                RTFREE((sc)->sc_route4.ro_rt);                          \
        pool_put(&syn_cache_pool, (sc));                                \
-} while (0)
+} while (/*CONSTCOND*/0)
 
 struct pool syn_cache_pool;
 
 /*
  * We don't estimate RTT with SYNs, so each packet starts with the default
- * RTT and each timer queue has a fixed timeout value.  This allows us to
- * optimize the timer queues somewhat.
+ * RTT and each timer step has a fixed timeout value.
  */
 #define        SYN_CACHE_TIMER_ARM(sc)                                         \
 do {                                                                   \
        TCPT_RANGESET((sc)->sc_rxtcur,                                  \
            TCPTV_SRTTDFLT * tcp_backoff[(sc)->sc_rxtshift], TCPTV_MIN, \
            TCPTV_REXMTMAX);                                            \
-       PRT_SLOW_ARM((sc)->sc_rexmt, (sc)->sc_rxtcur);                  \
-} while (0)
-
-TAILQ_HEAD(, syn_cache) tcp_syn_cache_timeq[TCP_MAXRXTSHIFT + 1];
+       callout_reset(&(sc)->sc_timer,                                  \
+           (sc)->sc_rxtcur * (hz / PR_SLOWHZ), syn_cache_timer, (sc)); \
+} while (/*CONSTCOND*/0)
 
 #define        SYN_CACHE_TIMESTAMP(sc) (tcp_now - (sc)->sc_timebase)
 
@@ -2626,11 +2625,7 @@
 
        /* Initialize the hash buckets. */
        for (i = 0; i < tcp_syn_cache_size; i++)
-               LIST_INIT(&tcp_syn_cache[i].sch_bucket);
-
-       /* Initialize the timer queues. */
-       for (i = 0; i <= TCP_MAXRXTSHIFT; i++)
-               TAILQ_INIT(&tcp_syn_cache_timeq[i]);
+               TAILQ_INIT(&tcp_syn_cache[i].sch_bucket);
 
        /* Initialize the syn cache pool. */
        pool_init(&syn_cache_pool, sizeof(struct syn_cache), 0, 0, 0,
@@ -2644,7 +2639,7 @@
 {
        struct syn_cache_head *scp;
        struct syn_cache *sc2;
-       int s, i;
+       int s;
 
        /*
         * If there are no entries in the hash table, reinitialize
@@ -2670,72 +2665,67 @@
                tcpstat.tcps_sc_bucketoverflow++;
                /*
                 * The bucket is full.  Toss the oldest element in the
-                * bucket.  This will be the entry with our bucket
-                * index closest to the front of the timer queue with
-                * the largest timeout value.
-                *
-                * Note: This timer queue traversal may be expensive, so
-                * we hope that this doesn't happen very often.  It is
-                * much more likely that we'll overflow the entire
-                * cache, which is much easier to handle; see below.
+                * bucket.  This will be the first entry in the bucket.
                 */
-               for (i = TCP_MAXRXTSHIFT; i >= 0; i--) {
-                       for (sc2 = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
-                            sc2 != NULL;
-                            sc2 = TAILQ_NEXT(sc2, sc_timeq)) {
-                               if (sc2->sc_bucketidx == sc->sc_bucketidx) {
-                                       SYN_CACHE_RM(sc2);
-                                       SYN_CACHE_PUT(sc2);
-                                       goto insert;    /* 2 level break */
-                               }
-                       }
-               }
+               sc2 = TAILQ_FIRST(&scp->sch_bucket);
 #ifdef DIAGNOSTIC
                /*
                 * This should never happen; we should always find an
                 * entry in our bucket.
                 */
-               panic("syn_cache_insert: bucketoverflow: impossible");
+               if (sc2 == NULL)
+                       panic("syn_cache_insert: bucketoverflow: impossible");
 #endif
+               SYN_CACHE_RM(sc2);
+               SYN_CACHE_PUT(sc2);
        } else if (syn_cache_count >= tcp_syn_cache_limit) {
+               struct syn_cache_head *scp2, *sce;
+
                tcpstat.tcps_sc_overflowed++;
                /*
                 * The cache is full.  Toss the oldest entry in the
-                * entire cache.  This is the front entry in the
-                * first non-empty timer queue with the largest
-                * timeout value.
+                * first non-empty bucket we can find.
+                *
+                * XXX We would really like to toss the oldest
+                * entry in the cache, but we hope that this
+                * condition doesn't happen very often.
                 */
-               for (i = TCP_MAXRXTSHIFT; i >= 0; i--) {
-                       sc2 = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
-                       if (sc2 == NULL)
-                               continue;
-                       SYN_CACHE_RM(sc2);
-                       SYN_CACHE_PUT(sc2);
-                       goto insert;            /* symmetry with above */
+               scp2 = scp;
+               if (TAILQ_EMPTY(&scp2->sch_bucket)) {
+                       sce = &tcp_syn_cache[tcp_syn_cache_size];
+                       for (++scp2; scp2 != scp; scp2++) {
+                               if (scp2 >= sce)
+                                       scp2 = &tcp_syn_cache[0];
+                               if (! TAILQ_EMPTY(&scp2->sch_bucket))
+                                       break;
+                       }
+#ifdef DIAGNOSTIC
+                       /*
+                        * This should never happen; we should always find a
+                        * non-empty bucket.
+                        */
+                       if (scp2 == scp)
+                               panic("syn_cache_insert: cacheoverflow: "
+                                   "impossible");
+#endif
                }
-#ifdef DIAGNOSTIC
-               /*
-                * This should never happen; we should always find an
-                * entry in the cache.
-                */
-               panic("syn_cache_insert: cache overflow: impossible");
-#endif
+               sc2 = TAILQ_FIRST(&scp2->sch_bucket);
+               SYN_CACHE_RM(sc2);
+               SYN_CACHE_PUT(sc2);
        }
 
- insert:
        /*
         * Initialize the entry's timer.
         */
        sc->sc_rxttot = 0;
        sc->sc_rxtshift = 0;
        SYN_CACHE_TIMER_ARM(sc);
-       TAILQ_INSERT_TAIL(&tcp_syn_cache_timeq[sc->sc_rxtshift], sc, sc_timeq);
 
        /* Link it from tcpcb entry */
        LIST_INSERT_HEAD(&tp->t_sc, sc, sc_tpq);
 
        /* Put it into the bucket. */
-       LIST_INSERT_HEAD(&scp->sch_bucket, sc, sc_bucketq);
+       TAILQ_INSERT_TAIL(&scp->sch_bucket, sc, sc_bucketq);
        scp->sch_length++;
        syn_cache_count++;
 
@@ -2749,60 +2739,41 @@
  * that entry.
  */
 void
-syn_cache_timer()
+syn_cache_timer(void *arg)
 {
-       struct syn_cache *sc, *nsc;
-       int i, s;
+       struct syn_cache *sc = arg;
+       int s;
 
        s = splsoftnet();
 
-       /*
-        * First, get all the entries that need to be retransmitted, or
-        * must be expired due to exceeding the initial keepalive time.
-        */
-       for (i = 0; i < TCP_MAXRXTSHIFT; i++) {
-               for (sc = TAILQ_FIRST(&tcp_syn_cache_timeq[i]);
-                    sc != NULL && PRT_SLOW_ISEXPIRED(sc->sc_rexmt);
-                    sc = nsc) {
-                       nsc = TAILQ_NEXT(sc, sc_timeq);
-
-                       /*
-                        * Compute the total amount of time this entry has
-                        * been on a queue.  If this entry has been on longer
-                        * than the keep alive timer would allow, expire it.
-                        */
-                       sc->sc_rxttot += sc->sc_rxtcur;
-                       if (sc->sc_rxttot >= TCPTV_KEEP_INIT) {
-                               tcpstat.tcps_sc_timed_out++;
-                               SYN_CACHE_RM(sc);
-                               SYN_CACHE_PUT(sc);
-                               continue;
-                       }
-
-                       tcpstat.tcps_sc_retransmitted++;
-                       (void) syn_cache_respond(sc, NULL);
-
-                       /* Advance this entry onto the next timer queue. */
-                       TAILQ_REMOVE(&tcp_syn_cache_timeq[i], sc, sc_timeq);
-                       sc->sc_rxtshift = i + 1;
-                       SYN_CACHE_TIMER_ARM(sc);
-                       TAILQ_INSERT_TAIL(&tcp_syn_cache_timeq[sc->sc_rxtshift],
-                           sc, sc_timeq);
-               }
+       if (__predict_false(sc->sc_rxtshift == TCP_MAXRXTSHIFT)) {
+               /* Drop it -- too many retransmissions. */
+               goto dropit;
        }
 
        /*
-        * Now get all the entries that are expired due to too many
-        * retransmissions.
+        * Compute the total amount of time this entry has
+        * been on a queue.  If this entry has been on longer
+        * than the keep alive timer would allow, expire it.
         */
-       for (sc = TAILQ_FIRST(&tcp_syn_cache_timeq[TCP_MAXRXTSHIFT]);
-            sc != NULL && PRT_SLOW_ISEXPIRED(sc->sc_rexmt);
-            sc = nsc) {
-               nsc = TAILQ_NEXT(sc, sc_timeq);
-               tcpstat.tcps_sc_timed_out++;
-               SYN_CACHE_RM(sc);
-               SYN_CACHE_PUT(sc);
-       }
+       sc->sc_rxttot += sc->sc_rxtcur;
+       if (sc->sc_rxttot >= TCPTV_KEEP_INIT)
+               goto dropit;
+
+       tcpstat.tcps_sc_retransmitted++;
+       (void) syn_cache_respond(sc, NULL);
+
+       /* Advance the timer back-off. */
+       sc->sc_rxtshift++;
+       SYN_CACHE_TIMER_ARM(sc);
+
+       splx(s);
+       return;
+
+ dropit:
+       tcpstat.tcps_sc_timed_out++;
+       SYN_CACHE_RM(sc);
+       SYN_CACHE_PUT(sc);
        splx(s);
 }
 
@@ -2855,8 +2826,8 @@
        scp = &tcp_syn_cache[hash % tcp_syn_cache_size];
        *headp = scp;
        s = splsoftnet();
-       for (sc = LIST_FIRST(&scp->sch_bucket); sc != NULL;
-            sc = LIST_NEXT(sc, sc_bucketq)) {
+       for (sc = TAILQ_FIRST(&scp->sch_bucket); sc != NULL;
+            sc = TAILQ_NEXT(sc, sc_bucketq)) {
                if (sc->sc_hash != hash)
                        continue;
                if (!bcmp(&sc->sc_src, src, src->sa_len) &&
@@ -3347,6 +3318,7 @@
         * Fill in the cache, and put the necessary IP and TCP
         * options into the reply.
         */
+       callout_init(&sc->sc_timer);
        bzero(sc, sizeof(struct syn_cache));
        bcopy(src, &sc->sc_src, src->sa_len);
        bcopy(dst, &sc->sc_dst, dst->sa_len);



Home | Main Index | Thread Index | Old Index