VNETify dummynet
This moves dn_cfg and other parameters into per VNET variables. The taskqueue and control state remains global. Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D29274
This commit is contained in:
parent
8682abbf7b
commit
fe3bcfbda3
@ -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 @@ update_stats(struct dn_queue *q, int len, int drop)
|
||||
if (drop) {
|
||||
qni->drops++;
|
||||
sni->drops++;
|
||||
dn_cfg.io_pkt_drop++;
|
||||
V_dn_cfg.io_pkt_drop++;
|
||||
} else {
|
||||
/*update queue stats */
|
||||
qni->length += inc;
|
||||
|
@ -202,7 +202,7 @@ codel_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts)
|
||||
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);
|
||||
|
@ -338,7 +338,7 @@ pie_extract_head(struct dn_queue *q, aqm_time_t *pkt_ts, int getts)
|
||||
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*/
|
||||
|
@ -187,7 +187,7 @@ dn_dequeue(struct dn_queue *q)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ codel_drop_head(struct fq_codel_flow *q, struct fq_codel_si *si)
|
||||
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);
|
||||
}
|
||||
|
@ -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 @@ fq_update_stats(struct fq_codel_flow *q, struct fq_codel_si *si, int len,
|
||||
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_codel_extract_head(struct fq_codel_flow *q, aqm_time_t *pkt_ts, struct fq_cod
|
||||
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;
|
||||
|
@ -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 @@ fq_update_stats(struct fq_pie_flow *q, struct fq_pie_si *si, int len,
|
||||
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_pie_extract_head(struct fq_pie_flow *q, aqm_time_t *pkt_ts,
|
||||
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 @@ pie_drop_head(struct fq_pie_flow *q, struct fq_pie_si *si)
|
||||
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;
|
||||
|
||||
|
@ -567,10 +567,10 @@ dn_compat_calc_size(void)
|
||||
* - 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;
|
||||
}
|
||||
|
@ -74,11 +74,10 @@ __FBSDID("$FreeBSD$");
|
||||
/*
|
||||
* 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 @@ sysctl_hash_size(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
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 @@ sysctl_limits(SYSCTL_HANDLER_ARGS)
|
||||
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 @@ sysctl_limits(SYSCTL_HANDLER_ARGS)
|
||||
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 @@ static SYSCTL_NODE(_net_inet_ip, OID_AUTO, dummynet,
|
||||
"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 @@ red_drops (struct dn_queue *q, int len)
|
||||
* 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 @@ dn_enqueue(struct dn_queue *q, struct mbuf* m, int drop)
|
||||
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 @@ transmit_event(struct mq *q, struct delay_line *dline, uint64_t now)
|
||||
}
|
||||
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 @@ serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now)
|
||||
(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 @@ serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now)
|
||||
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 @@ dummynet_task(void *context, int pending)
|
||||
{
|
||||
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;
|
||||
V_dn_cfg.prev_t = t;
|
||||
|
||||
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++;
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* serve pending events, accumulate in q */
|
||||
for (;;) {
|
||||
struct dn_id *p; /* generic parameter to handler */
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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.expire && ++dn_cfg.expire_cycle >= dn_cfg.expire) {
|
||||
dn_cfg.expire_cycle = 0;
|
||||
dn_drain_scheduler();
|
||||
dn_drain_queue();
|
||||
}
|
||||
|
||||
/* serve pending events, accumulate in q */
|
||||
for (;;) {
|
||||
struct dn_id *p; /* generic parameter to handler */
|
||||
|
||||
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();
|
||||
}
|
||||
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 @@ tag_mbuf(struct mbuf *m, int dir, struct ip_fw_args *fwa)
|
||||
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 @@ dummynet_io(struct mbuf **m0, struct ip_fw_args *fwa)
|
||||
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 @@ dummynet_io(struct mbuf **m0, struct ip_fw_args *fwa)
|
||||
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 @@ dummynet_io(struct mbuf **m0, struct ip_fw_args *fwa)
|
||||
}
|
||||
|
||||
/* 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 @@ done:
|
||||
return 0;
|
||||
|
||||
dropit:
|
||||
dn_cfg.io_pkt_drop++;
|
||||
V_dn_cfg.io_pkt_drop++;
|
||||
DN_BH_WUNLOCK();
|
||||
if (m)
|
||||
FREE_PKT(m);
|
||||
|
@ -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 @@ MALLOC_DECLARE(M_DUMMYNET);
|
||||
#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 @@ set_oid(struct dn_id *o, int type, int len)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_parms {
|
||||
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 @@ enum {
|
||||
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);
|
||||
|
@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip_var.h> /* ip_output(), IP_FORWARDING */
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <netinet/ip_dummynet.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
#include <netpfil/ipfw/ip_fw_private.h>
|
||||
#include <netpfil/ipfw/dn_heap.h>
|
||||
@ -87,10 +88,17 @@ struct schk_new_arg {
|
||||
|
||||
/*---- 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 @@ find_aqm_type(int type, char *name)
|
||||
{
|
||||
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 @@ find_sched_type(int type, char *name)
|
||||
{
|
||||
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 @@ q_new(uintptr_t key, int flags, void *arg)
|
||||
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_delete_queue(struct dn_queue *q, int flags)
|
||||
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 @@ si_new(uintptr_t key, int flags, void *arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
dn_cfg.si_count++;
|
||||
V_dn_cfg.si_count++;
|
||||
return si;
|
||||
|
||||
error:
|
||||
@ -552,10 +560,10 @@ si_destroy(void *_si, void *arg)
|
||||
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 @@ si_destroy(void *_si, void *arg)
|
||||
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 @@ si_reset_credit(void *_si, void *arg)
|
||||
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 @@ fsk_new(uintptr_t key, int flags, void *arg)
|
||||
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 @@ fsk_detach(struct dn_fsk *fs, int flags)
|
||||
(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 @@ fsk_detach(struct dn_fsk *fs, int flags)
|
||||
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 @@ delete_fs(int i, int locked)
|
||||
|
||||
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 @@ schk_new(uintptr_t key, int flags, void *arg)
|
||||
}
|
||||
}
|
||||
s->fp = NULL; /* mark as a new scheduler */
|
||||
dn_cfg.schk_count++;
|
||||
V_dn_cfg.schk_count++;
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -905,7 +913,7 @@ schk_delete_cb(void *obj, void *arg)
|
||||
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 @@ delete_schk(int i)
|
||||
{
|
||||
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 @@ copy_data_helper(void *_o, void *_arg)
|
||||
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 @@ config_red(struct dn_fsk *fs)
|
||||
/* 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 @@ config_red(struct dn_fsk *fs)
|
||||
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 @@ config_red(struct dn_fsk *fs)
|
||||
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 @@ fsk_attach(struct dn_fsk *fs, struct dn_schk *s)
|
||||
{
|
||||
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 @@ update_fs(struct dn_schk *s)
|
||||
{
|
||||
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 @@ get_aqm_parms(struct sockopt *sopt)
|
||||
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 @@ config_link(struct dn_link *p, struct dn_id *arg)
|
||||
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 @@ config_fs(struct dn_fs *nfs, struct dn_id *arg, int locked)
|
||||
/* 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 @@ config_fs(struct dn_fs *nfs, struct dn_id *arg, int locked)
|
||||
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 @@ config_fs(struct dn_fs *nfs, struct dn_id *arg, int locked)
|
||||
#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 @@ config_sched(struct dn_sch *_nsch, struct dn_id *arg)
|
||||
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 @@ again: /* run twice, for wfq and fifo */
|
||||
* 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 @@ again: /* run twice, for wfq and fifo */
|
||||
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 @@ again: /* run twice, for wfq and fifo */
|
||||
* 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 @@ next:
|
||||
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 @@ config_profile(struct dn_profile *pf, struct dn_id *arg)
|
||||
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 @@ dummynet_flush(void)
|
||||
{
|
||||
|
||||
/* 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 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
|
||||
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 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
|
||||
*/
|
||||
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 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
|
||||
}
|
||||
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 @@ compute_space(struct dn_id *cmd, struct copy_args *a)
|
||||
*/
|
||||
|
||||
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 @@ dummynet_get(struct sockopt *sopt, void **compat)
|
||||
}
|
||||
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 @@ dummynet_get(struct sockopt *sopt, void **compat)
|
||||
/* 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 @@ drain_scheduler_sch_cb(void *_s, void *arg)
|
||||
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 @@ void
|
||||
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 @@ ip_dn_ctl(struct sockopt *sopt)
|
||||
}
|
||||
|
||||
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_destroy(int last)
|
||||
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 @@ load_dn_sched(struct dn_alg *d)
|
||||
|
||||
/* 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 @@ unload_dn_sched(struct dn_alg *s)
|
||||
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 @@ MODULE_VERSION(dummynet, 3);
|
||||
* 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 @@ MODULE_VERSION(dummynet, 3);
|
||||
* 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 @@ load_dn_aqm(struct dn_aqm *d)
|
||||
}
|
||||
|
||||
/* 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 @@ unload_dn_aqm(struct dn_aqm *aqm)
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user