svn commit: r201844 - in user/luigi/ipfw3-head/sys/netinet: . ipfw
Luigi Rizzo
luigi at FreeBSD.org
Fri Jan 8 22:37:53 UTC 2010
Author: luigi
Date: Fri Jan 8 22:37:52 2010
New Revision: 201844
URL: http://svn.freebsd.org/changeset/base/201844
Log:
partial processing of 'configure'
Modified:
user/luigi/ipfw3-head/sys/netinet/ip_dummynet.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/sys/netinet/ip_dummynet.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 8 22:34:17 2010 (r201843)
+++ user/luigi/ipfw3-head/sys/netinet/ip_dummynet.h Fri Jan 8 22:37:52 2010 (r201844)
@@ -66,13 +66,15 @@ enum {
DN_FS_EXT,
DN_QUEUE_EXT,
DN_UNKNOW,
- DN_CMD_CONFIGURE,
- DN_CMD_DELETE,
+ DN_CMD_CONFIGURE, /* objects follow */
+ DN_CMD_DELETE, /* subtype + list of entries */
+ DN_CMD_GET, /* subtype + list of entries */
+ DN_CMD_FLUSH,
DN_LAST,
};
/* These values are in the subtype field of struct gen */
-enum dn_configure {
+enum {
DN_CONF_PIPE = 1,
DN_CONF_QUEUE = 2,
DN_CONF_SCHED = 3,
@@ -93,13 +95,21 @@ enum sched_flag {
typedef uint64_t dn_key;
+struct new_cmd { /* header for all sockopt */
+ struct dn_id oid;
+ int entries;
+ uint32_t data[0]; /* actually, entries elements */
+};
+
#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 pipe_nr;
int loss_level;
+ int bandwidth;
int samples_no;
int samples[ED_MAX_SAMPLES_NO]; /* this has actually samples_no slots */
};
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 22:34:17 2010 (r201843)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Fri Jan 8 22:37:52 2010 (r201844)
@@ -245,12 +245,12 @@ struct dn_pkt_tag {
static struct dn_pkt_tag *
dn_tag_get(struct mbuf *m)
{
- struct m_tag *mtag = m_tag_first(m);
- KASSERT(mtag != NULL &&
+ struct m_tag *mtag = m_tag_first(m);
+ KASSERT(mtag != NULL &&
mtag->m_tag_cookie == MTAG_ABI_COMPAT &&
mtag->m_tag_id == PACKET_TAG_DUMMYNET,
("packet on dummynet queue w/o dummynet tag!"));
- return (struct dn_pkt_tag *)(mtag+1);
+ return (struct dn_pkt_tag *)(mtag+1);
}
/*
@@ -262,6 +262,7 @@ transmit_event(struct delay_line *dline,
{
struct mbuf *m;
struct mbuf *head = NULL, *tail = NULL;
+ struct dn_pkt_tag *pkt = NULL;
/* XXX we are under scheduler lock */
while ((m = dline->head) != NULL) {
@@ -280,7 +281,6 @@ transmit_event(struct delay_line *dline,
tail->m_nextpkt = NULL;
if ((m = dline->head) != NULL) {
- struct dn_pkt_tag *pkt = dn_tag_get(m);
DN_HEAP_LOCK();
heap_insert(&dn_cfg.system_heap, pkt->output_time, dline);
DN_HEAP_UNLOCK();
@@ -471,7 +471,7 @@ create_scheduler_instance(struct new_sch
if (si == NULL)
goto error;
- si->dline = malloc(sizeof(*si->dline, M_DUMMYNET, M_NOWAIT | M_ZERO);
+ si->dline = malloc(sizeof(*si->dline), M_DUMMYNET, M_NOWAIT | M_ZERO);
if (si->dline == NULL)
goto error;
@@ -670,7 +670,7 @@ dummynet_task(void *context, int pending
struct mbuf *head = NULL;
DN_HEAP_LOCK();
- if (&dn_cfg.system_heap->elements > 0 &&
+ if (dn_cfg.system_heap.elements > 0 &&
DN_KEY_LEQ(HEAP_TOP(&dn_cfg.system_heap)->key, curr_time)) {
p = HEAP_TOP(&dn_cfg.system_heap)->object;
heap_extract(&dn_cfg.system_heap, NULL);
@@ -735,8 +735,6 @@ dummynet_task(void *context, int pending
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);
}
}
if (head != NULL)
@@ -1256,11 +1254,10 @@ dummynet_io(struct mbuf **m0, int dir, s
*m0 = NULL;
}
done:
- DUMMYNET_UNLOCK();
- if (head != NULL)
- dummynet_send(head);
-
- return 0;
+ DUMMYNET_UNLOCK();
+ if (head != NULL)
+ dummynet_send(head);
+ return 0;
dropit:
io_pkt_drop++;
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Fri Jan 8 22:34:17 2010 (r201843)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Fri Jan 8 22:37:52 2010 (r201844)
@@ -78,6 +78,7 @@ struct dn_parms {
int io_fast;
struct timeval prev_t;
+ struct dn_heap system_heap;
};
static inline void
Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c
==============================================================================
--- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 8 22:34:17 2010 (r201843)
+++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Fri Jan 8 22:37:52 2010 (r201844)
@@ -76,6 +76,10 @@ static struct taskqueue *dn_tq = NULL;
static struct dn_sched_head list_of_scheduler;
+static int config_pipe(struct new_pipe *p);
+static int config_profile(struct new_profile *p);
+static int config_fs(struct new_fs *p);
+static int config_sched(struct new_sch *p);
/*
* This is called one tick, after previous run. It is used to
* schedule next run.
@@ -183,7 +187,7 @@ really_deletescheduler(struct new_sch *s
return 0;
}
-
+/* remove a pipe and attached objects */
static void
free_pipe(struct new_pipe *p)
{
@@ -193,63 +197,6 @@ free_pipe(struct new_pipe *p)
}
/*
- * Dispose all packets and flow_queues on a flow_set.
- * If all=1, also remove red lookup table and other storage,
- * including the descriptor itself.
- * For the one in dn_pipe MUST also cleanup ready_heap...
- */
-static void
-purge_flow_set(struct new_fs *fs, int all)
-{
-#if 0
- struct new_queue *q, *qn;
- int i;
-
- DUMMYNET_LOCK_ASSERT();
-
- for (i = 0; i <= fs->rq_size; i++) {
- for (q = fs->rq[i]; q != NULL; q = qn) {
- dn_free_pkts(q->head);
- qn = q->next;
- free(q, M_DUMMYNET);
- }
- fs->rq[i] = NULL;
- }
-
- fs->rq_elements = 0;
- if (all) {
- /* RED - free lookup table. */
- if (fs->w_q_lookup != NULL)
- free(fs->w_q_lookup, M_DUMMYNET);
- if (fs->rq != NULL)
- free(fs->rq, M_DUMMYNET);
- /* If this fs is not part of a pipe, free it. */
- if (fs->pipe == NULL || fs != &(fs->pipe->fs))
- free(fs, M_DUMMYNET);
- }
-#endif
-}
-
-/*
- * Dispose all packets queued on a pipe (not a flow_set).
- * Also free all resources associated to a pipe, which is about
- * to be deleted.
- */
-static void
-purge_pipe(struct new_pipe *pipe)
-{
-#if 0
- purge_flow_set( &(pipe->fs), 1 );
-
- dn_free_pkts(pipe->head);
-
- heap_free( pipe->scheduler_heap );
- heap_free( pipe->not_eligible_heap );
- heap_free( pipe->idle_heap );
-#endif
-}
-
-/*
* Deelete all objects.
*/
static void
@@ -257,6 +204,7 @@ dummynet_flush(void)
{
struct new_pipe *pipe, *pipe1;
struct new_fs *fs, *fs1;
+ struct new_sch *sch_t, *sch_t1;
int i;
DUMMYNET_LOCK();
@@ -265,7 +213,7 @@ dummynet_flush(void)
heap_free(&dn_cfg.system_heap);
/* Free all pipes */
- for (i = 0; i < HASHSIZE; i++) {
+ for (i = 0; i < DN_HASHSIZE; i++) {
SLIST_FOREACH_SAFE(pipe, &pipehash[i], next, pipe1) {
SLIST_REMOVE(&pipehash[i], pipe, new_pipe, next);
free_pipe(pipe);
@@ -279,10 +227,10 @@ dummynet_flush(void)
}
/* Free all flowsets in the system */
- for (i = 0; i < HASHSIZE; i++) {
+ for (i = 0; i < DN_HASHSIZE; i++) {
SLIST_FOREACH_SAFE(fs, &flowsethash[i], next, fs1) {
SLIST_REMOVE(&flowsethash[i], fs, new_fs, next);
- fs->fp->delete_alg_fs(fs->alg_fs);
+ fs->fp->free_fs(fs->alg_fs);
fs->fp->ref_count--;
free(fs->alg_fs, M_DUMMYNET);
free(fs, M_DUMMYNET);
@@ -290,7 +238,7 @@ dummynet_flush(void)
}
/* Free all schedulers */
- for (i = 0; i < HASHSIZE; i++) {
+ for (i = 0; i < DN_HASHSIZE; i++) {
SLIST_FOREACH_SAFE(sch_t, &schedulerhash[i], next, sch_t1) {
SLIST_REMOVE(&schedulerhash[i], sch_t, new_sch, next);
sch_t->flags |= DN_SCH_DELETE_DELAY_LINE;
@@ -418,13 +366,44 @@ set_fs_parms(struct dn_flow_set *x, stru
static int
do_config(void *p, int l)
{
- struct dn_id *o = p;
+ struct dn_id *next, *o;
+ int err = 0, cmd = 0;
- while (l && o->len > 0) {
+ for (o = p; l >= sizeof(*o); o = next) {
+ err = EINVAL;
+ if (o->len < sizeof(*o) || l < o->len) {
+ printf("bad len o->len %d len %d\n", o->len, l);
+ break;
+ }
l -= o->len;
- o = (struct dn_id *)((char *)o + l);
+ printf("%s cmd %d len %d left %d\n",
+ __FUNCTION__, o->type, o->len, l);
+ next = (struct dn_id *)((char *)o + o->len);
+ switch (o->type) {
+ case DN_CMD_CONFIGURE:
+ case DN_CMD_GET:
+ case DN_CMD_DELETE:
+ case DN_CMD_FLUSH:
+ cmd = o->type;
+ err = 0;
+ break;
+ case DN_PIPE:
+ err = config_pipe((struct new_pipe *)o);
+ break;
+ case DN_PROFILE:
+ err = config_profile((struct new_profile *)o);
+ break;
+ case DN_SCH:
+ err = config_sched((struct new_sch *)o);
+ break;
+ case DN_FS:
+ err = config_fs((struct new_fs *)o);
+ break;
+ }
+ if (err != 0)
+ break;
}
- return 0;
+ return err;
}
static struct new_sch *
@@ -673,16 +652,17 @@ dn_fs_config(struct new_fs *fs)
* (re)configures the WFQ scheduler for the pipe.
*/
static int
-config_pipe(struct dn_pipe *p)
+config_pipe(struct new_pipe *p)
{
-#if 0
- struct dn_flow_set *pfs = &(p->fs);
- struct dn_flow_queue *q;
- int i, error;
+ struct new_pipe *pipe;
+ if (p->oid.len < sizeof(*p)) {
+ printf("%s: short pipe\n", __FUNCTION__);
+ return EINVAL;
+ }
/* We need either a pipe number or a flow_set number. */
- if (p->pipe_nr == 0 && pfs->fs_nr == 0)
- return (EINVAL);
+ if (p->pipe_nr <= 0 || p->pipe_nr >= DN_PIPEOFFSET)
+ return EINVAL;
/*
* The config program passes parameters as follows:
* bw = bits/second (0 means no limits),
@@ -694,79 +674,103 @@ config_pipe(struct dn_pipe *p)
p->burst *= 8 * hz;
DUMMYNET_LOCK();
- if (p->pipe_nr != 0) { /* this is a pipe */
- struct dn_pipe *pipe;
-
- pipe = locate_pipe(p->pipe_nr); /* locate pipe */
+ pipe = locate_pipe(p->pipe_nr); /* locate pipe */
- if (pipe == NULL) { /* new pipe */
- /* space for pipe + 3 heaps right after the pipe */
- pipe = malloc(sizeof(struct dn_pipe) +
- 3 * sizeof(struct dn_heap), M_DUMMYNET,
- M_NOWAIT | M_ZERO);
- if (pipe == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory for new pipe\n");
- return (ENOMEM);
- }
+ if (pipe == NULL) { /* brand new pipe */
+ pipe = malloc(sizeof(*pipe), M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (pipe == NULL) {
+ DUMMYNET_UNLOCK();
+ printf("dummynet: no memory for new pipe\n");
+ return (ENOMEM);
+ }
+ bcopy(p, pipe, sizeof(*pipe));
+ /* XXX schedulers should attach to us... */
+ } else {
+ /* pipe already exists, reconfigure it. */
+ struct new_sch *sch;
+ struct new_sch_inst *si;
+ int i;
+
+ sch = locate_scheduler(pipe->pipe_nr + DN_PIPEOFFSET);
+ if (sch) {
+ /* Flush accumulated credit for all queues. */
+ for (i = 0; i < sch->sch_i_size; i++)
+ for (si = sch->sch_i[i]; si; si = si->next)
+ si->numbytes = p->burst + dn_cfg.io_fast ?
+ p->bandwidth : 0;
+ }
+ pipe->delay = p->delay;
+ pipe->bandwidth = p->bandwidth;
+ pipe->burst = p->burst;
+ bcopy(p->if_name, pipe->if_name, sizeof(p->if_name));
+ pipe->ifp = NULL; /* reset interface ptr */
+ }
+ dn_cfg.id++;
+ DUMMYNET_UNLOCK();
+ return 0;
+}
- pipe->scheduler_heap = (struct dn_heap *)(pipe + 1);
- pipe->not_eligible_heap = pipe->scheduler_heap + 1;
- pipe->idle_heap = pipe->scheduler_heap + 2;
+static int
+config_sched(struct new_sch *sch)
+{
+ return 0;
+}
- pipe->pipe_nr = p->pipe_nr;
- pipe->fs.pipe = pipe;
- /*
- * idle_heap is the only one from which
- * we extract from the middle.
- */
- pipe->idle_heap->ofs =
- offsetof(struct dn_flow_queue, heap_pos);
- } else {
- /* Flush accumulated credit for all queues. */
- for (i = 0; i <= pipe->fs.rq_size; i++) {
- for (q = pipe->fs.rq[i]; q; q = q->next) {
- q->numbytes = p->burst +
- (dn_cfg.io_fast ? p->bandwidth : 0);
- }
- }
- }
+static int
+config_fs(struct new_fs *fs)
+{
+ return 0;
+}
+/*
+ * attach a profile to a pipe
+ */
+static int
+config_profile(struct new_profile *pf)
+{
+ struct new_pipe *pipe;
- pipe->bandwidth = p->bandwidth;
- pipe->burst = p->burst;
- pipe->numbytes = pipe->burst + (dn_cfg.io_fast ? pipe->bandwidth : 0);
- 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 (pf->oid.len < sizeof(*pf)) {
+ printf("%s: short profile\n", __FUNCTION__);
+ return EINVAL;
+ }
+ /* We need a pipe number . */
+ if (pf->pipe_nr <= 0 || pf->pipe_nr >= DN_PIPEOFFSET)
+ return EINVAL;
+ /* XXX other sanity checks */
+ DUMMYNET_LOCK();
+ pipe = locate_pipe(pf->pipe_nr); /* locate pipe */
- /* Handle changes in the delay profile. */
- if (p->samples_no > 0) {
- if (pipe->samples_no != p->samples_no) {
- if (pipe->samples != NULL)
- free(pipe->samples, M_DUMMYNET);
- pipe->samples =
- malloc(p->samples_no*sizeof(dn_key),
- M_DUMMYNET, M_NOWAIT | M_ZERO);
- if (pipe->samples == NULL) {
- DUMMYNET_UNLOCK();
- printf("dummynet: no memory "
- "for new samples\n");
- return (ENOMEM);
- }
- pipe->samples_no = p->samples_no;
- }
+ if (pipe == NULL) { /* brand new pipe */
+ DUMMYNET_UNLOCK();
+ printf("%s: no pipe %d\n", __FUNCTION__, pf->pipe_nr);
+ return EINVAL;
+ }
- strncpy(pipe->name,p->name,sizeof(pipe->name));
- pipe->loss_level = p->loss_level;
- for (i = 0; i<pipe->samples_no; ++i)
- pipe->samples[i] = p->samples[i];
- } else if (pipe->samples != NULL) {
- free(pipe->samples, M_DUMMYNET);
- pipe->samples = NULL;
- pipe->samples_no = 0;
+ dn_cfg.id++;
+ /* see if we need to allocate memory */
+ if (pipe->profile && (pf->samples_no == 0 ||
+ pipe->profile->oid.len < pf->oid.len)) {
+ free(pipe->profile, M_DUMMYNET);
+ pipe->profile = NULL;
+ }
+ if (pf->samples_no > 0) {
+ if (pipe->profile == NULL)
+ pipe->profile = malloc(pf->oid.len,
+ M_DUMMYNET, M_NOWAIT | M_ZERO);
+ if (pipe->profile == NULL) {
+ DUMMYNET_UNLOCK();
+ printf("%s: no memory\n", __FUNCTION__);
+ return ENOMEM;
}
-
+ bcopy(pf, pipe->profile, pf->oid.len);
+ }
+ DUMMYNET_UNLOCK();
+ return 0;
+}
+
+#if 0
+ /* We need either a pipe number or a flow_set number. */
+ set_fs_parms(&(pipe->fs), pfs);
if (pipe->fs.rq == NULL) { /* a new pipe */
error = alloc_hash(&(pipe->fs), pfs);
if (error) {
@@ -828,11 +832,9 @@ config_pipe(struct dn_pipe *p)
}
}
DUMMYNET_UNLOCK();
-#endif
return (0);
}
-#if 0
/*
* Helper function to remove from a heap queues which are linked to
* a flow_set about to be deleted.
@@ -860,16 +862,14 @@ scan_remove_pipe(void *_o, uintptr_t p)
{
return (0 == (void *)p) ? HEAP_SCAN_DEL | HEAP_SCAN_END : 0;
}
-#endif
/*
* Fully delete a pipe or a queue, cleaning up associated info.
*/
static int
-delete_pipe(struct dn_pipe *p)
+delete_pipe(struct dn_id *p, int l)
{
int err = 0;
-#if 0
struct dn_pipe *pipe;
struct new_fs *fs;
@@ -931,11 +931,9 @@ done:
DUMMYNET_UNLOCK();
if (pipe)
free_pipe(pipe);
-#endif
return err;
}
-#if 0
/*
* helper function used to copy data from kernel in DUMMYNET_GET
*/
@@ -1088,65 +1086,54 @@ dummynet_get(struct sockopt *sopt)
static int
ip_dn_ctl(struct sockopt *sopt)
{
- int error;
- struct dn_pipe *p = NULL;
- int l;
-
- error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET);
- if (error)
- return (error);
-
- /* Disallow sets in really-really secure mode. */
- if (sopt->sopt_dir == SOPT_SET) {
- error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
+ void *p = NULL;
+ int error, l;
+
+ error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET);
if (error)
- return (error);
- }
+ return (error);
- switch (sopt->sopt_name) {
- default :
- printf("dummynet: -- unknown option %d", sopt->sopt_name);
- error = EINVAL ;
- break;
-
- case IP_DUMMYNET_GET :
- error = dummynet_get(sopt);
- break ;
-
- case IP_DUMMYNET_FLUSH :
- dummynet_flush() ;
- break ;
-
- case IP_DUMMYNET_CONFIGURE :
- l = (sopt->sopt_dir == SOPT_SET) ? sopt->sopt_valsize :
- *(int *)(sopt->sopt_valsize);
- if (l < 0 || l > 12000) {
- printf("argument too large, %d\n", l);
- break;
+ /* Disallow sets in really-really secure mode. */
+ if (sopt->sopt_dir == SOPT_SET) {
+ error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
+ if (error)
+ return (error);
}
- printf("%s size %d\n", __FUNCTION__, l);
- p = malloc(l, M_TEMP, M_WAITOK);
- error = sooptcopyin(sopt, p, l, l);
- if (error)
- break ;
- error = do_config(p, l);
- break;
- error = config_pipe(p);
- break ;
-
- case IP_DUMMYNET_DEL : /* remove a pipe or queue */
- p = malloc(sizeof(struct dn_pipe), M_TEMP, M_WAITOK);
- error = sooptcopyin(sopt, p, sizeof(struct dn_pipe), sizeof *p);
- if (error)
- break ;
+ switch (sopt->sopt_name) {
+ default :
+ printf("dummynet: -- unknown option %d", sopt->sopt_name);
+ error = EINVAL;
+ break;
- error = delete_pipe(p);
- break ;
- }
+ case IP_DUMMYNET_GET :
+ error = dummynet_get(sopt);
+ break;
+
+ case IP_DUMMYNET_FLUSH :
+ dummynet_flush();
+ break;
+
+ case IP_DUMMYNET_CONFIGURE :
+ case IP_DUMMYNET_DEL : /* remove a pipe or queue */
+ l = (sopt->sopt_dir == SOPT_SET) ? sopt->sopt_valsize :
+ *(int *)(sopt->sopt_valsize);
+ if (l < 0 || l > 12000) {
+ printf("argument too large, %d\n", l);
+ break;
+ }
+ printf("%s size %d\n", __FUNCTION__, l);
+ p = malloc(l, M_TEMP, M_WAITOK);
+ error = sooptcopyin(sopt, p, l, l);
+ if (error)
+ break ;
+
+ error = do_config(p, l);
+ break;
+ }
- if (p != NULL)
- free(p, M_TEMP);
+ if (p != NULL)
+ free(p, M_TEMP);
return error ;
}
More information about the svn-src-user
mailing list