svn commit: r202660 - in user/luigi/ipfw3-head: sbin/ipfw
sys/netinet/ipfw
Luigi Rizzo
luigi at FreeBSD.org
Tue Jan 19 23:03:09 UTC 2010
Author: luigi
Date: Tue Jan 19 23:03:08 2010
New Revision: 202660
URL: http://svn.freebsd.org/changeset/base/202660
Log:
fix reconfiguration (still dropping packets in the process)
Modified:
user/luigi/ipfw3-head/sbin/ipfw/dummynet.c
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_dn_private.h
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 Tue Jan 19 22:44:29 2010 (r202659)
+++ user/luigi/ipfw3-head/sbin/ipfw/dummynet.c Tue Jan 19 23:03:08 2010 (r202660)
@@ -1104,8 +1104,10 @@ end_mask:
p->bandwidth = 0;
}
if (fs) {
+#if 0 /* XXX accept a 0 scheduler to keep the default */
if (fs->sched_nr == 0)
errx(EX_DATAERR, "sched must be > 0");
+#endif
if (fs->flags & DN_QSIZE_IS_BYTES) {
size_t len;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Tue Jan 19 22:44:29 2010 (r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Tue Jan 19 23:03:08 2010 (r202660)
@@ -125,7 +125,7 @@ struct dn_sched {
* if the refcount becomes 0
*/
void dn_free_pkts(struct mbuf *mnext);
-struct new_queue *dn_delete_queue(struct new_queue *, int do_free);
+void dn_delete_queue(struct new_queue *, int do_free);
int dn_enqueue(struct new_queue *q, struct mbuf* m, int drop);
/*
@@ -145,8 +145,6 @@ dn_dequeue(struct new_queue *q)
q->_si->ni.length--;
q->_si->ni.len_bytes -= m->m_pkthdr.len;
}
- if (q->mq.head == NULL && q->fs && q->fs->kflags & DN_DELETE)
- (void)dn_delete_queue(q, 1 /* free if possible */);
return m;
}
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Tue Jan 19 22:44:29 2010 (r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Tue Jan 19 23:03:08 2010 (r202660)
@@ -602,7 +602,7 @@ dummynet_io(struct mbuf **m0, int dir, s
if (fs->sched->fp->enqueue(si, q, m)) {
printf("%s dropped by enqueue\n", __FUNCTION__);
/* packet was dropped by enqueue() */
- *m0 = NULL;
+ m = *m0 = NULL;
goto dropit;
}
@@ -646,7 +646,8 @@ done:
dropit:
io_pkt_drop++;
DUMMYNET_UNLOCK();
- FREE_PKT(m);
+ if (m)
+ FREE_PKT(m);
*m0 = NULL;
return (fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS;
}
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Tue Jan 19 22:44:29 2010 (r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Tue Jan 19 23:03:08 2010 (r202660)
@@ -52,6 +52,18 @@ SLIST_HEAD(new_fsk_head, new_fsk);
SLIST_HEAD(new_queue_head, new_queue);
SLIST_HEAD(dn_sched_head, dn_sched);
+struct mq { /* a basic queue of packets*/
+ struct mbuf *head, *tail;
+};
+
+static inline void
+set_oid(struct dn_id *o, int type, int len)
+{
+ o->type = type;
+ o->len = len;
+ o->subtype = 0;
+};
+
/*
* configuration and global data for a dummynet instance
*
@@ -82,27 +94,23 @@ struct dn_parms {
int fsk_count;
int queue_count;
- /* flowsets and schedulers are in hash tables, whose size
- * is programmable. fshash is looked up at every packet arrival
+ /* flowsets and schedulers are in hash tables, with 'hash_size'
+ * buckets. fshash is looked up at every packet arrival
* so better be generous if we expect many entries.
*/
struct dn_ht *fshash;
struct dn_ht *schedhash;
/* list of flowsets without a scheduler -- use sch_chain */
- struct new_fsk_head fsu;
+ struct new_fsk_head fsu; /* list of unlinked flowsets */
struct dn_sched_head schedlist; /* list of algorithms */
-};
-static inline void
-set_oid(struct dn_id *o, int type, int len)
-{
- o->type = type;
- o->len = len;
- o->subtype = 0;
-};
-
-struct mq { /* a basic queue of packets*/
- struct mbuf *head, *tail;
+ /* if the upper half is busy doing something long,
+ * can set the busy flag and we will enqueue packets in
+ * a queue for later processing.
+ */
+ int busy;
+ struct mq pending;
+
};
/*
@@ -116,31 +124,23 @@ struct delay_line {
};
/*
- * The kernel side of a flowset. In addition to the user parameters
- * and kernel flags, it is linked in a hash table of flowsets,
- * and in a list of children of their parent scheduler.
- * It also contains a hash table of children queues (or one, if
- * there is no flow_mask).
- * When we remove a flowset, mark as DN_DELETE so it can go away
- * when the hash table will be empty.
- * XXX refcnt is redundant, the info is already in qht->entries
- * If we want to add scheduler-specific parameters, we need to
+ * The kernel side of a flowset. It is linked in a hash table
+ * of flowsets, and in a list of children of their parent scheduler.
+ * qht is either the queue or (if HAVE_MASK) a hash table queues.
+ * XXX If we want to add scheduler-specific parameters, we need to
* put them in external storage because the scheduler may not be
* available when the fsk is created.
*/
struct new_fsk { /* kernel side of a flowset */
struct new_fs fs;
SLIST_ENTRY(new_fsk) fsk_next; /* hash chain list */
- int kflags; /* kernel-side flags */
int refcnt; /* entries in qht */
- /* hash table of queues. XXX if we have no flow_mask we could
- * avoid the hash table and just allocate one queue.
- */
+ /* hash table of queues, or just single queue */
struct dn_ht *_qht;
struct new_schk *sched; /* Sched we are linked to */
SLIST_ENTRY(new_fsk) sch_chain; /* list of fsk attached to sched */
- void *sched_info; /* scheduler-specific info */
+ // void *sched_info; /* scheduler-specific info */
};
/*
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Tue Jan 19 22:44:29 2010 (r202659)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Tue Jan 19 23:03:08 2010 (r202660)
@@ -257,12 +257,12 @@ q_new(uintptr_t key, int flags, void *ar
}
/*
- * Delete a queue. The version for callbacks is called q_delete_cb().
- * Call the 'free_queue' routine on the scheduler.
- * If do_free is set, also free the packets.
+ * Notify schedulers that a queue is going away.
+ * If (flags & DN_DELETE), also free the packets.
+ * The version for callbacks is called q_delete_cb().
*/
-struct new_queue *
-dn_delete_queue(struct new_queue *q, int do_free)
+void
+dn_delete_queue(struct new_queue *q, int flags)
{
struct new_fsk *fs = q->fs;
@@ -271,21 +271,21 @@ dn_delete_queue(struct new_queue *q, int
if (fs && fs->sched->fp->free_queue)
fs->sched->fp->free_queue(q);
q->_si = NULL;
- if (!do_free)
- return q;
- if (q->mq.head)
- dn_free_pkts(q->mq.head);
- free(q, M_DUMMYNET);
- dn_cfg.queue_count--;
- fs->refcnt--;
- return NULL;
+ if (flags & DN_DELETE) {
+ if (q->mq.head)
+ dn_free_pkts(q->mq.head);
+ free(q, M_DUMMYNET);
+ dn_cfg.queue_count--;
+ fs->refcnt--;
+ }
}
static int
q_delete_cb(void *q, void *arg)
{
- (void)dn_delete_queue(q, (int)(uintptr_t)arg);
- return 0;
+ int flags = (int)(uintptr_t)arg;
+ dn_delete_queue(q, flags);
+ return (flags & DN_DELETE) ? DNHT_SCAN_DEL : 0;
}
/*
@@ -296,22 +296,26 @@ q_delete_cb(void *q, void *arg)
static void
qht_delete(struct new_fsk *fs, int flags)
{
- printf("+++ %s fs %d start\n", __FUNCTION__, fs->fs.fs_nr);
+ printf("+++ %s fs %d start flags %d qht %p\n",
+ __FUNCTION__, fs->fs.fs_nr, flags, fs->_qht);
if (!fs->_qht)
return;
- if (fs->kflags & DN_QHT_IS_Q) {
- fs->_qht = (struct dn_ht *)dn_delete_queue((struct new_queue *)(fs->_qht), flags);
- } else {
+ if (fs->fs.flags & DN_HAVE_MASK) {
dn_ht_scan(fs->_qht, q_delete_cb, (void *)flags);
if (flags & DN_DELETE) {
dn_ht_free(fs->_qht, 0);
fs->_qht = NULL;
}
+ } else {
+ dn_delete_queue((struct new_queue *)(fs->_qht), flags);
+ if (flags & DN_DELETE)
+ fs->_qht = NULL;
}
}
/*
- * only called in the DN_MULTIQUEUE CASE so we can handle errors
+ * Find and possibly create the right queue for a MULTIQUEUE scheduler.
+ * We never call it for !MULTIQUEUE (when the queue is in the sch_inst).
* in a better way.
*/
struct new_queue *
@@ -319,6 +323,7 @@ ipdn_q_find(struct new_fsk *fs, struct n
struct ipfw_flow_id *id)
{
struct new_queue template;
+
template._si = si;
template.fs = fs;
@@ -330,7 +335,6 @@ ipdn_q_find(struct new_fsk *fs, struct n
q_hash, q_match, q_new);
if (fs->_qht == NULL)
return NULL;
- fs->kflags &= ~DN_QHT_IS_Q;
}
masked_id = *id;
flow_id_mask(&fs->fs.flow_mask, &masked_id);
@@ -339,7 +343,6 @@ ipdn_q_find(struct new_fsk *fs, struct n
} else {
if (fs->_qht == NULL)
fs->_qht = q_new(0, 0, &template);
- fs->kflags |= DN_QHT_IS_Q;
return (struct new_queue *)fs->_qht;
}
}
@@ -395,12 +398,9 @@ si_new(uintptr_t key, int flags, void *a
si->sched = s;
si->dline.si = si;
- if (s->fp->new_sched) {
- int ret = s->fp->new_sched(si);
- if (ret) {
- printf("%s: new_sched error %d\n", __FUNCTION__, ret);
- goto error;
- }
+ if (s->fp->new_sched && s->fp->new_sched(si)) {
+ printf("%s: new_sched error\n", __FUNCTION__);
+ goto error;
}
if (s->sch.flags & DN_HAVE_MASK)
si->ni.id = *(struct ipfw_flow_id *)key;
@@ -415,10 +415,10 @@ error:
}
/*
- * callback from siht to delete all scheduler instances.
+ * Callback from siht to delete all scheduler instances. Remove
+ * si and delay line from the system heap, destroy all queues.
* We assume that all flowset have been notified and do not
* point to us anymore.
- * Remove si and delay line from the system heap, destroy all queues.
*/
static int
si_destroy(void *_si, void *arg)
@@ -434,6 +434,7 @@ si_destroy(void *_si, void *arg)
heap_extract(&dn_cfg.evheap, si);
if (s->fp->free_sched)
s->fp->free_sched(si);
+ bzero(si, sizeof(*si)); /* safety */
free(si, M_DUMMYNET);
dn_cfg.si_count--;
return 0;
@@ -446,18 +447,37 @@ si_destroy(void *_si, void *arg)
struct new_sch_inst *
ipdn_si_find(struct new_schk *s, struct ipfw_flow_id *id)
{
- struct new_sch_inst *si;
- if (!(s->sch.flags & DN_HAVE_MASK)) {
- if (s->siht == NULL)
- s->siht = si_new((uintptr_t)id, 0, s);
- si = (struct new_sch_inst *)s->siht;
- } else {
+ if (s->sch.flags & DN_HAVE_MASK) {
struct ipfw_flow_id id_t = *id;
flow_id_mask(&s->sch.sched_mask, &id_t);
- si = dn_ht_find(s->siht, (uintptr_t)&id_t, DNHT_INSERT, s);
+ return dn_ht_find(s->siht, (uintptr_t)&id_t,
+ DNHT_INSERT, s);
+ } else {
+ if (s->siht == NULL)
+ s->siht = si_new((uintptr_t)id, 0, s);
+ return (struct new_sch_inst *)s->siht;
}
- return si;
+}
+
+/* callback to flush credit for the scheduler instance */
+static int
+si_reset_credit(void *_si, void *arg)
+{
+ struct new_sch_inst *si = _si;
+ struct new_pipe *p = &si->sched->pipe;
+
+ si->credit = p->burst + (dn_cfg.io_fast ? p->bandwidth : 0);
+ return 0;
+}
+
+static void
+schk_reset_credit(struct new_schk *s)
+{
+ if (s->sch.flags & DN_HAVE_MASK)
+ dn_ht_scan(s->siht, si_reset_credit, NULL);
+ else if (s->siht)
+ si_reset_credit(s->siht, NULL);
}
/*---- end of sch_inst hashtable ---------------------*/
@@ -469,13 +489,12 @@ ipdn_si_find(struct new_schk *s, struct
static int
fsk_hash(uintptr_t key, int flags, void *arg)
{
- int i = ((flags & DNHT_KEY_IS_OBJ) == 0) ? key :
+ int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
((struct new_fsk *)key)->fs.fs_nr;
return ( (i>>8)^(i>>4)^i );
}
-/* match skips entries those marked as deleted */
static int
fsk_match(void *obj, uintptr_t key, int flags, void *arg)
{
@@ -483,7 +502,7 @@ fsk_match(void *obj, uintptr_t key, int
int i = !(flags & DNHT_KEY_IS_OBJ) ? key :
((struct new_fsk *)key)->fs.fs_nr;
- return !(fs->kflags & DN_DELETE) && (fs->fs.fs_nr == i);
+ return (fs->fs.fs_nr == i);
}
static void *
@@ -500,18 +519,27 @@ fsk_new(uintptr_t key, int flags, void *
return fs;
}
-/* detach flowset from its current scheduler */
+/*
+ * detach flowset from its current scheduler. Flags as follows:
+ * DN_DETACH removes from the fsk_list
+ * DN_DELETE deletes individual queues
+ * DN_DELETE_FS destroys the flowset (otherwise goes in unlinked).
+ */
static void
fsk_detach(struct new_fsk *fs, int flags)
{
if (flags & DN_DELETE_FS)
flags |= DN_DELETE;
+ printf("%s fs %d from sched %d flags %s %s %s\n",
+ __FUNCTION__, fs->fs.fs_nr, fs->fs.sched_nr,
+ (flags & DN_DELETE_FS) ? "DEL_FS":"",
+ (flags & DN_DELETE) ? "DEL":"",
+ (flags & DN_DETACH) ? "DET":"");
if (flags & DN_DETACH) { /* detach from the list */
struct new_fsk_head *h;
h = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu;
SLIST_REMOVE(h, fs, new_fsk, sch_chain);
}
- /* replica of the code in fsk_detach_list */
qht_delete(fs, flags);
if (fs->sched && fs->sched->fp->free_fsk)
fs->sched->fp->free_fsk(fs);
@@ -536,7 +564,7 @@ static void
fsk_detach_list(struct new_fsk_head *h, int flags)
{
struct new_fsk *fs;
- int n = 0;
+ int n = 0; /* only for stats */
printf("+++ %s head %p flags %x\n", __FUNCTION__, h, flags);
while ((fs = SLIST_FIRST(h))) {
@@ -552,16 +580,23 @@ fsk_detach_list(struct new_fsk_head *h,
* XXX note that fsk_detach_list also destroys a flowset.
*/
static int
-delete_fs(int i)
+delete_fs(int i, int locked)
{
struct new_fsk *fs;
+ int err = 0;
+ if (!locked)
+ DUMMYNET_LOCK();
fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL);
printf("%s fs %d found %p\n", __FUNCTION__, i, fs);
- if (fs == NULL)
- return EINVAL;
- fsk_detach(fs, DN_DETACH | DN_DELETE_FS);
- return 0;
+ if (fs) {
+ fsk_detach(fs, DN_DETACH | DN_DELETE_FS);
+ err = 0;
+ } else
+ err = EINVAL;
+ if (!locked)
+ DUMMYNET_UNLOCK();
+ return err;
}
/*----- end of flowset hashtable support -------------*/
@@ -671,29 +706,10 @@ delete_schk(int i)
return EINVAL;
/* detach flowsets, delete traffic */
schk_delete_cb(s, (void*)(uintptr_t)DN_DELETE);
- delete_fs(i + DN_MAX_ID); /* remove internal pipe */
- return 0;
-}
-
-/* callback to flush credit for the pipe */
-static int
-reset_credit(void *_si, void *arg)
-{
- struct new_sch_inst *si = _si;
- struct new_pipe *p = &si->sched->pipe;
-
- si->credit = p->burst + (dn_cfg.io_fast ? p->bandwidth : 0);
+ delete_fs(i + DN_MAX_ID, 1); /* remove internal pipe */
return 0;
}
-static void
-schk_reset_credit(struct new_schk *s)
-{
- if (s->sch.flags & DN_HAVE_MASK)
- dn_ht_scan(s->siht, reset_credit, NULL);
- else if (s->siht)
- reset_credit(s->siht, NULL);
-}
/*--- end of schk hashtable support ---*/
@@ -912,6 +928,14 @@ config_fs(struct new_fs *nfs, struct dn_
fs = dn_ht_find(dn_cfg.fshash, i, DNHT_INSERT, NULL);
if (fs == NULL)
break;
+ if (nfs->sched_nr == 0) {
+ printf("reuse existing number %d\n", fs->fs.sched_nr);
+ if (fs->fs.sched_nr == 0) {
+ fs = NULL;
+ break;
+ }
+ nfs->sched_nr = fs->fs.sched_nr;
+ }
dn_cfg.id++;
if (bcmp(&fs->fs, nfs, sizeof(*nfs)) == 0) {
printf("%s no change\n", __FUNCTION__);
@@ -924,6 +948,7 @@ config_fs(struct new_fs *nfs, struct dn_
*/
if (fs->sched) {
int flags = s ? DN_DETACH : (DN_DETACH | DN_DELETE);
+ flags |= DN_DELETE; /* XXX temporary */
fsk_detach(fs, flags);
}
fs->fs = *nfs; /* copy configuration */
@@ -1139,7 +1164,6 @@ do_config(void *p, int l)
l -= o->len;
next = (struct dn_id *)((char *)o + o->len);
err = 0;
- DUMMYNET_LOCK();
switch (o->type) {
default:
printf("cmd %d not implemented\n", o->type);
@@ -1152,8 +1176,10 @@ do_config(void *p, int l)
switch (o->subtype) {
case DN_PIPE:
/* delete base and derived schedulers */
+ DUMMYNET_LOCK();
err = delete_schk(o->id);
err2 = delete_schk(o->id + DN_MAX_ID);
+ DUMMYNET_UNLOCK();
if (!err)
err = err2;
break;
@@ -1166,13 +1192,15 @@ do_config(void *p, int l)
case DN_FS:
err = (o->id < 1 || o->id >= DN_MAX_ID) ?
- EINVAL : delete_fs(o->id) ;
+ EINVAL : delete_fs(o->id, 0) ;
break;
}
break;
case DN_CMD_FLUSH:
+ DUMMYNET_LOCK();
dummynet_flush();
+ DUMMYNET_UNLOCK();
break;
case DN_TEXT: /* store argument the next block */
prev = NULL;
@@ -1191,7 +1219,6 @@ do_config(void *p, int l)
err = (NULL==config_fs((struct new_fs *)o, arg, 0));
break;
}
- DUMMYNET_UNLOCK();
if (prev)
arg = NULL;
if (err != 0)
More information about the svn-src-user
mailing list