kernel - network adjustments (netisr, tcp, and socket buffer changes)
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Jul 2014 06:52:54 +0000 (23:52 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Jul 2014 06:52:54 +0000 (23:52 -0700)
* Change sowakeup() to use an atomic fetch when testing WAIT/WAKEUP for
  a quick return.  It is now coded properly.  Previous coding is not known
  to have created any bugs.

* Change sowakeup() to use ssb_space_prealloc() instead of ssb_space()
  when testing against the transmit low-water mark.  This is a bug fix
  which primarily effects very tiny write()'s.  The prior code is not
  known to have created any problems.

* Make the netisr packet counter before doing a rollup programmer and
  change the default from 512 to 32 for the moment.  This may be changed
  back to 512 (or some number inbetween) after further testing.

  The issue here is that interrupt/netisr pipelining can cause ack aggregation
  to be delayed for too many packets.

* For TCP, when timestamps are not being used, pass the correct delta
  to tcp_xmit_timer() in our fallback.  The function expects N+1.  This
  should improve/fix incorrect rtt calculations when tcp timestamps are
  not in use.

* Fix an edge case in tcp_xmit_bandwidth_limit() where the 'ticks' global
  could change values out from under the code.  Load the global into a local
  variable.

* Change the inflight code to use (t_srtt + t_rttvar) instead of
  (t_srtt + t_rttbest) / 2.

  This needs fine-tuning, the buffer is still too big.  Expect more commits
  later.

* Call sowwakeup() when appending a mbuf to a stream.  The append can call
  sbcompress() and make a stream buffer that has hit its mbuf limit writable
  again.

* Remove the ssb_notify() macro and collapse the sorwakeup() and sowwakeup()
  macros.  They now just call sowakeup() on the appropriate sockbuf.  The
  notify test is now done in sowakeup().

sys/kern/uipc_socket2.c
sys/net/netisr.c
sys/netinet/tcp_input.c
sys/netinet/tcp_subr.c
sys/netinet/tcp_usrreq.c
sys/sys/socketvar.h

index 85edb68..5342d5f 100644 (file)
@@ -95,7 +95,7 @@ ssb_wait(struct signalsockbuf *ssb)
                cpu_ccfence();
 
                /*
-                * WAKEUP and WAIT interlock eachother.  We can catch the
+                * WAKEUP and WAIT interlock each other.  We can catch the
                 * race by checking to see if WAKEUP has already been set,
                 * and only setting WAIT if WAKEUP is clear.
                 */
@@ -489,12 +489,24 @@ socantrcvmore(struct socket *so)
  *          thread.  aka is called on the 'head' listen socket when
  *          a new connection comes in.
  */
+
 void
 sowakeup(struct socket *so, struct signalsockbuf *ssb)
 {
        struct kqinfo *kqinfo = &ssb->ssb_kq;
        uint32_t flags;
 
+       /*
+        * Atomically check the flags.  When no special features are being
+        * used, WAIT is clear, and WAKEUP is already set, we can simply
+        * return.  The upcoming synchronous waiter will not block.
+        */
+       flags = atomic_fetchadd_int(&ssb->ssb_flags, 0);
+       if ((flags & SSB_NOTIFY_MASK) == 0) {
+               if (flags & SSB_WAKEUP)
+                       return;
+       }
+
        /*
         * Check conditions, set the WAKEUP flag, and clear and signal if
         * the WAIT flag is found to be set.  This interlocks against the
@@ -504,7 +516,8 @@ sowakeup(struct socket *so, struct signalsockbuf *ssb)
                flags = ssb->ssb_flags;
                cpu_ccfence();
 
-               if ((ssb == &so->so_snd && ssb_space(ssb) >= ssb->ssb_lowat) ||
+               if ((ssb == &so->so_snd &&
+                    ssb_space_prealloc(ssb) >= ssb->ssb_lowat) ||
                    (ssb == &so->so_rcv && ssb->ssb_cc >= ssb->ssb_lowat) ||
                    (ssb == &so->so_snd && (so->so_state & SS_CANTSENDMORE)) ||
                    (ssb == &so->so_rcv && (so->so_state & SS_CANTRCVMORE))
index 2b90c9a..587a780 100644 (file)
@@ -101,6 +101,10 @@ lwkt_port netisr_sync_port;
 static int (*netmsg_fwd_port_fn)(lwkt_port_t, lwkt_msg_t);
 
 SYSCTL_NODE(_net, OID_AUTO, netisr, CTLFLAG_RW, 0, "netisr");
+static int netisr_rollup_limit = 32;
+SYSCTL_INT(_net_netisr, OID_AUTO, rollup_limit, CTLFLAG_RW,
+       &netisr_rollup_limit, 0, "Message to process before rollup");
+
 
 /*
  * netisr_afree_rport replymsg function, only used to handle async
@@ -288,7 +292,7 @@ netmsg_service_loop(void *arg)
                /*
                 * Run up to 512 pending netmsgs.
                 */
-               limit = 512;
+               limit = netisr_rollup_limit;
                do {
                        KASSERT(msg->nm_dispatch != NULL,
                                ("netmsg_service isr %d badmsg",
index e2dfa59..4bbfc87 100644 (file)
@@ -1314,13 +1314,13 @@ after_listen:
                                 */
                                if ((to.to_flags & TOF_TS) && to.to_tsecr) {
                                        tcp_xmit_timer(tp,
-                                           ticks - to.to_tsecr + 1,
-                                           th->th_ack);
+                                                     ticks - to.to_tsecr + 1,
+                                                     th->th_ack);
                                } else if (tp->t_rtttime &&
                                           SEQ_GT(th->th_ack, tp->t_rtseq)) {
                                        tcp_xmit_timer(tp,
-                                           ticks - tp->t_rtttime,
-                                           th->th_ack);
+                                                     ticks - tp->t_rtttime + 1,
+                                                     th->th_ack);
                                }
                                tcp_xmit_bandwidth_limit(tp, th->th_ack);
                                acked = th->th_ack - tp->snd_una;
@@ -2159,9 +2159,11 @@ process_ACK:
                 * timestamps of 0.
                 */
                if ((to.to_flags & TOF_TS) && (to.to_tsecr != 0))
-                       tcp_xmit_timer(tp, ticks - to.to_tsecr + 1, th->th_ack);
+                       tcp_xmit_timer(tp, ticks - to.to_tsecr + 1,
+                                      th->th_ack);
                else if (tp->t_rtttime && SEQ_GT(th->th_ack, tp->t_rtseq))
-                       tcp_xmit_timer(tp, ticks - tp->t_rtttime, th->th_ack);
+                       tcp_xmit_timer(tp, ticks - tp->t_rtttime + 1,
+                                      th->th_ack);
                tcp_xmit_bandwidth_limit(tp, th->th_ack);
 
                /*
@@ -2830,8 +2832,8 @@ tcp_pulloutofband(struct socket *so, struct tcphdr *th, struct mbuf *m, int off)
 }
 
 /*
- * Collect new round-trip time estimate
- * and update averages and current timeout.
+ * Collect new round-trip time estimate and update averages and current
+ * timeout.
  */
 static void
 tcp_xmit_timer(struct tcpcb *tp, int rtt, tcp_seq ack)
@@ -2865,9 +2867,9 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt, tcp_seq ack)
 
                /*
                 * srtt is stored as fixed point with 5 bits after the
-                * binary point (i.e., scaled by 8).  The following magic
+                * binary point (i.e., scaled by 32).  The following magic
                 * is equivalent to the smoothing algorithm in rfc793 with
-                * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed
+                * an alpha of .875 (srtt = rtt/32 + srtt*31/32 in fixed
                 * point).  Adjust rtt to origin 0.
                 */
                delta = ((rtt - 1) << TCP_DELTA_SHIFT)
index 34a039a..28f14ba 100644 (file)
@@ -526,7 +526,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
            tcp_seq ack, tcp_seq seq, int flags)
 {
        int tlen;
-       int win = 0;
+       long win = 0;
        struct route *ro = NULL;
        struct route sro;
        struct ip *ip = ipgen;
@@ -1925,7 +1925,7 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
        cpu_ccfence();
        delta_ticks = save_ticks - tp->t_bw_rtttime;
        if (tp->t_bw_rtttime == 0 || delta_ticks < 0 || delta_ticks > hz * 10) {
-               tp->t_bw_rtttime = ticks;
+               tp->t_bw_rtttime = save_ticks;
                tp->t_bw_rtseq = ack_seq;
                if (tp->snd_bandwidth == 0)
                        tp->snd_bandwidth = tcp_inflight_min;
@@ -1995,7 +1995,7 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
         *          choice.
         */
 
-#define        USERTT  (((tp->t_srtt + tp->t_rttbest) / 2) + tcp_inflight_adjrtt)
+#define        USERTT  ((tp->t_srtt + tp->t_rttvar) + tcp_inflight_adjrtt)
        bw += bw * tcp_inflight_stab / 1000;
        bwnd = (int64_t)bw * USERTT / (hz << TCP_RTT_SHIFT) +
               (int)tp->t_maxseg * 2;
@@ -2003,11 +2003,11 @@ tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq)
 
        if (tcp_inflight_debug > 0) {
                static int ltime;
-               if ((u_int)(ticks - ltime) >= hz / tcp_inflight_debug) {
-                       ltime = ticks;
-                       kprintf("%p ibw %ld bw %ld rttbest %d srtt %d "
+               if ((u_int)(save_ticks - ltime) >= hz / tcp_inflight_debug) {
+                       ltime = save_ticks;
+                       kprintf("%p ibw %ld bw %ld rttvar %d srtt %d "
                                "bwnd %ld delta %d snd_win %ld\n",
-                               tp, ibw, bw, tp->t_rttbest, tp->t_srtt,
+                               tp, ibw, bw, tp->t_rttvar, tp->t_srtt,
                                bwnd, delta_ticks, tp->snd_wnd);
                }
        }
index 6a76285..eeba2ba 100644 (file)
@@ -804,8 +804,10 @@ tcp_usr_send(netmsg_t msg)
        /*
         * Pump the data into the socket.
         */
-       if (m)
+       if (m) {
                ssb_appendstream(&so->so_snd, m);
+               sowwakeup(so);
+       }
        if (flags & PRUS_OOB) {
                /*
                 * According to RFC961 (Assigned Protocols),
index af875ed..0c67fe4 100644 (file)
@@ -245,19 +245,6 @@ struct     xsocket {
      ((so)->so_state & SS_CANTSENDMORE) || \
      (so)->so_error)
 
-/*
- * Do we need to notify the other side when I/O is possible?
- *
- * NOTE: Interlock for ssb_wait/wakeup.  The protocol side will set
- *      SSB_WAKEUP asynchronously and this can race, so if it isn't
- *      set we have to go through the full-on notification check.
- *      If it is set but no waiting ever takes place it simply
- *      remains set.
- */
-#define ssb_notify(ssb)                                        \
-           (((ssb)->ssb_flags & SSB_NOTIFY_MASK) ||    \
-            ((ssb)->ssb_flags & SSB_WAKEUP) == 0)
-
 /* do we have to send all at once on a socket? */
 
 #ifdef _KERNEL
@@ -346,17 +333,8 @@ ssb_preallocstream(struct signalsockbuf *ssb, struct mbuf *m)
                atomic_clear_int(&(ssb)->ssb_flags, SSB_KNOTE);         \
 }
 
-#define        sorwakeup(so)                                           \
-       do {                                                    \
-               if (ssb_notify(&(so)->so_rcv))                  \
-                       sowakeup((so), &(so)->so_rcv);          \
-       } while (0)
-
-#define        sowwakeup(so)                                           \
-       do {                                                    \
-               if (ssb_notify(&(so)->so_snd))                  \
-                       sowakeup((so), &(so)->so_snd);          \
-       } while (0)
+#define        sorwakeup(so)   sowakeup((so), &(so)->so_rcv)
+#define        sowwakeup(so)   sowakeup((so), &(so)->so_snd)
 
 #ifdef _KERNEL