diff options
author | oleg <oleg@FreeBSD.org> | 2007-11-06 22:53:41 +0000 |
---|---|---|
committer | oleg <oleg@FreeBSD.org> | 2007-11-06 22:53:41 +0000 |
commit | dd5717deccd91591695d9f8054e6c7d8dfadf358 (patch) | |
tree | 1fb5aa700c61c8c1524b94bea9dcbba1deeeae01 /sys/netinet/ip_dummynet.c | |
parent | b67c0e7d8fda915cf2ef6d851866c42dd9d5ffb7 (diff) | |
download | FreeBSD-src-dd5717deccd91591695d9f8054e6c7d8dfadf358.zip FreeBSD-src-dd5717deccd91591695d9f8054e6c7d8dfadf358.tar.gz |
style(9) cleanup.
MFC after: 3 month
Diffstat (limited to 'sys/netinet/ip_dummynet.c')
-rw-r--r-- | sys/netinet/ip_dummynet.c | 690 |
1 files changed, 350 insertions, 340 deletions
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index 9951248..c33f90f 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -206,15 +206,15 @@ static struct mtx dummynet_mtx; #define DUMMYNET_UNLOCK() mtx_unlock(&dummynet_mtx) #define DUMMYNET_LOCK_ASSERT() mtx_assert(&dummynet_mtx, MA_OWNED) -static int config_pipe(struct dn_pipe *p); -static int ip_dn_ctl(struct sockopt *sopt); +static int config_pipe(struct dn_pipe *p); +static int ip_dn_ctl(struct sockopt *sopt); -static void dummynet(void *); -static void dummynet_flush(void); -static void dummynet_send(struct mbuf *); -void dummynet_drain(void); +static void dummynet(void *); +static void dummynet_flush(void); +static void dummynet_send(struct mbuf *); +void dummynet_drain(void); static ip_dn_io_t dummynet_io; -static void dn_rule_delete(void *); +static void dn_rule_delete(void *); /* * Heap management functions. @@ -483,7 +483,7 @@ transmit_event(struct dn_pipe *pipe, struct mbuf **head, struct mbuf **tail) if ((m = pipe->head) != NULL) { pkt = dn_tag_get(m); /* - * XXX: Should check errors on heap_insert, by draining the + * XXX Should check errors on heap_insert, by draining the * whole pipe p and hoping in the future we are more successful. */ heap_insert(&extract_heap, pkt->output_time, pipe); @@ -496,8 +496,8 @@ transmit_event(struct dn_pipe *pipe, struct mbuf **head, struct mbuf **tail) * either a pipe (WF2Q) or a flow_queue (per-flow queueing) */ #define SET_TICKS(_m, q, p) \ - ((_m)->m_pkthdr.len*8*hz - (q)->numbytes + p->bandwidth - 1 ) / \ - p->bandwidth ; + ((_m)->m_pkthdr.len * 8 * hz - (q)->numbytes + p->bandwidth - 1) / \ + p->bandwidth; /* * extract pkt from queue, compute output time (could be now) @@ -533,59 +533,62 @@ move_pkt(struct mbuf *pkt, struct dn_flow_queue *q, struct dn_pipe *p, static void ready_event(struct dn_flow_queue *q, struct mbuf **head, struct mbuf **tail) { - struct mbuf *pkt; - struct dn_pipe *p = q->fs->pipe ; - int p_was_empty ; + struct mbuf *pkt; + struct dn_pipe *p = q->fs->pipe; + int p_was_empty; - DUMMYNET_LOCK_ASSERT(); + DUMMYNET_LOCK_ASSERT(); - if (p == NULL) { - printf("dummynet: ready_event- pipe is gone\n"); - return ; - } - p_was_empty = (p->head == NULL) ; + if (p == NULL) { + printf("dummynet: ready_event- pipe is gone\n"); + return; + } + p_was_empty = (p->head == NULL); - /* - * schedule fixed-rate queues linked to this pipe: - * Account for the bw accumulated since last scheduling, then - * drain as many pkts as allowed by q->numbytes and move to - * the delay line (in p) computing output time. - * bandwidth==0 (no limit) means we can drain the whole queue, - * setting len_scaled = 0 does the job. - */ - 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 ; - if (len_scaled > q->numbytes ) - break ; - q->numbytes -= len_scaled ; - move_pkt(pkt, q, p, len); - } - /* - * If we have more packets queued, schedule next ready event - * (can only occur when bandwidth != 0, otherwise we would have - * flushed the whole queue in the previous loop). - * To this purpose we record the current time and compute how many - * ticks to go for the finish time of the packet. - */ - if ( (pkt = q->head) != NULL ) { /* this implies bandwidth != 0 */ - dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */ - q->sched_time = curr_time ; - heap_insert(&ready_heap, curr_time + t, (void *)q ); - /* XXX should check errors on heap_insert, and drain the whole - * queue on error hoping next time we are luckier. + /* + * Schedule fixed-rate queues linked to this pipe: + * account for the bw accumulated since last scheduling, then + * drain as many pkts as allowed by q->numbytes and move to + * the delay line (in p) computing output time. + * bandwidth==0 (no limit) means we can drain the whole queue, + * setting len_scaled = 0 does the job. */ - } else { /* RED needs to know when the queue becomes empty */ - q->q_time = curr_time; - q->numbytes = 0; - } - /* - * If the delay line was empty call transmit_event() now. - * Otherwise, the scheduler will take care of it. - */ - if (p_was_empty) - transmit_event(p, head, tail); + 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; + + if (len_scaled > q->numbytes) + break; + q->numbytes -= len_scaled; + move_pkt(pkt, q, p, len); + } + /* + * If we have more packets queued, schedule next ready event + * (can only occur when bandwidth != 0, otherwise we would have + * flushed the whole queue in the previous loop). + * To this purpose we record the current time and compute how many + * ticks to go for the finish time of the packet. + */ + if ((pkt = q->head) != NULL) { /* this implies bandwidth != 0 */ + dn_key t = SET_TICKS(pkt, q, p); /* ticks i have to wait */ + + q->sched_time = curr_time; + heap_insert(&ready_heap, curr_time + t, (void *)q); + /* + * XXX Should check errors on heap_insert, and drain the whole + * queue on error hoping next time we are luckier. + */ + } else { /* RED needs to know when the queue becomes empty. */ + q->q_time = curr_time; + q->numbytes = 0; + } + /* + * If the delay line was empty call transmit_event() now. + * Otherwise, the scheduler will take care of it. + */ + if (p_was_empty) + transmit_event(p, head, tail); } /* @@ -593,123 +596,133 @@ ready_event(struct dn_flow_queue *q, struct mbuf **head, struct mbuf **tail) * the queues at their start time, and enqueue into the delay line. * Packets are drained until p->numbytes < 0. As long as * len_scaled >= p->numbytes, the packet goes into the delay line - * with a deadline p->delay. For the last packet, if p->numbytes<0, + * with a deadline p->delay. For the last packet, if p->numbytes < 0, * there is an additional delay. */ static void ready_event_wfq(struct dn_pipe *p, struct mbuf **head, struct mbuf **tail) { - int p_was_empty = (p->head == NULL) ; - struct dn_heap *sch = &(p->scheduler_heap); - struct dn_heap *neh = &(p->not_eligible_heap) ; - - DUMMYNET_LOCK_ASSERT(); + int p_was_empty = (p->head == NULL); + struct dn_heap *sch = &(p->scheduler_heap); + struct dn_heap *neh = &(p->not_eligible_heap); - if (p->if_name[0] == 0) /* tx clock is simulated */ - p->numbytes += ( curr_time - p->sched_time ) * p->bandwidth; - else { /* tx clock is for real, the ifq must be empty or this is a NOP */ - if (p->ifp && p->ifp->if_snd.ifq_head != NULL) - return ; - else { - DPRINTF(("dummynet: pipe %d ready from %s --\n", - p->pipe_nr, p->if_name)); - } - } + DUMMYNET_LOCK_ASSERT(); - /* - * While we have backlogged traffic AND credit, we need to do - * something on the queue. - */ - while ( p->numbytes >=0 && (sch->elements>0 || neh->elements >0) ) { - if (sch->elements > 0) { /* have some eligible pkts to send out */ - struct dn_flow_queue *q = sch->p[0].object ; - 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 ; - - heap_extract(sch, NULL); /* remove queue from heap */ - p->numbytes -= len_scaled ; - move_pkt(pkt, q, p, len); - - p->V += (len<<MY_M) / p->sum ; /* update V */ - q->S = q->F ; /* update start time */ - if (q->len == 0) { /* Flow not backlogged any more */ - fs->backlogged-- ; - heap_insert(&(p->idle_heap), q->F, q); - } else { /* still backlogged */ - /* - * update F and position in backlogged queue, then - * put flow in not_eligible_heap (we will fix this later). + if (p->if_name[0] == 0) /* tx clock is simulated */ + p->numbytes += (curr_time - p->sched_time) * p->bandwidth; + else { /* + * tx clock is for real, + * the ifq must be empty or this is a NOP. */ - len = (q->head)->m_pkthdr.len; - q->F += (len<<MY_M)/(u_int64_t) fs->weight ; - if (DN_KEY_LEQ(q->S, p->V)) - heap_insert(neh, q->S, q); - else - heap_insert(sch, q->F, q); - } + if (p->ifp && p->ifp->if_snd.ifq_head != NULL) + return; + else { + DPRINTF(("dummynet: pipe %d ready from %s --\n", + p->pipe_nr, p->if_name)); + } } + /* - * now compute V = max(V, min(S_i)). Remember that all elements in sch - * have by definition S_i <= V so if sch is not empty, V is surely - * the max and we must not update it. Conversely, if sch is empty - * we only need to look at neh. + * While we have backlogged traffic AND credit, we need to do + * something on the queue. */ - if (sch->elements == 0 && neh->elements > 0) - p->V = MAX64 ( p->V, neh->p[0].key ); - /* move from neh to sch any packets that have become eligible */ - while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V) ) { - struct dn_flow_queue *q = neh->p[0].object ; - heap_extract(neh, NULL); - heap_insert(sch, q->F, q); + while (p->numbytes >= 0 && (sch->elements > 0 || neh->elements > 0)) { + if (sch->elements > 0) { + /* Have some eligible pkts to send out. */ + struct dn_flow_queue *q = sch->p[0].object; + struct mbuf *pkt = q->head; + struct dn_flow_set *fs = q->fs; + uint64_t len = pkt->m_pkthdr.len; + int len_scaled = p->bandwidth ? len * 8 * hz : 0; + + heap_extract(sch, NULL); /* Remove queue from heap. */ + p->numbytes -= len_scaled; + move_pkt(pkt, q, p, len); + + p->V += (len << MY_M) / p->sum; /* Update V. */ + q->S = q->F; /* Update start time. */ + if (q->len == 0) { + /* Flow not backlogged any more. */ + fs->backlogged--; + heap_insert(&(p->idle_heap), q->F, q); + } else { + /* Still backlogged. */ + + /* + * Update F and position in backlogged queue, + * then put flow in not_eligible_heap + * (we will fix this later). + */ + len = (q->head)->m_pkthdr.len; + q->F += (len << MY_M) / (uint64_t)fs->weight; + if (DN_KEY_LEQ(q->S, p->V)) + heap_insert(neh, q->S, q); + else + heap_insert(sch, q->F, q); + } + } + /* + * Now compute V = max(V, min(S_i)). Remember that all elements + * in sch have by definition S_i <= V so if sch is not empty, + * V is surely the max and we must not update it. Conversely, + * if sch is empty we only need to look at neh. + */ + if (sch->elements == 0 && neh->elements > 0) + p->V = MAX64(p->V, neh->p[0].key); + /* Move from neh to sch any packets that have become eligible */ + while (neh->elements > 0 && DN_KEY_LEQ(neh->p[0].key, p->V)) { + struct dn_flow_queue *q = neh->p[0].object; + heap_extract(neh, NULL); + heap_insert(sch, q->F, q); + } + + if (p->if_name[0] != '\0') { /* Tx clock is from a real thing */ + p->numbytes = -1; /* Mark not ready for I/O. */ + break; + } } + if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0 && + p->idle_heap.elements > 0) { + /* + * No traffic and no events scheduled. + * We can get rid of idle-heap. + */ + int i; - if (p->if_name[0] != '\0') {/* tx clock is from a real thing */ - p->numbytes = -1 ; /* mark not ready for I/O */ - break ; + for (i = 0; i < p->idle_heap.elements; i++) { + struct dn_flow_queue *q = p->idle_heap.p[i].object; + + q->F = 0; + q->S = q->F + 1; + } + p->sum = 0; + p->V = 0; + p->idle_heap.elements = 0; } - } - if (sch->elements == 0 && neh->elements == 0 && p->numbytes >= 0 - && p->idle_heap.elements > 0) { /* - * no traffic and no events scheduled. We can get rid of idle-heap. + * If we are getting clocks from dummynet (not a real interface) and + * If we are under credit, schedule the next ready event. + * Also fix the delivery time of the last packet. */ - int i ; - - for (i = 0 ; i < p->idle_heap.elements ; i++) { - struct dn_flow_queue *q = p->idle_heap.p[i].object ; - - q->F = 0 ; - q->S = q->F + 1 ; + if (p->if_name[0]==0 && p->numbytes < 0) { /* This implies bw > 0. */ + dn_key t = 0; /* Number of ticks i have to wait. */ + + if (p->bandwidth > 0) + t = (p->bandwidth - 1 - p->numbytes) / p->bandwidth; + dn_tag_get(p->tail)->output_time += t; + p->sched_time = curr_time; + heap_insert(&wfq_ready_heap, curr_time + t, (void *)p); + /* + * XXX Should check errors on heap_insert, and drain the whole + * queue on error hoping next time we are luckier. + */ } - p->sum = 0 ; - p->V = 0 ; - p->idle_heap.elements = 0 ; - } - /* - * If we are getting clocks from dummynet (not a real interface) and - * If we are under credit, schedule the next ready event. - * Also fix the delivery time of the last packet. - */ - if (p->if_name[0]==0 && p->numbytes < 0) { /* this implies bandwidth >0 */ - dn_key t=0 ; /* number of ticks i have to wait */ - - if (p->bandwidth > 0) - t = ( p->bandwidth -1 - p->numbytes) / p->bandwidth ; - dn_tag_get(p->tail)->output_time += t ; - p->sched_time = curr_time ; - heap_insert(&wfq_ready_heap, curr_time + t, (void *)p); - /* XXX should check errors on heap_insert, and drain the whole - * queue on error hoping next time we are luckier. + /* + * If the delay line was empty call transmit_event() now. + * Otherwise, the scheduler will take care of it. */ - } - /* - * If the delay line was empty call transmit_event() now. - * Otherwise, the scheduler will take care of it. - */ - if (p_was_empty) - transmit_event(p, head, tail); + if (p_was_empty) + transmit_event(p, head, tail); } /* @@ -924,29 +937,27 @@ expire_queues(struct dn_flow_set *fs) static struct dn_flow_queue * create_queue(struct dn_flow_set *fs, int i) { - struct dn_flow_queue *q ; + struct dn_flow_queue *q; - if (fs->rq_elements > fs->rq_size * dn_max_ratio && + if (fs->rq_elements > fs->rq_size * dn_max_ratio && expire_queues(fs) == 0) { - /* - * No way to get room, use or create overflow queue. - */ - i = fs->rq_size ; - if ( fs->rq[i] != NULL ) - return fs->rq[i] ; - } - q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO); - if (q == NULL) { - printf("dummynet: sorry, cannot allocate queue for new flow\n"); - return NULL ; - } - q->fs = fs ; - q->hash_slot = i ; - q->next = fs->rq[i] ; - q->S = q->F + 1; /* hack - mark timestamp as invalid */ - fs->rq[i] = q ; - fs->rq_elements++ ; - return q ; + /* No way to get room, use or create overflow queue. */ + i = fs->rq_size; + if (fs->rq[i] != NULL) + return fs->rq[i]; + } + q = malloc(sizeof(*q), M_DUMMYNET, M_NOWAIT | M_ZERO); + if (q == NULL) { + printf("dummynet: sorry, cannot allocate queue for new flow\n"); + return (NULL); + } + q->fs = fs; + q->hash_slot = i; + q->next = fs->rq[i]; + q->S = q->F + 1; /* hack - mark timestamp as invalid. */ + fs->rq[i] = q; + fs->rq_elements++; + return (q); } /* @@ -1200,185 +1211,184 @@ locate_pipe(int pipe_nr) * ifp the 'ifp' parameter from the caller. * NULL in ip_input, destination interface in ip_output, * rule matching rule, in case of multiple passes - * */ static int dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa) { - struct mbuf *head = NULL, *tail = NULL; - struct dn_pkt_tag *pkt; - struct m_tag *mtag; - struct dn_flow_set *fs = NULL; - struct dn_pipe *pipe ; - u_int64_t len = m->m_pkthdr.len ; - struct dn_flow_queue *q = NULL ; - int is_pipe; - ipfw_insn *cmd = ACTION_PTR(fwa->rule); - - KASSERT(m->m_nextpkt == NULL, - ("dummynet_io: mbuf queue passed to dummynet")); - - if (cmd->opcode == O_LOG) - cmd += F_LEN(cmd); - if (cmd->opcode == O_ALTQ) - cmd += F_LEN(cmd); - if (cmd->opcode == O_TAG) - cmd += F_LEN(cmd); - is_pipe = (cmd->opcode == O_PIPE); + struct mbuf *head = NULL, *tail = NULL; + struct dn_pkt_tag *pkt; + struct m_tag *mtag; + struct dn_flow_set *fs = NULL; + struct dn_pipe *pipe; + uint64_t len = m->m_pkthdr.len; + struct dn_flow_queue *q = NULL; + int is_pipe; + ipfw_insn *cmd = ACTION_PTR(fwa->rule); + + KASSERT(m->m_nextpkt == NULL, + ("dummynet_io: mbuf queue passed to dummynet")); + + if (cmd->opcode == O_LOG) + cmd += F_LEN(cmd); + if (cmd->opcode == O_ALTQ) + cmd += F_LEN(cmd); + if (cmd->opcode == O_TAG) + cmd += F_LEN(cmd); + is_pipe = (cmd->opcode == O_PIPE); - DUMMYNET_LOCK(); - /* - * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule. - * - * XXXGL: probably the pipe->fs and fs->pipe logic here - * below can be simplified. - */ - if (is_pipe) { - pipe = locate_pipe(fwa->cookie); - if (pipe != NULL) - fs = &(pipe->fs); - } else - fs = locate_flowset(fwa->cookie); - - if (fs == NULL) - goto dropit; /* This queue/pipe does not exist! */ - pipe = fs->pipe; - if (pipe == NULL) { /* Must be a queue, try find a matching pipe. */ - pipe = locate_pipe(fs->parent_nr); - if (pipe != NULL) - fs->pipe = pipe; - else { - printf("dummynet: no pipe %d for queue %d, drop pkt\n", - fs->parent_nr, fs->fs_nr); - goto dropit ; + DUMMYNET_LOCK(); + /* + * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule. + * + * XXXGL: probably the pipe->fs and fs->pipe logic here + * below can be simplified. + */ + if (is_pipe) { + pipe = locate_pipe(fwa->cookie); + if (pipe != NULL) + fs = &(pipe->fs); + } else + fs = locate_flowset(fwa->cookie); + + if (fs == NULL) + goto dropit; /* This queue/pipe does not exist! */ + pipe = fs->pipe; + if (pipe == NULL) { /* Must be a queue, try find a matching pipe. */ + pipe = locate_pipe(fs->parent_nr); + if (pipe != NULL) + fs->pipe = pipe; + else { + printf("dummynet: no pipe %d for queue %d, drop pkt\n", + fs->parent_nr, fs->fs_nr); + goto dropit; + } } - } - q = find_queue(fs, &(fwa->f_id)); - if ( q == NULL ) - goto dropit ; /* cannot allocate queue */ - /* - * update statistics, then check reasons to drop pkt - */ - q->tot_bytes += len ; - q->tot_pkts++ ; - if ( fs->plr && random() < fs->plr ) - goto dropit ; /* random pkt drop */ - if ( fs->flags_fs & DN_QSIZE_IS_BYTES) { - if (q->len_bytes > fs->qsize) - goto dropit ; /* queue size overflow */ - } else { - if (q->len >= fs->qsize) - goto dropit ; /* queue count overflow */ - } - if ( fs->flags_fs & DN_IS_RED && red_drops(fs, q, len) ) - goto dropit ; - - /* XXX expensive to zero, see if we can remove it*/ - mtag = m_tag_get(PACKET_TAG_DUMMYNET, - sizeof(struct dn_pkt_tag), M_NOWAIT|M_ZERO); - 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); - /* ok, i can handle the pkt now... */ - /* build and enqueue packet + parameters */ - pkt->rule = fwa->rule ; - pkt->dn_dir = dir ; - - pkt->ifp = fwa->oif; - - if (q->head == NULL) - q->head = m; - else - q->tail->m_nextpkt = m; - q->tail = m; - q->len++; - q->len_bytes += len ; + q = find_queue(fs, &(fwa->f_id)); + if (q == NULL) + goto dropit; /* Cannot allocate queue. */ + + /* Update statistics, then check reasons to drop pkt. */ + q->tot_bytes += len; + q->tot_pkts++; + if (fs->plr && random() < fs->plr) + goto dropit; /* Random pkt drop. */ + if (fs->flags_fs & DN_QSIZE_IS_BYTES) { + if (q->len_bytes > fs->qsize) + goto dropit; /* Queue size overflow. */ + } else { + if (q->len >= fs->qsize) + goto dropit; /* Queue count overflow. */ + } + if (fs->flags_fs & DN_IS_RED && red_drops(fs, q, len)) + goto dropit; - if ( q->head != m ) /* flow was not idle, we are done */ - goto done; - /* - * If we reach this point the flow was previously idle, so we need - * to schedule it. This involves different actions for fixed-rate or - * WF2Q queues. - */ - if (is_pipe) { + /* XXX expensive to zero, see if we can remove it. */ + mtag = m_tag_get(PACKET_TAG_DUMMYNET, + sizeof(struct dn_pkt_tag), M_NOWAIT | M_ZERO); + 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); /* - * Fixed-rate queue: just insert into the ready_heap. + * Ok, i can handle the pkt now... + * Build and enqueue packet + parameters. */ - dn_key t = 0 ; - if (pipe->bandwidth) - t = SET_TICKS(m, q, pipe); - q->sched_time = curr_time ; - if (t == 0) /* must process it now */ - ready_event(q, &head, &tail); + pkt->rule = fwa->rule; + pkt->dn_dir = dir; + + pkt->ifp = fwa->oif; + + if (q->head == NULL) + q->head = m; else - heap_insert(&ready_heap, curr_time + t , q ); - } else { - /* - * WF2Q. First, compute start time S: if the flow was idle (S=F+1) - * set S to the virtual time V for the controlling pipe, and update - * the sum of weights for the pipe; otherwise, remove flow from - * idle_heap and set S to max(F,V). - * Second, compute finish time F = S + len/weight. - * Third, if pipe was idle, update V=max(S, V). - * Fourth, count one more backlogged flow. - */ - if (DN_KEY_GT(q->S, q->F)) { /* means timestamps are invalid */ - q->S = pipe->V ; - pipe->sum += fs->weight ; /* add weight of new queue */ - } else { - heap_extract(&(pipe->idle_heap), q); - q->S = MAX64(q->F, pipe->V ) ; - } - q->F = q->S + ( len<<MY_M )/(u_int64_t) fs->weight; + q->tail->m_nextpkt = m; + q->tail = m; + q->len++; + q->len_bytes += len; - if (pipe->not_eligible_heap.elements == 0 && - pipe->scheduler_heap.elements == 0) - pipe->V = MAX64 ( q->S, pipe->V ); - fs->backlogged++ ; + if (q->head != m) /* Flow was not idle, we are done. */ + goto done; /* - * Look at eligibility. A flow is not eligibile if S>V (when - * this happens, it means that there is some other flow already - * scheduled for the same pipe, so the scheduler_heap cannot be - * empty). If the flow is not eligible we just store it in the - * not_eligible_heap. Otherwise, we store in the scheduler_heap - * and possibly invoke ready_event_wfq() right now if there is - * leftover credit. - * Note that for all flows in scheduler_heap (SCH), S_i <= V, - * and for all flows in not_eligible_heap (NEH), S_i > V . - * So when we need to compute max( V, min(S_i) ) forall i in SCH+NEH, - * we only need to look into NEH. + * If we reach this point the flow was previously idle, so we need + * to schedule it. This involves different actions for fixed-rate or + * WF2Q queues. */ - if (DN_KEY_GT(q->S, pipe->V) ) { /* not eligible */ - if (pipe->scheduler_heap.elements == 0) - printf("dummynet: ++ ouch! not eligible but empty scheduler!\n"); - heap_insert(&(pipe->not_eligible_heap), q->S, q); + if (is_pipe) { + /* Fixed-rate queue: just insert into the ready_heap. */ + dn_key t = 0; + + if (pipe->bandwidth) + t = SET_TICKS(m, q, pipe); + q->sched_time = curr_time; + if (t == 0) /* Must process it now. */ + ready_event(q, &head, &tail); + else + heap_insert(&ready_heap, curr_time + t , q); } else { - heap_insert(&(pipe->scheduler_heap), q->F, q); - if (pipe->numbytes >= 0) { /* pipe is idle */ - if (pipe->scheduler_heap.elements != 1) - printf("dummynet: OUCH! pipe should have been idle!\n"); - DPRINTF(("dummynet: waking up pipe %d at %d\n", - pipe->pipe_nr, (int)(q->F >> MY_M))); - pipe->sched_time = curr_time ; - ready_event_wfq(pipe, &head, &tail); - } + /* + * WF2Q. First, compute start time S: if the flow was + * idle (S = F + 1) set S to the virtual time V for the + * controlling pipe, and update the sum of weights for the pipe; + * otherwise, remove flow from idle_heap and set S to max(F,V). + * Second, compute finish time F = S + len / weight. + * Third, if pipe was idle, update V = max(S, V). + * Fourth, count one more backlogged flow. + */ + if (DN_KEY_GT(q->S, q->F)) { /* Means timestamps are invalid. */ + q->S = pipe->V; + pipe->sum += fs->weight; /* Add weight of new queue. */ + } else { + heap_extract(&(pipe->idle_heap), q); + q->S = MAX64(q->F, pipe->V); + } + q->F = q->S + (len << MY_M) / (uint64_t)fs->weight; + + if (pipe->not_eligible_heap.elements == 0 && + pipe->scheduler_heap.elements == 0) + pipe->V = MAX64(q->S, pipe->V); + fs->backlogged++; + /* + * Look at eligibility. A flow is not eligibile if S>V (when + * this happens, it means that there is some other flow already + * scheduled for the same pipe, so the scheduler_heap cannot be + * empty). If the flow is not eligible we just store it in the + * not_eligible_heap. Otherwise, we store in the scheduler_heap + * and possibly invoke ready_event_wfq() right now if there is + * leftover credit. + * Note that for all flows in scheduler_heap (SCH), S_i <= V, + * and for all flows in not_eligible_heap (NEH), S_i > V. + * So when we need to compute max(V, min(S_i)) forall i in + * SCH+NEH, we only need to look into NEH. + */ + if (DN_KEY_GT(q->S, pipe->V)) { /* Not eligible. */ + if (pipe->scheduler_heap.elements == 0) + printf("dummynet: ++ ouch! not eligible but empty scheduler!\n"); + heap_insert(&(pipe->not_eligible_heap), q->S, q); + } else { + heap_insert(&(pipe->scheduler_heap), q->F, q); + if (pipe->numbytes >= 0) { /* Pipe is idle. */ + if (pipe->scheduler_heap.elements != 1) + printf("dummynet: OUCH! pipe should have been idle!\n"); + DPRINTF(("dummynet: waking up pipe %d at %d\n", + pipe->pipe_nr, (int)(q->F >> MY_M))); + pipe->sched_time = curr_time; + ready_event_wfq(pipe, &head, &tail); + } + } } - } done: - DUMMYNET_UNLOCK(); - if (head != NULL) - dummynet_send(head); - return 0; + DUMMYNET_UNLOCK(); + if (head != NULL) + dummynet_send(head); + return (0); dropit: - if (q) - q->drops++ ; - DUMMYNET_UNLOCK(); - m_freem(m); - return ( (fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS); + if (q) + q->drops++; + DUMMYNET_UNLOCK(); + m_freem(m); + return ((fs && (fs->flags_fs & DN_NOERROR)) ? 0 : ENOBUFS); } /* |