summaryrefslogtreecommitdiff
path: root/sys/altq/altq_cbq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/altq/altq_cbq.c')
-rw-r--r--sys/altq/altq_cbq.c332
1 files changed, 322 insertions, 10 deletions
diff --git a/sys/altq/altq_cbq.c b/sys/altq/altq_cbq.c
index 6800608635d..97864cbffa1 100644
--- a/sys/altq/altq_cbq.c
+++ b/sys/altq/altq_cbq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: altq_cbq.c,v 1.5 2002/10/05 02:57:58 kjc Exp $ */
+/* $OpenBSD: altq_cbq.c,v 1.6 2002/10/11 09:30:30 kjc Exp $ */
/* $KAME: altq_cbq.c,v 1.9 2000/12/14 08:12:45 thorpej Exp $ */
/*
@@ -46,6 +46,7 @@
#include <net/if_types.h>
#include <netinet/in.h>
+#include <net/pfvar.h>
#include <altq/altq.h>
#include <altq/altq_conf.h>
#include <altq/altq_cbq.h>
@@ -65,7 +66,7 @@ static int cbq_modify_class(struct cbq_modify_class *);
static int cbq_class_create(cbq_state_t *, struct cbq_add_class *,
struct rm_class *, struct rm_class *);
static int cbq_class_destroy(cbq_state_t *, struct rm_class *);
-static struct rm_class *clh_to_clp(cbq_state_t *, u_long);
+static struct rm_class *clh_to_clp(cbq_state_t *, u_int32_t);
static int cbq_add_filter(struct cbq_add_filter *);
static int cbq_delete_filter(struct cbq_delete_filter *);
@@ -173,7 +174,7 @@ cbq_modify_class(acp)
/*
* struct rm_class *
* cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp,
- * u_long handle, struct rm_class *parent,
+ * u_int32_t handle, struct rm_class *parent,
* struct rm_class *borrow)
*
* This function create a new traffic class in the CBQ class hierarchy of
@@ -189,7 +190,7 @@ cbq_class_create(cbqp, acp, parent, borrow)
{
struct rm_class *cl;
cbq_class_spec_t *spec = &acp->cbq_class;
- u_long chandle;
+ u_int32_t chandle;
int i;
/*
@@ -220,7 +221,7 @@ cbq_class_create(cbqp, acp, parent, borrow)
break;
if (i == CBQ_MAX_CLASSES)
return (ENOSPC);
- chandle = (u_long)i;
+ chandle = (u_int32_t)i;
break;
default:
/* more than two flags bits set */
@@ -282,7 +283,7 @@ cbq_class_destroy(cbqp, cl)
cbq_state_t *cbqp;
struct rm_class *cl;
{
- u_long chandle;
+ u_int32_t chandle;
chandle = cl->stats_.handle;
@@ -317,7 +318,7 @@ cbq_class_destroy(cbqp, cl)
static struct rm_class *
clh_to_clp(cbqp, chandle)
cbq_state_t *cbqp;
- u_long chandle;
+ u_int32_t chandle;
{
switch (chandle) {
case NULL_CLASS_HANDLE:
@@ -564,6 +565,9 @@ cbq_getstats(gsp)
case 2:
cl = cbqp->ifnp.ctl_;
stats.handle = CTL_CLASS_HANDLE;
+#if 1 /* PFALTQ */
+ if (cl != NULL)
+#endif
break;
default:
while ((cl = cbqp->cbq_class_tbl[chandle]) == NULL)
@@ -585,6 +589,296 @@ cbq_getstats(gsp)
return (error);
}
+#if 1 /* PFALTQ */
+
+int
+cbq_pfattach(struct pf_altq *a)
+{
+ struct ifnet *ifp;
+ int s, error;
+
+ if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
+ return (EINVAL);
+ s = splimp();
+ error = altq_attach(&ifp->if_snd, ALTQT_CBQ, a->altq_disc,
+ cbq_enqueue, cbq_dequeue, cbq_request, NULL, NULL);
+ splx(s);
+ return (error);
+}
+
+int
+cbq_add_altq(struct pf_altq *a)
+{
+ cbq_state_t *cbqp;
+ struct ifnet *ifp;
+
+ if ((ifp = ifunit(a->ifname)) == NULL)
+ return (ENXIO);
+ if (!ALTQ_IS_READY(&ifp->if_snd))
+ return (ENXIO);
+
+ /* allocate and initialize cbq_state_t */
+ MALLOC(cbqp, cbq_state_t *, sizeof(cbq_state_t), M_DEVBUF, M_WAITOK);
+ if (cbqp == NULL)
+ return (ENOMEM);
+ bzero(cbqp, sizeof(cbq_state_t));
+ CALLOUT_INIT(&cbqp->cbq_callout);
+ MALLOC(cbqp->cbq_class_tbl, struct rm_class **,
+ sizeof(struct rm_class *) * CBQ_MAX_CLASSES, M_DEVBUF, M_WAITOK);
+ if (cbqp->cbq_class_tbl == NULL) {
+ FREE(cbqp, M_DEVBUF);
+ return (ENOMEM);
+ }
+ bzero(cbqp->cbq_class_tbl, sizeof(struct rm_class *) * CBQ_MAX_CLASSES);
+ cbqp->cbq_qlen = 0;
+ cbqp->ifnp.ifq_ = &ifp->if_snd; /* keep the ifq */
+
+ /* keep the state in pf_altq */
+ a->altq_disc = cbqp;
+
+ /* prepend to the list of cbq_state_t's. */
+ cbqp->cbq_next = cbq_list;
+ cbq_list = cbqp;
+
+ return (0);
+}
+
+int
+cbq_remove_altq(struct pf_altq *a)
+{
+ cbq_state_t *cbqp;
+
+ if ((cbqp = a->altq_disc) == NULL)
+ return (EINVAL);
+ a->altq_disc = NULL;
+
+ cbq_clear_interface(cbqp);
+
+ if (cbqp->ifnp.ctl_)
+ cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
+ if (cbqp->ifnp.default_)
+ cbq_class_destroy(cbqp, cbqp->ifnp.default_);
+ if (cbqp->ifnp.root_)
+ cbq_class_destroy(cbqp, cbqp->ifnp.root_);
+
+ /* remove from the list of cbq_state_t's. */
+ if (cbq_list == cbqp)
+ cbq_list = cbqp->cbq_next;
+ else {
+ cbq_state_t *cp;
+
+ for (cp = cbq_list; cp != NULL; cp = cp->cbq_next)
+ if (cp->cbq_next == cbqp) {
+ cp->cbq_next = cbqp->cbq_next;
+ break;
+ }
+ ASSERT(cp != NULL);
+ }
+
+ /* deallocate cbq_state_t */
+ FREE(cbqp->cbq_class_tbl, M_DEVBUF);
+ FREE(cbqp, M_DEVBUF);
+
+ return (0);
+}
+
+int
+cbq_add_queue(struct pf_altq *a)
+{
+ struct rm_class *borrow, *parent;
+ cbq_state_t *cbqp;
+ struct rm_class *cl;
+ struct cbq_opts *opts;
+ u_int32_t chandle;
+ int i;
+
+ if ((cbqp = a->altq_disc) == NULL)
+ return (EINVAL);
+
+ opts = &a->pq_u.cbq_opts;
+ /* check parameters */
+ if (a->priority >= RM_MAXPRIO)
+ return (EINVAL);
+
+ /* Get pointers to parent and borrow classes. */
+ parent = clh_to_clp(cbqp, a->parent_qid);
+ if (opts->flags & CBQCLF_BORROW)
+ borrow = parent;
+ else
+ borrow = NULL;
+
+ /*
+ * A class must borrow from it's parent or it can not
+ * borrow at all. Hence, borrow can be null.
+ */
+
+ if (parent == NULL && (opts->flags & CBQCLF_ROOTCLASS) == 0) {
+ printf("cbq_add_queue: no parent class!\n");
+ return (EINVAL);
+ }
+
+ if ((borrow != parent) && (borrow != NULL)) {
+ printf("cbq_add_class: borrow class != parent\n");
+ return (EINVAL);
+ }
+
+ /*
+ * allocate class handle
+ */
+ switch (opts->flags & CBQCLF_CLASSMASK) {
+ case CBQCLF_ROOTCLASS:
+ if (parent != NULL)
+ return (EINVAL);
+ if (cbqp->ifnp.root_)
+ return (EINVAL);
+ chandle = ROOT_CLASS_HANDLE;
+ break;
+ case CBQCLF_DEFCLASS:
+ if (cbqp->ifnp.default_)
+ return (EINVAL);
+ chandle = DEFAULT_CLASS_HANDLE;
+ break;
+ case CBQCLF_CTLCLASS:
+ if (cbqp->ifnp.ctl_)
+ return (EINVAL);
+ chandle = CTL_CLASS_HANDLE;
+ break;
+ case 0:
+ /* find a free class slot */
+#if 1 /* PFALTQ */
+ /* for now, reserve qid 0 */
+ for (i = 1; i < CBQ_MAX_CLASSES; i++)
+#else
+ for (i = 0; i < CBQ_MAX_CLASSES; i++)
+#endif
+ if (cbqp->cbq_class_tbl[i] == NULL)
+ break;
+ if (i == CBQ_MAX_CLASSES)
+ return (ENOSPC);
+ chandle = (u_int32_t)i;
+ break;
+ default:
+ /* more than two flags bits set */
+ return (EINVAL);
+ }
+
+ /*
+ * create a class. if this is a root class, initialize the
+ * interface.
+ */
+ if (chandle == ROOT_CLASS_HANDLE) {
+ rmc_init(cbqp->ifnp.ifq_, &cbqp->ifnp, opts->ns_per_byte,
+ cbqrestart, a->qlimit, RM_MAXQUEUED,
+ opts->maxidle, opts->minidle, opts->offtime,
+ opts->flags);
+ cl = cbqp->ifnp.root_;
+ } else {
+ cl = rmc_newclass(a->priority,
+ &cbqp->ifnp, opts->ns_per_byte,
+ rmc_delay_action, a->qlimit, parent, borrow,
+ opts->maxidle, opts->minidle, opts->offtime,
+ opts->pktsize, opts->flags);
+ }
+ if (cl == NULL)
+ return (ENOMEM);
+
+ /* return handle to user space. */
+ a->qid = chandle;
+
+ cl->stats_.handle = chandle;
+ cl->stats_.depth = cl->depth_;
+
+ /* save the allocated class */
+ switch (chandle) {
+ case NULL_CLASS_HANDLE:
+ case ROOT_CLASS_HANDLE:
+ break;
+ case DEFAULT_CLASS_HANDLE:
+ cbqp->ifnp.default_ = cl;
+ break;
+ case CTL_CLASS_HANDLE:
+ cbqp->ifnp.ctl_ = cl;
+ break;
+ default:
+ cbqp->cbq_class_tbl[chandle] = cl;
+ break;
+ }
+ return (0);
+}
+
+int
+cbq_remove_queue(struct pf_altq *a)
+{
+ struct rm_class *cl;
+ cbq_state_t *cbqp;
+
+ if ((cbqp = a->altq_disc) == NULL)
+ return (EINVAL);
+
+ if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
+ return (EINVAL);
+
+ /* if we are a parent class, then return an error. */
+ if (is_a_parent_class(cl))
+ return (EINVAL);
+
+ /* delete the class */
+ rmc_delete_class(&cbqp->ifnp, cl);
+
+ /*
+ * free the class handle
+ */
+ switch (a->qid) {
+ case ROOT_CLASS_HANDLE:
+ cbqp->ifnp.root_ = NULL;
+ break;
+ case DEFAULT_CLASS_HANDLE:
+ cbqp->ifnp.default_ = NULL;
+ break;
+ case CTL_CLASS_HANDLE:
+ cbqp->ifnp.ctl_ = NULL;
+ break;
+ case NULL_CLASS_HANDLE:
+ break;
+ default:
+ if (a->qid >= CBQ_MAX_CLASSES)
+ break;
+ cbqp->cbq_class_tbl[a->qid] = NULL;
+ }
+
+ return (0);
+}
+
+int
+cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+{
+ cbq_state_t *cbqp;
+ struct rm_class *cl;
+ class_stats_t stats;
+ int error = 0;
+
+ if ((cbqp = altq_lookup(a->ifname, ALTQT_CBQ)) == NULL)
+ return (EBADF);
+
+ if ((cl = clh_to_clp(cbqp, a->qid)) == NULL)
+ return (EINVAL);
+
+ if (*nbytes < sizeof(stats))
+ return (EINVAL);
+
+ get_class_stats(&stats, cl);
+#if 1
+ stats.handle = a->qid;
+#endif
+
+ if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
+ return (error);
+ *nbytes = sizeof(stats);
+ return (0);
+}
+
+#endif /* PFALTQ */
+
static int
cbq_ifattach(ifacep)
struct cbq_interface *ifacep;
@@ -707,9 +1001,25 @@ cbq_enqueue(ifq, m, pktattr)
int len;
/* grab class set by classifier */
- if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
- cl = cbqp->ifnp.default_;
- cl->pktattr_ = pktattr; /* save proto hdr used by ECN */
+ if (PFALTQ_IS_ACTIVE()) {
+ struct m_tag *t;
+
+ t = m_tag_find(m, PACKET_TAG_PF_QID, NULL);
+ if (t == NULL ||
+ (cl = clh_to_clp(cbqp, ((struct altq_tag *)(t+1))->qid))
+ == NULL) {
+ cl = cbqp->ifnp.default_;
+ if (cl == NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ }
+ cl->pktattr_ = NULL;
+ } else {
+ if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
+ cl = cbqp->ifnp.default_;
+ cl->pktattr_ = pktattr; /* save proto hdr used by ECN */
+ }
len = m_pktlen(m);
if (rmc_queue_packet(cl, m) != 0) {
@@ -797,6 +1107,8 @@ cbqopen(dev, flag, fmt, p)
int flag, fmt;
struct proc *p;
{
+ if (PFALTQ_IS_ACTIVE())
+ return (EBUSY);
return (0);
}