From owner-svn-src-user@FreeBSD.ORG Mon Jan 11 22:35:19 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id CC6AD1065672; Mon, 11 Jan 2010 22:35:19 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id BB2578FC14; Mon, 11 Jan 2010 22:35:19 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o0BMZJ0k096407; Mon, 11 Jan 2010 22:35:19 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o0BMZJU7096402; Mon, 11 Jan 2010 22:35:19 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201001112235.o0BMZJU7096402@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 11 Jan 2010 22:35:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r202124 - user/luigi/ipfw3-head/sys/netinet/ipfw X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Jan 2010 22:35:19 -0000 Author: luigi Date: Mon Jan 11 22:35:19 2010 New Revision: 202124 URL: http://svn.freebsd.org/changeset/base/202124 Log: remove some debugging messages, start implementing the new sockopt Modified: 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/sys/netinet/ipfw/dn_sched.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Mon Jan 11 22:34:25 2010 (r202123) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/dn_sched.h Mon Jan 11 22:35:19 2010 (r202124) @@ -32,8 +32,6 @@ #ifndef _DN_SCHED_H #define _DN_SCHED_H -// MALLOC_DECLARE(M_DUMMYNET); - /* * Descriptor for the scheduler. * Contains all function pointers for a given scheduler @@ -144,14 +142,6 @@ SLIST_HEAD(dn_sched_head, dn_sched); */ /* - * You must call dn_pkt_done() when extracting packets from a queue. - * The function is used to update packet and queue statistics. - * - pkt: packet to return; - * - q: packet belongs to this queue - */ -struct mbuf* dn_pkt_done(struct mbuf *pkt, struct new_queue *q); - -/* * delete a queue, which we assume nobody references */ int dn_delete_queue(struct new_queue *q); @@ -199,7 +189,7 @@ struct new_queue * dn_q_hash_id(struct i /* * Extract the head of a queue, update stats. Must be the very last - * thing done on a queue as it may go away. + * thing done on a queue as the queue itself may go away. */ static __inline struct mbuf* dn_return_packet(struct new_queue *q) @@ -207,8 +197,9 @@ dn_return_packet(struct new_queue *q) struct mbuf *m = q->mq.head; KASSERT(m != NULL, ("empty queue to dn_return_packet")); q->mq.head = m->m_nextpkt; - q->lenght--; - q->len_bytes -= m->m_pkthdr.len; + q->ni.length--; + q->si->ni.len_bytes -= m->m_pkthdr.len; + q->si->ni.len_bytes -= m->m_pkthdr.len; if (q->mq.head == NULL && q->fs && q->fs->kflags & DN_DELETE) dn_delete_queue(q); Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Mon Jan 11 22:34:25 2010 (r202123) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_io.c Mon Jan 11 22:35:19 2010 (r202124) @@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -//#include #include #include #include /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */ @@ -205,10 +204,8 @@ struct dn_pkt_tag { }; /* - * Return the mbuf tag holding the dummynet state. As an optimization - * this is assumed to be the first tag on the list. If this turns out - * wrong we'll need to search the list. - * XXX OK + * Return the mbuf tag holding the dummynet state (it should + * be the first one on the list). */ static struct dn_pkt_tag * dn_tag_get(struct mbuf *m) @@ -233,12 +230,9 @@ mq_append(struct mq *q, struct mbuf *m) } /* - * Check if the packet should be drop depending on the queue management - * or queue size overflow. - * Put the packet m into the queue q. - * Update statistics for the queue. - * - * The function returns 1 if the packet is dropped. + * Enqueue a packet in q, subject to space and queue management policy. + * Update stats for the queue and the scheduler. + * Return 0 on success, 1 on drop. The packet is consumed anyways. */ int dn_queue_packet(struct new_queue *q, struct mbuf* m) @@ -248,28 +242,28 @@ dn_queue_packet(struct new_queue *q, str uint64_t len = m->m_pkthdr.len; /* Update statistics, then check reasons to drop pkt. */ - q->tot_bytes += len; - q->tot_pkts++; + q->ni.tot_bytes += len; + q->ni.tot_pkts++; ni->tot_bytes += len; ni->tot_pkts++; if (f->plr && random() < f->plr) goto drop; if (f->flags & DN_QSIZE_BYTES) { - if (q->len_bytes > f->qsize) + if (q->ni.len_bytes > f->qsize) goto drop; - } else if (q->lenght >= f->qsize) { + } else if (q->ni.length >= f->qsize) { goto drop; } mq_append(&q->mq, m); - q->lenght++; - q->len_bytes += len; + q->ni.length++; + q->ni.len_bytes += len; ni->length++; ni->len_bytes += len; return 0; drop: io_pkt_drop++; - q->drops++; + q->ni.drops++; ni->drops++; FREE_PKT(m); return 1; @@ -278,14 +272,14 @@ drop: /* * Fetch packets from the delay line which are due now. If there are * leftover packets, reinsert the delay line in the heap. + * Runs under scheduler lock. */ static void transmit_event(struct mq *q, struct delay_line *dline, dn_key now) { - struct mbuf *m = NULL; + struct mbuf *m; struct dn_pkt_tag *pkt = NULL; - /* XXX we are under scheduler lock */ while ((m = dline->mq.head) != NULL) { pkt = dn_tag_get(m); if (!DN_KEY_LEQ(pkt->output_time, now)) @@ -301,8 +295,8 @@ transmit_event(struct mq *q, struct dela /* * Convert the additional MAC overheads/delays into an equivalent - * number of bits for the given data rate. The samples are in milliseconds - * so we need to divide by 1000. + * number of bits for the given data rate. The samples are + * in milliseconds so we need to divide by 1000. */ static uint64_t extra_bits(struct mbuf *m, struct new_pipe *p) @@ -323,19 +317,6 @@ extra_bits(struct mbuf *m, struct new_pi return bits; } -#if 0 -/* Insert packet pkt into delay line, adding the delay. - * dt->output_time was already set */ -static void -move_pkt(struct mbuf *m, struct new_pipe *p, struct delay_line *d) -{ - struct dn_pkt_tag *dt = dn_tag_get(m); - - dt->output_time += p->delay ; - mq_append(&d->mq, m); -} -#endif - /* Do masking depending of flow id */ static struct ipfw_flow_id * do_mask(struct ipfw_flow_id *mask, struct ipfw_flow_id *id) @@ -406,11 +387,10 @@ do_hash(struct ipfw_flow_id *id) } /* - * returns 0 masks match, - * returns 1 otherwise + * Like bcmp, returns 0 if ids match, 1 otherwise. */ static int -mask_are_equals (struct ipfw_flow_id *id1, struct ipfw_flow_id *id2) +flow_id_cmp(struct ipfw_flow_id *id1, struct ipfw_flow_id *id2) { int is_v6 = IS_IP6_FLOW_ID(id1); if (is_v6 != IS_IP6_FLOW_ID(id2)) @@ -450,7 +430,6 @@ create_si(struct new_schk *s, int slot) int l = sizeof(*si) + s->fp->sch_inst_len; si = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO); - if (si == NULL) goto error; /* XXX note we set the length only for the initial part which @@ -473,7 +452,6 @@ create_si(struct new_schk *s, int slot) /* Initialize list of queues attached here */ SLIST_INIT(&si->ql_list); - si->idle_time = 0; /* Put entry in front of the hash list of the parent. */ SLIST_INSERT_HEAD(&s->ht[slot], si, next); si->ni.hash_slot = slot; @@ -486,50 +464,60 @@ error: return NULL; } -/* find the scheduler instance for this packet */ +/* + * Find the scheduler instance for this packet. If we need to apply + * a mask, do on a local copy of the flow_id to preserve the original. + */ static struct new_sch_inst * find_sch_inst(struct new_schk *s, struct ipfw_flow_id *id) { - struct new_sch_inst *si; - int i; - struct ipfw_flow_id id_t; - - if ( 0 == (s->sch.flags & DN_HAVE_MASK) ) { - i = 0; - si = SLIST_FIRST(&s->ht[0]); - } else { - id_t = *id; - do_mask(&s->sch.sched_mask, &id_t); - i = do_hash(&id_t); - i = i % s->ht_slots; - /* finally, scan the current hash bucket for a match */ - searches++; - SLIST_FOREACH(si, &s->ht[i], next) { - search_steps++; - if (!mask_are_equals(&id_t, &si->ni.id)) - break; /* found */ - } - } - - if (si == NULL) { /* no match, need to allocate a new entry */ - si = create_si(s, i); - if (si && s->sch.flags & DN_HAVE_MASK) - si->ni.id = id_t; - } - return si; + struct new_sch_inst *si; + struct ipfw_flow_id id_t; + int i; + + if ( 0 == (s->sch.flags & DN_HAVE_MASK) ) { + i = 0; + si = SLIST_FIRST(&s->ht[0]); + } else { + id_t = *id; + do_mask(&s->sch.sched_mask, &id_t); + i = do_hash(&id_t); + i = i % s->ht_slots; + /* finally, scan the current hash bucket for a match */ + searches++; + SLIST_FOREACH(si, &s->ht[i], next) { + search_steps++; + if (!flow_id_cmp(&id_t, &si->ni.id)) + break; /* found */ + } + } + + if (si == NULL) { /* no match, allocate a new entry */ + si = create_si(s, i); + if (si && s->sch.flags & DN_HAVE_MASK) + si->ni.id = id_t; + } + return si; } /* - * Send traffic from a scheduler instance due by 'now' + * Send traffic from a scheduler instance due by 'now'. + * Return a pointer to the head of the queue. */ -static void +static struct mbuf * serve_sched(struct mq *q, struct new_sch_inst *si, dn_key now) { + struct mq def_q; struct new_schk *s = si->sched; struct mbuf *m = NULL; int delay_line_idle = (si->dline.mq.head == NULL); int done, bw; + if (q == NULL) { + q = &def_q; + q->head = NULL; + } + bw = s->pipe.bandwidth; si->kflags &= ~DN_ACTIVE; @@ -543,35 +531,31 @@ serve_sched(struct mq *q, struct new_sch uint64_t len_scaled; done++; len_scaled = bw == 0 ? 0 : hz * - (m->m_pkthdr.len * 8 + extra_bits(m, &s->pipe)); + (m->m_pkthdr.len * 8 + extra_bits(m, &s->pipe)); si->credit -= len_scaled; /* Move packet in the delay line */ dn_tag_get(m)->output_time += s->pipe.delay ; mq_append(&si->dline.mq, m); } + /* + * If credit >= 0 the instance is idle, mark time. + * Otherwise put back in the heap, and adjust the output + * time of the last inserted packet, m, which was too early. + */ if (si->credit >= 0) { - /* Instance is idle, because it did not return - * packets while credit was available. - */ - si->idle_time = curr_time; + si->idle_time = now; } else { - /* 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; KASSERT (bw > 0, ("bw=0 and credit<0 ?")); t = (bw - 1 - si->credit) / bw; - /* Delay output time because under credit */ if (m) dn_tag_get(m)->output_time += t; si->kflags |= DN_ACTIVE; - heap_insert(&dn_cfg.system_heap, curr_time + t, si); + heap_insert(&dn_cfg.system_heap, now + t, si); } - if (delay_line_idle && done) transmit_event(q, &si->dline, now); + return q->head; } /* @@ -623,7 +607,7 @@ dummynet_task(void *context, int pending tick_adjustment++; } - /* serve all pending events */ + /* serve pending events, accumulate in q */ for (;;) { struct dn_id *p; /* generic parameter to handler */ @@ -658,20 +642,21 @@ dummynet_send(struct mbuf *m) for (; m != NULL; m = n) { struct ifnet *ifp; - int dst; struct m_tag *tag; + int dst; n = m->m_nextpkt; m->m_nextpkt = NULL; tag = m_tag_first(m); - if (tag == NULL) { + if (tag == NULL) { /* should not happen */ dst = DIR_DROP; } else { struct dn_pkt_tag *pkt = dn_tag_get(m); - /* extract the dummynet info, rename the tag */ + /* extract the dummynet info, rename the tag + * to carry reinject info. + */ dst = pkt->dn_dir; ifp = pkt->ifp; - /* rename the tag so it carries reinject info */ tag->m_tag_cookie = MTAG_IPFW_RULE; tag->m_tag_id = 0; } @@ -681,11 +666,13 @@ dummynet_send(struct mbuf *m) SET_HOST_IPLEN(mtod(m, struct ip *)); ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); break ; + case DIR_IN : /* put header in network format for ip_input() */ //SET_NET_IPLEN(mtod(m, struct ip *)); netisr_dispatch(NETISR_IP, m); break; + #ifdef INET6 case DIR_IN | PROTO_IPV6: netisr_dispatch(NETISR_IPV6, m); @@ -696,6 +683,7 @@ dummynet_send(struct mbuf *m) ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL); break; #endif + case DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */ if (bridge_dn_p != NULL) ((*bridge_dn_p)(m, ifp)); @@ -703,6 +691,7 @@ dummynet_send(struct mbuf *m) printf("dummynet: if_bridge not loaded\n"); break; + case DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */ /* * The Ethernet code assumes the Ethernet header is @@ -717,6 +706,7 @@ dummynet_send(struct mbuf *m) } ether_demux(m->m_pkthdr.rcvif, m); break; + case DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */ ether_output_frame(ifp, m); break; @@ -760,13 +750,8 @@ int dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa) { struct mbuf *m = *m0; - struct dn_pkt_tag *pkt; - struct m_tag *mtag; struct new_fsk *fs = NULL; - struct new_pipe *pipe = NULL; - struct new_queue *q = NULL; - struct new_schk *sch; - struct new_sch_inst *sch_inst; + struct new_sch_inst *si; dn_key now; /* save a copy of curr_time */ int fs_id = (fwa->rule.info & IPFW_INFO_MASK) + @@ -777,57 +762,58 @@ dummynet_io(struct mbuf **m0, int dir, s fs = ipdn_locate_flowset(fs_id); if (fs == NULL) goto dropit; /* This queue/pipe does not exist! */ - sch = fs->sched; - if (sch == NULL) /* should not happen */ + if (fs->sched == NULL) /* should not happen */ goto dropit; /* find_sch_inst can be fast */ - sch_inst = find_sch_inst(sch, &(fwa->f_id)); - if (sch_inst == NULL) + si = find_sch_inst(fs->sched, &(fwa->f_id)); + if (si == NULL) goto dropit; /* tag the mbuf */ + { + struct dn_pkt_tag *dt; + struct m_tag *mtag; mtag = m_tag_get(PACKET_TAG_DUMMYNET, - sizeof(struct dn_pkt_tag), M_NOWAIT | M_ZERO); + sizeof(*dt), M_NOWAIT | M_ZERO); if (mtag == NULL) goto dropit; /* Cannot allocate packet header. */ m_tag_prepend(m, mtag); /* Attach to mbuf chain. */ - pkt = (struct dn_pkt_tag *)(mtag + 1); - pkt->rule = fwa->rule; - 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 */ - + dt = (struct dn_pkt_tag *)(mtag + 1); + dt->rule = fwa->rule; + dt->rule.info &= IPFW_ONEPASS; /* only keep this info */ + dt->dn_dir = dir; + dt->ifp = fwa->oif; + /* dt->output tame is updated as we move through */ + dt->output_time = now = curr_time; + } if (fs->kflags & DN_HAVE_MASK) do_mask(&fs->fs.flow_mask, &(fwa->f_id)); - if (sch->fp->enqueue(sch_inst, fs, m, &(fwa->f_id))) { + if (fs->sched->fp->enqueue(si, fs, m, &(fwa->f_id))) { printf("%s dropped by enqueue\n", __FUNCTION__); /* packet was dropped by enqueue() */ *m0 = NULL; goto dropit; } - if (sch_inst->kflags & DN_ACTIVE) { + if (si->kflags & DN_ACTIVE) { m = *m0 = NULL; /* consumed */ goto done; /* already active, nothing to do */ } /* compute the initial allowance */ - pipe = &sch->pipe; - sch_inst->credit = dn_cfg.io_fast ? pipe->bandwidth : 0; + { + struct new_pipe *pipe = &fs->sched->pipe; + si->credit = dn_cfg.io_fast ? pipe->bandwidth : 0; if (pipe->burst) { - uint64_t burst = (now - sch_inst->idle_time) * + uint64_t burst = (now - si->idle_time) * pipe->bandwidth; if (burst > pipe->burst) burst = pipe->burst; - sch_inst->credit += burst; + si->credit += burst; } - { /* pass through scheduler and delay line */ - struct mq q = { NULL, NULL }; - serve_sched(&q, sch_inst, now); - m = q.head; - } + } + /* pass through scheduler and delay line */ + m = serve_sched(NULL, si, now); /* optimization -- pass it back to ipfw for immediate send */ if (dn_cfg.io_fast && m == *m0 && (dir & PROTO_LAYER2) == 0 ) { @@ -849,10 +835,8 @@ done: dropit: io_pkt_drop++; - if (q) - q->drops++; DUMMYNET_UNLOCK(); FREE_PKT(m); *m0 = NULL; - return ((fs && (fs->fs.flags & DN_NOERROR)) ? 0 : ENOBUFS); + 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 Mon Jan 11 22:34:25 2010 (r202123) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dn_private.h Mon Jan 11 22:35:19 2010 (r202124) @@ -169,10 +169,9 @@ struct new_schk { struct dn_sched *fp; /* Pointer to scheduler functions */ }; -/* Implementation of the packets queue associated with a scheduler instance */ +/* The packets queue associated with a scheduler instance */ struct new_queue { - struct dn_id oid; - struct ipfw_flow_id id; + struct new_inst ni; /* oid, flow_id, stats */ struct mq mq; /* packets queue */ SLIST_ENTRY(new_queue) ql_next; /* linked list to sch_inst */ @@ -180,13 +179,6 @@ struct new_queue { struct new_fsk *fs; /* parent flowset. */ /* If fs->kflags & DN_DELETE, remove the queue when empty. */ - - /* stats */ - 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; }; SLIST_HEAD(new_queue_head, new_queue); Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 11 22:34:25 2010 (r202123) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 11 22:35:19 2010 (r202124) @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include #include /* IFNAMSIZ, struct ifaddr, ifq head, lock.h mutex.h */ #include -//#include /* ip_len, ip_off */ #include /* ip_output(), IP_FORWARDING */ #include #include @@ -61,7 +60,7 @@ __FBSDID("$FreeBSD$"); static int ip_dn_ctl(struct sockopt *sopt); - /* which objects to copy */ +/* which objects to copy */ #define DN_C_PIPE 0x01 #define DN_C_SCH 0x02 #define DN_C_SCH_INST 0x04 @@ -203,7 +202,7 @@ dn_create_queue(struct new_sch_inst *si, return NULL; } - set_oid(&q->oid, DN_QUEUE, 0, size); + set_oid(&q->ni.oid, DN_QUEUE, 0, size); q->fs = fs; q->si = si; fs->refcnt++; @@ -400,29 +399,33 @@ static int do_config(void *p, int l) { struct dn_id *next, *o; - int err = 0, cmd = 0; + int err = 0; struct dn_id *arg = NULL; for (o = p; l >= sizeof(*o); o = next) { struct dn_id *prev = arg; - err = EINVAL; if (o->len < sizeof(*o) || l < o->len) { printf("bad len o->len %d len %d\n", o->len, l); + err = EINVAL; break; } l -= o->len; printf("%s cmd %d len %d left %d\n", __FUNCTION__, o->type, o->len, l); next = (struct dn_id *)((char *)o + o->len); + err = 0; switch (o->type) { + default: + printf("cmd %d not implemented\n", o->type); + break; + case DN_CMD_CONFIGURE: - case DN_CMD_GET: - case DN_CMD_DELETE: + break; + case DN_CMD_FLUSH: - cmd = o->type; - err = 0; + dummynet_flush(); break; - case DN_TEXT: /* store for the next block */ + case DN_TEXT: /* store argument the next block */ prev = NULL; arg = o; break; @@ -450,13 +453,12 @@ do_config(void *p, int l) static struct new_schk * locate_scheduler(int sch_nr) { - struct new_schk *sch; - - SLIST_FOREACH(sch, &dn_cfg.schedhash[HASH(sch_nr)], next) - if (sch->sch.sched_nr == sch_nr) - return (sch); + struct new_schk *sch; - return (NULL); + SLIST_FOREACH(sch, &dn_cfg.schedhash[HASH(sch_nr)], next) + if (sch->sch.sched_nr == sch_nr) + return (sch); + return (NULL); } /* update all flowsets which may refer to this scheduler */ @@ -634,7 +636,6 @@ config_fs(struct new_fs *nfs, struct dn_ DUMMYNET_LOCK(); fs = ipdn_locate_flowset(i); - printf("%s %d old %p\n", __FUNCTION__, i, fs); if (fs == NULL) { fs = create_fs(); if (fs == NULL) { @@ -646,27 +647,21 @@ config_fs(struct new_fs *nfs, struct dn_ /* copy values, check if scheduler exists and mark active */ s = locate_scheduler(nfs->sched_nr); s_changed = s == NULL || fs->sched == NULL || fs->sched->fp != s->fp; - if (fs->sched) { - printf("%s remove from fsk_list\n", __FUNCTION__); + if (fs->sched) { // XXX and not DN_DELETE ? SLIST_REMOVE(&fs->sched->fsk_list, fs, new_fsk, sch_chain); - printf("%s remove from fshash\n", __FUNCTION__); SLIST_REMOVE(&dn_cfg.fshash[HASH(i)], fs, new_fsk, next); if (s_changed && fs->sched->fp->free_fs) fs->sched->fp->free_fs(fs); } else { - printf("%s remove from fsunlinked\n", __FUNCTION__); SLIST_REMOVE(&dn_cfg.fsunlinked, fs, new_fsk, next); } fs->sched = s; if (s) { - printf("%s insert in fsk_list\n", __FUNCTION__); SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain); - printf("%s insert in fshash\n", __FUNCTION__); SLIST_INSERT_HEAD(&dn_cfg.fshash[HASH(i)], fs, next); if (s_changed && s->fp->new_fs) s->fp->new_fs(fs, arg, 1); } else { - printf("%s insert in fsunlinked\n", __FUNCTION__); SLIST_INSERT_HEAD(&dn_cfg.fsunlinked, fs, next); } dn_cfg.id++; @@ -737,69 +732,84 @@ config_profile(struct new_profile *pf, s } static int -dummynet_get(struct sockopt *sopt) +compute_space(struct dn_id *cmd, int *to_copy) { - int have = 0, i, need, error; - char *start = NULL, *buf, *end; - size_t sopt_valsize; - struct dn_id cmd; - int to_copy = 0; - - /* save original values */ - sopt_valsize = sopt->sopt_valsize; - printf("%s have %d bytes\n", __FUNCTION__, sopt_valsize); - - error = sooptcopyin(sopt, &cmd, sizeof(cmd), sizeof(cmd)); - sopt->sopt_valsize = sopt_valsize; - if (error) - return error; - printf("%s cmd %d len %d\n", __FUNCTION__, cmd.type, cmd.len); - for (have = 0, i = 0; i < 10; i++) { - DUMMYNET_LOCK(); - switch (cmd.subtype) { + int need; + + *to_copy = 0; + switch (cmd->subtype) { default: - return EINVAL; + return -1; case DN_SCH: /* pipe show */ - to_copy = DN_C_SCH | DN_C_PIPE | DN_C_SCH_INST; - need = dn_cfg.schk_count * - (sizeof(struct new_sch) + sizeof(struct new_pipe)); - need += dn_cfg.si_count * sizeof(struct new_inst); - break; + *to_copy = DN_C_SCH | DN_C_PIPE | DN_C_SCH_INST; + need = dn_cfg.schk_count * + (sizeof(struct new_sch) + sizeof(struct new_pipe)); + need += dn_cfg.si_count * sizeof(struct new_inst); + break; case DN_FS: /* queue show */ - to_copy = DN_C_FS; - need = dn_cfg.fsk_count * - (sizeof(struct new_fs)); - break; - } - need += sizeof(cmd); - cmd.id = need; - printf("pass %d have %d need %d len %d\n", - i, have, need, sopt_valsize); - if (have >= need) - break; - DUMMYNET_UNLOCK(); - if (start) - free(start, M_DUMMYNET); - buf = NULL; - if (need > sopt_valsize) - break; - have = need; - start = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO); + *to_copy = DN_C_FS; + need = dn_cfg.fsk_count * (sizeof(struct new_fs)); + break; + } + return need; +} + +static int +dummynet_get(struct sockopt *sopt) +{ + int have, i, need, error, to_copy = 0; + char *start = NULL, *buf, *end; + size_t sopt_valsize; + struct dn_id cmd; + + /* save and restore original sopt_valsize around copyin */ + sopt_valsize = sopt->sopt_valsize; + printf("%s have %d bytes\n", __FUNCTION__, sopt_valsize); + error = sooptcopyin(sopt, &cmd, sizeof(cmd), sizeof(cmd)); + sopt->sopt_valsize = sopt_valsize; + if (error) + return error; + printf("%s cmd %d len %d\n", __FUNCTION__, cmd.type, cmd.len); + /* Count space (under lock) and allocate (outside lock). + * Exit with lock held if we manage to get enough buffer. + * Try a few times then give up. + */ + for (have = 0, i = 0; i < 10; i++) { + DUMMYNET_LOCK(); + need = compute_space(&cmd, &to_copy); + if (need < 0) { + DUMMYNET_UNLOCK(); + return EINVAL; + } + need += sizeof(cmd); + cmd.id = need; + printf("pass %d have %d need %d len %d\n", + i, have, need, sopt_valsize); + if (have >= need) + break; + DUMMYNET_UNLOCK(); + if (start) + free(start, M_DUMMYNET); + buf = NULL; + if (need > sopt_valsize) + break; + have = need; + start = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO); + if (start == NULL) + return ENOMEM; + } if (start == NULL) - return ENOMEM; - } - if (start == NULL) - return sooptcopyout(sopt, &cmd, sizeof(cmd)); - end = start + have; - sopt->sopt_valsize = sopt_valsize; - bcopy(&cmd, start, sizeof(cmd)); - buf = start + sizeof(cmd); - /* start copying other objects */ - copy_data(&buf, end, to_copy); - DUMMYNET_UNLOCK(); - error = sooptcopyout(sopt, start, buf - start); - free(start, M_DUMMYNET); - return error; + return sooptcopyout(sopt, &cmd, sizeof(cmd)); + end = start + have; + sopt->sopt_valsize = sopt_valsize; + bcopy(&cmd, start, sizeof(cmd)); + buf = start + sizeof(cmd); + /* start copying other objects */ + copy_data(&buf, end, to_copy); + DUMMYNET_UNLOCK(); + error = sooptcopyout(sopt, start, buf - start); + free(start, M_DUMMYNET); + return error; } /* @@ -828,16 +838,19 @@ ip_dn_ctl(struct sockopt *sopt) error = EINVAL; 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 */ + case IP_DUMMYNET_GET : + printf("dummynet: -- compat option %d", sopt->sopt_name); + error = EINVAL; + break; + + case IP_DUMMYNET3 : /* remove a pipe or queue */ + if (sopt->sopt_dir == SOPT_GET) { + error = dummynet_get(sopt); + break; + } l = sopt->sopt_valsize; if (l < 0 || l > 12000) { printf("argument too large, %d\n", l); @@ -964,18 +977,9 @@ load_descriptor(struct dn_sched *d) { struct dn_sched *s; - ip_dn_init(); if (d == NULL) return 1; /* error */ - - printf("%s %s start\n", __FUNCTION__, d->name); - /* Search if scheduler already exists */ - SLIST_FOREACH(s, &list_of_scheduler, next) { - if (strcmp(s->name, d->name) == 0) { - printf("%s %s already there\n", __FUNCTION__, d->name); - return 1; /* scheduler already exists */ - } - } + ip_dn_init(); /* just in case */ /* Check that mandatory funcs exists */ if (d->enqueue == NULL || d->dequeue == NULL) { @@ -983,12 +987,20 @@ load_descriptor(struct dn_sched *d) return 1; } + /* Search if scheduler already exists */ DUMMYNET_LOCK(); - SLIST_INSERT_HEAD(&list_of_scheduler, d, next); - printf("%s %s loaded\n", __FUNCTION__, d->name); + SLIST_FOREACH(s, &list_of_scheduler, next) { + if (strcmp(s->name, d->name) == 0) { + printf("%s %s already loaded\n", __FUNCTION__, d->name); + break; /* scheduler already exists */ + } + } + if (s == NULL) + SLIST_INSERT_HEAD(&list_of_scheduler, d, next); DUMMYNET_UNLOCK(); + printf("dn_sched %s %sloaded\n", d->name, s ? "not ":""); - return 0; /* ok */ + return s ? 1 : 0; } static int @@ -1017,27 +1029,18 @@ unload_descriptor(struct dn_sched *s) int dn_sched_modevent(module_t mod, int cmd, void *arg) { - struct dn_sched *sch = arg; - int error = EOPNOTSUPP; - printf("%s called\n", __FUNCTION__); - - switch(cmd) { - case MOD_LOAD: - error = load_descriptor(sch); - break; - - case MOD_UNLOAD: - error = unload_descriptor(sch); - break; - } - - return error; + struct dn_sched *sch = arg; + + if (cmd == MOD_LOAD) + return load_descriptor(sch); + else if (cmd == MOD_UNLOAD) + return unload_descriptor(sch); + else + return EINVAL; } static moduledata_t dummynet_mod = { - "dummynet", - dummynet_modevent, - NULL + "dummynet", dummynet_modevent, NULL }; DECLARE_MODULE(dummynet, dummynet_mod,