svn commit: r201789 - in user/luigi/ipfw3-head: sbin/ipfw
sys/netinet sys/netinet/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Fri Jan 8 14:55:11 UTC 2010
Author: luigi
Date: Fri Jan 8 14:55:10 2010
New Revision: 201789
URL: http://svn.freebsd.org/changeset/base/201789
Log:
snapshot for today
Modified:
user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
Modified: user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Fri Jan 8 14:33:03 2010 (r201788)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Fri Jan 8 14:55:10 2010 (r201789)
@@ -730,13 +730,13 @@ ipfw_config_pipe(int ac, char **av)
char *end;
void *par = NULL;
struct dn_id *buf, *base;
- struct new_sch *sch = NULL, *sch2 = NULL;
+ struct new_sch *sch = NULL;
struct new_pipe *p = NULL;
struct new_fs *fs = NULL;
+ struct new_profile *pf = NULL;
struct ipfw_flow_id *mask = NULL;
- int lmax = sizeof(*sch)*2 + sizeof(*p) + sizeof(*fs);
+ int lmax = sizeof(*sch) + sizeof(*p) + sizeof(*fs) + sizeof(*pf);
-fprintf(stderr, "configuring %d\n", co.do_pipe);
base = buf = calloc(1, lmax);
if (buf == NULL) {
errx(1, "no memory for pipe buffer");
@@ -752,27 +752,27 @@ fprintf(stderr, "configuring %d\n", co.d
switch (co.do_pipe) {
case 1:
sch = o_next(&buf, sizeof(*sch), DN_SCH);
- sch2 = o_next(&buf, sizeof(*sch2), DN_SCH);
p = o_next(&buf, sizeof(*p), DN_PIPE);
fs = o_next(&buf, sizeof(*fs), DN_FS);
mask = &sch->sched_mask; // XXX or both ?
- p->pipe_nr = i + DN_PIPEOFFSET;
- fs->fs_nr = i;
- fs->sched_nr = i;
- sch->sched_nr = i;
- sch2->sched_nr = i + DN_PIPEOFFSET;
+ sch->pipe_nr = p->pipe_nr = i;
+ fs->fs_nr = i + DN_PIPEOFFSET;
+ fs->sched_nr = sch->sched_nr = i + DN_PIPEOFFSET;
break;
+
case 2: /* flowset */
fs = o_next(&buf, sizeof(*fs), DN_FS);
fs->fs_nr = i;
mask = &fs->flow_mask;
break;
+
case 3: /* scheduler */
sch = o_next(&buf, sizeof(*sch), DN_SCH);
sch->sched_nr = i;
mask = &sch->sched_mask; // XXX or both ?
break;
}
+
while (ac > 0) {
double d;
int tok = match_token(dummynet_params, *av);
@@ -1003,7 +1003,10 @@ end_mask:
#if 0
case TOK_PIPE_PROFILE:
+ NEED((!pf), "profile already set");
+ NEED(p, "profile");
{
+ pf = o_next(&buf, sizeof(*pf));
int samples[ED_MAX_SAMPLES_NO];
if (co.do_pipe != 1)
errx(EX_DATAERR, "extra delay only valid for pipes");
@@ -1015,14 +1018,14 @@ end_mask:
break;
#endif
case TOK_BURST:
- NEED(sch, "burst");
+ NEED(p, "burst");
NEED1("burst needs argument\n");
errno = 0;
- if (expand_number(av[0], (int64_t *)&sch->burst) < 0)
+ if (expand_number(av[0], (int64_t *)&p->burst) < 0)
if (errno != ERANGE)
errx(EX_DATAERR,
"burst: invalid argument");
- if (errno || sch->burst > (1ULL << 48) - 1)
+ if (errno || p->burst > (1ULL << 48) - 1)
errx(EX_DATAERR,
"burst: out of range (0..2^48-1)");
ac--; av++;
Modified: user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 8 14:33:03 2010 (r201788)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 8 14:55:10 2010 (r201789)
@@ -47,6 +47,7 @@ struct dn_id {
uint8_t type;
uint8_t subtype;
uint32_t id; /* identifier in the sequence */
+ struct dn_id *next; /* link field, for kernel */
};
/*
@@ -90,15 +91,25 @@ enum sched_flag {
DN_SCH_DELETE_DELAY_LINE = 0x0040, /* (k) */
};
-SLIST_HEAD(new_queue_head, new_queue);
typedef uint64_t dn_key;
+#define ED_MAX_SAMPLES_NO 1024
+struct new_profile {
+ struct dn_id oid;
+ /* fields to simulate a delay profile */
+#define ED_MAX_NAME_LEN 32
+ char name[ED_MAX_NAME_LEN];
+ int loss_level;
+ int samples_no;
+ int samples[ED_MAX_SAMPLES_NO]; /* this has actually samples_no slots */
+};
+
/* Pipe template
* All pipe are linked in a list, there is a 1-1 mapping between
* 'ipfw pipe XX ...' commands and pipe XX
*/
struct new_pipe {
- struct dn_id id;
+ struct dn_id oid;
/* these initial fields are set from the command line
* pipe N config bw B delay D profile PRF (mask M1 plr P queue Q
@@ -112,6 +123,7 @@ struct new_pipe {
int32_t pipe_nr ; /* N, number */
int bandwidth; /* B, really, bits/tick. */
int delay ; /* D, really, ticks */
+ uint64_t burst; /* burst size, scaled. bits*Hz XXX */
/*
* When the tx clock comes from an interface (if_name[0] != '\0'),
@@ -119,18 +131,12 @@ struct new_pipe {
*/
char if_name[IFNAMSIZ];
- /* fields to simulate a delay profile */
-#define ED_MAX_NAME_LEN 32
- char name[ED_MAX_NAME_LEN];
- int loss_level;
- int samples_no;
- int user_samples[0]; /* this has actually samples_no slots */
+ struct new_profile *profile;
/*
* The following parameters set at runtime and only valid
* in the kernel. Userland should not look at these fields.
*/
- int *samples; /* pointer to memory for user_samples[] */
struct ifnet *ifp;
int ready ; /* set if ifp != NULL and we got a signal from it */
@@ -141,7 +147,7 @@ struct new_pipe {
* generic text string, in case we need one
*/
struct new_text {
- struct dn_id id;
+ struct dn_id oid;
int len;
char text[0]; /* len bytes, NUL terminated */
};
@@ -153,7 +159,7 @@ struct new_text {
* (plus there is a FIFO flowset for each pipe)
*/
struct new_fs {
- struct dn_id id;
+ struct dn_id oid;
/* these initial fields are set from the command line
* queue N config mask M pipe P buckets B plr PLR queue QSZ ...
@@ -181,11 +187,11 @@ struct new_fs {
struct new_fs *confnext;
/* DN_FS_DELETE
- * DN_FS_REENQUEUE
- * DN_HAVE_FLOW_MASK
- * DN_QSIZE_IS_BYTES
- * DN_NOERROR
- */
+ * DN_FS_REENQUEUE
+ * DN_HAVE_FLOW_MASK
+ * DN_QSIZE_IS_BYTES
+ * DN_NOERROR
+ */
int flags;
/* Number of queues attached to this flowset */
@@ -197,8 +203,8 @@ struct new_fs {
/* Scheduler associated with this flowset, set when the
* scheduler for the pipe P is defined.
*/
- struct new_sch *ptr_sched;
- int ptr_sched_val; /* to check if the pointer is correct */
+ struct new_sch *sched;
+ int sched_id; /* to check if the pointer is correct */
/*
* Pointer to scheduler-specific parameters for this flowset
@@ -206,9 +212,42 @@ struct new_fs {
*/
struct dn_id *alg_fs;
/* Pointer to scheduler functions */
- struct scheduler *fp;
+ struct dn_sched *fp;
};
+/* Implementation of the packets queue associated with a scheduler instance */
+struct new_queue {
+ struct dn_id oid;
+
+ /* Number and pointer to the parent flowset */
+ int fs_nr;
+ struct new_fs *fs;
+
+ u_int lenght; /* Queue lenght, in packets */
+ u_int len_bytes; /* Queue lenght, in bytes */
+
+ uint64_t tot_pkts; /* statistics counters */
+ uint64_t tot_bytes;
+ uint32_t drops;
+
+ /* Used to print the id of the queue */
+ int hash_slot;
+
+ /* Pointer to the scheduler instance that the packet belongs */
+ void *sch_inst; /* Pointer to scheduler specific data */
+
+ /* packets queue */
+ struct mbuf *head, *tail;
+
+ /* flow id associated with this queue */
+ struct ipfw_flow_id id;
+
+ struct new_queue *next; /* Next queue in the bucket */
+
+ /* Pointer to scheduler functions */
+ struct dn_sched *fp;
+};
+SLIST_HEAD(new_queue_head, new_queue);
/*
* Scheduler instance.
* Contains variables and all queues relative to a this instance.
@@ -221,7 +260,7 @@ struct new_sch_inst {
/* Parent scheduler */
int sched_nr;
- struct new_sch * ptr_sched;
+ struct new_sch *sched;
int hash_slot; /* used to print the id of the scheduler instance */
@@ -250,14 +289,13 @@ struct new_sch_inst {
* (plus there is a FIFO scheduler for each pipe)
*/
struct new_sch {
- struct dn_id id;
+ struct dn_id oid;
/* these initial fields are set from the command line
* sched N config mask M ...
*/
int sched_nr; /* N, scheduler number */
- uint64_t burst; /* burst size, scaled. bits*Hz */
int bucket; /* number of buckets for the instances */
/* mask to select the appropriate scheduler instance */
@@ -281,7 +319,7 @@ struct new_sch {
/* Pointer to the parent pipe */
int pipe_nr;
- struct new_pipe *ptr_pipe;
+ struct new_pipe *pipe;
/* Copy of command line */
#define DN_MAX_COMMAND 256
@@ -304,7 +342,7 @@ struct new_sch {
int flags;
/* Pointer to scheduler functions */
- struct scheduler *fp;
+ struct dn_sched *fp;
/* Counter of packets pending to entering in this scheduler.
* Used to avoid to delete the scheduler if some packets are in the mutex
@@ -507,7 +545,6 @@ struct dn_flow_set {
int avg_pkt_size ; /* medium packet size */
int max_pkt_size ; /* max packet size */
};
-SLIST_HEAD(dn_flow_set_head, dn_flow_set);
struct dn_heap;
/*
@@ -567,15 +604,4 @@ struct dn_pipe { /* a pipe */
int *samples;
};
-/* dn_pipe_max is used to pass pipe configuration from userland onto
- * kernel space and back
- */
-#define ED_MAX_SAMPLES_NO 1024
-struct dn_pipe_max {
- struct dn_pipe pipe;
- int samples[ED_MAX_SAMPLES_NO];
-};
-
-SLIST_HEAD(dn_pipe_head, dn_pipe);
-
#endif /* _IP_DUMMYNET_H */
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Fri Jan 8 14:33:03 2010 (r201788)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Fri Jan 8 14:55:10 2010 (r201789)
@@ -120,10 +120,10 @@ struct dn_sched {
int (*config)(char *command, void *sch, int reconfigure);
int (*destroy)(void* sch);
- int (*new_sched)(void *v);
+ int (*new_sched)(void *sch_priv, void *sch_t_priv);
int (*free_sched)(void *s);
- int (*new_fs)(char *command, struct dn_id *g, int reconfigure);
+ int (*new_fs)(void *command, struct dn_id *g, int reconfigure);
int (*free_fs)(struct dn_id *f);
int (*new_queue)(struct new_queue *q, struct dn_id *f);
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Fri Jan 8 14:33:03 2010 (r201788)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Fri Jan 8 14:55:10 2010 (r201789)
@@ -88,7 +88,7 @@ struct dn_parms dn_cfg = {
.red_max_pkt_size = 1500, /* RED - default max packet size */
};
-//static long tick_last; /* Last tick duration (usec). */
+static long tick_last; /* Last tick duration (usec). */
static long tick_delta; /* Last vs standard tick diff (usec). */
static long tick_delta_sum; /* Accumulated tick difference (usec).*/
static long tick_adjustment; /* Tick adjustments done. */
@@ -133,6 +133,9 @@ MALLOC_DEFINE(M_DUMMYNET, "dummynet", "d
struct new_pipe_head pipehash[DN_HASHSIZE]; /* all pipes */
struct new_fs_head flowsethash[DN_HASHSIZE]; /* all flowsets */
+struct new_sch_head schedulerhash[DN_HASHSIZE]; /* all schedulers */
+struct new_fs_head flowsetunlinked; /* all unlinked flowsets */
+
extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
@@ -322,12 +325,13 @@ compute_extra_bits(struct mbuf *pkt, str
{
int index;
dn_key extra_bits;
+ struct new_profile *pf = p->profile;
- if (!p->samples || p->samples_no == 0)
+ if (!pf || pf->samples_no == 0)
return 0;
- index = random() % p->samples_no;
- extra_bits = div64((dn_key)p->samples[index] * p->bandwidth, 1000);
- if (index >= p->loss_level) {
+ index = random() % pf->samples_no;
+ extra_bits = div64((dn_key)pf->samples[index] * p->bandwidth, 1000);
+ if (index >= pf->loss_level) {
struct dn_pkt_tag *dt = dn_tag_get(pkt);
if (dt)
dt->dn_dir = DIR_DROP;
@@ -335,14 +339,14 @@ compute_extra_bits(struct mbuf *pkt, str
return extra_bits;
}
-/* Insert packet pkt into delay line */
+/* Insert packet pkt into delay line, adding the delay.
+ * dt->output_time was already set */
static void
-move_pkt(struct mbuf *pkt, struct new_pipe *p, struct delay_line *d,
- dn_key l_curr_time)
+move_pkt(struct mbuf *pkt, struct new_pipe *p, struct delay_line *d)
{
struct dn_pkt_tag *dt = dn_tag_get(pkt);
- dt->output_time = l_curr_time + p->delay ;
+ dt->output_time += p->delay ;
if (d->head == NULL)
d->head = pkt;
@@ -459,7 +463,7 @@ mask_are_equals (struct ipfw_flow_id *id
* XXX why do we need separate delay lines ?
*/
static struct new_sch_inst *
-create_scheduler_instance(struct new_sch *sch_t, dn_key l_curr_time)
+create_scheduler_instance(struct new_sch *sch_t)
{
struct new_sch_inst *si;
int ret;
@@ -471,20 +475,13 @@ create_scheduler_instance(struct new_sch
if (si == NULL)
goto error;
- si->dline = malloc(sizeof(struct delay_line), M_DUMMYNET, M_NOWAIT);
- if (si->dline == NULL)
- goto error;
- si->dline->si = si;
- set_oid(&si->dline->id, DN_DELAY_LINE, 0, sizeof(struct delay_line));
- si->dline->head = si->dline->tail = NULL;
-
set_oid(&si->oid, DN_SCH_I, 0, l);
si->sched_nr = sch_t->sched_nr;
- si->ptr_sched = sch_t;
+ si->sched = sch_t;
/* XXX do we make assumption on this starting with dn_id ? */
- ret = sch_t->fp->new_sched((void *)(si + 1));
+ ret = sch_t->fp->new_sched(si + 1, sch_t + 1);
if (ret) {
msg = "new_sched error";
goto error;
@@ -493,9 +490,7 @@ create_scheduler_instance(struct new_sch
/* Initialize scheduler instance queues list */
SLIST_INIT(&si->ql_list);
- si->oid.subtype = ((struct dn_id*)(si + 1))->subtype;
- ((struct dn_id*)(si + 1))->type = DN_SCH_I;
- si->idle_time = l_curr_time;
+ si->idle_time = 0;
return si;
error:
@@ -507,7 +502,7 @@ error:
static struct new_sch_inst *
find_scheduler(struct new_sch *sch_t, struct new_fs *fs,
- struct ipfw_flow_id *id, dn_key l_curr_time)
+ struct ipfw_flow_id *id)
{
struct new_sch_inst *prev, *s; /* returning scheduler instance */
struct ipfw_flow_id *id_t;
@@ -544,7 +539,7 @@ find_scheduler(struct new_sch *sch_t, st
}
if (s == NULL) { /* no match, need to allocate a new entry */
- s = create_scheduler_instance(sch_t, l_curr_time);
+ s = create_scheduler_instance(sch_t);
if (s == NULL)
return NULL;
/* Link scheduler in front of array */
@@ -559,6 +554,63 @@ find_scheduler(struct new_sch *sch_t, st
return s;
}
+/*
+ * Send traffic from a scheduler instance.
+ */
+static struct mbuf *
+serve_sched(struct new_sch_inst *s, dn_key now)
+{
+ struct mbuf *head;
+ struct new_sch *sch_t = s->sched;
+ struct mbuf *tosend = NULL;
+ dn_key len_scaled;
+ struct new_pipe *pipe = sch_t->pipe;
+ int delay_line_idle = (s->dline->head == NULL);
+ int done;
+ s->flags &= ~DN_SCH_ACTIVE;
+
+ if (pipe->bandwidth > 0)
+ s->numbytes += (now - s->sched_time) * pipe->bandwidth;
+ else
+ s->numbytes = 0;
+ s->sched_time = now;
+ done = 0;
+ while (s->numbytes >= 0 && (tosend = sch_t->fp->dequeue(s + 1)) != NULL) {
+ done++;
+ len_scaled = pipe->bandwidth ? tosend->m_pkthdr.len * 8 * hz
+ + compute_extra_bits(tosend, pipe) * hz : 0;
+ s->numbytes -= len_scaled;
+ /* Move packet in the delay line */
+ move_pkt(tosend, pipe, s->dline);
+ }
+ if (done > 0 && s->numbytes < 0) {
+ /* credit has become negative, so reinsert the
+ * instance in the heap for when credit will be
+ * positive again. Also update the output time
+ * of the last packet, which is 'tosend'
+ */
+ dn_key t = 0;
+ if (pipe->bandwidth > 0)
+ t = (pipe->bandwidth - 1 - s->numbytes) / pipe->bandwidth;
+ /* Delay the output time because under credit */
+ dn_tag_get(tosend)->output_time += t;
+
+ s->sched->inst_counter++;
+ s->flags |= DN_SCH_ACTIVE;
+ DN_HEAP_LOCK();
+ heap_insert(system_heap, curr_time + t, s);
+ DN_HEAP_UNLOCK();
+ } else {
+ /* scheduler instance should be idle, because it
+ * did not return packets while credit was available.
+ */
+ s->idle_time = curr_time;
+ }
+
+ head = (delay_line_idle && done) ?
+ transmit_event(s->dline, curr_time) : NULL;
+ return head;
+}
/*
* The timer handler for dummynet. Time is computed in ticks, but
@@ -568,21 +620,13 @@ find_scheduler(struct new_sch *sch_t, st
void
dummynet_task(void *context, int pending)
{
-#if 0
- struct mbuf *head = NULL, *tail = NULL;
- struct new_pipe *pipe;
- struct dn_heap *heaps[3];
- struct dn_heap *h;
- void *p; /* generic parameter to handler */
- int i;
+ struct new_sch_inst *s;
+ struct new_sch *sch_t;
+ struct mbuf *head = NULL;
struct timeval t;
DUMMYNET_LOCK();
- heaps[0] = &ready_heap; /* fixed-rate queues */
- heaps[1] = &wfq_ready_heap; /* wfq queues */
- heaps[2] = &extract_heap; /* delay line */
-
/* Update number of lost(coalesced) ticks. */
tick_lost += pending - 1;
@@ -617,54 +661,82 @@ dummynet_task(void *context, int pending
tick_delta_sum += tick;
tick_adjustment++;
}
+ DUMMYNET_UNLOCK();
+ for (;;) {
+ struct dn_id *p; /* generic parameter to handler */
+ DN_HEAP_LOCK();
+ if (system_heap->elements > 0 &&
+ DN_KEY_LEQ(HEAP_TOP(system_heap)->key, curr_time)) {
+ p = HEAP_TOP(system_heap)->object;
+ heap_extract(system_heap, NULL);
+ } else {
+ p = NULL;
+ }
+ DN_HEAP_UNLOCK();
+ if (p == NULL)
+ break;
- for (i = 0; i < 3; i++) {
- h = heaps[i];
- while (h->elements > 0 && DN_KEY_LEQ(HEAP_TOP(h)->key, curr_time)) {
- // XXX can this happen ?
- if (HEAP_TOP(h)->key > curr_time)
- printf("dummynet: warning, "
- "heap %d is %d ticks late\n",
- i, (int)(curr_time - HEAP_TOP(h)->key));
- /* store a copy before heap_extract */
- p = HEAP_TOP(h)->object;
- /* need to extract before processing */
- heap_extract(h, NULL);
- if (i == 0)
- ready_event(p, &head, &tail);
- 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", pipe->if_name);
- else
- ready_event_wfq(p, &head, &tail);
- } else
- transmit_event(p, &head, &tail);
+ if (p->type == DN_SCH_I) {
+ /*
+ * Working with scheduler instances:
+ * - Remove a scheduler instance from the heap and decrement
+ * the scheduler counter.
+ * - If the scheduler is deleting and no other scheduler
+ * instances (of this scheduler) are into the heap,
+ * it's now possible to delete scheduler and call the
+ * function to do this;
+ * - If the scheduer is deleting and this isn't the last
+ * instance in the heap, don't call the dequeue() function
+ * so the instance isn't inserted in the heap
+ * - Else, call the dequeue() function.
+ */
+ s = (struct new_sch_inst *)p;
+ sch_t = s->sched;
+ DN_S_LOCK(sch_t);
+
+ sch_t->inst_counter--;
+ if (sch_t->flags & DN_SCH_DELETE) {
+ /* Wait for scheduler->busy == 0 */
+ while(sch_t->busy) { /* XXX check */
+ DN_S_UNLOCK(sch_t);
+ DN_S_LOCK(sch_t);
+ }
+ /* Scheduler is deleting, don't dequeue packets from
+ * this instance
+ */
+ if (sch_t->inst_counter == 0) {
+ /* No other scheduler instance in the heap.
+ * We can safely delete scheduler
+ */
+ really_deletescheduler(sch_t);
+ DN_S_UNLOCK(sch_t); /* XXX */
+ }
+ } else {
+ head = serve_sched(s, curr_time);
+ DN_S_UNLOCK(sch_t);
+ if (head != NULL)
+ dummynet_send(head);
}
- }
-
- /* Sweep pipes trying to expire idle flow_queues. */
- for (i = 0; i < DN_HASHSIZE; i++) {
- SLIST_FOREACH(pipe, &pipehash[i], next) {
- if (pipe->idle_heap->elements > 0 &&
- DN_KEY_LT(HEAP_TOP(pipe->idle_heap)->key, pipe->V)) {
- struct dn_flow_queue *q =
- HEAP_TOP(pipe->idle_heap)->object;
-
- heap_extract(pipe->idle_heap, NULL);
- /* Mark timestamp as invalid. */
- q->S = q->F + 1;
- pipe->sum -= q->fs->weight;
- }
+ } else { /* extracted a delay line */
+ struct delay_line *dline = (struct delay_line *)p;
+ /*
+ * Managing delay lines.
+ * If the pointer to the scheduler instance is NULL, the delay
+ * line should be deleted because pipe or scheduler was deleted,
+ * else the transmit event is called to send out packets and
+ * eventually reinsert the delay line into the heap.
+ */
+ if (dline->si == NULL)
+ delete_delay_line(dline);
+ else {
+ DN_S_LOCK(dline->si->ptr_sched);
+ head = transmit_event(dline, curr_time);
+ DN_S_UNLOCK(dline->si->ptr_sched);
+ if (head != NULL)
+ dummynet_send(head);
}
- }
-
- DUMMYNET_UNLOCK();
-
- if (head != NULL)
- dummynet_send(head);
-#endif
+ }
+ }
dn_reschedule();
}
@@ -1047,19 +1119,6 @@ ipdn_locate_flowset(int fs_nr)
return (NULL);
}
-struct new_pipe *
-ipdn_locate_pipe(int pipe_nr)
-{
- struct new_pipe *pipe;
-
- SLIST_FOREACH(pipe, &pipehash[HASH(pipe_nr)], next)
- if (pipe->pipe_nr == pipe_nr)
- return (pipe);
-
- return (NULL);
-}
-
-
/*
* dummynet hook for packets. Below 'pipe' is a pipe or a queue
* depending on whether WF2Q or fixed bw is used.
@@ -1084,20 +1143,21 @@ dummynet_io(struct mbuf **m0, int dir, s
struct new_fs *fs = NULL;
struct new_pipe *pipe = NULL;
struct new_queue *q = NULL;
- int fs_id = fwa->rule.info & IPFW_INFO_MASK;
struct new_sch *sch;
struct new_sch_inst *sch_inst;
struct delay_line *dline;
int ret;
- dn_key l_curr_time; /* save a copy of curr_time */
+ dn_key now; /* save a copy of curr_time */
int delay_line_idle;
-
- if (fwa->rule.info & IPFW_IS_PIPE)
- fs_id += DN_PIPEOFFSET;
+ int fs_id = (fwa->rule.info & IPFW_INFO_MASK) +
+ (fwa->rule.info & IPFW_IS_PIPE) ? DN_PIPEOFFSET : 0;
KASSERT(m->m_nextpkt == NULL,
("dummynet_io: mbuf queue passed to dummynet"));
+ /*
+ * find flowset and schedset, protected by the UH lock
+ */
DUMMYNET_LOCK();
io_pkt++;
fs = ipdn_locate_flowset(fs_id);
@@ -1105,7 +1165,7 @@ dummynet_io(struct mbuf **m0, int dir, s
if (fs == NULL)
goto dropit; /* This queue/pipe does not exist! */
- if (fs->sched_id != dn_cfg.id) {
+ if (fs->sched_id != dn_cfg.id) { /* fs->sched invalid, update */
/* configuration changed, update */
int ret = dn_fs_config(fs);
if (ret)
@@ -1119,11 +1179,12 @@ dummynet_io(struct mbuf **m0, int dir, s
if (sch == NULL)
goto dropit;
pipe = sch->pipe;
- if (pipe == NULL) /* should not happen ? */
+ if (pipe == NULL) { /* should not happen ? */
+ printf("%s strange, scheduler without a pipe\n", __FUNCTION__);
goto dropit;
+ }
- l_curr_time = curr_time;
- sch_inst = find_scheduler(sch, fs, &(fwa->f_id), l_curr_time);
+ sch_inst = find_scheduler(sch, fs, &(fwa->f_id));
if (sch_inst == NULL)
goto dropit;
dline = sch_inst->dline;
@@ -1148,6 +1209,8 @@ dummynet_io(struct mbuf **m0, int dir, s
pkt->rule.info &= IPFW_ONEPASS; /* only keep this info */
pkt->dn_dir = dir;
pkt->ifp = fwa->oif;
+ now = curr_time; /* in case it changes, use the same value */
+ pkt->output_time = now; /* XXX rewritten when reaches head */
/*
* - 'sch_inst + 1' is the pointer to scheduler instance's
@@ -1158,82 +1221,45 @@ dummynet_io(struct mbuf **m0, int dir, s
* packet, it must call the queue_packet()
*/
- ret = sch->fp->enqueue(
- (sch_inst + 1), fs->alg_fs, m,
- &(fwa->f_id));
+ ret = sch->fp->enqueue(sch_inst + 1, fs->alg_fs, m, &(fwa->f_id));
if (ret) { /* packet was dropped by enqueue() */
*m0 = NULL;
goto dropit;
}
- /*
- * Now check if the dequeue should be called now.
- * If the instance is in the heap, the dequeue() will be called later,
- * else if the instance has credit the dequeue() is called now.
- */
- if (!(sch_inst->flags & DN_SCH_ACTIVE)) {
+ /*
+ * Now check if the dequeue should be called now.
+ * If the instance is in the heap, the dequeue() will be called later,
+ * and we are done.
+ */
+ if (sch_inst->flags & DN_SCH_ACTIVE)
+ goto done;
+ // XXX see if we can merge with dummynet task.
/* If the instance is not in the heap, credit must be >= 0 */
- struct mbuf *tosend;
- dn_key len_scaled;
- /* If the instance isn't in the heap, it is idle, so we can skip
- * some checks XXX
- */
- if (sch->burst) {
- sch_inst->numbytes = (l_curr_time - sch_inst->idle_time) *
+ sch_inst->numbytes = dn_cfg.io_fast ? pipe->bandwidth : 0;
+ if (pipe->burst) {
+ uint64_t burst = (now - sch_inst->idle_time) *
pipe->bandwidth;
- if (sch_inst->numbytes > sch->burst)
- sch_inst->numbytes = sch->burst;
- sch_inst->numbytes += dn_cfg.io_fast ? pipe->bandwidth : 0;
- } else
- sch_inst->numbytes = dn_cfg.io_fast ? pipe->bandwidth : 0;
-
- sch_inst->idle_time = l_curr_time;
-
- /* Doing an 'if' instead of 'while' because only the packet
- * just enqueued can be returned by dequeue() */
- tosend = sch->fp->dequeue(sch_inst + 1);
- if (tosend) {
- len_scaled = pipe->bandwidth ? tosend->m_pkthdr.len * 8 * hz +
- compute_extra_bits(tosend, pipe) * hz : 0;
- sch_inst->numbytes -= len_scaled;
- /* Move packet in the delay line XXX three parameters? */
- move_pkt(tosend, pipe, sch_inst->dline, l_curr_time);
- if (sch_inst->numbytes < 0) {
- /*
- * Credit became negative, so insert the instance in the
- * heap so that it will not be wake up until credit come
- * back positive
- * NOTE: numbytes < 0 implies bandwidth != 0.
- */
- dn_key t = 0, tmp;
- t = (pipe->bandwidth - 1 - sch_inst->numbytes) /
- pipe->bandwidth;
- /* Delay the output time because under credit */
- (dn_tag_get(dline->tail))->output_time += t;
-
- sch_inst->ptr_sched->inst_counter++;
- sch_inst->flags |= DN_SCH_ACTIVE;
- tmp = l_curr_time + t;
- //DN_HEAP_LOCK();
- heap_insert(system_heap, (uint64_t)tmp, sch_inst);
- //DN_HEAP_UNLOCK();
- }
- if (delay_line_idle)
- head = transmit_event(dline, l_curr_time);
+ if (burst > pipe->burst)
+ burst = pipe->burst;
+ sch_inst->numbytes += burst;
}
- }
+ head = serve_sched(sch_inst, now);
- if (dn_cfg.io_fast && head == m && (dir & PROTO_LAYER2) == 0 ) {
- /* fast io */
- io_pkt_fast++;
- printf("dummynet TEST: ** IOFAST **\n");
- if (m->m_nextpkt != NULL)
- printf("dummynet: fast io: pkt chain detected!\n");
- head = m->m_nextpkt = NULL;
- } else
- *m0 = NULL;
+ /* optimization -- pass it back to ipfw for immediate send */
+ if (dn_cfg.io_fast && head == m && (dir & PROTO_LAYER2) == 0 ) {
+ /* fast io */
+ io_pkt_fast++;
+ printf("dummynet TEST: ** IOFAST **\n");
+ if (m->m_nextpkt != NULL)
+ printf("dummynet: fast io: pkt chain detected!\n");
+ head = m->m_nextpkt = NULL;
+ } else {
+ *m0 = NULL;
+ }
+done:
DUMMYNET_UNLOCK();
if (head != NULL)
dummynet_send(head);
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 8 14:33:03 2010 (r201788)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 8 14:55:10 2010 (r201789)
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/ipfw/dn_heap.h>
#include <netinet/ip_dummynet.h>
#include <netinet/ipfw/ip_dn_private.h>
+#include <netinet/ipfw/dn_sched.h>
//#include <netinet/if_ether.h> /* various ether_* routines */
@@ -72,6 +73,9 @@ static int ip_dn_ctl(struct sockopt *sop
static struct callout dn_timeout;
static struct task dn_task;
static struct taskqueue *dn_tq = NULL;
+
+static struct dn_sched_head list_of_scheduler;
+
/*
* This is called one tick, after previous run. It is used to
* schedule next run.
@@ -91,6 +95,23 @@ dn_reschedule(void)
/*
+ * Return a scheduler descriptor given the type.
+ * If the descriptor isn't found, return NULL. This case shouldn't occur.
+ */
+static struct dn_sched *
+load_scheduler(int type)
+{
+ struct dn_sched *d = NULL;
+
+ SLIST_FOREACH(d, &list_of_scheduler, next) {
+ if (d->type == type)
+ return d;
+ }
+
+ return NULL; /* error */
+}
+
+/*
* Dispose a list of packet. Use an inline functions so if we
* need to free extra state associated to a packet, this is a
* central point to do it.
@@ -106,11 +127,71 @@ static __inline void dn_free_pkts(struct
}
}
+int
+delete_delay_line(struct delay_line *dline)
+{
+ struct mbuf *m;
+
+ m = dline->head;
+ dn_free_pkts(m);
+ free(dline, M_DUMMYNET);
+ return 0;
+}
+
+static int
+delete_scheduler_instance(struct new_sch_inst *si)
+{
+ struct new_sch *sch_t = si->sched;
+
+ sch_t->fp->free_sched(si + 1);
+ /* XXX packet from delay line must be freed */
+ if (si->dline->head == NULL || sch_t->flags & DN_SCH_DELETE_DELAY_LINE) {
+ /* Delay line empty, or forced delete, so delete delay line now */
+ delete_delay_line(si->dline);
+ } else {
+ /* Packet in delay line, will be removed when extracted from heap */
+ si->dline->si = NULL;
+ }
+ free(si, M_DUMMYNET);
+ return 0;
+}
+
+/*
+ * Called when no scheduler instances are in the heap, so it's safe
+ * to remove the scheduler template, scheduler hash table and scheduler
+ * instances
+ */
+int
+really_deletescheduler(struct new_sch *sch_t)
+{
+ int i;
+ struct new_sch_inst *si, *sid;
+
+ /* XXX checks, maybe all scheduler instance are deleted before */
+ for (i = 0; i < sch_t->sch_i_size; i++) {
+ si = sch_t->sch_i[i];
+ while (si) {
+ sid = si;
+ si = si->next;
+ /* remove scheduler instance */
+ delete_scheduler_instance(sid);
+ }
+ }
+ sch_t->fp->free_sched(sch_t + 1);
+ sch_t->fp->ref_count--;
+ DN_S_LOCK_DESTROY(sch_t);
+ if (sch_t->sch_i_size > 0)
+ free(sch_t->sch_i, M_DUMMYNET);
+ free(sch_t, M_DUMMYNET);
+ return 0;
+}
+
+
static void
free_pipe(struct new_pipe *p)
{
- if (p->samples)
- free(p->samples, M_DUMMYNET);
+ if (p->profile)
+ free(p->profile, M_DUMMYNET);
free(p, M_DUMMYNET);
}
@@ -322,6 +403,242 @@ do_config(void *p, int l)
return 0;
}
+static struct new_sch *
+locate_scheduler(int sch_nr)
+{
+ struct new_sch *sch;
+
+ SLIST_FOREACH(sch, &schedulerhash[HASH(sch_nr)], next)
+ if (sch->sched_nr == sch_nr)
+ return (sch);
+
+ return (NULL);
+}
+
+static struct new_pipe *
+locate_pipe(int pipe_nr)
+{
+ struct new_pipe *pipe;
+
+ SLIST_FOREACH(pipe, &pipehash[HASH(pipe_nr)], next)
+ if (pipe->pipe_nr == pipe_nr)
+ return (pipe);
+
+ return (NULL);
+}
+
+/*
+ * Starting from a flow set, check if pointers are ok.
+ * First, check if the scheduler exist and eventually if the pipe exists.
+ * If the scheduler is NULL, the flowset should be inserted in the unlinked
+ * flowset list and removed from flowset list. So new packet are discarded
+ * when they arrives, and this flowset become of general type and can be
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-user
mailing list