First step in removing welding between ipfw(4) and dummynet.
o Do not use ipfw_insn_pipe->pipe_ptr in locate_flowset(). The _ipfw_insn_pipe isn't touched by this commit to preserve ABI compatibility. o To optimize the lookup of the pipe/flowset in locate_flowset() introduce hashes for pipes and queues: - To preserve ABI compatibility utilize the place of global list pointer for SLIST_ENTRY. - Introduce locate_flowset(queue nr) and locate_pipe(pipe nr). o Rework all the dummynet code to deal with the hashes, not global lists. Also did some style(9) changes in the code blocks that were touched by this sweep: - Be conservative about flowset and pipe variable names on stack, use "fs" and "pipe" everywhere. - Cleanup whitespaces. - Sort variables. - Give variables more meaningful names. - Uppercase and dots in comments. - ENOMEM when malloc(9) failed.
This commit is contained in:
parent
9fb0767374
commit
99b41b34fb
@ -122,8 +122,10 @@ static void heap_extract(struct dn_heap *h, void *obj);
|
||||
static void transmit_event(struct dn_pipe *pipe);
|
||||
static void ready_event(struct dn_flow_queue *q);
|
||||
|
||||
static struct dn_pipe *all_pipes = NULL ; /* list of all pipes */
|
||||
static struct dn_flow_set *all_flow_sets = NULL ;/* list of all flow_sets */
|
||||
#define HASHSIZE 16
|
||||
#define HASH(num) ((((num) >> 8) ^ ((num) >> 4) ^ (num)) & 0x0f)
|
||||
static struct dn_pipe_head pipehash[HASHSIZE]; /* all pipes */
|
||||
static struct dn_flow_set_head flowsethash[HASHSIZE]; /* all flowsets */
|
||||
|
||||
static struct callout dn_timeout;
|
||||
|
||||
@ -750,11 +752,11 @@ ready_event_wfq(struct dn_pipe *p)
|
||||
static void
|
||||
dummynet(void * __unused unused)
|
||||
{
|
||||
void *p ; /* generic parameter to handler */
|
||||
struct dn_heap *h ;
|
||||
struct dn_pipe *pipe;
|
||||
struct dn_heap *heaps[3];
|
||||
struct dn_heap *h;
|
||||
void *p; /* generic parameter to handler */
|
||||
int i;
|
||||
struct dn_pipe *pe ;
|
||||
|
||||
heaps[0] = &ready_heap ; /* fixed-rate queues */
|
||||
heaps[1] = &wfq_ready_heap ; /* wfq queues */
|
||||
@ -783,16 +785,18 @@ dummynet(void * __unused unused)
|
||||
transmit_event(p);
|
||||
}
|
||||
}
|
||||
/* sweep pipes trying to expire idle flow_queues */
|
||||
for (pe = all_pipes; pe ; pe = pe->next )
|
||||
if (pe->idle_heap.elements > 0 &&
|
||||
DN_KEY_LT(pe->idle_heap.p[0].key, pe->V) ) {
|
||||
struct dn_flow_queue *q = pe->idle_heap.p[0].object ;
|
||||
/* Sweep pipes trying to expire idle flow_queues. */
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next)
|
||||
if (pipe->idle_heap.elements > 0 &&
|
||||
DN_KEY_LT(pipe->idle_heap.p[0].key, pipe->V) ) {
|
||||
struct dn_flow_queue *q = pipe->idle_heap.p[0].object;
|
||||
|
||||
heap_extract(&(pipe->idle_heap), NULL);
|
||||
q->S = q->F + 1; /* Mark timestamp as invalid. */
|
||||
pipe->sum -= q->fs->weight;
|
||||
}
|
||||
|
||||
heap_extract(&(pe->idle_heap), NULL);
|
||||
q->S = q->F + 1 ; /* mark timestamp as invalid */
|
||||
pe->sum -= q->fs->weight ;
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
|
||||
callout_reset(&dn_timeout, 1, dummynet, NULL);
|
||||
@ -804,26 +808,30 @@ dummynet(void * __unused unused)
|
||||
int
|
||||
if_tx_rdy(struct ifnet *ifp)
|
||||
{
|
||||
struct dn_pipe *p;
|
||||
struct dn_pipe *pipe;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
for (p = all_pipes; p ; p = p->next )
|
||||
if (p->ifp == ifp)
|
||||
break ;
|
||||
if (p == NULL) {
|
||||
for (p = all_pipes; p ; p = p->next )
|
||||
if (!strcmp(p->if_name, ifp->if_xname) ) {
|
||||
p->ifp = ifp ;
|
||||
DPRINTF(("dummynet: ++ tx rdy from %s (now found)\n",
|
||||
ifp->if_xname));
|
||||
break ;
|
||||
}
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next)
|
||||
if (pipe->ifp == ifp)
|
||||
break;
|
||||
if (pipe == NULL) {
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next)
|
||||
if (!strcmp(pipe->if_name, ifp->if_xname) ) {
|
||||
pipe->ifp = ifp ;
|
||||
DPRINTF(("dummynet: ++ tx rdy from %s (now found)\n",
|
||||
ifp->if_xname));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p != NULL) {
|
||||
|
||||
if (pipe != NULL) {
|
||||
DPRINTF(("dummynet: ++ tx rdy from %s - qlen %d\n", ifp->if_xname,
|
||||
ifp->if_snd.ifq_len));
|
||||
p->numbytes = 0 ; /* mark ready for I/O */
|
||||
ready_event_wfq(p);
|
||||
pipe->numbytes = 0; /* Mark ready for I/O. */
|
||||
ready_event_wfq(pipe);
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
|
||||
@ -1107,41 +1115,28 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
|
||||
return 0 ; /* accept */
|
||||
}
|
||||
|
||||
static __inline
|
||||
struct dn_flow_set *
|
||||
locate_flowset(int pipe_nr, struct ip_fw *rule)
|
||||
static __inline struct dn_flow_set *
|
||||
locate_flowset(int fs_nr)
|
||||
{
|
||||
struct dn_flow_set *fs;
|
||||
ipfw_insn *cmd = ACTION_PTR(rule);
|
||||
struct dn_flow_set *fs;
|
||||
|
||||
if (cmd->opcode == O_LOG)
|
||||
cmd += F_LEN(cmd);
|
||||
#ifdef __i386__
|
||||
fs = ((ipfw_insn_pipe *)cmd)->pipe_ptr;
|
||||
#else
|
||||
bcopy(& ((ipfw_insn_pipe *)cmd)->pipe_ptr, &fs, sizeof(fs));
|
||||
#endif
|
||||
SLIST_FOREACH(fs, &flowsethash[HASH(fs_nr)], next)
|
||||
if (fs->fs_nr == fs_nr)
|
||||
return (fs);
|
||||
|
||||
if (fs != NULL)
|
||||
return fs;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (cmd->opcode == O_QUEUE)
|
||||
for (fs=all_flow_sets; fs && fs->fs_nr != pipe_nr; fs=fs->next)
|
||||
;
|
||||
else {
|
||||
struct dn_pipe *p1;
|
||||
for (p1 = all_pipes; p1 && p1->pipe_nr != pipe_nr; p1 = p1->next)
|
||||
;
|
||||
if (p1 != NULL)
|
||||
fs = &(p1->fs) ;
|
||||
}
|
||||
/* record for the future */
|
||||
#ifdef __i386__
|
||||
((ipfw_insn_pipe *)cmd)->pipe_ptr = fs;
|
||||
#else
|
||||
bcopy(&fs, & ((ipfw_insn_pipe *)cmd)->pipe_ptr, sizeof(fs));
|
||||
#endif
|
||||
return fs ;
|
||||
static __inline struct dn_pipe *
|
||||
locate_pipe(int pipe_nr)
|
||||
{
|
||||
struct dn_pipe *pipe;
|
||||
|
||||
SLIST_FOREACH(pipe, &pipehash[HASH(pipe_nr)], next)
|
||||
if (pipe->pipe_nr == pipe_nr)
|
||||
return (pipe);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1162,7 +1157,7 @@ dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa)
|
||||
{
|
||||
struct dn_pkt_tag *pkt;
|
||||
struct m_tag *mtag;
|
||||
struct dn_flow_set *fs;
|
||||
struct dn_flow_set *fs = NULL;
|
||||
struct dn_pipe *pipe ;
|
||||
u_int64_t len = m->m_pkthdr.len ;
|
||||
struct dn_flow_queue *q = NULL ;
|
||||
@ -1179,17 +1174,24 @@ dummynet_io(struct mbuf *m, int dir, struct ip_fw_args *fwa)
|
||||
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.
|
||||
*/
|
||||
fs = locate_flowset(fwa->cookie, fwa->rule);
|
||||
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 */
|
||||
for (pipe = all_pipes; pipe && pipe->pipe_nr != fs->parent_nr;
|
||||
pipe = pipe->next)
|
||||
;
|
||||
if (is_pipe) {
|
||||
pipe = locate_pipe(fwa->cookie);
|
||||
if (pipe != NULL)
|
||||
fs->pipe = pipe ;
|
||||
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);
|
||||
@ -1403,41 +1405,35 @@ purge_pipe(struct dn_pipe *pipe)
|
||||
static void
|
||||
dummynet_flush(void)
|
||||
{
|
||||
struct dn_pipe *curr_p, *p ;
|
||||
struct dn_flow_set *fs, *curr_fs;
|
||||
struct dn_pipe *pipe, *pipe1;
|
||||
struct dn_flow_set *fs, *fs1;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/* remove all references to pipes ...*/
|
||||
flush_pipe_ptrs(NULL);
|
||||
/* prevent future matches... */
|
||||
p = all_pipes ;
|
||||
all_pipes = NULL ;
|
||||
fs = all_flow_sets ;
|
||||
all_flow_sets = NULL ;
|
||||
/* and free heaps so we don't have unwanted events */
|
||||
heap_free(&ready_heap);
|
||||
heap_free(&wfq_ready_heap);
|
||||
heap_free(&extract_heap);
|
||||
DUMMYNET_LOCK();
|
||||
/* Free heaps so we don't have unwanted events. */
|
||||
heap_free(&ready_heap);
|
||||
heap_free(&wfq_ready_heap);
|
||||
heap_free(&extract_heap);
|
||||
|
||||
/*
|
||||
* Now purge all queued pkts and delete all pipes
|
||||
*/
|
||||
/* scan and purge all flow_sets. */
|
||||
for ( ; fs ; ) {
|
||||
curr_fs = fs ;
|
||||
fs = fs->next ;
|
||||
purge_flow_set(curr_fs, 1);
|
||||
}
|
||||
for ( ; p ; ) {
|
||||
purge_pipe(p);
|
||||
curr_p = p ;
|
||||
p = p->next ;
|
||||
free(curr_p, M_DUMMYNET);
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
/*
|
||||
* Now purge all queued pkts and delete all pipes.
|
||||
*
|
||||
* XXXGL: can we merge the for(;;) cycles into one or not?
|
||||
*/
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH_SAFE(fs, &flowsethash[i], next, fs1) {
|
||||
SLIST_REMOVE(&flowsethash[i], fs, dn_flow_set, next);
|
||||
purge_flow_set(fs, 1);
|
||||
}
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH_SAFE(pipe, &pipehash[i], next, pipe1) {
|
||||
SLIST_REMOVE(&pipehash[i], pipe, dn_pipe, next);
|
||||
purge_pipe(pipe);
|
||||
free(pipe, M_DUMMYNET);
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
extern struct ip_fw *ip_fw_default_rule ;
|
||||
static void
|
||||
dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
|
||||
@ -1461,10 +1457,11 @@ dn_rule_delete_fs(struct dn_flow_set *fs, void *r)
|
||||
void
|
||||
dn_rule_delete(void *r)
|
||||
{
|
||||
struct dn_pipe *p ;
|
||||
struct dn_flow_set *fs ;
|
||||
struct dn_pkt_tag *pkt ;
|
||||
struct mbuf *m ;
|
||||
struct dn_pipe *pipe;
|
||||
struct dn_flow_set *fs;
|
||||
struct dn_pkt_tag *pkt;
|
||||
struct mbuf *m;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/*
|
||||
@ -1472,17 +1469,20 @@ dn_rule_delete(void *r)
|
||||
* the flow set, otherwise scan pipes. Should do either, but doing
|
||||
* both does not harm.
|
||||
*/
|
||||
for ( fs = all_flow_sets ; fs ; fs = fs->next )
|
||||
dn_rule_delete_fs(fs, r);
|
||||
for ( p = all_pipes ; p ; p = p->next ) {
|
||||
fs = &(p->fs) ;
|
||||
dn_rule_delete_fs(fs, r);
|
||||
for (m = p->head ; m ; m = m->m_nextpkt ) {
|
||||
pkt = dn_tag_get(m) ;
|
||||
if (pkt->rule == r)
|
||||
pkt->rule = ip_fw_default_rule ;
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(fs, &flowsethash[i], next)
|
||||
dn_rule_delete_fs(fs, r);
|
||||
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next) {
|
||||
fs = &(pipe->fs);
|
||||
dn_rule_delete_fs(fs, r);
|
||||
for (m = pipe->head ; m ; m = m->m_nextpkt ) {
|
||||
pkt = dn_tag_get(m);
|
||||
if (pkt->rule == r)
|
||||
pkt->rule = ip_fw_default_rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
}
|
||||
|
||||
@ -1559,7 +1559,7 @@ alloc_hash(struct dn_flow_set *x, struct dn_flow_set *pfs)
|
||||
M_DUMMYNET, M_NOWAIT | M_ZERO);
|
||||
if (x->rq == NULL) {
|
||||
printf("dummynet: sorry, cannot allocate queue\n");
|
||||
return ENOSPC;
|
||||
return (ENOMEM);
|
||||
}
|
||||
x->rq_elements = 0;
|
||||
return 0 ;
|
||||
@ -1593,9 +1593,9 @@ set_fs_parms(struct dn_flow_set *x, struct dn_flow_set *src)
|
||||
static int
|
||||
config_pipe(struct dn_pipe *p)
|
||||
{
|
||||
int i, r;
|
||||
struct dn_flow_set *pfs = &(p->fs);
|
||||
struct dn_flow_queue *q;
|
||||
int i, error;
|
||||
|
||||
/*
|
||||
* The config program passes parameters as follows:
|
||||
@ -1610,104 +1610,91 @@ config_pipe(struct dn_pipe *p)
|
||||
if (p->pipe_nr != 0 && pfs->fs_nr != 0)
|
||||
return EINVAL ;
|
||||
if (p->pipe_nr != 0) { /* this is a pipe */
|
||||
struct dn_pipe *x, *a, *b;
|
||||
struct dn_pipe *pipe;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/* locate pipe */
|
||||
for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
|
||||
a = b , b = b->next) ;
|
||||
pipe = locate_pipe(p->pipe_nr); /* locate pipe */
|
||||
|
||||
if (b == NULL || b->pipe_nr != p->pipe_nr) { /* new pipe */
|
||||
x = malloc(sizeof(struct dn_pipe), M_DUMMYNET, M_NOWAIT | M_ZERO);
|
||||
if (x == NULL) {
|
||||
if (pipe == NULL) { /* new pipe */
|
||||
pipe = malloc(sizeof(struct dn_pipe), M_DUMMYNET,
|
||||
M_NOWAIT | M_ZERO);
|
||||
if (pipe == NULL) {
|
||||
DUMMYNET_UNLOCK();
|
||||
printf("dummynet: no memory for new pipe\n");
|
||||
return ENOSPC;
|
||||
return (ENOMEM);
|
||||
}
|
||||
x->pipe_nr = p->pipe_nr;
|
||||
x->fs.pipe = x ;
|
||||
pipe->pipe_nr = p->pipe_nr;
|
||||
pipe->fs.pipe = pipe ;
|
||||
/* idle_heap is the only one from which we extract from the middle.
|
||||
*/
|
||||
x->idle_heap.size = x->idle_heap.elements = 0 ;
|
||||
x->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos);
|
||||
} else {
|
||||
x = b;
|
||||
pipe->idle_heap.size = pipe->idle_heap.elements = 0 ;
|
||||
pipe->idle_heap.offset=OFFSET_OF(struct dn_flow_queue, heap_pos);
|
||||
} else
|
||||
/* Flush accumulated credit for all queues */
|
||||
for (i = 0; i <= x->fs.rq_size; i++)
|
||||
for (q = x->fs.rq[i]; q; q = q->next)
|
||||
for (i = 0; i <= pipe->fs.rq_size; i++)
|
||||
for (q = pipe->fs.rq[i]; q; q = q->next)
|
||||
q->numbytes = 0;
|
||||
}
|
||||
|
||||
x->bandwidth = p->bandwidth ;
|
||||
x->numbytes = 0; /* just in case... */
|
||||
bcopy(p->if_name, x->if_name, sizeof(p->if_name) );
|
||||
x->ifp = NULL ; /* reset interface ptr */
|
||||
x->delay = p->delay ;
|
||||
set_fs_parms(&(x->fs), pfs);
|
||||
pipe->bandwidth = p->bandwidth ;
|
||||
pipe->numbytes = 0; /* just in case... */
|
||||
bcopy(p->if_name, pipe->if_name, sizeof(p->if_name) );
|
||||
pipe->ifp = NULL ; /* reset interface ptr */
|
||||
pipe->delay = p->delay ;
|
||||
set_fs_parms(&(pipe->fs), pfs);
|
||||
|
||||
|
||||
if ( x->fs.rq == NULL ) { /* a new pipe */
|
||||
r = alloc_hash(&(x->fs), pfs) ;
|
||||
if (r) {
|
||||
if (pipe->fs.rq == NULL) { /* a new pipe */
|
||||
error = alloc_hash(&(pipe->fs), pfs);
|
||||
if (error) {
|
||||
DUMMYNET_UNLOCK();
|
||||
free(x, M_DUMMYNET);
|
||||
return r ;
|
||||
free(pipe, M_DUMMYNET);
|
||||
return (error);
|
||||
}
|
||||
x->next = b ;
|
||||
if (a == NULL)
|
||||
all_pipes = x ;
|
||||
else
|
||||
a->next = x ;
|
||||
SLIST_INSERT_HEAD(&pipehash[HASH(pipe->pipe_nr)], pipe, next);
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
} else { /* config queue */
|
||||
struct dn_flow_set *x, *a, *b ;
|
||||
struct dn_flow_set *fs;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/* locate flow_set */
|
||||
for (a=NULL, b=all_flow_sets ; b && b->fs_nr < pfs->fs_nr ;
|
||||
a = b , b = b->next) ;
|
||||
fs = locate_flowset(pfs->fs_nr); /* locate flow_set */
|
||||
|
||||
if (b == NULL || b->fs_nr != pfs->fs_nr) { /* new */
|
||||
if (fs == NULL) { /* new */
|
||||
if (pfs->parent_nr == 0) { /* need link to a pipe */
|
||||
DUMMYNET_UNLOCK();
|
||||
return EINVAL ;
|
||||
}
|
||||
x = malloc(sizeof(struct dn_flow_set), M_DUMMYNET, M_NOWAIT|M_ZERO);
|
||||
if (x == NULL) {
|
||||
fs = malloc(sizeof(struct dn_flow_set), M_DUMMYNET,
|
||||
M_NOWAIT|M_ZERO);
|
||||
if (fs == NULL) {
|
||||
DUMMYNET_UNLOCK();
|
||||
printf("dummynet: no memory for new flow_set\n");
|
||||
return ENOSPC;
|
||||
return (ENOMEM);
|
||||
}
|
||||
x->fs_nr = pfs->fs_nr;
|
||||
x->parent_nr = pfs->parent_nr;
|
||||
x->weight = pfs->weight ;
|
||||
if (x->weight == 0)
|
||||
x->weight = 1 ;
|
||||
else if (x->weight > 100)
|
||||
x->weight = 100 ;
|
||||
fs->fs_nr = pfs->fs_nr;
|
||||
fs->parent_nr = pfs->parent_nr;
|
||||
fs->weight = pfs->weight;
|
||||
if (fs->weight == 0)
|
||||
fs->weight = 1;
|
||||
else if (fs->weight > 100)
|
||||
fs->weight = 100;
|
||||
} else {
|
||||
/* Change parent pipe not allowed; must delete and recreate */
|
||||
if (pfs->parent_nr != 0 && b->parent_nr != pfs->parent_nr) {
|
||||
if (pfs->parent_nr != 0 && fs->parent_nr != pfs->parent_nr) {
|
||||
DUMMYNET_UNLOCK();
|
||||
return EINVAL ;
|
||||
}
|
||||
x = b;
|
||||
}
|
||||
set_fs_parms(x, pfs);
|
||||
set_fs_parms(fs, pfs);
|
||||
|
||||
if ( x->rq == NULL ) { /* a new flow_set */
|
||||
r = alloc_hash(x, pfs) ;
|
||||
if (r) {
|
||||
if (fs->rq == NULL) { /* a new flow_set */
|
||||
error = alloc_hash(fs, pfs);
|
||||
if (error) {
|
||||
DUMMYNET_UNLOCK();
|
||||
free(x, M_DUMMYNET);
|
||||
return r ;
|
||||
free(fs, M_DUMMYNET);
|
||||
return (error);
|
||||
}
|
||||
x->next = b;
|
||||
if (a == NULL)
|
||||
all_flow_sets = x;
|
||||
else
|
||||
a->next = x;
|
||||
SLIST_INSERT_HEAD(&flowsethash[HASH(fs->fs_nr)], fs, next);
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
}
|
||||
@ -1759,8 +1746,9 @@ void
|
||||
dummynet_drain()
|
||||
{
|
||||
struct dn_flow_set *fs;
|
||||
struct dn_pipe *p;
|
||||
struct dn_pipe *pipe;
|
||||
struct mbuf *m, *mnext;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK_ASSERT();
|
||||
|
||||
@ -1768,18 +1756,21 @@ dummynet_drain()
|
||||
heap_free(&wfq_ready_heap);
|
||||
heap_free(&extract_heap);
|
||||
/* remove all references to this pipe from flow_sets */
|
||||
for (fs = all_flow_sets; fs; fs= fs->next )
|
||||
purge_flow_set(fs, 0);
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(fs, &flowsethash[i], next)
|
||||
purge_flow_set(fs, 0);
|
||||
|
||||
for (p = all_pipes; p; p= p->next ) {
|
||||
purge_flow_set(&(p->fs), 0);
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next) {
|
||||
purge_flow_set(&(pipe->fs), 0);
|
||||
|
||||
mnext = p->head;
|
||||
while ((m = mnext) != NULL) {
|
||||
mnext = m->m_nextpkt;
|
||||
DN_FREE_PKT(m);
|
||||
mnext = pipe->head;
|
||||
while ((m = mnext) != NULL) {
|
||||
mnext = m->m_nextpkt;
|
||||
DN_FREE_PKT(m);
|
||||
}
|
||||
pipe->head = pipe->tail = NULL;
|
||||
}
|
||||
p->head = p->tail = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1794,71 +1785,62 @@ delete_pipe(struct dn_pipe *p)
|
||||
if (p->pipe_nr != 0 && p->fs.fs_nr != 0)
|
||||
return EINVAL ;
|
||||
if (p->pipe_nr != 0) { /* this is an old-style pipe */
|
||||
struct dn_pipe *a, *b;
|
||||
struct dn_pipe *pipe;
|
||||
struct dn_flow_set *fs;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
pipe = locate_pipe(p->pipe_nr); /* locate pipe */
|
||||
|
||||
if (pipe == NULL) {
|
||||
DUMMYNET_UNLOCK();
|
||||
return (ENOENT); /* not found */
|
||||
}
|
||||
|
||||
/* Unlink from list of pipes. */
|
||||
SLIST_REMOVE(&pipehash[HASH(pipe->pipe_nr)], pipe, dn_pipe, next);
|
||||
|
||||
/* Remove all references to this pipe from flow_sets. */
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(fs, &flowsethash[i], next)
|
||||
if (fs->pipe == pipe) {
|
||||
printf("dummynet: ++ ref to pipe %d from fs %d\n",
|
||||
p->pipe_nr, fs->fs_nr);
|
||||
fs->pipe = NULL ;
|
||||
purge_flow_set(fs, 0);
|
||||
}
|
||||
fs_remove_from_heap(&ready_heap, &(pipe->fs));
|
||||
purge_pipe(pipe); /* remove all data associated to this pipe */
|
||||
/* remove reference to here from extract_heap and wfq_ready_heap */
|
||||
pipe_remove_from_heap(&extract_heap, pipe);
|
||||
pipe_remove_from_heap(&wfq_ready_heap, pipe);
|
||||
DUMMYNET_UNLOCK();
|
||||
|
||||
free(pipe, M_DUMMYNET);
|
||||
} else { /* this is a WF2Q queue (dn_flow_set) */
|
||||
struct dn_flow_set *fs;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/* locate pipe */
|
||||
for (a = NULL , b = all_pipes ; b && b->pipe_nr < p->pipe_nr ;
|
||||
a = b , b = b->next) ;
|
||||
if (b == NULL || (b->pipe_nr != p->pipe_nr) ) {
|
||||
fs = locate_flowset(p->fs.fs_nr); /* locate set */
|
||||
|
||||
if (fs == NULL) {
|
||||
DUMMYNET_UNLOCK();
|
||||
return EINVAL ; /* not found */
|
||||
return (ENOENT); /* not found */
|
||||
}
|
||||
|
||||
/* unlink from list of pipes */
|
||||
if (a == NULL)
|
||||
all_pipes = b->next ;
|
||||
else
|
||||
a->next = b->next ;
|
||||
/* remove references to this pipe from the ip_fw rules. */
|
||||
flush_pipe_ptrs(&(b->fs));
|
||||
/* Unlink from list of flowsets. */
|
||||
SLIST_REMOVE( &flowsethash[HASH(fs->fs_nr)], fs, dn_flow_set, next);
|
||||
|
||||
/* remove all references to this pipe from flow_sets */
|
||||
for (fs = all_flow_sets; fs; fs= fs->next )
|
||||
if (fs->pipe == b) {
|
||||
printf("dummynet: ++ ref to pipe %d from fs %d\n",
|
||||
p->pipe_nr, fs->fs_nr);
|
||||
fs->pipe = NULL ;
|
||||
purge_flow_set(fs, 0);
|
||||
}
|
||||
fs_remove_from_heap(&ready_heap, &(b->fs));
|
||||
purge_pipe(b); /* remove all data associated to this pipe */
|
||||
/* remove reference to here from extract_heap and wfq_ready_heap */
|
||||
pipe_remove_from_heap(&extract_heap, b);
|
||||
pipe_remove_from_heap(&wfq_ready_heap, b);
|
||||
DUMMYNET_UNLOCK();
|
||||
|
||||
free(b, M_DUMMYNET);
|
||||
} else { /* this is a WF2Q queue (dn_flow_set) */
|
||||
struct dn_flow_set *a, *b;
|
||||
|
||||
DUMMYNET_LOCK();
|
||||
/* locate set */
|
||||
for (a = NULL, b = all_flow_sets ; b && b->fs_nr < p->fs.fs_nr ;
|
||||
a = b , b = b->next) ;
|
||||
if (b == NULL || (b->fs_nr != p->fs.fs_nr) ) {
|
||||
DUMMYNET_UNLOCK();
|
||||
return EINVAL ; /* not found */
|
||||
}
|
||||
|
||||
if (a == NULL)
|
||||
all_flow_sets = b->next ;
|
||||
else
|
||||
a->next = b->next ;
|
||||
/* remove references to this flow_set from the ip_fw rules. */
|
||||
flush_pipe_ptrs(b);
|
||||
|
||||
if (b->pipe != NULL) {
|
||||
/* Update total weight on parent pipe and cleanup parent heaps */
|
||||
b->pipe->sum -= b->weight * b->backlogged ;
|
||||
fs_remove_from_heap(&(b->pipe->not_eligible_heap), b);
|
||||
fs_remove_from_heap(&(b->pipe->scheduler_heap), b);
|
||||
if (fs->pipe != NULL) {
|
||||
/* Update total weight on parent pipe and cleanup parent heaps. */
|
||||
fs->pipe->sum -= fs->weight * fs->backlogged ;
|
||||
fs_remove_from_heap(&(fs->pipe->not_eligible_heap), fs);
|
||||
fs_remove_from_heap(&(fs->pipe->scheduler_heap), fs);
|
||||
#if 1 /* XXX should i remove from idle_heap as well ? */
|
||||
fs_remove_from_heap(&(b->pipe->idle_heap), b);
|
||||
fs_remove_from_heap(&(fs->pipe->idle_heap), fs);
|
||||
#endif
|
||||
}
|
||||
purge_flow_set(b, 1);
|
||||
purge_flow_set(fs, 1);
|
||||
DUMMYNET_UNLOCK();
|
||||
}
|
||||
return 0 ;
|
||||
@ -1899,21 +1881,24 @@ dn_copy_set(struct dn_flow_set *set, char *bp)
|
||||
static size_t
|
||||
dn_calc_size(void)
|
||||
{
|
||||
struct dn_flow_set *set ;
|
||||
struct dn_pipe *p ;
|
||||
size_t size ;
|
||||
struct dn_flow_set *fs;
|
||||
struct dn_pipe *pipe;
|
||||
size_t size = 0;
|
||||
int i;
|
||||
|
||||
DUMMYNET_LOCK_ASSERT();
|
||||
/*
|
||||
* compute size of data structures: list of pipes and flow_sets.
|
||||
* Compute size of data structures: list of pipes and flow_sets.
|
||||
*/
|
||||
for (p = all_pipes, size = 0 ; p ; p = p->next )
|
||||
size += sizeof( *p ) +
|
||||
p->fs.rq_elements * sizeof(struct dn_flow_queue);
|
||||
for (set = all_flow_sets ; set ; set = set->next )
|
||||
size += sizeof ( *set ) +
|
||||
set->rq_elements * sizeof(struct dn_flow_queue);
|
||||
return size ;
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next)
|
||||
size += sizeof(*pipe) +
|
||||
pipe->fs.rq_elements * sizeof(struct dn_flow_queue);
|
||||
SLIST_FOREACH(fs, &flowsethash[i], next)
|
||||
size += sizeof (*fs) +
|
||||
fs->rq_elements * sizeof(struct dn_flow_queue);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1921,8 +1906,8 @@ dummynet_get(struct sockopt *sopt)
|
||||
{
|
||||
char *buf, *bp ; /* bp is the "copy-pointer" */
|
||||
size_t size ;
|
||||
struct dn_flow_set *set ;
|
||||
struct dn_pipe *p ;
|
||||
struct dn_flow_set *fs;
|
||||
struct dn_pipe *pipe;
|
||||
int error=0, i ;
|
||||
|
||||
/* XXX lock held too long */
|
||||
@ -1945,42 +1930,48 @@ dummynet_get(struct sockopt *sopt)
|
||||
DUMMYNET_UNLOCK();
|
||||
return ENOBUFS ;
|
||||
}
|
||||
for (p = all_pipes, bp = buf ; p ; p = p->next ) {
|
||||
struct dn_pipe *pipe_bp = (struct dn_pipe *)bp ;
|
||||
bp = buf;
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(pipe, &pipehash[i], next) {
|
||||
struct dn_pipe *pipe_bp = (struct dn_pipe *)bp;
|
||||
|
||||
/*
|
||||
* copy pipe descriptor into *bp, convert delay back to ms,
|
||||
* then copy the flow_set descriptor(s) one at a time.
|
||||
* After each flow_set, copy the queue descriptor it owns.
|
||||
*/
|
||||
bcopy(p, bp, sizeof( *p ) );
|
||||
pipe_bp->delay = (pipe_bp->delay * 1000) / hz ;
|
||||
/*
|
||||
* XXX the following is a hack based on ->next being the
|
||||
* first field in dn_pipe and dn_flow_set. The correct
|
||||
* solution would be to move the dn_flow_set to the beginning
|
||||
* of struct dn_pipe.
|
||||
*/
|
||||
pipe_bp->next = (struct dn_pipe *)DN_IS_PIPE ;
|
||||
/* clean pointers */
|
||||
pipe_bp->head = pipe_bp->tail = NULL ;
|
||||
pipe_bp->fs.next = NULL ;
|
||||
pipe_bp->fs.pipe = NULL ;
|
||||
pipe_bp->fs.rq = NULL ;
|
||||
/*
|
||||
* Copy pipe descriptor into *bp, convert delay back to ms,
|
||||
* then copy the flow_set descriptor(s) one at a time.
|
||||
* After each flow_set, copy the queue descriptor it owns.
|
||||
*/
|
||||
bcopy(pipe, bp, sizeof(*pipe));
|
||||
pipe_bp->delay = (pipe_bp->delay * 1000) / hz;
|
||||
/*
|
||||
* XXX the following is a hack based on ->next being the
|
||||
* first field in dn_pipe and dn_flow_set. The correct
|
||||
* solution would be to move the dn_flow_set to the beginning
|
||||
* of struct dn_pipe.
|
||||
*/
|
||||
pipe_bp->next.sle_next = (struct dn_pipe *)DN_IS_PIPE;
|
||||
/* Clean pointers. */
|
||||
pipe_bp->head = pipe_bp->tail = NULL;
|
||||
pipe_bp->fs.next.sle_next = NULL;
|
||||
pipe_bp->fs.pipe = NULL;
|
||||
pipe_bp->fs.rq = NULL;
|
||||
|
||||
bp += sizeof(*pipe) ;
|
||||
bp = dn_copy_set(&(pipe->fs), bp);
|
||||
}
|
||||
|
||||
for (i = 0; i < HASHSIZE; i++)
|
||||
SLIST_FOREACH(fs, &flowsethash[i], next) {
|
||||
struct dn_flow_set *fs_bp = (struct dn_flow_set *)bp;
|
||||
|
||||
bcopy(fs, bp, sizeof(*fs));
|
||||
/* XXX same hack as above */
|
||||
fs_bp->next.sle_next = (struct dn_flow_set *)DN_IS_QUEUE;
|
||||
fs_bp->pipe = NULL;
|
||||
fs_bp->rq = NULL;
|
||||
bp += sizeof(*fs);
|
||||
bp = dn_copy_set(fs, bp);
|
||||
}
|
||||
|
||||
bp += sizeof( *p ) ;
|
||||
bp = dn_copy_set( &(p->fs), bp );
|
||||
}
|
||||
for (set = all_flow_sets ; set ; set = set->next ) {
|
||||
struct dn_flow_set *fs_bp = (struct dn_flow_set *)bp ;
|
||||
bcopy(set, bp, sizeof( *set ) );
|
||||
/* XXX same hack as above */
|
||||
fs_bp->next = (struct dn_flow_set *)DN_IS_QUEUE ;
|
||||
fs_bp->pipe = NULL ;
|
||||
fs_bp->rq = NULL ;
|
||||
bp += sizeof( *set ) ;
|
||||
bp = dn_copy_set( set, bp );
|
||||
}
|
||||
DUMMYNET_UNLOCK();
|
||||
|
||||
error = sooptcopyout(sopt, buf, size);
|
||||
@ -2045,13 +2036,17 @@ ip_dn_ctl(struct sockopt *sopt)
|
||||
static void
|
||||
ip_dn_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bootverbose)
|
||||
printf("DUMMYNET with IPv6 initialized (040826)\n");
|
||||
|
||||
DUMMYNET_LOCK_INIT();
|
||||
|
||||
all_pipes = NULL ;
|
||||
all_flow_sets = NULL ;
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
SLIST_INIT(&pipehash[i]);
|
||||
SLIST_INIT(&flowsethash[i]);
|
||||
}
|
||||
ready_heap.size = ready_heap.elements = 0 ;
|
||||
ready_heap.offset = 0 ;
|
||||
|
||||
|
@ -249,7 +249,7 @@ struct dn_flow_queue {
|
||||
* latter case, the structure is located inside the struct dn_pipe).
|
||||
*/
|
||||
struct dn_flow_set {
|
||||
struct dn_flow_set *next; /* next flow set in all_flow_sets list */
|
||||
SLIST_ENTRY(dn_flow_set) next; /* linked list in a hash slot */
|
||||
|
||||
u_short fs_nr ; /* flow_set number */
|
||||
u_short flags_fs;
|
||||
@ -297,7 +297,8 @@ struct dn_flow_set {
|
||||
int lookup_weight ; /* equal to (1-w_q)^t / (1-w_q)^(t+1) */
|
||||
int avg_pkt_size ; /* medium packet size */
|
||||
int max_pkt_size ; /* max packet size */
|
||||
} ;
|
||||
};
|
||||
SLIST_HEAD(dn_flow_set_head, dn_flow_set);
|
||||
|
||||
/*
|
||||
* Pipe descriptor. Contains global parameters, delay-line queue,
|
||||
@ -314,7 +315,7 @@ struct dn_flow_set {
|
||||
*
|
||||
*/
|
||||
struct dn_pipe { /* a pipe */
|
||||
struct dn_pipe *next ;
|
||||
SLIST_ENTRY(dn_pipe) next; /* linked list in a hash slot */
|
||||
|
||||
int pipe_nr ; /* number */
|
||||
int bandwidth; /* really, bytes/tick. */
|
||||
@ -343,6 +344,7 @@ struct dn_pipe { /* a pipe */
|
||||
|
||||
struct dn_flow_set fs ; /* used with fixed-rate flows */
|
||||
};
|
||||
SLIST_HEAD(dn_pipe_head, dn_pipe);
|
||||
|
||||
#ifdef _KERNEL
|
||||
typedef int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
|
||||
|
Loading…
Reference in New Issue
Block a user