Date: Tue, 19 Jan 2010 23:03:08 +0000 (UTC) From: Luigi Rizzo <luigi@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202660 - in user/luigi/ipfw3-head: sbin/ipfw sys/netinet/ipfw Message-ID: <201001192303.o0JN38Q3033399@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001192303.o0JN38Q3033399>