]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet/ip_dummynet.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / bsd / netinet / ip_dummynet.c
index 013ccbf43cf049c74992d7327014a895c7f2623b..6b95dd5af93f4f71f4a67253543fa821e9f0d8a3 100644 (file)
@@ -1,23 +1,29 @@
 /*
  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa
  */
 static dn_key curr_time = 0 ; /* current simulation time */
 
+/* this is for the timer that fires to call dummynet() - we only enable the timer when
+       there are packets to process, otherwise it's disabled */
+static int timer_enabled = 0;  
+
 static int dn_hash_size = 64 ; /* default hash size */
 
 /* statistics on number of queue searches and search steps */
@@ -469,9 +479,6 @@ transmit_event(struct dn_pipe *pipe)
                                break ;
                        }
                        case DN_TO_IP_IN :
-                               ip = mtod(m, struct ip *);
-                               ip->ip_len = htons(ip->ip_len);
-                               ip->ip_off = htons(ip->ip_off);
                                proto_inject(PF_INET, m);
                                break ;
                
@@ -519,8 +526,15 @@ transmit_event(struct dn_pipe *pipe)
  * before being able to transmit a packet. The credit is taken from
  * either a pipe (WF2Q) or a flow_queue (per-flow queueing)
  */
+/* hz is 100, which gives a granularity of 10ms in the old timer. 
+ * The timer has been changed to fire every 1ms, so the use of
+ * hz has been modified here. All instances of hz have been left
+ * in place but adjusted by a factor of 10 so that hz is functionally 
+ * equal to 1000.
+ */
 #define SET_TICKS(_m, q, p)    \
-    ((_m)->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \
+    ((_m)->m_pkthdr.len*8*(hz*10) - (q)->numbytes + p->bandwidth - 1 ) / \
            p->bandwidth ;
 
 /*
@@ -580,7 +594,7 @@ ready_event(struct dn_flow_queue *q)
     q->numbytes += ( curr_time - q->sched_time ) * p->bandwidth;
     while ( (pkt = q->head) != NULL ) {
        int len = pkt->m_pkthdr.len;
-       int len_scaled = p->bandwidth ? len*8*hz : 0 ;
+       int len_scaled = p->bandwidth ? len*8*(hz*10) : 0 ;
        if (len_scaled > q->numbytes )
            break ;
        q->numbytes -= len_scaled ;
@@ -650,7 +664,7 @@ ready_event_wfq(struct dn_pipe *p)
            struct mbuf *pkt = q->head;
            struct dn_flow_set *fs = q->fs;
            u_int64_t len = pkt->m_pkthdr.len;
-           int len_scaled = p->bandwidth ? len*8*hz : 0 ;
+           int len_scaled = p->bandwidth ? len*8*(hz*10) : 0 ;
 
            heap_extract(sch, NULL); /* remove queue from heap */
            p->numbytes -= len_scaled ;
@@ -737,7 +751,7 @@ ready_event_wfq(struct dn_pipe *p)
 }
 
 /*
- * This is called once per tick, or HZ times per second. It is used to
+ * This is called every 1ms. It is used to
  * increment the current tick counter and schedule expired events.
  */
 static void
@@ -748,6 +762,8 @@ dummynet(void * __unused unused)
     struct dn_heap *heaps[3];
     int i;
     struct dn_pipe *pe ;
+    struct timespec ts;
+    struct timeval     tv;
 
     heaps[0] = &ready_heap ;           /* fixed-rate queues */
     heaps[1] = &wfq_ready_heap ;       /* wfq queues */
@@ -755,25 +771,31 @@ dummynet(void * __unused unused)
     
        lck_mtx_lock(dn_mutex);
        
-    curr_time++ ;
+        /* make all time measurements in milliseconds (ms) -  
+         * here we convert secs and usecs to msecs (just divide the 
+        * usecs and take the closest whole number).
+         */
+        microuptime(&tv);
+        curr_time = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+       
     for (i=0; i < 3 ; i++) {
        h = heaps[i];
        while (h->elements > 0 && DN_KEY_LEQ(h->p[0].key, curr_time) ) {
-           if (h->p[0].key > curr_time)
+               if (h->p[0].key > curr_time)
                printf("dummynet: warning, heap %d is %d ticks late\n",
-                   i, (int)(curr_time - h->p[0].key));
-           p = h->p[0].object ; /* store a copy before heap_extract */
-           heap_extract(h, NULL); /* need to extract before processing */
-           if (i == 0)
+                       i, (int)(curr_time - h->p[0].key));
+               p = h->p[0].object ; /* store a copy before heap_extract */
+               heap_extract(h, NULL); /* need to extract before processing */
+               if (i == 0)
                ready_event(p) ;
-           else if (i == 1) {
+               else if (i == 1) {
                struct dn_pipe *pipe = p;
                if (pipe->if_name[0] != '\0')
-                   printf("dummynet: bad ready_event_wfq for pipe %s\n",
+                       printf("dummynet: bad ready_event_wfq for pipe %s\n",
                        pipe->if_name);
                else
-                   ready_event_wfq(p) ;
-           } else
+                       ready_event_wfq(p) ;
+               } else
                transmit_event(p);
        }
     }
@@ -788,9 +810,22 @@ dummynet(void * __unused unused)
            pe->sum -= q->fs->weight ;
        }
        
-       lck_mtx_unlock(dn_mutex);
+       /* check the heaps to see if there's still stuff in there, and 
+        * only set the timer if there are packets to process 
+        */
+       timer_enabled = 0;
+       for (i=0; i < 3 ; i++) {
+               h = heaps[i];
+               if (h->elements > 0) { // set the timer
+                       ts.tv_sec = 0;
+                       ts.tv_nsec = 1 * 1000000;       // 1ms
+                       timer_enabled = 1;
+                       bsd_timeout(dummynet, NULL, &ts);
+                       break;
+               }
+       }
        
-    timeout(dummynet, NULL, 1);
+    lck_mtx_unlock(dn_mutex);
 }
  
 /*
@@ -1121,6 +1156,8 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
     u_int64_t len = m->m_pkthdr.len ;
     struct dn_flow_queue *q = NULL ;
     int is_pipe;
+    struct timespec ts;
+    struct timeval     tv;
     
 #if IPFW2
     ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs;
@@ -1135,6 +1172,13 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
     pipe_nr &= 0xffff ;
 
        lck_mtx_lock(dn_mutex);
+
+       /* make all time measurements in milliseconds (ms) - 
+         * here we convert secs and usecs to msecs (just divide the 
+         * usecs and take the closest whole number).
+        */
+        microuptime(&tv);
+       curr_time = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
        
    /*
      * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule.
@@ -1177,12 +1221,13 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
 
     /* XXX expensive to zero, see if we can remove it*/
     mtag = m_tag_alloc(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_DUMMYNET,
-               sizeof(struct dn_pkt_tag), M_NOWAIT|M_ZERO);
+               sizeof(struct dn_pkt_tag), M_NOWAIT);
     if ( mtag == NULL )
                goto dropit ;           /* cannot allocate packet header        */
     m_tag_prepend(m, mtag);    /* attach to mbuf chain */
 
     pkt = (struct dn_pkt_tag *)(mtag+1);
+    bzero(pkt, sizeof(struct dn_pkt_tag));
     /* ok, i can handle the pkt now... */
     /* build and enqueue packet + parameters */
     pkt->rule = fwa->rule ;
@@ -1286,6 +1331,14 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
        }
     }
 done:
+       /* start the timer and set global if not already set */
+       if (!timer_enabled) {
+               ts.tv_sec = 0;
+               ts.tv_nsec = 1 * 1000000;       // 1ms
+               timer_enabled = 1;
+               bsd_timeout(dummynet, NULL, &ts);
+    }
+
        lck_mtx_unlock(dn_mutex);
     return 0;
 
@@ -1585,7 +1638,7 @@ config_pipe(struct dn_pipe *p)
      * delay = ms, must be translated into ticks.
      * qsize = slots/bytes
      */
-    p->delay = ( p->delay * hz ) / 1000 ;
+    p->delay = ( p->delay * (hz*10) ) / 1000 ;
     /* We need either a pipe number or a flow_set number */
     if (p->pipe_nr == 0 && pfs->fs_nr == 0)
        return EINVAL ;
@@ -1937,7 +1990,7 @@ dummynet_get(struct sockopt *sopt)
         * After each flow_set, copy the queue descriptor it owns.
         */
        bcopy(p, bp, sizeof( *p ) );
-       pipe_bp->delay = (pipe_bp->delay * 1000) / hz ;
+       pipe_bp->delay = (pipe_bp->delay * 1000) / (hz*10) ; 
        /*
         * XXX the following is a hack based on ->next being the
         * first field in dn_pipe and dn_flow_set. The correct
@@ -2024,7 +2077,6 @@ ip_dn_init(void)
        dn_mutex_grp_attr = lck_grp_attr_alloc_init();
        dn_mutex_grp = lck_grp_alloc_init("dn", dn_mutex_grp_attr);
        dn_mutex_attr = lck_attr_alloc_init();
-       lck_attr_setdefault(dn_mutex_attr);
 
        if ((dn_mutex = lck_mtx_alloc_init(dn_mutex_grp, dn_mutex_attr)) == NULL) {
                printf("ip_dn_init: can't alloc dn_mutex\n");
@@ -2044,6 +2096,4 @@ ip_dn_init(void)
     ip_dn_ctl_ptr = ip_dn_ctl;
     ip_dn_io_ptr = dummynet_io;
     ip_dn_ruledel_ptr = dn_rule_delete;
-    
-    timeout(dummynet, NULL, 1);
 }