Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/ip_dummynet.c
Show All 38 Lines | |||||
/* | /* | ||||
* Configuration and internal object management for dummynet. | * Configuration and internal object management for dummynet. | ||||
*/ | */ | ||||
#include "opt_inet6.h" | #include "opt_inet6.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/ck.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
Show All 34 Lines | |||||
/*---- callout hooks. ----*/ | /*---- callout hooks. ----*/ | ||||
static struct callout dn_timeout; | static struct callout dn_timeout; | ||||
static int dn_tasks_started = 0; | static int dn_tasks_started = 0; | ||||
static int dn_gone; | static int dn_gone; | ||||
static struct task dn_task; | static struct task dn_task; | ||||
static struct taskqueue *dn_tq = NULL; | static struct taskqueue *dn_tq = NULL; | ||||
/* global scheduler list */ | /* global scheduler list */ | ||||
struct dn_alg_head schedlist; | struct mtx sched_mtx; | ||||
CK_LIST_HEAD(, dn_alg) schedlist; | |||||
#ifdef NEW_AQM | #ifdef NEW_AQM | ||||
struct dn_aqm_head aqmlist; /* list of AQMs */ | CK_LIST_HEAD(, dn_aqm) aqmlist; /* list of AQMs */ | ||||
#endif | #endif | ||||
static void | static void | ||||
dummynet(void *arg) | dummynet(void *arg) | ||||
{ | { | ||||
(void)arg; /* UNUSED */ | (void)arg; /* UNUSED */ | ||||
taskqueue_enqueue(dn_tq, &dn_task); | taskqueue_enqueue(dn_tq, &dn_task); | ||||
Show All 12 Lines | |||||
#ifdef NEW_AQM | #ifdef NEW_AQM | ||||
/* Return AQM descriptor for given type or name. */ | /* Return AQM descriptor for given type or name. */ | ||||
static struct dn_aqm * | static struct dn_aqm * | ||||
find_aqm_type(int type, char *name) | find_aqm_type(int type, char *name) | ||||
{ | { | ||||
struct dn_aqm *d; | struct dn_aqm *d; | ||||
SLIST_FOREACH(d, &aqmlist, next) { | NET_EPOCH_ASSERT(); | ||||
CK_LIST_FOREACH(d, &aqmlist, next) { | |||||
if (d->type == type || (name && !strcasecmp(d->name, name))) | if (d->type == type || (name && !strcasecmp(d->name, name))) | ||||
return d; | return d; | ||||
} | } | ||||
return NULL; /* not found */ | return NULL; /* not found */ | ||||
} | } | ||||
#endif | #endif | ||||
/* Return a scheduler descriptor given the type or name. */ | /* Return a scheduler descriptor given the type or name. */ | ||||
static struct dn_alg * | static struct dn_alg * | ||||
find_sched_type(int type, char *name) | find_sched_type(int type, char *name) | ||||
{ | { | ||||
struct dn_alg *d; | struct dn_alg *d; | ||||
SLIST_FOREACH(d, &schedlist, next) { | NET_EPOCH_ASSERT(); | ||||
CK_LIST_FOREACH(d, &schedlist, next) { | |||||
if (d->type == type || (name && !strcasecmp(d->name, name))) | if (d->type == type || (name && !strcasecmp(d->name, name))) | ||||
return d; | return d; | ||||
} | } | ||||
return NULL; /* not found */ | return NULL; /* not found */ | ||||
} | } | ||||
int | int | ||||
ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg) | ipdn_bound_var(int *v, int dflt, int lo, int hi, const char *msg) | ||||
▲ Show 20 Lines • Show All 1,199 Lines • ▼ Show 20 Lines | get_aqm_parms(struct sockopt *sopt) | ||||
sopt_valsize = sopt->sopt_valsize; | sopt_valsize = sopt->sopt_valsize; | ||||
l = sizeof(*ep); | l = sizeof(*ep); | ||||
if (sopt->sopt_valsize < l) { | if (sopt->sopt_valsize < l) { | ||||
D("bad len sopt->sopt_valsize %d len %d", | D("bad len sopt->sopt_valsize %d len %d", | ||||
(int) sopt->sopt_valsize , l); | (int) sopt->sopt_valsize , l); | ||||
err = EINVAL; | err = EINVAL; | ||||
return err; | return err; | ||||
} | } | ||||
ep = malloc(l, M_DUMMYNET, M_WAITOK); | ep = malloc(l, M_DUMMYNET, M_NOWAIT); | ||||
if(!ep) { | if(!ep) { | ||||
err = ENOMEM ; | err = ENOMEM ; | ||||
return err; | return err; | ||||
} | } | ||||
do { | do { | ||||
err = sooptcopyin(sopt, ep, l, l); | err = sooptcopyin(sopt, ep, l, l); | ||||
if(err) | if(err) | ||||
break; | break; | ||||
Show All 38 Lines | get_sched_parms(struct sockopt *sopt) | ||||
sopt_valsize = sopt->sopt_valsize; | sopt_valsize = sopt->sopt_valsize; | ||||
l = sizeof(*ep); | l = sizeof(*ep); | ||||
if (sopt->sopt_valsize < l) { | if (sopt->sopt_valsize < l) { | ||||
D("bad len sopt->sopt_valsize %d len %d", | D("bad len sopt->sopt_valsize %d len %d", | ||||
(int) sopt->sopt_valsize , l); | (int) sopt->sopt_valsize , l); | ||||
err = EINVAL; | err = EINVAL; | ||||
return err; | return err; | ||||
} | } | ||||
ep = malloc(l, M_DUMMYNET, M_WAITOK); | ep = malloc(l, M_DUMMYNET, M_NOWAIT); | ||||
if(!ep) { | if(!ep) { | ||||
err = ENOMEM ; | err = ENOMEM ; | ||||
return err; | return err; | ||||
} | } | ||||
do { | do { | ||||
err = sooptcopyin(sopt, ep, l, l); | err = sooptcopyin(sopt, ep, l, l); | ||||
if(err) | if(err) | ||||
break; | break; | ||||
Show All 28 Lines | |||||
/* Configure AQM for flowset 'fs'. | /* Configure AQM for flowset 'fs'. | ||||
* extra parameters are passed from userland. | * extra parameters are passed from userland. | ||||
*/ | */ | ||||
static int | static int | ||||
config_aqm(struct dn_fsk *fs, struct dn_extra_parms *ep, int busy) | config_aqm(struct dn_fsk *fs, struct dn_extra_parms *ep, int busy) | ||||
{ | { | ||||
int err = 0; | int err = 0; | ||||
NET_EPOCH_ASSERT(); | |||||
do { | do { | ||||
/* no configurations */ | /* no configurations */ | ||||
if (!ep) { | if (!ep) { | ||||
err = 0; | err = 0; | ||||
break; | break; | ||||
} | } | ||||
/* no AQM for this flowset*/ | /* no AQM for this flowset*/ | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | if (nfs->oid.len != sizeof(*nfs)) { | ||||
return NULL; | return NULL; | ||||
} | } | ||||
i = nfs->fs_nr; | i = nfs->fs_nr; | ||||
if (i <= 0 || i >= 3*DN_MAX_ID) | if (i <= 0 || i >= 3*DN_MAX_ID) | ||||
return NULL; | return NULL; | ||||
#ifdef NEW_AQM | #ifdef NEW_AQM | ||||
ep = NULL; | ep = NULL; | ||||
if (arg != NULL) { | if (arg != NULL) { | ||||
ep = malloc(sizeof(*ep), M_TEMP, locked ? M_NOWAIT : M_WAITOK); | ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); | ||||
if (ep == NULL) | if (ep == NULL) | ||||
return (NULL); | return (NULL); | ||||
memcpy(ep, arg, sizeof(*ep)); | memcpy(ep, arg, sizeof(*ep)); | ||||
} | } | ||||
#endif | #endif | ||||
ND("flowset %d", i); | ND("flowset %d", i); | ||||
/* XXX other sanity checks */ | /* XXX other sanity checks */ | ||||
if (nfs->flags & DN_QSIZE_BYTES) { | if (nfs->flags & DN_QSIZE_BYTES) { | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | config_sched(struct dn_sch *_nsch, struct dn_id *arg) | ||||
struct dn_profile *pf = NULL; /* copy of old link profile */ | struct dn_profile *pf = NULL; /* copy of old link profile */ | ||||
/* Used to preserv mask parameter */ | /* Used to preserv mask parameter */ | ||||
struct ipfw_flow_id new_mask; | struct ipfw_flow_id new_mask; | ||||
int new_buckets = 0; | int new_buckets = 0; | ||||
int new_flags = 0; | int new_flags = 0; | ||||
int pipe_cmd; | int pipe_cmd; | ||||
int err = ENOMEM; | int err = ENOMEM; | ||||
NET_EPOCH_ASSERT(); | |||||
a.sch = _nsch; | a.sch = _nsch; | ||||
if (a.sch->oid.len != sizeof(*a.sch)) { | if (a.sch->oid.len != sizeof(*a.sch)) { | ||||
D("bad sched len %d", a.sch->oid.len); | D("bad sched len %d", a.sch->oid.len); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
i = a.sch->sched_nr; | i = a.sch->sched_nr; | ||||
if (i <= 0 || i >= DN_MAX_ID) | if (i <= 0 || i >= DN_MAX_ID) | ||||
return EINVAL; | return EINVAL; | ||||
▲ Show 20 Lines • Show All 327 Lines • ▼ Show 20 Lines | case DN_CMD_DELETE: | ||||
break; | break; | ||||
case DN_CMD_FLUSH: | case DN_CMD_FLUSH: | ||||
DN_BH_WLOCK(); | DN_BH_WLOCK(); | ||||
dummynet_flush(); | dummynet_flush(); | ||||
DN_BH_WUNLOCK(); | DN_BH_WUNLOCK(); | ||||
break; | break; | ||||
case DN_TEXT: /* store argument of next block */ | case DN_TEXT: /* store argument of next block */ | ||||
if (arg != NULL) | |||||
free(arg, M_TEMP); | free(arg, M_TEMP); | ||||
arg = malloc(o.len, M_TEMP, M_WAITOK); | arg = malloc(o.len, M_TEMP, M_NOWAIT); | ||||
if (arg == NULL) { | |||||
err = ENOMEM; | |||||
break; | |||||
} | |||||
memcpy(arg, (char *)p + off, o.len); | memcpy(arg, (char *)p + off, o.len); | ||||
break; | break; | ||||
case DN_LINK: | case DN_LINK: | ||||
if (dn == NULL) | if (dn == NULL) | ||||
dn = malloc(sizeof(*dn), M_TEMP, M_WAITOK); | dn = malloc(sizeof(*dn), M_TEMP, M_NOWAIT); | ||||
if (dn == NULL) { | |||||
err = ENOMEM; | |||||
break; | |||||
} | |||||
memcpy(&dn->link, (char *)p + off, sizeof(dn->link)); | memcpy(&dn->link, (char *)p + off, sizeof(dn->link)); | ||||
err = config_link(&dn->link, arg); | err = config_link(&dn->link, arg); | ||||
break; | break; | ||||
case DN_PROFILE: | case DN_PROFILE: | ||||
if (dn == NULL) | if (dn == NULL) | ||||
dn = malloc(sizeof(*dn), M_TEMP, M_WAITOK); | dn = malloc(sizeof(*dn), M_TEMP, M_NOWAIT); | ||||
if (dn == NULL) { | |||||
err = ENOMEM; | |||||
break; | |||||
} | |||||
memcpy(&dn->profile, (char *)p + off, | memcpy(&dn->profile, (char *)p + off, | ||||
sizeof(dn->profile)); | sizeof(dn->profile)); | ||||
err = config_profile(&dn->profile, arg); | err = config_profile(&dn->profile, arg); | ||||
break; | break; | ||||
case DN_SCH: | case DN_SCH: | ||||
if (dn == NULL) | if (dn == NULL) | ||||
dn = malloc(sizeof(*dn), M_TEMP, M_WAITOK); | dn = malloc(sizeof(*dn), M_TEMP, M_NOWAIT); | ||||
if (dn == NULL) { | |||||
err = ENOMEM; | |||||
break; | |||||
} | |||||
memcpy(&dn->sched, (char *)p + off, | memcpy(&dn->sched, (char *)p + off, | ||||
sizeof(dn->sched)); | sizeof(dn->sched)); | ||||
err = config_sched(&dn->sched, arg); | err = config_sched(&dn->sched, arg); | ||||
break; | break; | ||||
case DN_FS: | case DN_FS: | ||||
if (dn == NULL) | if (dn == NULL) | ||||
dn = malloc(sizeof(*dn), M_TEMP, M_WAITOK); | dn = malloc(sizeof(*dn), M_TEMP, M_NOWAIT); | ||||
if (dn == NULL) { | |||||
err = ENOMEM; | |||||
break; | |||||
} | |||||
memcpy(&dn->fs, (char *)p + off, sizeof(dn->fs)); | memcpy(&dn->fs, (char *)p + off, sizeof(dn->fs)); | ||||
err = (NULL == config_fs(&dn->fs, arg, 0)); | err = (NULL == config_fs(&dn->fs, arg, 0)); | ||||
break; | break; | ||||
} | } | ||||
if (err != 0) | if (err != 0) | ||||
break; | break; | ||||
off += o.len; | off += o.len; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | if (!compat) { | ||||
l = cmd->len; | l = cmd->len; | ||||
#ifdef EMULATE_SYSCTL | #ifdef EMULATE_SYSCTL | ||||
/* sysctl emulation. */ | /* sysctl emulation. */ | ||||
if (cmd->type == DN_SYSCTL_GET) | if (cmd->type == DN_SYSCTL_GET) | ||||
return kesysctl_emu_get(sopt); | return kesysctl_emu_get(sopt); | ||||
#endif | #endif | ||||
if (l > sizeof(r)) { | if (l > sizeof(r)) { | ||||
/* request larger than default, allocate buffer */ | /* request larger than default, allocate buffer */ | ||||
cmd = malloc(l, M_DUMMYNET, M_WAITOK); | cmd = malloc(l, M_DUMMYNET, M_NOWAIT); | ||||
if (cmd == NULL) { | |||||
error = ENOMEM; | |||||
goto done; | |||||
} | |||||
error = sooptcopyin(sopt, cmd, l, l); | error = sooptcopyin(sopt, cmd, l, l); | ||||
sopt->sopt_valsize = sopt_valsize; | sopt->sopt_valsize = sopt_valsize; | ||||
if (error) | if (error) | ||||
goto done; | goto done; | ||||
} | } | ||||
} else { /* compatibility */ | } else { /* compatibility */ | ||||
error = 0; | error = 0; | ||||
cmd->type = DN_CMD_GET; | cmd->type = DN_CMD_GET; | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | for (have = 0, i = 0; i < 10; i++) { | ||||
DN_BH_WUNLOCK(); | DN_BH_WUNLOCK(); | ||||
if (start) | if (start) | ||||
free(start, M_DUMMYNET); | free(start, M_DUMMYNET); | ||||
start = NULL; | start = NULL; | ||||
if (need > sopt_valsize) | if (need > sopt_valsize) | ||||
break; | break; | ||||
have = need; | have = need; | ||||
start = malloc(have, M_DUMMYNET, M_WAITOK | M_ZERO); | start = malloc(have, M_DUMMYNET, M_NOWAIT | M_ZERO); | ||||
} | } | ||||
if (start == NULL) { | if (start == NULL) { | ||||
if (compat) { | if (compat) { | ||||
*compat = NULL; | *compat = NULL; | ||||
error = 1; // XXX | error = 1; // XXX | ||||
} else { | } else { | ||||
error = sooptcopyout(sopt, cmd, sizeof(*cmd)); | error = sooptcopyout(sopt, cmd, sizeof(*cmd)); | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Handler for the various dummynet socket options | * Handler for the various dummynet socket options | ||||
*/ | */ | ||||
static int | static int | ||||
ip_dn_ctl(struct sockopt *sopt) | ip_dn_ctl(struct sockopt *sopt) | ||||
{ | { | ||||
struct epoch_tracker et; | |||||
void *p = NULL; | void *p = NULL; | ||||
int error, l; | int error, l; | ||||
error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET); | error = priv_check(sopt->sopt_td, PRIV_NETINET_DUMMYNET); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
/* Disallow sets in really-really secure mode. */ | /* Disallow sets in really-really secure mode. */ | ||||
if (sopt->sopt_dir == SOPT_SET) { | if (sopt->sopt_dir == SOPT_SET) { | ||||
error = securelevel_ge(sopt->sopt_td->td_ucred, 3); | error = securelevel_ge(sopt->sopt_td->td_ucred, 3); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | |||||
switch (sopt->sopt_name) { | switch (sopt->sopt_name) { | ||||
default : | default : | ||||
D("dummynet: unknown option %d", sopt->sopt_name); | D("dummynet: unknown option %d", sopt->sopt_name); | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
case IP_DUMMYNET_FLUSH: | case IP_DUMMYNET_FLUSH: | ||||
case IP_DUMMYNET_CONFIGURE: | case IP_DUMMYNET_CONFIGURE: | ||||
case IP_DUMMYNET_DEL: /* remove a pipe or queue */ | case IP_DUMMYNET_DEL: /* remove a pipe or queue */ | ||||
case IP_DUMMYNET_GET: | case IP_DUMMYNET_GET: | ||||
D("dummynet: compat option %d", sopt->sopt_name); | D("dummynet: compat option %d", sopt->sopt_name); | ||||
error = ip_dummynet_compat(sopt); | error = ip_dummynet_compat(sopt); | ||||
break; | break; | ||||
case IP_DUMMYNET3 : | case IP_DUMMYNET3 : | ||||
if (sopt->sopt_dir == SOPT_GET) { | if (sopt->sopt_dir == SOPT_GET) { | ||||
error = dummynet_get(sopt, NULL); | error = dummynet_get(sopt, NULL); | ||||
break; | break; | ||||
} | } | ||||
l = sopt->sopt_valsize; | l = sopt->sopt_valsize; | ||||
if (l < sizeof(struct dn_id) || l > 12000) { | if (l < sizeof(struct dn_id) || l > 12000) { | ||||
D("argument len %d invalid", l); | D("argument len %d invalid", l); | ||||
break; | break; | ||||
} | } | ||||
p = malloc(l, M_TEMP, M_WAITOK); // XXX can it fail ? | p = malloc(l, M_TEMP, M_NOWAIT); | ||||
if (p == NULL) { | |||||
error = ENOMEM; | |||||
break; | |||||
} | |||||
error = sooptcopyin(sopt, p, l, l); | error = sooptcopyin(sopt, p, l, l); | ||||
if (error) | if (error) | ||||
break ; | break ; | ||||
error = do_config(p, l); | error = do_config(p, l); | ||||
break; | break; | ||||
} | } | ||||
if (p != NULL) | if (p != NULL) | ||||
free(p, M_TEMP); | free(p, M_TEMP); | ||||
NET_EPOCH_EXIT(et); | |||||
return error ; | return error ; | ||||
} | } | ||||
static void | static void | ||||
ip_dn_vnet_init(void) | ip_dn_vnet_init(void) | ||||
{ | { | ||||
if (V_dn_cfg.init_done) | if (V_dn_cfg.init_done) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | ip_dn_vnet_destroy(void) | ||||
DN_LOCK_DESTROY(); | DN_LOCK_DESTROY(); | ||||
} | } | ||||
static void | static void | ||||
ip_dn_init(void) | ip_dn_init(void) | ||||
{ | { | ||||
if (dn_tasks_started) | if (dn_tasks_started) | ||||
return; | return; | ||||
mtx_init(&sched_mtx, "dn_sched", NULL, MTX_DEF); | |||||
dn_tasks_started = 1; | dn_tasks_started = 1; | ||||
TASK_INIT(&dn_task, 0, dummynet_task, NULL); | TASK_INIT(&dn_task, 0, dummynet_task, NULL); | ||||
dn_tq = taskqueue_create_fast("dummynet", M_WAITOK, | dn_tq = taskqueue_create_fast("dummynet", M_WAITOK, | ||||
taskqueue_thread_enqueue, &dn_tq); | taskqueue_thread_enqueue, &dn_tq); | ||||
taskqueue_start_threads(&dn_tq, 1, PI_NET, "dummynet"); | taskqueue_start_threads(&dn_tq, 1, PI_NET, "dummynet"); | ||||
SLIST_INIT(&schedlist); | CK_LIST_INIT(&schedlist); | ||||
callout_init(&dn_timeout, 1); | callout_init(&dn_timeout, 1); | ||||
dn_reschedule(); | dn_reschedule(); | ||||
} | } | ||||
static void | static void | ||||
ip_dn_destroy(int last) | ip_dn_destroy(int last) | ||||
{ | { | ||||
/* ensure no more callouts are started */ | /* ensure no more callouts are started */ | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | load_dn_sched(struct dn_alg *d) | ||||
/* Check that mandatory funcs exists */ | /* Check that mandatory funcs exists */ | ||||
if (d->enqueue == NULL || d->dequeue == NULL) { | if (d->enqueue == NULL || d->dequeue == NULL) { | ||||
D("missing enqueue or dequeue for %s", d->name); | D("missing enqueue or dequeue for %s", d->name); | ||||
return 1; | return 1; | ||||
} | } | ||||
/* Search if scheduler already exists */ | /* Search if scheduler already exists */ | ||||
DN_BH_WLOCK(); | mtx_lock(&sched_mtx); | ||||
SLIST_FOREACH(s, &schedlist, next) { | CK_LIST_FOREACH(s, &schedlist, next) { | ||||
if (strcmp(s->name, d->name) == 0) { | if (strcmp(s->name, d->name) == 0) { | ||||
D("%s already loaded", d->name); | D("%s already loaded", d->name); | ||||
break; /* scheduler already exists */ | break; /* scheduler already exists */ | ||||
} | } | ||||
} | } | ||||
if (s == NULL) | if (s == NULL) | ||||
SLIST_INSERT_HEAD(&schedlist, d, next); | CK_LIST_INSERT_HEAD(&schedlist, d, next); | ||||
DN_BH_WUNLOCK(); | mtx_unlock(&sched_mtx); | ||||
D("dn_sched %s %sloaded", d->name, s ? "not ":""); | D("dn_sched %s %sloaded", d->name, s ? "not ":""); | ||||
return s ? 1 : 0; | return s ? 1 : 0; | ||||
} | } | ||||
static int | static int | ||||
unload_dn_sched(struct dn_alg *s) | unload_dn_sched(struct dn_alg *s) | ||||
{ | { | ||||
struct dn_alg *tmp, *r; | struct dn_alg *tmp, *r; | ||||
int err = EINVAL; | int err = EINVAL; | ||||
ND("called for %s", s->name); | ND("called for %s", s->name); | ||||
DN_BH_WLOCK(); | mtx_lock(&sched_mtx); | ||||
SLIST_FOREACH_SAFE(r, &schedlist, next, tmp) { | CK_LIST_FOREACH_SAFE(r, &schedlist, next, tmp) { | ||||
if (strcmp(s->name, r->name) != 0) | if (strcmp(s->name, r->name) != 0) | ||||
continue; | continue; | ||||
ND("ref_count = %d", r->ref_count); | ND("ref_count = %d", r->ref_count); | ||||
err = (r->ref_count != 0) ? EBUSY : 0; | err = (r->ref_count != 0) ? EBUSY : 0; | ||||
if (err == 0) | if (err == 0) | ||||
SLIST_REMOVE(&schedlist, r, dn_alg, next); | CK_LIST_REMOVE(r, next); | ||||
break; | break; | ||||
} | } | ||||
DN_BH_WUNLOCK(); | mtx_unlock(&sched_mtx); | ||||
NET_EPOCH_WAIT(); | |||||
D("dn_sched %s %sunloaded", s->name, err ? "not ":""); | D("dn_sched %s %sunloaded", s->name, err ? "not ":""); | ||||
return err; | return err; | ||||
} | } | ||||
int | int | ||||
dn_sched_modevent(module_t mod, int cmd, void *arg) | dn_sched_modevent(module_t mod, int cmd, void *arg) | ||||
{ | { | ||||
struct dn_alg *sch = arg; | struct dn_alg *sch = arg; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | load_dn_aqm(struct dn_aqm *d) | ||||
ip_dn_init(); /* just in case, we need the lock */ | ip_dn_init(); /* just in case, we need the lock */ | ||||
/* Check that mandatory funcs exists */ | /* Check that mandatory funcs exists */ | ||||
if (d->enqueue == NULL || d->dequeue == NULL) { | if (d->enqueue == NULL || d->dequeue == NULL) { | ||||
D("missing enqueue or dequeue for %s", d->name); | D("missing enqueue or dequeue for %s", d->name); | ||||
return 1; | return 1; | ||||
} | } | ||||
mtx_lock(&sched_mtx); | |||||
/* Search if AQM already exists */ | /* Search if AQM already exists */ | ||||
DN_BH_WLOCK(); /* XXX Global lock? */ | CK_LIST_FOREACH(aqm, &aqmlist, next) { | ||||
SLIST_FOREACH(aqm, &aqmlist, next) { | |||||
if (strcmp(aqm->name, d->name) == 0) { | if (strcmp(aqm->name, d->name) == 0) { | ||||
D("%s already loaded", d->name); | D("%s already loaded", d->name); | ||||
break; /* AQM already exists */ | break; /* AQM already exists */ | ||||
} | } | ||||
} | } | ||||
if (aqm == NULL) | if (aqm == NULL) | ||||
SLIST_INSERT_HEAD(&aqmlist, d, next); | CK_LIST_INSERT_HEAD(&aqmlist, d, next); | ||||
DN_BH_WUNLOCK(); | |||||
mtx_unlock(&sched_mtx); | |||||
D("dn_aqm %s %sloaded", d->name, aqm ? "not ":""); | D("dn_aqm %s %sloaded", d->name, aqm ? "not ":""); | ||||
return aqm ? 1 : 0; | return aqm ? 1 : 0; | ||||
} | } | ||||
/* Callback to clean up AQM status for queues connected to a flowset | /* Callback to clean up AQM status for queues connected to a flowset | ||||
* and then deconfigure the flowset. | * and then deconfigure the flowset. | ||||
* This function is called before an AQM module is unloaded | * This function is called before an AQM module is unloaded | ||||
*/ | */ | ||||
Show All 12 Lines | |||||
static int | static int | ||||
unload_dn_aqm(struct dn_aqm *aqm) | unload_dn_aqm(struct dn_aqm *aqm) | ||||
{ | { | ||||
struct dn_aqm *tmp, *r; | struct dn_aqm *tmp, *r; | ||||
int err = EINVAL; | int err = EINVAL; | ||||
err = 0; | err = 0; | ||||
ND("called for %s", aqm->name); | ND("called for %s", aqm->name); | ||||
DN_BH_WLOCK(); | |||||
/* clean up AQM status and deconfig flowset */ | /* clean up AQM status and deconfig flowset */ | ||||
dn_ht_scan(V_dn_cfg.fshash, fs_cleanup, &aqm->type); | dn_ht_scan(V_dn_cfg.fshash, fs_cleanup, &aqm->type); | ||||
SLIST_FOREACH_SAFE(r, &aqmlist, next, tmp) { | mtx_lock(&sched_mtx); | ||||
CK_LIST_FOREACH_SAFE(r, &aqmlist, next, tmp) { | |||||
if (strcmp(aqm->name, r->name) != 0) | if (strcmp(aqm->name, r->name) != 0) | ||||
continue; | continue; | ||||
ND("ref_count = %d", r->ref_count); | ND("ref_count = %d", r->ref_count); | ||||
err = (r->ref_count != 0 || r->cfg_ref_count != 0) ? EBUSY : 0; | err = (r->ref_count != 0 || r->cfg_ref_count != 0) ? EBUSY : 0; | ||||
if (err == 0) | if (err == 0) | ||||
SLIST_REMOVE(&aqmlist, r, dn_aqm, next); | CK_LIST_REMOVE(r, next); | ||||
break; | break; | ||||
} | } | ||||
DN_BH_WUNLOCK(); | |||||
mtx_unlock(&sched_mtx); | |||||
NET_EPOCH_WAIT(); | |||||
D("%s %sunloaded", aqm->name, err ? "not ":""); | D("%s %sunloaded", aqm->name, err ? "not ":""); | ||||
if (err) | if (err) | ||||
D("ref_count=%d, cfg_ref_count=%d", r->ref_count, r->cfg_ref_count); | D("ref_count=%d, cfg_ref_count=%d", r->ref_count, r->cfg_ref_count); | ||||
return err; | return err; | ||||
} | } | ||||
int | int | ||||
dn_aqm_modevent(module_t mod, int cmd, void *arg) | dn_aqm_modevent(module_t mod, int cmd, void *arg) | ||||
Show All 13 Lines |