diff --git a/sys/netpfil/ipfw/dn_aqm.h b/sys/netpfil/ipfw/dn_aqm.h --- a/sys/netpfil/ipfw/dn_aqm.h +++ b/sys/netpfil/ipfw/dn_aqm.h @@ -37,9 +37,9 @@ #define _IP_DN_AQM_H /* NOW is the current time in millisecond*/ -#define NOW ((dn_cfg.curr_time * tick) / 1000) +#define NOW ((V_dn_cfg.curr_time * tick) / 1000) -#define AQM_UNOW (dn_cfg.curr_time * tick) +#define AQM_UNOW (V_dn_cfg.curr_time * tick) #define AQM_TIME_1US ((aqm_time_t)(1)) #define AQM_TIME_1MS ((aqm_time_t)(1000)) #define AQM_TIME_1S ((aqm_time_t)(AQM_TIME_1MS * 1000)) @@ -134,7 +134,7 @@ if (drop) { qni->drops++; sni->drops++; - dn_cfg.io_pkt_drop++; + V_dn_cfg.io_pkt_drop++; } else { /*update queue stats */ qni->length += inc; diff --git a/sys/netpfil/ipfw/dn_aqm_codel.c b/sys/netpfil/ipfw/dn_aqm_codel.c --- a/sys/netpfil/ipfw/dn_aqm_codel.c +++ b/sys/netpfil/ipfw/dn_aqm_codel.c @@ -202,7 +202,7 @@ update_stats(q, -m->m_pkthdr.len, 0); if (q->ni.length == 0) /* queue is now idle */ - q->q_time = dn_cfg.curr_time; + q->q_time = V_dn_cfg.curr_time; /* extract packet TS*/ mtag = m_tag_locate(m, MTAG_ABI_COMPAT, DN_AQM_MTAG_TS, NULL); diff --git a/sys/netpfil/ipfw/dn_aqm_pie.c b/sys/netpfil/ipfw/dn_aqm_pie.c --- a/sys/netpfil/ipfw/dn_aqm_pie.c +++ b/sys/netpfil/ipfw/dn_aqm_pie.c @@ -338,7 +338,7 @@ update_stats(q, -m->m_pkthdr.len, 0); if (q->ni.length == 0) /* queue is now idle */ - q->q_time = dn_cfg.curr_time; + q->q_time = V_dn_cfg.curr_time; if (getts) { /* extract packet TS*/ diff --git a/sys/netpfil/ipfw/dn_sched.h b/sys/netpfil/ipfw/dn_sched.h --- a/sys/netpfil/ipfw/dn_sched.h +++ b/sys/netpfil/ipfw/dn_sched.h @@ -187,7 +187,7 @@ q->_si->ni.len_bytes -= m->m_pkthdr.len; } if (q->ni.length == 0) /* queue is now idle */ - q->q_time = dn_cfg.curr_time; + q->q_time = V_dn_cfg.curr_time; return m; } diff --git a/sys/netpfil/ipfw/dn_sched_fq_codel.h b/sys/netpfil/ipfw/dn_sched_fq_codel.h --- a/sys/netpfil/ipfw/dn_sched_fq_codel.h +++ b/sys/netpfil/ipfw/dn_sched_fq_codel.h @@ -36,6 +36,9 @@ #ifndef _IP_DN_SCHED_FQ_CODEL_H #define _IP_DN_SCHED_FQ_CODEL_H +VNET_DECLARE(unsigned long, io_pkt_drop); +#define V_io_pkt_drop VNET(io_pkt_drop) + /* list of queues */ STAILQ_HEAD(fq_codel_list, fq_codel_flow) ; @@ -104,7 +107,7 @@ si->main_q.ni.drops ++; q->stats.drops ++; si->_si.ni.drops ++; - dn_cfg.io_pkt_drop ++; + V_dn_cfg.io_pkt_drop ++; } if (!drop || (drop && len < 0)) { @@ -147,7 +150,7 @@ fq_update_stats(q, si, -m->m_pkthdr.len, 0); if (si->main_q.ni.length == 0) /* queue is now idle */ - si->main_q.q_time = dn_cfg.curr_time; + si->main_q.q_time = V_dn_cfg.curr_time; /* extract packet timestamp*/ struct m_tag *mtag; diff --git a/sys/netpfil/ipfw/dn_sched_fq_codel.c b/sys/netpfil/ipfw/dn_sched_fq_codel.c --- a/sys/netpfil/ipfw/dn_sched_fq_codel.c +++ b/sys/netpfil/ipfw/dn_sched_fq_codel.c @@ -165,7 +165,7 @@ fq_update_stats(q, si, -m->m_pkthdr.len, 1); if (si->main_q.ni.length == 0) /* queue is now idle */ - si->main_q.q_time = dn_cfg.curr_time; + si->main_q.q_time = V_dn_cfg.curr_time; FREE_PKT(m); } diff --git a/sys/netpfil/ipfw/dn_sched_fq_pie.c b/sys/netpfil/ipfw/dn_sched_fq_pie.c --- a/sys/netpfil/ipfw/dn_sched_fq_pie.c +++ b/sys/netpfil/ipfw/dn_sched_fq_pie.c @@ -82,6 +82,9 @@ #define DN_SCHED_FQ_PIE 7 +VNET_DECLARE(unsigned long, io_pkt_drop); +#define V_io_pkt_drop VNET(io_pkt_drop) + /* list of queues */ STAILQ_HEAD(fq_pie_list, fq_pie_flow) ; @@ -299,7 +302,7 @@ si->main_q.ni.drops ++; q->stats.drops ++; si->_si.ni.drops ++; - dn_cfg.io_pkt_drop ++; + V_dn_cfg.io_pkt_drop ++; } if (!drop || (drop && len < 0)) { @@ -347,7 +350,7 @@ fq_update_stats(q, si, -m->m_pkthdr.len, 0); if (si->main_q.ni.length == 0) /* queue is now idle */ - si->main_q.q_time = dn_cfg.curr_time; + si->main_q.q_time = V_dn_cfg.curr_time; if (getts) { /* extract packet timestamp*/ @@ -768,7 +771,7 @@ fq_update_stats(q, si, -m->m_pkthdr.len, 1); if (si->main_q.ni.length == 0) /* queue is now idle */ - si->main_q.q_time = dn_cfg.curr_time; + si->main_q.q_time = V_dn_cfg.curr_time; /* reset accu_prob after packet drop */ q->pst.accu_prob = 0; diff --git a/sys/netpfil/ipfw/ip_dn_glue.c b/sys/netpfil/ipfw/ip_dn_glue.c --- a/sys/netpfil/ipfw/ip_dn_glue.c +++ b/sys/netpfil/ipfw/ip_dn_glue.c @@ -567,10 +567,10 @@ * - all flowset queues: queue_count * - all pipe queue: si_count */ - need += dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2; - need += dn_cfg.fsk_count * sizeof(struct dn_flow_set); - need += dn_cfg.si_count * sizeof(struct dn_flow_queue8); - need += dn_cfg.queue_count * sizeof(struct dn_flow_queue8); + need += V_dn_cfg.schk_count * sizeof(struct dn_pipe8) / 2; + need += V_dn_cfg.fsk_count * sizeof(struct dn_flow_set); + need += V_dn_cfg.si_count * sizeof(struct dn_flow_queue8); + need += V_dn_cfg.queue_count * sizeof(struct dn_flow_queue8); return need; } diff --git a/sys/netpfil/ipfw/ip_dn_io.c b/sys/netpfil/ipfw/ip_dn_io.c --- a/sys/netpfil/ipfw/ip_dn_io.c +++ b/sys/netpfil/ipfw/ip_dn_io.c @@ -74,11 +74,10 @@ /* * We keep a private variable for the simulation time, but we could * probably use an existing one ("softticks" in sys/kern/kern_timeout.c) - * instead of dn_cfg.curr_time + * instead of V_dn_cfg.curr_time */ - -struct dn_parms dn_cfg; -//VNET_DEFINE(struct dn_parms, _base_dn_cfg); +VNET_DEFINE(struct dn_parms, dn_cfg); +#define V_dn_cfg VNET(dn_cfg) /* * We use a heap to store entities for which we have pending timer events. @@ -102,13 +101,13 @@ { int error, value; - value = dn_cfg.hash_size; + value = V_dn_cfg.hash_size; error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (value < 16 || value > 65536) return (EINVAL); - dn_cfg.hash_size = value; + V_dn_cfg.hash_size = value; return (0); } @@ -119,9 +118,9 @@ long value; if (arg2 != 0) - value = dn_cfg.slot_limit; + value = V_dn_cfg.slot_limit; else - value = dn_cfg.byte_limit; + value = V_dn_cfg.byte_limit; error = sysctl_handle_long(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) @@ -129,11 +128,11 @@ if (arg2 != 0) { if (value < 1) return (EINVAL); - dn_cfg.slot_limit = value; + V_dn_cfg.slot_limit = value; } else { if (value < 1500) return (EINVAL); - dn_cfg.byte_limit = value; + V_dn_cfg.byte_limit = value; } return (0); } @@ -151,9 +150,9 @@ "Dummynet"); #endif -/* wrapper to pass dn_cfg fields to SYSCTL_* */ -//#define DC(x) (&(VNET_NAME(_base_dn_cfg).x)) -#define DC(x) (&(dn_cfg.x)) +/* wrapper to pass V_dn_cfg fields to SYSCTL_* */ +#define DC(x) (&(VNET_NAME(dn_cfg).x)) + /* parameters */ SYSCTL_PROC(_net_inet_ip_dummynet, OID_AUTO, hash_size, @@ -349,7 +348,7 @@ * XXX check wraps... */ if (q->avg) { - u_int t = div64((dn_cfg.curr_time - q->q_time), fs->lookup_step); + u_int t = div64((V_dn_cfg.curr_time - q->q_time), fs->lookup_step); q->avg = (t < fs->lookup_depth) ? SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0; @@ -524,7 +523,7 @@ return (0); drop: - dn_cfg.io_pkt_drop++; + V_dn_cfg.io_pkt_drop++; q->ni.drops++; ni->drops++; FREE_PKT(m); @@ -553,7 +552,7 @@ } if (m != NULL) { dline->oid.subtype = 1; /* in heap */ - heap_insert(&dn_cfg.evheap, pkt->output_time, dline); + heap_insert(&V_dn_cfg.evheap, pkt->output_time, dline); } } @@ -616,7 +615,7 @@ (m->m_pkthdr.len * 8 + extra_bits(m, s)); si->credit -= len_scaled; /* Move packet in the delay line */ - dn_tag_get(m)->output_time = dn_cfg.curr_time + s->link.delay ; + dn_tag_get(m)->output_time = V_dn_cfg.curr_time + s->link.delay ; mq_append(&si->dline.mq, m); } @@ -634,7 +633,7 @@ if (m) dn_tag_get(m)->output_time += t; si->kflags |= DN_ACTIVE; - heap_insert(&dn_cfg.evheap, now + t, si); + heap_insert(&V_dn_cfg.evheap, now + t, si); } if (delay_line_idle && done) transmit_event(q, &si->dline, now); @@ -651,74 +650,85 @@ { struct timeval t; struct mq q = { NULL, NULL }; /* queue to accumulate results */ + struct epoch_tracker et; - CURVNET_SET((struct vnet *)context); + VNET_ITERATOR_DECL(vnet_iter); + VNET_LIST_RLOCK(); + NET_EPOCH_ENTER(et); - DN_BH_WLOCK(); + VNET_FOREACH(vnet_iter) { + memset(&q, 0, sizeof(struct mq)); + CURVNET_SET(vnet_iter); - /* Update number of lost(coalesced) ticks. */ - dn_cfg.tick_lost += pending - 1; + DN_BH_WLOCK(); - getmicrouptime(&t); - /* Last tick duration (usec). */ - dn_cfg.tick_last = (t.tv_sec - dn_cfg.prev_t.tv_sec) * 1000000 + - (t.tv_usec - dn_cfg.prev_t.tv_usec); - /* Last tick vs standard tick difference (usec). */ - dn_cfg.tick_delta = (dn_cfg.tick_last * hz - 1000000) / hz; - /* Accumulated tick difference (usec). */ - dn_cfg.tick_delta_sum += dn_cfg.tick_delta; + /* Update number of lost(coalesced) ticks. */ + V_dn_cfg.tick_lost += pending - 1; - dn_cfg.prev_t = t; + getmicrouptime(&t); + /* Last tick duration (usec). */ + V_dn_cfg.tick_last = (t.tv_sec - V_dn_cfg.prev_t.tv_sec) * 1000000 + + (t.tv_usec - V_dn_cfg.prev_t.tv_usec); + /* Last tick vs standard tick difference (usec). */ + V_dn_cfg.tick_delta = (V_dn_cfg.tick_last * hz - 1000000) / hz; + /* Accumulated tick difference (usec). */ + V_dn_cfg.tick_delta_sum += V_dn_cfg.tick_delta; - /* - * Adjust curr_time if the accumulated tick difference is - * greater than the 'standard' tick. Since curr_time should - * be monotonically increasing, we do positive adjustments - * as required, and throttle curr_time in case of negative - * adjustment. - */ - dn_cfg.curr_time++; - if (dn_cfg.tick_delta_sum - tick >= 0) { - int diff = dn_cfg.tick_delta_sum / tick; - - dn_cfg.curr_time += diff; - dn_cfg.tick_diff += diff; - dn_cfg.tick_delta_sum %= tick; - dn_cfg.tick_adjustment++; - } else if (dn_cfg.tick_delta_sum + tick <= 0) { - dn_cfg.curr_time--; - dn_cfg.tick_diff--; - dn_cfg.tick_delta_sum += tick; - dn_cfg.tick_adjustment++; - } + V_dn_cfg.prev_t = t; - /* serve pending events, accumulate in q */ - for (;;) { - struct dn_id *p; /* generic parameter to handler */ + /* + * Adjust curr_time if the accumulated tick difference is + * greater than the 'standard' tick. Since curr_time should + * be monotonically increasing, we do positive adjustments + * as required, and throttle curr_time in case of negative + * adjustment. + */ + V_dn_cfg.curr_time++; + if (V_dn_cfg.tick_delta_sum - tick >= 0) { + int diff = V_dn_cfg.tick_delta_sum / tick; + + V_dn_cfg.curr_time += diff; + V_dn_cfg.tick_diff += diff; + V_dn_cfg.tick_delta_sum %= tick; + V_dn_cfg.tick_adjustment++; + } else if (V_dn_cfg.tick_delta_sum + tick <= 0) { + V_dn_cfg.curr_time--; + V_dn_cfg.tick_diff--; + V_dn_cfg.tick_delta_sum += tick; + V_dn_cfg.tick_adjustment++; + } - if (dn_cfg.evheap.elements == 0 || - DN_KEY_LT(dn_cfg.curr_time, HEAP_TOP(&dn_cfg.evheap)->key)) - break; - p = HEAP_TOP(&dn_cfg.evheap)->object; - heap_extract(&dn_cfg.evheap, NULL); + /* serve pending events, accumulate in q */ + for (;;) { + struct dn_id *p; /* generic parameter to handler */ - if (p->type == DN_SCH_I) { - serve_sched(&q, (struct dn_sch_inst *)p, dn_cfg.curr_time); - } else { /* extracted a delay line */ - transmit_event(&q, (struct delay_line *)p, dn_cfg.curr_time); + if (V_dn_cfg.evheap.elements == 0 || + DN_KEY_LT(V_dn_cfg.curr_time, HEAP_TOP(&V_dn_cfg.evheap)->key)) + break; + p = HEAP_TOP(&V_dn_cfg.evheap)->object; + heap_extract(&V_dn_cfg.evheap, NULL); + if (p->type == DN_SCH_I) { + serve_sched(&q, (struct dn_sch_inst *)p, V_dn_cfg.curr_time); + } else { /* extracted a delay line */ + transmit_event(&q, (struct delay_line *)p, V_dn_cfg.curr_time); + } } + if (V_dn_cfg.expire && ++V_dn_cfg.expire_cycle >= V_dn_cfg.expire) { + V_dn_cfg.expire_cycle = 0; + dn_drain_scheduler(); + dn_drain_queue(); + } + DN_BH_WUNLOCK(); + if (q.head != NULL) + dummynet_send(q.head); + + CURVNET_RESTORE(); } - if (dn_cfg.expire && ++dn_cfg.expire_cycle >= dn_cfg.expire) { - dn_cfg.expire_cycle = 0; - dn_drain_scheduler(); - dn_drain_queue(); - } + NET_EPOCH_EXIT(et); + VNET_LIST_RUNLOCK(); + /* Schedule our next run. */ dn_reschedule(); - DN_BH_WUNLOCK(); - if (q.head != NULL) - dummynet_send(q.head); - CURVNET_RESTORE(); } /* @@ -834,7 +844,7 @@ dt->dn_dir = dir; dt->ifp = fwa->flags & IPFW_ARGS_OUT ? fwa->ifp : NULL; /* dt->output tame is updated as we move through */ - dt->output_time = dn_cfg.curr_time; + dt->output_time = V_dn_cfg.curr_time; dt->iphdr_off = (dir & PROTO_LAYER2) ? ETHER_HDR_LEN : 0; return 0; } @@ -866,12 +876,12 @@ else if (fwa->flags & IPFW_ARGS_IP6) dir |= PROTO_IPV6; DN_BH_WLOCK(); - dn_cfg.io_pkt++; + V_dn_cfg.io_pkt++; /* we could actually tag outside the lock, but who cares... */ if (tag_mbuf(m, dir, fwa)) goto dropit; /* XXX locate_flowset could be optimised with a direct ref. */ - fs = dn_ht_find(dn_cfg.fshash, fs_id, 0, NULL); + fs = dn_ht_find(V_dn_cfg.fshash, fs_id, 0, NULL); if (fs == NULL) goto dropit; /* This queue/pipe does not exist! */ if (fs->sched == NULL) /* should not happen */ @@ -894,7 +904,7 @@ m = *m0 = NULL; /* dn_enqueue already increases io_pkt_drop */ - dn_cfg.io_pkt_drop--; + V_dn_cfg.io_pkt_drop--; goto dropit; } @@ -905,34 +915,34 @@ } /* compute the initial allowance */ - if (si->idle_time < dn_cfg.curr_time) { + if (si->idle_time < V_dn_cfg.curr_time) { /* Do this only on the first packet on an idle pipe */ struct dn_link *p = &fs->sched->link; - si->sched_time = dn_cfg.curr_time; - si->credit = dn_cfg.io_fast ? p->bandwidth : 0; + si->sched_time = V_dn_cfg.curr_time; + si->credit = V_dn_cfg.io_fast ? p->bandwidth : 0; if (p->burst) { - uint64_t burst = (dn_cfg.curr_time - si->idle_time) * p->bandwidth; + uint64_t burst = (V_dn_cfg.curr_time - si->idle_time) * p->bandwidth; if (burst > p->burst) burst = p->burst; si->credit += burst; } } /* pass through scheduler and delay line */ - m = serve_sched(NULL, si, dn_cfg.curr_time); + m = serve_sched(NULL, si, V_dn_cfg.curr_time); /* optimization -- pass it back to ipfw for immediate send */ /* XXX Don't call dummynet_send() if scheduler return the packet * just enqueued. This avoid a lock order reversal. * */ - if (/*dn_cfg.io_fast &&*/ m == *m0 && (dir & PROTO_LAYER2) == 0 ) { + if (/*V_dn_cfg.io_fast &&*/ m == *m0 && (dir & PROTO_LAYER2) == 0 ) { /* fast io, rename the tag * to carry reinject info. */ struct m_tag *tag = m_tag_first(m); tag->m_tag_cookie = MTAG_IPFW_RULE; tag->m_tag_id = 0; - dn_cfg.io_pkt_fast++; + V_dn_cfg.io_pkt_fast++; if (m->m_nextpkt != NULL) { printf("dummynet: fast io: pkt chain detected!\n"); m->m_nextpkt = NULL; @@ -948,7 +958,7 @@ return 0; dropit: - dn_cfg.io_pkt_drop++; + V_dn_cfg.io_pkt_drop++; DN_BH_WUNLOCK(); if (m) FREE_PKT(m); diff --git a/sys/netpfil/ipfw/ip_dn_private.h b/sys/netpfil/ipfw/ip_dn_private.h --- a/sys/netpfil/ipfw/ip_dn_private.h +++ b/sys/netpfil/ipfw/ip_dn_private.h @@ -46,7 +46,7 @@ #define D(fmt, ...) printf("%-10s " fmt "\n", \ __FUNCTION__, ## __VA_ARGS__) #define DX(lev, fmt, ...) do { \ - if (dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0) + if (V_dn_cfg.debug > lev) D(fmt, ## __VA_ARGS__); } while (0) #endif MALLOC_DECLARE(M_DUMMYNET); @@ -56,26 +56,26 @@ #endif #define DN_LOCK_INIT() do { \ - mtx_init(&dn_cfg.uh_mtx, "dn_uh", NULL, MTX_DEF); \ - mtx_init(&dn_cfg.bh_mtx, "dn_bh", NULL, MTX_DEF); \ + mtx_init(&V_dn_cfg.uh_mtx, "dn_uh", NULL, MTX_DEF); \ + mtx_init(&V_dn_cfg.bh_mtx, "dn_bh", NULL, MTX_DEF); \ } while (0) #define DN_LOCK_DESTROY() do { \ - mtx_destroy(&dn_cfg.uh_mtx); \ - mtx_destroy(&dn_cfg.bh_mtx); \ + mtx_destroy(&V_dn_cfg.uh_mtx); \ + mtx_destroy(&V_dn_cfg.bh_mtx); \ } while (0) #if 0 /* not used yet */ -#define DN_UH_RLOCK() mtx_lock(&dn_cfg.uh_mtx) -#define DN_UH_RUNLOCK() mtx_unlock(&dn_cfg.uh_mtx) -#define DN_UH_WLOCK() mtx_lock(&dn_cfg.uh_mtx) -#define DN_UH_WUNLOCK() mtx_unlock(&dn_cfg.uh_mtx) -#define DN_UH_LOCK_ASSERT() mtx_assert(&dn_cfg.uh_mtx, MA_OWNED) +#define DN_UH_RLOCK() mtx_lock(&V_dn_cfg.uh_mtx) +#define DN_UH_RUNLOCK() mtx_unlock(&V_dn_cfg.uh_mtx) +#define DN_UH_WLOCK() mtx_lock(&V_dn_cfg.uh_mtx) +#define DN_UH_WUNLOCK() mtx_unlock(&V_dn_cfg.uh_mtx) +#define DN_UH_LOCK_ASSERT() mtx_assert(&V_dn_cfg.uh_mtx, MA_OWNED) #endif -#define DN_BH_RLOCK() mtx_lock(&dn_cfg.uh_mtx) -#define DN_BH_RUNLOCK() mtx_unlock(&dn_cfg.uh_mtx) -#define DN_BH_WLOCK() mtx_lock(&dn_cfg.uh_mtx) -#define DN_BH_WUNLOCK() mtx_unlock(&dn_cfg.uh_mtx) -#define DN_BH_LOCK_ASSERT() mtx_assert(&dn_cfg.uh_mtx, MA_OWNED) +#define DN_BH_RLOCK() mtx_lock(&V_dn_cfg.uh_mtx) +#define DN_BH_RUNLOCK() mtx_unlock(&V_dn_cfg.uh_mtx) +#define DN_BH_WLOCK() mtx_lock(&V_dn_cfg.uh_mtx) +#define DN_BH_WUNLOCK() mtx_unlock(&V_dn_cfg.uh_mtx) +#define DN_BH_LOCK_ASSERT() mtx_assert(&V_dn_cfg.uh_mtx, MA_OWNED) SLIST_HEAD(dn_schk_head, dn_schk); SLIST_HEAD(dn_sch_inst_head, dn_sch_inst); @@ -101,7 +101,7 @@ } /* - * configuration and global data for a dummynet instance + * configuration and data for a dummynet instance * * When a configuration is modified from userland, 'id' is incremented * so we can use the value to check for stale pointers. @@ -154,10 +154,6 @@ struct dn_ht *schedhash; /* list of flowsets without a scheduler -- use sch_chain */ struct dn_fsk_head fsu; /* list of unlinked flowsets */ - struct dn_alg_head schedlist; /* list of algorithms */ -#ifdef NEW_AQM - struct dn_aqm_head aqmlist; /* list of AQMs */ -#endif /* Store the fs/sch to scan when draining. The value is the * bucket number of the hash table. Expire can be disabled @@ -406,9 +402,9 @@ PROTO_IFB = 0x0c, /* layer2 + ifbridge */ }; -extern struct dn_parms dn_cfg; -//VNET_DECLARE(struct dn_parms, _base_dn_cfg); -//#define dn_cfg VNET(_base_dn_cfg) +//extern struct dn_parms V_dn_cfg; +VNET_DECLARE(struct dn_parms, dn_cfg); +#define V_dn_cfg VNET(dn_cfg) int dummynet_io(struct mbuf **, struct ip_fw_args *); void dummynet_task(void *context, int pending); diff --git a/sys/netpfil/ipfw/ip_dummynet.c b/sys/netpfil/ipfw/ip_dummynet.c --- a/sys/netpfil/ipfw/ip_dummynet.c +++ b/sys/netpfil/ipfw/ip_dummynet.c @@ -63,6 +63,7 @@ #include /* ip_output(), IP_FORWARDING */ #include #include +#include #include #include @@ -87,10 +88,17 @@ /*---- callout hooks. ----*/ static struct callout dn_timeout; +static int dn_tasks_started = 0; static int dn_gone; static struct task dn_task; static struct taskqueue *dn_tq = NULL; +/* global scheduler list */ +struct dn_alg_head schedlist; +#ifdef NEW_AQM +struct dn_aqm_head aqmlist; /* list of AQMs */ +#endif + static void dummynet(void *arg) { @@ -117,7 +125,7 @@ { struct dn_aqm *d; - SLIST_FOREACH(d, &dn_cfg.aqmlist, next) { + SLIST_FOREACH(d, &aqmlist, next) { if (d->type == type || (name && !strcasecmp(d->name, name))) return d; } @@ -131,7 +139,7 @@ { struct dn_alg *d; - SLIST_FOREACH(d, &dn_cfg.schedlist, next) { + SLIST_FOREACH(d, &schedlist, next) { if (d->type == type || (name && !strcasecmp(d->name, name))) return d; } @@ -354,7 +362,7 @@ if(fs->aqmfp->init(q)) D("unable to init AQM for fs %d", fs->fs.fs_nr); #endif - dn_cfg.queue_count++; + V_dn_cfg.queue_count++; return q; } @@ -387,7 +395,7 @@ dn_free_pkts(q->mq.head); bzero(q, sizeof(*q)); // safety free(q, M_DUMMYNET); - dn_cfg.queue_count--; + V_dn_cfg.queue_count--; } } @@ -527,7 +535,7 @@ } #endif - dn_cfg.si_count++; + V_dn_cfg.si_count++; return si; error: @@ -552,10 +560,10 @@ struct delay_line *dl = &si->dline; if (dl->oid.subtype) /* remove delay line from event heap */ - heap_extract(&dn_cfg.evheap, dl); + heap_extract(&V_dn_cfg.evheap, dl); dn_free_pkts(dl->mq.head); /* drain delay line */ if (si->kflags & DN_ACTIVE) /* remove si from event heap */ - heap_extract(&dn_cfg.evheap, si); + heap_extract(&V_dn_cfg.evheap, si); #ifdef NEW_AQM /* clean up AQM status for !DN_MULTIQUEUE sched @@ -574,7 +582,7 @@ s->fp->free_sched(si); bzero(si, sizeof(*si)); /* safety */ free(si, M_DUMMYNET); - dn_cfg.si_count--; + V_dn_cfg.si_count--; return DNHT_SCAN_DEL; } @@ -605,7 +613,7 @@ struct dn_sch_inst *si = _si; struct dn_link *p = &si->sched->link; - si->credit = p->burst + (dn_cfg.io_fast ? p->bandwidth : 0); + si->credit = p->burst + (V_dn_cfg.io_fast ? p->bandwidth : 0); return 0; } @@ -651,9 +659,9 @@ fs = malloc(sizeof(*fs), M_DUMMYNET, M_NOWAIT | M_ZERO); if (fs) { set_oid(&fs->fs.oid, DN_FS, sizeof(fs->fs)); - dn_cfg.fsk_count++; + V_dn_cfg.fsk_count++; fs->drain_bucket = 0; - SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain); + SLIST_INSERT_HEAD(&V_dn_cfg.fsu, fs, sch_chain); } return fs; } @@ -737,7 +745,7 @@ (flags & DN_DETACH) ? "DET":""); if (flags & DN_DETACH) { /* detach from the list */ struct dn_fsk_head *h; - h = fs->sched ? &fs->sched->fsk_list : &dn_cfg.fsu; + h = fs->sched ? &fs->sched->fsk_list : &V_dn_cfg.fsu; SLIST_REMOVE(h, fs, dn_fsk, sch_chain); } /* Free the RED parameters, they will be recomputed on @@ -757,9 +765,9 @@ if (flags & DN_DELETE_FS) { bzero(fs, sizeof(*fs)); /* safety */ free(fs, M_DUMMYNET); - dn_cfg.fsk_count--; + V_dn_cfg.fsk_count--; } else { - SLIST_INSERT_HEAD(&dn_cfg.fsu, fs, sch_chain); + SLIST_INSERT_HEAD(&V_dn_cfg.fsu, fs, sch_chain); } } @@ -797,7 +805,7 @@ if (!locked) DN_BH_WLOCK(); - fs = dn_ht_find(dn_cfg.fshash, i, DNHT_REMOVE, NULL); + fs = dn_ht_find(V_dn_cfg.fshash, i, DNHT_REMOVE, NULL); ND("fs %d found %p", i, fs); if (fs) { fsk_detach(fs, DN_DETACH | DN_DELETE_FS); @@ -866,7 +874,7 @@ } } s->fp = NULL; /* mark as a new scheduler */ - dn_cfg.schk_count++; + V_dn_cfg.schk_count++; return s; } @@ -905,7 +913,7 @@ s->fp->destroy(s); bzero(s, sizeof(*s)); // safety free(obj, M_DUMMYNET); - dn_cfg.schk_count--; + V_dn_cfg.schk_count--; return DNHT_SCAN_DEL; } @@ -919,7 +927,7 @@ { struct dn_schk *s; - s = dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL); + s = dn_ht_find(V_dn_cfg.schedhash, i, DNHT_REMOVE, NULL); ND("%d %p", i, s); if (!s) return EINVAL; @@ -1176,7 +1184,7 @@ static inline struct dn_schk * locate_scheduler(int i) { - return dn_ht_find(dn_cfg.schedhash, i, 0, NULL); + return dn_ht_find(V_dn_cfg.schedhash, i, 0, NULL); } /* @@ -1194,10 +1202,10 @@ /* Doing stuff that was in userland */ i = fs->sched->link.bandwidth; s = (i <= 0) ? 0 : - hz * dn_cfg.red_avg_pkt_size * 8 * SCALE(1) / i; + hz * V_dn_cfg.red_avg_pkt_size * 8 * SCALE(1) / i; idle = div64((s * 3) , fs->w_q); /* s, fs->w_q scaled; idle not scaled */ - fs->lookup_step = div64(idle , dn_cfg.red_lookup_depth); + fs->lookup_step = div64(idle , V_dn_cfg.red_lookup_depth); /* fs->lookup_step not scaled, */ if (!fs->lookup_step) fs->lookup_step = 1; @@ -1227,14 +1235,14 @@ free(fs->w_q_lookup, M_DUMMYNET); fs->w_q_lookup = NULL; } - if (dn_cfg.red_lookup_depth == 0) { + if (V_dn_cfg.red_lookup_depth == 0) { printf("\ndummynet: net.inet.ip.dummynet.red_lookup_depth" "must be > 0\n"); fs->fs.flags &= ~DN_IS_RED; fs->fs.flags &= ~DN_IS_GENTLE_RED; return (EINVAL); } - fs->lookup_depth = dn_cfg.red_lookup_depth; + fs->lookup_depth = V_dn_cfg.red_lookup_depth; fs->w_q_lookup = (u_int *)malloc(fs->lookup_depth * sizeof(int), M_DUMMYNET, M_NOWAIT); if (fs->w_q_lookup == NULL) { @@ -1251,12 +1259,12 @@ fs->w_q_lookup[i] = SCALE_MUL(fs->w_q_lookup[i - 1], fs->lookup_weight); - if (dn_cfg.red_avg_pkt_size < 1) - dn_cfg.red_avg_pkt_size = 512; - fs->avg_pkt_size = dn_cfg.red_avg_pkt_size; - if (dn_cfg.red_max_pkt_size < 1) - dn_cfg.red_max_pkt_size = 1500; - fs->max_pkt_size = dn_cfg.red_max_pkt_size; + if (V_dn_cfg.red_avg_pkt_size < 1) + V_dn_cfg.red_avg_pkt_size = 512; + fs->avg_pkt_size = V_dn_cfg.red_avg_pkt_size; + if (V_dn_cfg.red_max_pkt_size < 1) + V_dn_cfg.red_max_pkt_size = 1500; + fs->max_pkt_size = V_dn_cfg.red_max_pkt_size; ND("exit"); return 0; } @@ -1278,7 +1286,7 @@ { ND("remove fs %d from fsunlinked, link to sched %d", fs->fs.fs_nr, s->sch.sched_nr); - SLIST_REMOVE(&dn_cfg.fsu, fs, dn_fsk, sch_chain); + SLIST_REMOVE(&V_dn_cfg.fsu, fs, dn_fsk, sch_chain); fs->sched = s; SLIST_INSERT_HEAD(&s->fsk_list, fs, sch_chain); if (s->fp->new_fsk) @@ -1317,7 +1325,7 @@ { struct dn_fsk *fs, *tmp; - SLIST_FOREACH_SAFE(fs, &dn_cfg.fsu, sch_chain, tmp) { + SLIST_FOREACH_SAFE(fs, &V_dn_cfg.fsu, sch_chain, tmp) { if (s->sch.sched_nr != fs->fs.sched_nr) { D("fs %d for sch %d not %d still unlinked", fs->fs.fs_nr, fs->fs.sched_nr, @@ -1362,7 +1370,7 @@ break; } - fs = dn_ht_find(dn_cfg.fshash, ep->nr, 0, NULL); + fs = dn_ht_find(V_dn_cfg.fshash, ep->nr, 0, NULL); if (!fs) { D("fs %d not found", ep->nr); err = EINVAL; @@ -1579,7 +1587,7 @@ s->link.burst = p->burst; schk_reset_credit(s); } - dn_cfg.id++; + V_dn_cfg.id++; DN_BH_WUNLOCK(); return 0; } @@ -1616,15 +1624,15 @@ /* XXX other sanity checks */ if (nfs->flags & DN_QSIZE_BYTES) { ipdn_bound_var(&nfs->qsize, 16384, - 1500, dn_cfg.byte_limit, NULL); // "queue byte size"); + 1500, V_dn_cfg.byte_limit, NULL); // "queue byte size"); } else { ipdn_bound_var(&nfs->qsize, 50, - 1, dn_cfg.slot_limit, NULL); // "queue slot size"); + 1, V_dn_cfg.slot_limit, NULL); // "queue slot size"); } if (nfs->flags & DN_HAVE_MASK) { /* make sure we have some buckets */ - ipdn_bound_var((int *)&nfs->buckets, dn_cfg.hash_size, - 1, dn_cfg.max_hash_size, "flowset buckets"); + ipdn_bound_var((int *)&nfs->buckets, V_dn_cfg.hash_size, + 1, V_dn_cfg.max_hash_size, "flowset buckets"); } else { nfs->buckets = 1; /* we only need 1 */ } @@ -1634,8 +1642,8 @@ struct dn_schk *s; int flags = nfs->sched_nr ? DNHT_INSERT : 0; int j; - int oldc = dn_cfg.fsk_count; - fs = dn_ht_find(dn_cfg.fshash, i, flags, NULL); + int oldc = V_dn_cfg.fsk_count; + fs = dn_ht_find(V_dn_cfg.fshash, i, flags, NULL); if (fs == NULL) { D("missing sched for flowset %d", i); break; @@ -1662,8 +1670,8 @@ #endif break; /* no change, nothing to do */ } - if (oldc != dn_cfg.fsk_count) /* new item */ - dn_cfg.id++; + if (oldc != V_dn_cfg.fsk_count) /* new item */ + V_dn_cfg.id++; s = locate_scheduler(nfs->sched_nr); /* detach from old scheduler if needed, preserving * queues if we need to reattach. Then update the @@ -1729,8 +1737,8 @@ return EINVAL; /* make sure we have some buckets */ if (a.sch->flags & DN_HAVE_MASK) - ipdn_bound_var((int *)&a.sch->buckets, dn_cfg.hash_size, - 1, dn_cfg.max_hash_size, "sched buckets"); + ipdn_bound_var((int *)&a.sch->buckets, V_dn_cfg.hash_size, + 1, V_dn_cfg.max_hash_size, "sched buckets"); /* XXX other sanity checks */ bzero(&p, sizeof(p)); @@ -1748,14 +1756,14 @@ * lookup the type. If not supplied, use the previous one * or default to WF2Q+. Otherwise, return an error. */ - dn_cfg.id++; + V_dn_cfg.id++; a.fp = find_sched_type(a.sch->oid.subtype, a.sch->name); if (a.fp != NULL) { /* found. Lookup or create entry */ - s = dn_ht_find(dn_cfg.schedhash, i, DNHT_INSERT, &a); + s = dn_ht_find(V_dn_cfg.schedhash, i, DNHT_INSERT, &a); } else if (a.sch->oid.subtype == 0 && !a.sch->name[0]) { /* No type. search existing s* or retry with WF2Q+ */ - s = dn_ht_find(dn_cfg.schedhash, i, 0, &a); + s = dn_ht_find(V_dn_cfg.schedhash, i, 0, &a); if (s != NULL) { a.fp = s->fp; /* Scheduler exists, skip to FIFO scheduler @@ -1827,7 +1835,7 @@ memcpy(pf, s->profile, sizeof(*pf)); } /* remove from the hash */ - dn_ht_find(dn_cfg.schedhash, i, DNHT_REMOVE, NULL); + dn_ht_find(V_dn_cfg.schedhash, i, DNHT_REMOVE, NULL); /* Detach flowsets, preserve queues. */ // schk_delete_cb(s, NULL); // XXX temporarily, kill queues @@ -1845,7 +1853,7 @@ * trying to reuse existing ones if available */ if (!(s->fp->flags & DN_MULTIQUEUE) && !s->fs) { - s->fs = dn_ht_find(dn_cfg.fshash, i, 0, NULL); + s->fs = dn_ht_find(V_dn_cfg.fshash, i, 0, NULL); if (!s->fs) { struct dn_fs fs; bzero(&fs, sizeof(fs)); @@ -1874,7 +1882,7 @@ a.sch->flags = new_flags; } else { /* sched config shouldn't modify the FIFO scheduler */ - if (dn_ht_find(dn_cfg.schedhash, i, 0, &a) != NULL) { + if (dn_ht_find(V_dn_cfg.schedhash, i, 0, &a) != NULL) { /* FIFO already exist, don't touch it */ err = 0; /* and this is not an error */ goto error; @@ -1918,7 +1926,7 @@ err = EINVAL; break; } - dn_cfg.id++; + V_dn_cfg.id++; /* * If we had a profile and the new one does not fit, * or it is deleted, then we need to free memory. @@ -1961,14 +1969,14 @@ { /* delete all schedulers and related links/queues/flowsets */ - dn_ht_scan(dn_cfg.schedhash, schk_delete_cb, + dn_ht_scan(V_dn_cfg.schedhash, schk_delete_cb, (void *)(uintptr_t)DN_DELETE_FS); /* delete all remaining (unlinked) flowsets */ - DX(4, "still %d unlinked fs", dn_cfg.fsk_count); - dn_ht_free(dn_cfg.fshash, DNHT_REMOVE); - fsk_detach_list(&dn_cfg.fsu, DN_DELETE_FS); + DX(4, "still %d unlinked fs", V_dn_cfg.fsk_count); + dn_ht_free(V_dn_cfg.fshash, DNHT_REMOVE); + fsk_detach_list(&V_dn_cfg.fsu, DN_DELETE_FS); /* Reinitialize system heap... */ - heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id)); + heap_init(&V_dn_cfg.evheap, 16, offsetof(struct dn_id, id)); } /* @@ -2113,10 +2121,10 @@ ED_MAX_SAMPLES_NO*sizeof(int); /* NOTE about compute space: - * NP = dn_cfg.schk_count - * NSI = dn_cfg.si_count - * NF = dn_cfg.fsk_count - * NQ = dn_cfg.queue_count + * NP = V_dn_cfg.schk_count + * NSI = V_dn_cfg.si_count + * NF = V_dn_cfg.fsk_count + * NQ = V_dn_cfg.queue_count * - ipfw pipe show * (NP/2)*(dn_link + dn_sch + dn_id + dn_fs) only half scheduler * link, scheduler template, flowset @@ -2145,14 +2153,14 @@ */ case DN_LINK: /* pipe show */ x = DN_C_LINK | DN_C_SCH | DN_C_FLOW; - need += dn_cfg.schk_count * + need += V_dn_cfg.schk_count * (sizeof(struct dn_fs) + profile_size) / 2; - need += dn_cfg.fsk_count * sizeof(uint32_t); + need += V_dn_cfg.fsk_count * sizeof(uint32_t); break; case DN_SCH: /* sched show */ - need += dn_cfg.schk_count * + need += V_dn_cfg.schk_count * (sizeof(struct dn_fs) + profile_size) / 2; - need += dn_cfg.fsk_count * sizeof(uint32_t); + need += V_dn_cfg.fsk_count * sizeof(uint32_t); x = DN_C_SCH | DN_C_LINK | DN_C_FLOW; break; case DN_FS: /* queue show */ @@ -2164,14 +2172,14 @@ } a->flags = x; if (x & DN_C_SCH) { - need += dn_cfg.schk_count * sizeof(struct dn_sch) / 2; + need += V_dn_cfg.schk_count * sizeof(struct dn_sch) / 2; /* NOT also, each fs might be attached to a sched */ - need += dn_cfg.schk_count * sizeof(struct dn_id) / 2; + need += V_dn_cfg.schk_count * sizeof(struct dn_id) / 2; } if (x & DN_C_FS) - need += dn_cfg.fsk_count * sizeof(struct dn_fs); + need += V_dn_cfg.fsk_count * sizeof(struct dn_fs); if (x & DN_C_LINK) { - need += dn_cfg.schk_count * sizeof(struct dn_link) / 2; + need += V_dn_cfg.schk_count * sizeof(struct dn_link) / 2; } /* * When exporting a queue to userland, only pass up the @@ -2179,9 +2187,9 @@ */ if (x & DN_C_QUEUE) - need += dn_cfg.queue_count * sizeof(struct dn_flow); + need += V_dn_cfg.queue_count * sizeof(struct dn_flow); if (x & DN_C_FLOW) - need += dn_cfg.si_count * (sizeof(struct dn_flow)); + need += V_dn_cfg.si_count * (sizeof(struct dn_flow)); return need; } @@ -2304,11 +2312,11 @@ } ND("have %d:%d sched %d, %d:%d links %d, %d:%d flowsets %d, " "%d:%d si %d, %d:%d queues %d", - dn_cfg.schk_count, sizeof(struct dn_sch), DN_SCH, - dn_cfg.schk_count, sizeof(struct dn_link), DN_LINK, - dn_cfg.fsk_count, sizeof(struct dn_fs), DN_FS, - dn_cfg.si_count, sizeof(struct dn_flow), DN_SCH_I, - dn_cfg.queue_count, sizeof(struct dn_queue), DN_QUEUE); + V_dn_cfg.schk_count, sizeof(struct dn_sch), DN_SCH, + V_dn_cfg.schk_count, sizeof(struct dn_link), DN_LINK, + V_dn_cfg.fsk_count, sizeof(struct dn_fs), DN_FS, + V_dn_cfg.si_count, sizeof(struct dn_flow), DN_SCH_I, + V_dn_cfg.queue_count, sizeof(struct dn_queue), DN_QUEUE); sopt->sopt_valsize = sopt_valsize; a.type = cmd->subtype; @@ -2323,13 +2331,13 @@ /* start copying other objects */ if (compat) { a.type = DN_COMPAT_PIPE; - dn_ht_scan(dn_cfg.schedhash, copy_data_helper_compat, &a); + dn_ht_scan(V_dn_cfg.schedhash, copy_data_helper_compat, &a); a.type = DN_COMPAT_QUEUE; - dn_ht_scan(dn_cfg.fshash, copy_data_helper_compat, &a); + dn_ht_scan(V_dn_cfg.fshash, copy_data_helper_compat, &a); } else if (a.type == DN_FS) { - dn_ht_scan(dn_cfg.fshash, copy_data_helper, &a); + dn_ht_scan(V_dn_cfg.fshash, copy_data_helper, &a); } else { - dn_ht_scan(dn_cfg.schedhash, copy_data_helper, &a); + dn_ht_scan(V_dn_cfg.schedhash, copy_data_helper, &a); } DN_BH_WUNLOCK(); @@ -2395,9 +2403,9 @@ void dn_drain_scheduler(void) { - dn_ht_scan_bucket(dn_cfg.schedhash, &dn_cfg.drain_sch, + dn_ht_scan_bucket(V_dn_cfg.schedhash, &V_dn_cfg.drain_sch, drain_scheduler_sch_cb, NULL); - dn_cfg.drain_sch++; + V_dn_cfg.drain_sch++; } /* Callback called on queue to delete if it is idle */ @@ -2442,9 +2450,9 @@ dn_drain_queue(void) { /* scan a bucket of flowset */ - dn_ht_scan_bucket(dn_cfg.fshash, &dn_cfg.drain_fs, + dn_ht_scan_bucket(V_dn_cfg.fshash, &V_dn_cfg.drain_fs, drain_queue_fs_cb, NULL); - dn_cfg.drain_fs++; + V_dn_cfg.drain_fs++; } /* @@ -2506,64 +2514,84 @@ } static void -ip_dn_init(void) +ip_dn_vnet_init(void) { - if (dn_cfg.init_done) + if (V_dn_cfg.init_done) return; - dn_cfg.init_done = 1; + V_dn_cfg.init_done = 1; /* Set defaults here. MSVC does not accept initializers, * and this is also useful for vimages */ /* queue limits */ - dn_cfg.slot_limit = 100; /* Foot shooting limit for queues. */ - dn_cfg.byte_limit = 1024 * 1024; - dn_cfg.expire = 1; + V_dn_cfg.slot_limit = 100; /* Foot shooting limit for queues. */ + V_dn_cfg.byte_limit = 1024 * 1024; + V_dn_cfg.expire = 1; /* RED parameters */ - dn_cfg.red_lookup_depth = 256; /* default lookup table depth */ - dn_cfg.red_avg_pkt_size = 512; /* default medium packet size */ - dn_cfg.red_max_pkt_size = 1500; /* default max packet size */ + V_dn_cfg.red_lookup_depth = 256; /* default lookup table depth */ + V_dn_cfg.red_avg_pkt_size = 512; /* default medium packet size */ + V_dn_cfg.red_max_pkt_size = 1500; /* default max packet size */ /* hash tables */ - dn_cfg.max_hash_size = 65536; /* max in the hash tables */ - dn_cfg.hash_size = 64; /* default hash size */ + V_dn_cfg.max_hash_size = 65536; /* max in the hash tables */ + V_dn_cfg.hash_size = 64; /* default hash size */ /* create hash tables for schedulers and flowsets. * In both we search by key and by pointer. */ - dn_cfg.schedhash = dn_ht_init(NULL, dn_cfg.hash_size, + V_dn_cfg.schedhash = dn_ht_init(NULL, V_dn_cfg.hash_size, offsetof(struct dn_schk, schk_next), schk_hash, schk_match, schk_new); - dn_cfg.fshash = dn_ht_init(NULL, dn_cfg.hash_size, + V_dn_cfg.fshash = dn_ht_init(NULL, V_dn_cfg.hash_size, offsetof(struct dn_fsk, fsk_next), fsk_hash, fsk_match, fsk_new); /* bucket index to drain object */ - dn_cfg.drain_fs = 0; - dn_cfg.drain_sch = 0; + V_dn_cfg.drain_fs = 0; + V_dn_cfg.drain_sch = 0; - heap_init(&dn_cfg.evheap, 16, offsetof(struct dn_id, id)); - SLIST_INIT(&dn_cfg.fsu); - SLIST_INIT(&dn_cfg.schedlist); + heap_init(&V_dn_cfg.evheap, 16, offsetof(struct dn_id, id)); + SLIST_INIT(&V_dn_cfg.fsu); DN_LOCK_INIT(); - NET_TASK_INIT(&dn_task, 0, dummynet_task, curvnet); + /* Initialize curr_time adjustment mechanics. */ + getmicrouptime(&V_dn_cfg.prev_t); +} + +static void +ip_dn_vnet_destroy(void) +{ + DN_BH_WLOCK(); + dummynet_flush(); + DN_BH_WUNLOCK(); + + dn_ht_free(V_dn_cfg.schedhash, 0); + dn_ht_free(V_dn_cfg.fshash, 0); + heap_free(&V_dn_cfg.evheap); + + DN_LOCK_DESTROY(); +} + +static void +ip_dn_init(void) +{ + if (dn_tasks_started) + return; + dn_tasks_started = 1; + TASK_INIT(&dn_task, 0, dummynet_task, NULL); dn_tq = taskqueue_create_fast("dummynet", M_WAITOK, taskqueue_thread_enqueue, &dn_tq); taskqueue_start_threads(&dn_tq, 1, PI_NET, "dummynet"); + SLIST_INIT(&schedlist); callout_init(&dn_timeout, 1); dn_reschedule(); - - /* Initialize curr_time adjustment mechanics. */ - getmicrouptime(&dn_cfg.prev_t); } static void ip_dn_destroy(int last) { - DN_BH_WLOCK(); /* ensure no more callouts are started */ dn_gone = 1; @@ -2574,18 +2602,9 @@ ip_dn_io_ptr = NULL; } - dummynet_flush(); - DN_BH_WUNLOCK(); - callout_drain(&dn_timeout); taskqueue_drain(dn_tq, &dn_task); taskqueue_free(dn_tq); - - dn_ht_free(dn_cfg.schedhash, 0); - dn_ht_free(dn_cfg.fshash, 0); - heap_free(&dn_cfg.evheap); - - DN_LOCK_DESTROY(); } static int @@ -2626,14 +2645,14 @@ /* Search if scheduler already exists */ DN_BH_WLOCK(); - SLIST_FOREACH(s, &dn_cfg.schedlist, next) { + SLIST_FOREACH(s, &schedlist, next) { if (strcmp(s->name, d->name) == 0) { D("%s already loaded", d->name); break; /* scheduler already exists */ } } if (s == NULL) - SLIST_INSERT_HEAD(&dn_cfg.schedlist, d, next); + SLIST_INSERT_HEAD(&schedlist, d, next); DN_BH_WUNLOCK(); D("dn_sched %s %sloaded", d->name, s ? "not ":""); return s ? 1 : 0; @@ -2648,13 +2667,13 @@ ND("called for %s", s->name); DN_BH_WLOCK(); - SLIST_FOREACH_SAFE(r, &dn_cfg.schedlist, next, tmp) { + SLIST_FOREACH_SAFE(r, &schedlist, next, tmp) { if (strcmp(s->name, r->name) != 0) continue; ND("ref_count = %d", r->ref_count); err = (r->ref_count != 0) ? EBUSY : 0; if (err == 0) - SLIST_REMOVE(&dn_cfg.schedlist, r, dn_alg, next); + SLIST_REMOVE(&schedlist, r, dn_alg, next); break; } DN_BH_WUNLOCK(); @@ -2689,7 +2708,7 @@ * Starting up. Done in order after dummynet_modevent() has been called. * VNET_SYSINIT is also called for each existing vnet and each new vnet. */ -//VNET_SYSINIT(vnet_dn_init, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_init, NULL); +VNET_SYSINIT(vnet_dn_init, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_vnet_init, NULL); /* * Shutdown handlers up shop. These are done in REVERSE ORDER, but still @@ -2697,7 +2716,7 @@ * VNET_SYSUNINIT is also called for each exiting vnet as it exits. * or when the module is unloaded. */ -//VNET_SYSUNINIT(vnet_dn_uninit, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_destroy, NULL); +VNET_SYSUNINIT(vnet_dn_uninit, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_vnet_destroy, NULL); #ifdef NEW_AQM @@ -2718,15 +2737,15 @@ } /* Search if AQM already exists */ - DN_BH_WLOCK(); - SLIST_FOREACH(aqm, &dn_cfg.aqmlist, next) { + DN_BH_WLOCK(); /* XXX Global lock? */ + SLIST_FOREACH(aqm, &aqmlist, next) { if (strcmp(aqm->name, d->name) == 0) { D("%s already loaded", d->name); break; /* AQM already exists */ } } if (aqm == NULL) - SLIST_INSERT_HEAD(&dn_cfg.aqmlist, d, next); + SLIST_INSERT_HEAD(&aqmlist, d, next); DN_BH_WUNLOCK(); D("dn_aqm %s %sloaded", d->name, aqm ? "not ":""); return aqm ? 1 : 0; @@ -2759,15 +2778,15 @@ DN_BH_WLOCK(); /* clean up AQM status and deconfig flowset */ - dn_ht_scan(dn_cfg.fshash, fs_cleanup, &aqm->type); + dn_ht_scan(V_dn_cfg.fshash, fs_cleanup, &aqm->type); - SLIST_FOREACH_SAFE(r, &dn_cfg.aqmlist, next, tmp) { + SLIST_FOREACH_SAFE(r, &aqmlist, next, tmp) { if (strcmp(aqm->name, r->name) != 0) continue; ND("ref_count = %d", r->ref_count); err = (r->ref_count != 0 || r->cfg_ref_count != 0) ? EBUSY : 0; if (err == 0) - SLIST_REMOVE(&dn_cfg.aqmlist, r, dn_aqm, next); + SLIST_REMOVE(&aqmlist, r, dn_aqm, next); break; } DN_BH_WUNLOCK();