Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

ALTQ 2.0

  • Loading branch information...
commit 0fca29c22ea9c7067d78438a11552ad91309c8c2 1 parent 0d7c7b6
itojun authored
Showing with 5,120 additions and 774 deletions.
  1. +38 −12 kame/sys/net/altq_conf.c
  2. +5 −1 kame/sys/net/altq_conf.h
  3. +5 −13 kame/sys/net/if_altq.h
  4. +26 −1 kame/sys/netinet/altq.h
  5. +16 −15 kame/sys/netinet/altq_afmap.c
  6. +1 −1  kame/sys/netinet/altq_afmap.h
  7. +677 −0 kame/sys/netinet/altq_blue.c
  8. +118 −0 kame/sys/netinet/altq_blue.h
  9. +30 −45 kame/sys/netinet/altq_cbq.c
  10. +9 −14 kame/sys/netinet/altq_cbq.h
  11. +1,095 −0 kame/sys/netinet/altq_cdnr.c
  12. +284 −0 kame/sys/netinet/altq_cdnr.h
  13. +9 −8 kame/sys/netinet/altq_classq.h
  14. +1 −1  kame/sys/netinet/altq_fifoq.c
  15. +1 −1  kame/sys/netinet/altq_fifoq.h
  16. +1 −1  kame/sys/netinet/altq_flowvalve.h
  17. +1,951 −0 kame/sys/netinet/altq_hfsc.c
  18. +283 −0 kame/sys/netinet/altq_hfsc.h
  19. +39 −7 kame/sys/netinet/altq_red.c
  20. +26 −1 kame/sys/netinet/altq_red.h
  21. +221 −531 kame/sys/netinet/altq_rio.c
  22. +24 −72 kame/sys/netinet/altq_rio.h
  23. +63 −34 kame/sys/netinet/altq_rmclass.c
  24. +5 −4 kame/sys/netinet/altq_rmclass.h
  25. +2 −2 kame/sys/netinet/altq_rmclass_debug.h
  26. +146 −6 kame/sys/netinet/altq_subr.c
  27. +42 −1 kame/sys/netinet/altq_var.h
  28. +1 −1  kame/sys/netinet/altq_wfq.c
  29. +1 −2  kame/sys/netinet/altq_wfq.h
View
50 kame/sys/net/altq_conf.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: altq_conf.c,v 1.1 1999/08/05 17:18:22 itojun Exp $
+ * $Id: altq_conf.c,v 1.1.1.1 1999/10/02 05:52:29 itojun Exp $
*/
#ifdef ALTQ
@@ -42,18 +42,12 @@
#include <sys/socket.h>
#include <sys/kernel.h>
#include <sys/errno.h>
-#ifdef DEVFS
+#if defined(__FreeBSD__) && defined(DEVFS)
#include <sys/devfsext.h>
#endif /*DEVFS*/
-#include <net/if_altq.h>
+#include <net/if.h>
#include <net/altq_conf.h>
-
-/* ioctl cmd type (copied from altq_var.h not to include netinet headers) */
-#if defined(__FreeBSD__) && (__FreeBSD__ < 3)
-typedef int ioctlcmd_t;
-#else
-typedef u_long ioctlcmd_t;
-#endif
+#include <netinet/altq.h>
#ifdef CBQ
altqdev_decl(cbq);
@@ -76,6 +70,15 @@ altqdev_decl(rio);
#ifdef LOCALQ
altqdev_decl(localq);
#endif
+#ifdef HFSC
+altqdev_decl(hfsc);
+#endif
+#ifdef CDNR
+altqdev_decl(cdnr);
+#endif
+#ifdef BLUE
+altqdev_decl(blue);
+#endif
/*
* altq minor device (discipline) table
@@ -117,6 +120,21 @@ static struct altqsw altqsw[] = { /* minor */
#else
{"noq", noopen, noclose, noioctl}, /* 7 (local use) */
#endif
+#ifdef HFSC
+ {"hfsc",hfscopen, hfscclose, hfscioctl}, /* 8 */
+#else
+ {"noq", noopen, noclose, noioctl}, /* 8 */
+#endif
+#ifdef CDNR
+ {"cdnr",cdnropen, cdnrclose, cdnrioctl}, /* 9 */
+#else
+ {"noq", noopen, noclose, noioctl}, /* 9 */
+#endif
+#ifdef BLUE
+ {"blue",blueopen, blueclose, blueioctl}, /* 10 */
+#else
+ {"noq", noopen, noclose, noioctl}, /* 10 */
+#endif
};
/*
@@ -127,9 +145,17 @@ int naltqsw = sizeof (altqsw) / sizeof (altqsw[0]);
static d_open_t altqopen;
static d_close_t altqclose;
static d_ioctl_t altqioctl;
+#ifdef __FreeBSD__
static void altq_drvinit __P((void *));
+#else
+void altqattach __P((int));
+#endif
-#define CDEV_MAJOR 96 /* FreeBSD official number */
+#if defined(__FreeBSD__)
+#define CDEV_MAJOR 96 /* FreeBSD official number */
+#elif defined(__NetBSD__)
+#define CDEV_MAJOR 65 /* not official */
+#endif
#ifndef __NetBSD__
static struct cdevsw altq_cdevsw =
@@ -185,7 +211,7 @@ altqioctl(dev, cmd, addr, flag, p)
}
-static altq_devsw_installed = 0;
+static int altq_devsw_installed = 0;
#ifdef __FreeBSD__
#ifdef DEVFS
View
6 kame/sys/net/altq_conf.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: altq_conf.h,v 1.1 1999/08/05 17:18:22 itojun Exp $
+ * $Id: altq_conf.h,v 1.1.1.1 1999/10/02 05:52:29 itojun Exp $
*/
#ifndef _NET_ALTQ_CONF_H_
#define _NET_ALTQ_CONF_H_
@@ -55,6 +55,10 @@ typedef int d_open_t __P((dev_t dev, int oflags, int devtype, struct proc *p));
typedef int d_close_t __P((dev_t dev, int fflag, int devtype, struct proc *p));
typedef int d_ioctl_t __P((dev_t dev, u_long cmd, caddr_t data,
int fflag, struct proc *p));
+
+#define noopen (dev_type_open((*))) enodev
+#define noclose (dev_type_close((*))) enodev
+#define noioctl (dev_type_ioctl((*))) enodev
#endif
/*
View
18 kame/sys/net/if_altq.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_altq.h,v 1.1 1999/08/05 17:18:22 itojun Exp $
+ * $Id: if_altq.h,v 1.1.1.1 1999/10/02 05:52:29 itojun Exp $
*/
#ifndef _NET_IF_ALTQ_H_
#define _NET_IF_ALTQ_H_
@@ -42,28 +42,20 @@ struct pr_hdr {
#define ALTQF_READY 0x01 /* driver supports alternate queueing */
#define ALTQF_ENABLE 0x02 /* altq is in use */
#define ALTQF_ACCOUNTING 0x04 /* altq accounting is enabled */
+#define ALTQF_CNDTNING 0x08 /* altq traffic conditioning is enabled */
#define ALTQF_DRIVER1 0x40 /* driver specific */
-/* if_altqtype */
-#define ALTQT_NONE 0 /* reserved */
-#define ALTQT_CBQ 1 /* cbq */
-#define ALTQT_WFQ 2 /* wfq */
-#define ALTQT_AFMAP 3 /* afmap */
-#define ALTQT_FIFOQ 4 /* fifoq */
-#define ALTQT_RED 5 /* red */
-#define ALTQT_RIO 6 /* rio */
-#define ALTQT_LOCALQ 7 /* local use */
-#define ALTQT_MAX 8
-
/* if_altqflags set internally only: */
#define ALTQF_CANTCHANGE (ALTQF_READY)
#define ALTQ_IS_READY(ifp) ((ifp)->if_altqflags & ALTQF_READY)
#define ALTQ_IS_ON(ifp) ((ifp)->if_altqflags & ALTQF_ENABLE)
+#define ALTQ_IS_CNDTNING(ifp) ((ifp)->if_altqflags & ALTQF_CNDTNING)
#define SET_ACCOUNTING(ifp) ((ifp)->if_altqflags |= ALTQF_ACCOUNTING)
#define CLEAR_ACCOUNTING(ifp) ((ifp)->if_altqflags &= ~ALTQF_ACCOUNTING)
-
+#define SET_CNDTNING(ifp) ((ifp)->if_altqflags |= ALTQF_CNDTNING)
+#define CLEAR_CNDTNING(ifp) ((ifp)->if_altqflags &= ~ALTQF_CNDTNING)
/* if_altqenqueue 4th arg */
#define ALTEQ_NORMAL 0 /* normal queueing */
View
27 kame/sys/netinet/altq.h
@@ -23,13 +23,27 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: altq.h,v 1.1 1999/08/05 17:18:17 itojun Exp $
+ * $Id: altq.h,v 1.1.1.1 1999/10/02 05:52:42 itojun Exp $
*/
#ifndef _NETINET_ALTQ_H_
#define _NETINET_ALTQ_H_
#include <netinet/in.h>
+/* altq discipline type */
+#define ALTQT_NONE 0 /* reserved */
+#define ALTQT_CBQ 1 /* cbq */
+#define ALTQT_WFQ 2 /* wfq */
+#define ALTQT_AFMAP 3 /* afmap */
+#define ALTQT_FIFOQ 4 /* fifoq */
+#define ALTQT_RED 5 /* red */
+#define ALTQT_RIO 6 /* rio */
+#define ALTQT_LOCALQ 7 /* local use */
+#define ALTQT_HFSC 8 /* hfsc */
+#define ALTQT_CDNR 9 /* traffic conditioner */
+#define ALTQT_BLUE 10 /* blue */
+#define ALTQT_MAX 10
+
/*
* common network flow info structure
*/
@@ -78,6 +92,7 @@ struct flowinfo_in6 {
* flow filters for AF_INET and AF_INET6
*/
struct flow_filter {
+ int ff_ruleno;
struct flowinfo_in ff_flow;
struct {
struct in_addr mask_dst;
@@ -90,6 +105,7 @@ struct flow_filter {
#ifdef SIN6_LEN
struct flow_filter6 {
+ int ff_ruleno;
struct flowinfo_in6 ff_flow6;
struct {
struct in6_addr mask6_dst;
@@ -104,4 +120,13 @@ struct flow_filter6 {
#include <netinet/altq_var.h>
#endif
+/* queue macros only in FreeBSD */
+#ifndef LIST_EMPTY
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+#endif
+#ifndef LIST_FOREACH
+#define LIST_FOREACH(var, head, field) \
+ for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
+#endif
+
#endif /* _NETINET_ALTQ_H_ */
View
31 kame/sys/netinet/altq_afmap.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: altq_afmap.c,v 1.2 1999/08/16 20:03:56 shin Exp $
+ * $Id: altq_afmap.c,v 1.1.1.1 1999/10/02 05:52:42 itojun Exp $
*/
/*
@@ -58,6 +58,7 @@
#include <net/altq_conf.h>
#include <netinet/in.h>
+#include <netinet/altq.h>
#include <netinet/altq_afmap.h>
LIST_HEAD(, afm_head) afhead_chain;
@@ -262,29 +263,29 @@ afm_match6(head, fp)
for (afm = head->afh_head.lh_first; afm != NULL;
afm = afm->afm_list.le_next) {
- if (afm->afm_flowinfo6.fi_flowlabel != 0 &&
- afm->afm_flowinfo6.fi_flowlabel != fp->fi_flowlabel)
+ if (afm->afm_flowinfo6.fi6_flowlabel != 0 &&
+ afm->afm_flowinfo6.fi6_flowlabel != fp->fi6_flowlabel)
continue;
#ifdef notyet
- if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi_dst) &&
- !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi_dst,
- &fp->fi_dst))
+ if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_dst) &&
+ !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_dst,
+ &fp->fi6_dst))
continue;
- if (afm->afm_flowinfo6.fi_dport != 0 &&
- afm->afm_flowinfo6.fi_dport != fp->fi_dport)
+ if (afm->afm_flowinfo6.fi6_dport != 0 &&
+ afm->afm_flowinfo6.fi6_dport != fp->fi6_dport)
continue;
#endif
- if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi_src) &&
- !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi_src,
- &fp->fi_src))
+ if (!IN6_IS_ADDR_UNSPECIFIED(&afm->afm_flowinfo6.fi6_src) &&
+ !IN6_ARE_ADDR_EQUAL(&afm->afm_flowinfo6.fi6_src,
+ &fp->fi6_src))
continue;
#ifdef notyet
- if (afm->afm_flowinfo6.fi_sport != 0 &&
- afm->afm_flowinfo6.fi_sport != fp->fi_sport)
+ if (afm->afm_flowinfo6.fi6_sport != 0 &&
+ afm->afm_flowinfo6.fi6_sport != fp->fi6_sport)
continue;
#endif
- if (afm->afm_flowinfo6.fi_proto != 0 &&
- afm->afm_flowinfo6.fi_proto != fp->fi_proto)
+ if (afm->afm_flowinfo6.fi6_proto != 0 &&
+ afm->afm_flowinfo6.fi6_proto != fp->fi6_proto)
continue;
/* match found! */
return (afm);
View
2  kame/sys/netinet/altq_afmap.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: altq_afmap.h,v 1.2 1999/08/16 20:03:56 shin Exp $
+ * $Id: altq_afmap.h,v 1.1.1.1 1999/10/02 05:52:42 itojun Exp $
*/
#ifndef _NETINET_ALTQ_AFMAP_H_
View
677 kame/sys/netinet/altq_blue.c
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 1997-1999
+ * Sony Computer Science Laboratory Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * Copyright (c) 1990-1994 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: altq_blue.c,v 1.1 1999/10/01 04:38:05 kjc Exp $
+ */
+
+#ifndef _NO_OPT_ALTQ_H_
+#include "opt_altq.h"
+#if !defined(__FreeBSD__) || (__FreeBSD__ > 2)
+#include "opt_inet.h"
+#endif
+#endif /* !_NO_OPT_ALTQ_H_ */
+#ifdef BLUE /* blue is enabled by BLUE option in opt_altq.h */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/altq_conf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/altq.h>
+#include <netinet/altq_classq.h>
+#include <netinet/altq_blue.h>
+
+/*
+ * Blue is proposed and implemented by Wu-chang Feng <wuchang@eecs.umich.edu>.
+ * more information on Blue is available from
+ * http://www.eecs.umich.edu/~wuchang/blue/
+ */
+
+/* fixed-point uses 12-bit decimal places */
+#define FP_SHIFT 12 /* fixed-point shift */
+
+#define BLUE_LIMIT 200 /* default max queue lenght */
+#define BLUE_STATS /* collect statistics */
+
+/* blue_list keeps all blue_state_t's allocated. */
+static blue_queue_t *blue_list = NULL;
+
+/* internal function prototypes */
+static int blue_enqueue __P((struct ifnet *, struct mbuf *,
+ struct pr_hdr *, int));
+static struct mbuf *blue_dequeue __P((struct ifnet *, int));
+static int drop_early __P((blue_t *));
+static int mark_ecn __P((struct pr_hdr *, int));
+static int blue_detach __P((blue_queue_t *));
+
+/*
+ * blue device interface
+ */
+altqdev_decl(blue);
+
+int
+blueopen(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ /* everything will be done when the queueing scheme is attached. */
+ return 0;
+}
+
+int
+blueclose(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ blue_queue_t *rqp;
+ int err, error = 0;
+
+ while ((rqp = blue_list) != NULL) {
+ /* destroy all */
+ err = blue_detach(rqp);
+ if (err != 0 && error == 0)
+ error = err;
+ }
+
+ return error;
+}
+
+int
+blueioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ blue_queue_t *rqp;
+ struct blue_interface *ifacep;
+ struct ifnet *ifp;
+ int error = 0;
+
+ /* check super-user privilege */
+ switch (cmd) {
+ case BLUE_GETSTATS:
+ break;
+ default:
+ if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+ return (error);
+ break;
+ }
+
+ switch (cmd) {
+
+ case BLUE_ENABLE:
+ ifacep = (struct blue_interface *)addr;
+ if ((rqp = altq_lookup(ifacep->blue_ifname, ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ error = if_altqenable(rqp->rq_ifp);
+ break;
+
+ case BLUE_DISABLE:
+ ifacep = (struct blue_interface *)addr;
+ if ((rqp = altq_lookup(ifacep->blue_ifname, ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ error = if_altqdisable(rqp->rq_ifp);
+ break;
+
+ case BLUE_IF_ATTACH:
+ ifp = ifunit(((struct blue_interface *)addr)->blue_ifname);
+ if (ifp == NULL) {
+ error = ENXIO;
+ break;
+ }
+
+ /* allocate and initialize blue_state_t */
+ MALLOC(rqp, blue_queue_t *, sizeof(blue_queue_t), M_DEVBUF, M_WAITOK);
+ bzero(rqp, sizeof(blue_queue_t));
+
+ MALLOC(rqp->rq_q, class_queue_t *, sizeof(class_queue_t),
+ M_DEVBUF, M_WAITOK);
+ bzero(rqp->rq_q, sizeof(class_queue_t));
+
+ MALLOC(rqp->rq_blue, blue_t *, sizeof(blue_t), M_DEVBUF, M_WAITOK);
+ bzero(rqp->rq_blue, sizeof(blue_t));
+
+ rqp->rq_ifp = ifp;
+ qtail(rqp->rq_q) = NULL;
+ qlen(rqp->rq_q) = 0;
+ qlimit(rqp->rq_q) = BLUE_LIMIT;
+
+ /* default packet time: 1000 bytes / 10Mbps * 8 * 1000000 */
+ blue_init(rqp->rq_blue, 0, 800, 1000, 50000);
+
+ /*
+ * set BLUE to this ifnet structure.
+ */
+ error = if_altqattach(ifp, rqp, blue_enqueue, blue_dequeue,
+ ALTQT_BLUE);
+ if (error) {
+ FREE(rqp->rq_blue, M_DEVBUF);
+ FREE(rqp->rq_q, M_DEVBUF);
+ FREE(rqp, M_DEVBUF);
+ break;
+ }
+
+ /* add this state to the blue list */
+ rqp->rq_next = blue_list;
+ blue_list = rqp;
+ break;
+
+ case BLUE_IF_DETACH:
+ ifacep = (struct blue_interface *)addr;
+ if ((rqp = altq_lookup(ifacep->blue_ifname, ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ error = blue_detach(rqp);
+ break;
+
+ case BLUE_GETSTATS:
+ do {
+ struct blue_stats *q_stats;
+ blue_t *rp;
+
+ q_stats = (struct blue_stats *)addr;
+ if ((rqp = altq_lookup(q_stats->iface.blue_ifname,
+ ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+
+ q_stats->q_len = qlen(rqp->rq_q);
+ q_stats->q_limit = qlimit(rqp->rq_q);
+
+ rp = rqp->rq_blue;
+ q_stats->q_pmark = rp->blue_pmark;
+ q_stats->xmit_packets = rp->blue_stats.xmit_packets;
+ q_stats->xmit_bytes = rp->blue_stats.xmit_bytes;
+ q_stats->drop_packets = rp->blue_stats.drop_packets;
+ q_stats->drop_bytes = rp->blue_stats.drop_bytes;
+ q_stats->drop_forced = rp->blue_stats.drop_forced;
+ q_stats->drop_unforced = rp->blue_stats.drop_unforced;
+ q_stats->marked_packets = rp->blue_stats.marked_packets;
+
+ } while (0);
+ break;
+
+ case BLUE_CONFIG:
+ do {
+ struct blue_conf *fc;
+ int limit;
+
+ fc = (struct blue_conf *)addr;
+ if ((rqp = altq_lookup(fc->iface.blue_ifname,
+ ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ limit = fc->blue_limit;
+ qlimit(rqp->rq_q) = limit;
+ fc->blue_limit = limit; /* write back the new value */
+ if (fc->blue_pkttime > 0)
+ rqp->rq_blue->blue_pkttime = fc->blue_pkttime;
+ if (fc->blue_max_pmark > 0)
+ rqp->rq_blue->blue_max_pmark = fc->blue_max_pmark;
+ if (fc->blue_hold_time > 0)
+ rqp->rq_blue->blue_hold_time = fc->blue_hold_time;
+ rqp->rq_blue->blue_flags = fc->blue_flags;
+
+ blue_init(rqp->rq_blue, rqp->rq_blue->blue_flags,
+ rqp->rq_blue->blue_pkttime,
+ rqp->rq_blue->blue_max_pmark,
+ rqp->rq_blue->blue_hold_time);
+ } while (0);
+ break;
+
+ case BLUE_ACC_ENABLE:
+ /* enable accounting mode */
+ ifacep = (struct blue_interface *)addr;
+ if ((rqp = altq_lookup(ifacep->blue_ifname, ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ SET_ACCOUNTING(rqp->rq_ifp);
+ break;
+
+ case BLUE_ACC_DISABLE:
+ /* disable accounting mode */
+ ifacep = (struct blue_interface *)addr;
+ if ((rqp = altq_lookup(ifacep->blue_ifname, ALTQT_BLUE)) == NULL) {
+ error = EBADF;
+ break;
+ }
+ CLEAR_ACCOUNTING(rqp->rq_ifp);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static int blue_detach(rqp)
+ blue_queue_t *rqp;
+{
+ blue_queue_t *tmp;
+ int error = 0;
+
+ if (ALTQ_IS_ON(rqp->rq_ifp))
+ if_altqdisable(rqp->rq_ifp);
+
+ _flushq(rqp->rq_q);
+
+ if ((error = if_altqdetach(rqp->rq_ifp)))
+ return (error);
+
+ if (blue_list == rqp)
+ blue_list = rqp->rq_next;
+ else {
+ for (tmp = blue_list; tmp != NULL; tmp = tmp->rq_next)
+ if (tmp->rq_next == rqp) {
+ tmp->rq_next = rqp->rq_next;
+ break;
+ }
+ if (tmp == NULL)
+ printf("blue_detach: no state found in blue_list!\n");
+ }
+
+ FREE(rqp->rq_q, M_DEVBUF);
+ FREE(rqp->rq_blue, M_DEVBUF);
+ FREE(rqp, M_DEVBUF);
+ return (error);
+}
+
+/*
+ * blue support routines
+ */
+
+int
+blue_init(rp, flags, pkttime, blue_max_pmark, blue_hold_time)
+ blue_t *rp;
+ int flags;
+ int pkttime;
+ int blue_max_pmark;
+ int blue_hold_time;
+{
+ int npkts_per_sec;
+
+ rp->blue_idle = 1;
+ rp->blue_flags = flags;
+ rp->blue_pkttime = pkttime;
+ rp->blue_max_pmark = blue_max_pmark;
+ rp->blue_hold_time = blue_hold_time;
+ if (pkttime == 0)
+ rp->blue_pkttime = 1;
+
+ /* when the link is very slow, adjust blue parameters */
+ npkts_per_sec = 1000000 / rp->blue_pkttime;
+ if (npkts_per_sec < 50) {
+ }
+ else if (npkts_per_sec < 300) {
+ }
+
+ microtime(&rp->blue_last);
+ return (0);
+}
+
+/*
+ * enqueue routine:
+ *
+ * returns: 0 when successfully queued.
+ * ENOBUFS when drop occurs.
+ */
+static int
+blue_enqueue(ifp, m, pr_hdr, mode)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct pr_hdr *pr_hdr;
+ int mode;
+{
+ blue_queue_t *rqp = (blue_queue_t *)ifp->if_altqp;
+ int error = 0;
+
+ switch (mode) {
+ case ALTEQ_NORMAL:
+ if (blue_addq(rqp->rq_blue, rqp->rq_q, m, pr_hdr) == 0) {
+ /* successfully queued. start the driver */
+ if (ifp->if_start && (ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ }
+ else
+ error = ENOBUFS;
+ break;
+
+#if defined(ALTQ_ACCOUNT) && defined(BLUE_STATS)
+ /*
+ * altq accounting mode: used just for statistics.
+ */
+ case ALTEQ_ACCOK:
+ rqp->rq_blue->blue_stats.xmit_packets++;
+ rqp->rq_blue->blue_stats.xmit_bytes += m->m_pkthdr.len;
+ break;
+
+ case ALTEQ_ACCDROP:
+ rqp->rq_blue->blue_stats.drop_packets++;
+ rqp->rq_blue->blue_stats.drop_bytes += m->m_pkthdr.len;
+ break;
+
+#endif /* ALTQ_ACCOUNT && BLUE_STATS */
+ }
+ return error;
+}
+
+#define DTYPE_NODROP 0 /* no drop */
+#define DTYPE_FORCED 1 /* a "forced" drop */
+#define DTYPE_EARLY 2 /* an "unforced" (early) drop */
+
+int blue_addq(rp, q, m, pr_hdr)
+ blue_t *rp;
+ class_queue_t *q;
+ struct mbuf *m;
+ struct pr_hdr *pr_hdr;
+{
+ int droptype;
+
+ /*
+ * if we were idle, this is an enqueue onto an empty queue
+ * and we should decrement marking probability
+ *
+ */
+ if (rp->blue_idle) {
+ struct timeval now;
+ int t;
+ rp->blue_idle = 0;
+ microtime(&now);
+ t = (now.tv_sec - rp->blue_last.tv_sec);
+ if ( t > 1) {
+ rp->blue_pmark = 1;
+ microtime(&rp->blue_last);
+ }
+ else {
+ t = t * 1000000 + (now.tv_usec - rp->blue_last.tv_usec);
+ if (t > rp->blue_hold_time) {
+ rp->blue_pmark--;
+ if (rp->blue_pmark < 0) rp->blue_pmark = 0;
+ microtime(&rp->blue_last);
+ }
+ }
+ }
+
+ /* see if we drop early */
+ droptype = DTYPE_NODROP;
+ if (drop_early(rp) && qlen(q) > 1) {
+ /* mark or drop by blue */
+ if ((rp->blue_flags & BLUEF_ECN) &&
+ mark_ecn(pr_hdr, rp->blue_flags)) {
+ /* successfully marked. do not drop. */
+#ifdef BLUE_STATS
+ rp->blue_stats.marked_packets++;
+#endif
+ }
+ else {
+ /* unforced drop by blue */
+ droptype = DTYPE_EARLY;
+ }
+ }
+
+ /*
+ * if the queue length hits the hard limit, it's a forced drop.
+ */
+ if (droptype == DTYPE_NODROP && qlen(q) >= qlimit(q))
+ droptype = DTYPE_FORCED;
+
+ /* if successful or forced drop, enqueue this packet. */
+ if (droptype != DTYPE_EARLY)
+ _addq(q, m);
+
+ if (droptype != DTYPE_NODROP) {
+ if (droptype == DTYPE_EARLY) {
+ /* drop the incoming packet */
+#ifdef BLUE_STATS
+ rp->blue_stats.drop_unforced++;
+#endif
+ }
+ else {
+ struct timeval now;
+ int t;
+ /* forced drop, select a victim packet in the queue. */
+ m = _getq_random(q);
+ microtime(&now);
+ t = (now.tv_sec - rp->blue_last.tv_sec);
+ t = t * 1000000 + (now.tv_usec - rp->blue_last.tv_usec);
+ if (t > rp->blue_hold_time) {
+ rp->blue_pmark += rp->blue_max_pmark >> 3;
+ if (rp->blue_pmark > rp->blue_max_pmark)
+ rp->blue_pmark = rp->blue_max_pmark;
+ microtime(&rp->blue_last);
+ }
+#ifdef BLUE_STATS
+ rp->blue_stats.drop_forced++;
+#endif
+ }
+#ifdef BLUE_STATS
+ rp->blue_stats.drop_packets++;
+ rp->blue_stats.drop_bytes += m->m_pkthdr.len;
+#endif
+ m_freem(m);
+ return (-1);
+ }
+ /* successfully queued */
+ return (0);
+}
+
+/*
+ * early-drop probability is kept in blue_pmark
+ *
+ */
+static int drop_early(rp)
+ blue_t *rp;
+{
+ if ((random() % rp->blue_max_pmark) < rp->blue_pmark) {
+ /* drop or mark */
+ return (1);
+ }
+ /* no drop/mark */
+ return (0);
+}
+
+/*
+ * try to mark CE bit to the packet.
+ * returns 1 if successfully marked, 0 otherwise.
+ */
+static int mark_ecn(pr_hdr, flags)
+ struct pr_hdr *pr_hdr;
+ int flags;
+{
+
+ switch (pr_hdr->ph_family) {
+ case AF_INET:
+ if (flags & BLUEF_ECN4) {
+ struct ip *ip = (struct ip *)pr_hdr->ph_hdr;
+
+ if (ip->ip_tos & IPTOS_ECT) {
+ /* ECN-capable, mark ECN bit. */
+ if ((ip->ip_tos & IPTOS_CE) == 0) {
+ long sum;
+
+ ip->ip_tos |= IPTOS_CE;
+ /*
+ * update checksum (from RFC1624)
+ * HC' = ~(~HC + ~m + m')
+ */
+ sum = ~ntohs(ip->ip_sum) & 0xffff;
+ sum += 0xffff + IPTOS_CE;
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16); /* add carry */
+
+ ip->ip_sum = htons(~sum & 0xffff);
+ }
+ return (1);
+ }
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (flags & BLUEF_ECN6) {
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)pr_hdr->ph_hdr;
+
+ if (ip6->ip6_flow & (IPTOS_ECT << 20)) {
+ /* ECN-capable, mark ECN bit. */
+ ip6->ip6_flow |= (IPTOS_CE << 20);
+ return (1);
+ }
+ }
+ break;
+#endif /* INET6 */
+ }
+
+ /* not marked */
+ return (0);
+}
+
+/*
+ * dequeue routine:
+ * must be called in splimp.
+ *
+ * returns: mbuf dequeued.
+ * NULL when no packet is available in the queue.
+ */
+
+static struct mbuf *
+blue_dequeue(ifp, mode)
+ struct ifnet *ifp;
+ int mode;
+{
+ blue_queue_t *rqp = (blue_queue_t *)ifp->if_altqp;
+ struct mbuf *m = NULL;
+
+ switch (mode) {
+ case ALTDQ_DEQUEUE:
+ m = blue_getq(rqp->rq_blue, rqp->rq_q);
+ break;
+
+ case ALTDQ_PEEK:
+ m = qhead(rqp->rq_q);
+ break;
+
+ case ALTDQ_FLUSH:
+ _flushq(rqp->rq_q);
+ m = NULL;
+ break;
+ }
+ return m;
+}
+
+struct mbuf *blue_getq(rp, q)
+ blue_t *rp;
+ class_queue_t *q;
+{
+ struct mbuf *m;
+
+ if ((m = _getq(q)) == NULL) {
+ if (rp->blue_idle == 0) {
+ rp->blue_idle = 1;
+ microtime(&rp->blue_last);
+ }
+ return NULL;
+ }
+
+ rp->blue_idle = 0;
+#ifdef BLUE_STATS
+ rp->blue_stats.xmit_packets++;
+ rp->blue_stats.xmit_bytes += m->m_pkthdr.len;
+#endif
+ return (m);
+}
+
+#ifdef KLD_MODULE
+
+#include <net/altq_conf.h>
+
+static struct altqsw blue_sw =
+ {"blue", blueopen, blueclose, blueioctl};
+
+ALTQ_MODULE(altq_blue, ALTQT_BLUE, &blue_sw);
+
+#endif /* KLD_MODULE */
+
+#endif /* BLUE */
View
118 kame/sys/netinet/altq_blue.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 1997-1999
+ * Sony Computer Science Laboratory Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: altq_blue.h,v 1.1 1999/10/01 04:38:05 kjc Exp $
+ */
+
+#ifndef _NETINET_ALTQ_BLUE_H_
+#define _NETINET_ALTQ_BLUE_H_
+
+struct blue_interface {
+ char blue_ifname[IFNAMSIZ];
+};
+
+struct blue_stats {
+ struct blue_interface iface;
+ int q_len;
+ int q_limit;
+ int q_pmark;
+ quad_t xmit_packets;
+ quad_t xmit_bytes;
+ quad_t drop_packets;
+ quad_t drop_bytes;
+ quad_t drop_forced;
+ quad_t drop_unforced;
+ quad_t marked_packets;
+};
+
+struct blue_conf {
+ struct blue_interface iface;
+ int blue_limit;
+ int blue_max_pmark;
+ int blue_hold_time;
+ int blue_pkttime; /* average packet time in usec */
+ int blue_flags; /* see below */
+};
+
+/* blue flags */
+#define BLUEF_ECN4 0x01 /* use packet marking for IPv4 packets */
+#define BLUEF_ECN6 0x02 /* use packet marking for IPv6 packets */
+#define BLUEF_ECN (BLUEF_ECN4 | BLUEF_ECN6)
+
+/*
+ * IOCTLs for BLUE
+ */
+#define BLUE_ENABLE _IOW('Q', 1, struct blue_interface)
+#define BLUE_DISABLE _IOW('Q', 2, struct blue_interface)
+#define BLUE_IF_ATTACH _IOW('Q', 3, struct blue_interface)
+#define BLUE_IF_DETACH _IOW('Q', 4, struct blue_interface)
+#define BLUE_ACC_ENABLE _IOW('Q', 5, struct blue_interface)
+#define BLUE_ACC_DISABLE _IOW('Q', 6, struct blue_interface)
+#define BLUE_GETSTATS _IOWR('Q', 7, struct blue_stats)
+#define BLUE_CONFIG _IOWR('Q', 8, struct blue_conf)
+
+#if defined(KERNEL) || defined(_KERNEL)
+
+typedef struct blue {
+ int blue_pkttime; /* average packet time in micro sec
+ used for idle calibration */
+ int blue_flags; /* blue flags */
+
+ /* blue parameters */
+ int blue_pmark; /* 0-1000 (mark probability*10000) */
+ int blue_max_pmark; /* sets precision of marking probability */
+ int blue_hold_time; /* hold time in usec */
+
+ int blue_idle; /* queue was empty */
+ struct timeval blue_last; /* timestamp when the queue becomes idle */
+
+ struct {
+ quad_t xmit_packets;
+ quad_t xmit_bytes;
+ quad_t drop_packets;
+ quad_t drop_bytes;
+ quad_t drop_forced;
+ quad_t drop_unforced;
+ quad_t marked_packets;
+ } blue_stats;
+} blue_t;
+
+typedef struct blue_queue {
+ struct blue_queue *rq_next; /* next blue_state in the list */
+ struct ifnet *rq_ifp; /* backpointer to ifnet */
+
+ class_queue_t *rq_q;
+
+ blue_t *rq_blue;
+} blue_queue_t;
+
+extern int blue_init __P((blue_t *, int, int, int, int));
+extern int blue_addq __P((blue_t *, class_queue_t *, struct mbuf *,
+ struct pr_hdr *));
+extern struct mbuf *blue_getq __P((blue_t *, class_queue_t *));
+
+#endif /* KERNEL */
+
+#endif /* _NETINET_ALTQ_BLUE_H_ */
View
75 kame/sys/netinet/altq_cbq.c
@@ -27,7 +27,7 @@
*
* These notices must be retained in any copies of any part of this software.
*
- * $Id: altq_cbq.c,v 1.1 1999/08/05 17:18:18 itojun Exp $
+ * $Id: altq_cbq.c,v 1.1.1.1 1999/10/02 05:52:42 itojun Exp $
*/
#ifndef _NO_OPT_ALTQ_H_
@@ -38,7 +38,7 @@
#endif /* !_NO_OPT_ALTQ_H_ */
#ifdef CBQ /* cbq is enabled by CBQ option in opt_altq.h */
-#pragma ident "@(#)cbq.c 1.39 98/05/13 SMI"
+/* #pragma ident "@(#)cbq.c 1.39 98/05/13 SMI" */
#include <sys/param.h>
#include <sys/malloc.h>
@@ -58,12 +58,8 @@
#include <netinet/altq.h>
#include <netinet/altq_classq.h>
#include <netinet/altq_rmclass.h>
-#ifdef CBQ_RED
#include <netinet/altq_red.h>
-#ifdef CBQ_RIO
#include <netinet/altq_rio.h>
-#endif
-#endif /* CBQ_RED */
#include <netinet/altq_cbq.h>
/*
@@ -397,9 +393,6 @@ cbq_delete_filter(dfp)
/*
* cbq_clear_hierarchy deletes all classes and their filters on the
* given interface.
- * note that this doesn't affect the enable state and leaves
- * the root class and the default class intact. This behavior is
- * different from Sun's CBQ implementation.
*/
static int
cbq_clear_hierarchy(ifacep)
@@ -432,10 +425,27 @@ cbq_clear_interface(cbqp)
if ((cl = cbqp->cbq_class_tbl[i]) != NULL) {
if (is_a_parent_class(cl))
again++;
- else
+ else {
cbq_class_destroy(cbqp, cl);
+ cbqp->cbq_class_tbl[i] = NULL;
+ }
}
}
+ if (cbqp->ifnp.ctl_ != NULL &&
+ !is_a_parent_class(cbqp->ifnp.ctl_)) {
+ cbq_class_destroy(cbqp, cbqp->ifnp.ctl_);
+ cbqp->ifnp.ctl_ = NULL;
+ }
+ if (cbqp->ifnp.default_ != NULL &&
+ !is_a_parent_class(cbqp->ifnp.default_)) {
+ cbq_class_destroy(cbqp, cbqp->ifnp.default_);
+ cbqp->ifnp.default_ = NULL;
+ }
+ if (cbqp->ifnp.root_ != NULL &&
+ !is_a_parent_class(cbqp->ifnp.root_)) {
+ cbq_class_destroy(cbqp, cbqp->ifnp.root_);
+ cbqp->ifnp.root_ = NULL;
+ }
} while (again);
return (0);
@@ -528,43 +538,14 @@ get_class_stats(statsp, cl)
statsp->qcnt = qlen(cl->q_);
statsp->avgidle = cl->avgidle_;
+ statsp->qtype = qtype(cl->q_);
#ifdef CBQ_RED
- if (cl->red_ != NULL) {
- if (q_is_red(cl->q_)) {
- red_t *rp = cl->red_;
- statsp->q_avg = rp->red_avg >> cl->red_->red_wshift;
- statsp->xmit_packets = rp->red_stats.xmit_packets;
- statsp->drop_forced = rp->red_stats.drop_forced;
- statsp->drop_unforced = rp->red_stats.drop_unforced;
- statsp->marked_packets = rp->red_stats.marked_packets;
- statsp->in_xmit_packets = 0;
- }
-#ifdef CBQ_RIO
- else {
- rio_t *rp = (rio_t *)cl->red_;
-
- statsp->q_avg = rp->q.avg >> rp->rio_wshift;
- statsp->xmit_packets = rp->q_stat.xmit_packets;
- statsp->drop_forced = rp->q_stat.drop_forced;
- statsp->drop_unforced = rp->q_stat.drop_unforced;
- statsp->marked_packets = rp->q_stat.marked_packets;
- statsp->in_avg = rp->in.avg >> rp->rio_wshift;
- statsp->in_xmit_packets = rp->in_stat.xmit_packets;
- statsp->in_drop_forced = rp->in_stat.drop_forced;
- statsp->in_drop_unforced = rp->in_stat.drop_unforced;
- statsp->in_marked_packets = rp->in_stat.marked_packets;
- }
+ if (q_is_red(cl->q_))
+ red_getstats(cl->red_, &statsp->red[0]);
#endif
- }
- else {
-#endif /* CBQ_RED */
- statsp->xmit_packets = 0;
- statsp->in_xmit_packets = 0;
- statsp->drop_forced = 0;
- statsp->drop_unforced = 0;
- statsp->marked_packets = 0;
-#ifdef CBQ_RED
- }
+#ifdef CBQ_RIO
+ if (q_is_rio(cl->q_))
+ rio_getstats((rio_t *)cl->red_, &statsp->red[0]);
#endif
}
@@ -903,6 +884,9 @@ static int
cbq_add_riometer(rmp)
struct cbq_riometer *rmp;
{
+#if 1
+ return (0);
+#else
char *ifacename;
cbq_state_t *cbqp;
rio_t *rp;
@@ -936,6 +920,7 @@ cbq_add_riometer(rmp)
if (depth == 0)
depth = cl->ifdat_->maxpkt_ * 6;
return rio_set_meter(rp, rate, depth, rmp->codepoint);
+#endif
}
#endif /* CBQ_RIO */
View
23 kame/sys/netinet/altq_cbq.h
@@ -1,3 +1,4 @@
+/* $Id: altq_cbq.h,v 1.1.1.1 1999/10/02 05:52:42 itojun Exp $ */
/*
* Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
*
@@ -31,10 +32,13 @@
#ifndef _NETINET_ALTQ_CBQ_H_
#define _NETINET_ALTQ_CBQ_H_
-#pragma ident "@(#)cbq.h 1.18 98/05/13 SMI"
+/* #pragma ident "@(#)cbq.h 1.18 98/05/13 SMI" */
#include <sys/ioccom.h>
#include <netinet/altq.h>
+#include <netinet/altq_red.h>
+#include <netinet/altq_rio.h>
+#include <netinet/altq_classq.h>
#ifdef __cplusplus
extern "C" {
@@ -106,6 +110,7 @@ typedef struct cbq_class_spec {
#define CBQCLF_ECN 0x0002 /* use RED/ECN */
#define CBQCLF_RIO 0x0004 /* use RIO */
#define CBQCLF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */
+#define CBQCLF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
/* class flags only for root class */
#define CBQCLF_WRR 0x0100 /* weighted-round robin */
@@ -162,19 +167,9 @@ typedef struct _cbq_class_stats_ {
int qcnt; /* # packets in queue */
int avgidle;
- /* red related info */
- int q_avg;
- u_int xmit_packets;
- u_int drop_forced;
- u_int drop_unforced;
- u_int marked_packets;
- /* rio related info */
- int in_avg;
- u_int in_xmit_packets;
- u_int in_drop_forced;
- u_int in_drop_unforced;
- u_int in_marked_packets;
-
+ /* red and rio related info */
+ int qtype;
+ struct redstats red[3];
} class_stats_t;
struct cbq_getstats {
View
1,095 kame/sys/netinet/altq_cdnr.c
@@ -0,0 +1,1095 @@
+/*
+ * Copyright (C) 1999
+ * Sony Computer Science Laboratories Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: altq_cdnr.c,v 1.1 1999/10/01 04:38:05 kjc Exp $
+ */
+
+#ifndef _NO_OPT_ALTQ_H_
+#include "opt_altq.h"
+#if !defined(__FreeBSD__) || (__FreeBSD__ > 2)
+#include "opt_inet.h"
+#endif
+#endif /* !_NO_OPT_ALTQ_H_ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/altq_conf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif
+#include <netinet/altq.h>
+#include <netinet/altq_cdnr.h>
+
+/*
+ * diffserv traffic conditioning module
+ */
+
+int altq_cdnr_enabled = 0;
+
+/* traffic conditioner is enabled by CDNR option in opt_altq.h */
+#ifdef CDNR
+
+/* cdnr_list keeps all cdnr's allocated. */
+static LIST_HEAD(, top_cdnr) tcb_list;
+
+int cdnropen __P((dev_t, int, int, struct proc *));
+int cdnrclose __P((dev_t, int, int, struct proc *));
+int cdnrioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct proc *));
+
+static struct top_cdnr *tcb_lookup(char *ifname);
+static struct cdnr_block *cdnr_handle2cb(u_long);
+static u_long cdnr_cb2handle(struct cdnr_block *);
+static void *cdnr_cballoc(struct top_cdnr *, int,
+ struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *));
+static void cdnr_cbdestroy(void *);
+static int tca_verify_action(struct tc_action *);
+static void tca_import_action(struct tc_action *, struct tc_action *);
+static void tca_invalidate_action(struct tc_action *);
+
+static int generic_element_destroy(struct cdnr_block *);
+static struct top_cdnr *top_create(struct ifnet *);
+static int top_destroy(struct top_cdnr *);
+static struct cdnr_block *element_create(struct top_cdnr *,
+ struct tc_action *);
+static int element_destroy(struct cdnr_block *);
+static void tb_import_profile(struct tbe *, struct tb_profile *);
+static struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *,
+ struct tc_action *, struct tc_action *);
+static int tbm_destroy(struct tbmeter *);
+static struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *);
+static struct trtcm *trtcm_create(struct top_cdnr *,
+ struct tb_profile *, struct tb_profile *,
+ struct tc_action *, struct tc_action *, struct tc_action *,
+ int);
+static int trtcm_destroy(struct trtcm *);
+static struct tc_action *trtcm_input(struct cdnr_block *,
+ struct cdnr_pktinfo *);
+
+static int cdnrcmd_if_attach(char *);
+static int cdnrcmd_if_detach(char *);
+static int cdnrcmd_add_element(struct cdnr_add_element *);
+static int cdnrcmd_delete_element(struct cdnr_delete_element *);
+static int cdnrcmd_add_filter(struct cdnr_add_filter *);
+static int cdnrcmd_delete_filter(struct cdnr_delete_filter *);
+static int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *);
+static int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *);
+static int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *);
+static int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *);
+static int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *);
+static int cdnrcmd_trtcm_stats(struct cdnr_trtcm_stats *);
+static int cdnrcmd_get_stats(struct cdnr_get_stats *);
+
+/*
+ * top level input function called from ip_input.
+ * should be called before converting header fields to host-byte-order.
+ */
+int
+altq_cdnr_input(m, af)
+ struct mbuf *m;
+ int af; /* address family */
+{
+ struct ifnet *ifp;
+ struct ip *ip;
+ struct top_cdnr *top;
+ struct tc_action *tca;
+ struct cdnr_block *cb;
+ struct cdnr_pktinfo pktinfo;
+ struct pr_hdr pr_hdr;
+ struct flowinfo flow;
+
+ ifp = m->m_pkthdr.rcvif;
+ if (!ALTQ_IS_CNDTNING(ifp))
+ /* traffic conditioner is not enabled to this interface */
+ return (1);
+
+ top = ifp->if_altqcdnr;
+
+ ip = mtod(m, struct ip *);
+ pktinfo.pkt_len = m_pktlen(m);
+#ifdef INET6
+ if (af == AF_INET6) {
+ u_int32_t flowlabel;
+
+ flowlabel = ((struct ip6_hdr *)ip)->ip6_flow;
+ pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK;
+ }
+ else
+#endif
+ pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK;
+
+ tca = NULL;
+
+ pr_hdr.ph_family = af;
+ pr_hdr.ph_hdr = (caddr_t)ip;
+ altq_extractflow(m, &pr_hdr, &flow,
+ top->tc_classifier.acc_fbmask);
+ cb = acc_classify(&top->tc_classifier, &flow);
+ if (cb != NULL)
+ tca = &cb->cb_action;
+
+ if (tca == NULL)
+ tca = &top->tc_block.cb_action;
+
+ while (1) {
+ top->tc_stats[tca->tca_code].packets++;
+ top->tc_stats[tca->tca_code].bytes += m_pktlen(m);
+
+ switch (tca->tca_code) {
+ case TCACODE_PASS:
+ return (1);
+ case TCACODE_DROP:
+ m_freem(m);
+ return (0);
+ case TCACODE_RETURN:
+ return (0);
+ case TCACODE_MARK:
+#ifdef INET6
+ if (af == AF_INET6) {
+ struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
+ u_int32_t flowlabel;
+
+ flowlabel = ntohl(ip6->ip6_flow);
+ flowlabel = (tca->tca_dscp << 20) |
+ (flowlabel & ~(DSCP_MASK << 20));
+ ip6->ip6_flow = htonl(flowlabel);
+ }
+ else
+#endif
+ ip->ip_tos = tca->tca_dscp |
+ (ip->ip_tos & DSCP_CUMASK);
+ return (1);
+ case TCACODE_NEXT:
+ cb = tca->tca_next;
+ tca = (*cb->cb_input)(cb, &pktinfo);
+ break;
+ case TCACODE_NONE:
+ default:
+ return (1);
+ }
+ }
+}
+
+static struct top_cdnr *
+tcb_lookup(ifname)
+ char *ifname;
+{
+ struct top_cdnr *top;
+ struct ifnet *ifp;
+
+ if ((ifp = ifunit(ifname)) != NULL)
+ LIST_FOREACH(top, &tcb_list, tc_next)
+ if (top->tc_ifp == ifp)
+ return (top);
+ return (NULL);
+}
+
+static struct cdnr_block *
+cdnr_handle2cb(handle)
+ u_long handle;
+{
+ struct cdnr_block *cb;
+
+ cb = (struct cdnr_block *)handle;
+ if (handle != ALIGN(cb))
+ return (NULL);
+
+ if (cb == NULL || cb->cb_handle != handle)
+ return (NULL);
+ return (cb);
+}
+
+static u_long
+cdnr_cb2handle(cb)
+ struct cdnr_block *cb;
+{
+ return (cb->cb_handle);
+}
+
+static void *
+cdnr_cballoc(top, type, input_func)
+ struct top_cdnr *top;
+ int type;
+ struct tc_action *(*input_func)(struct cdnr_block *,
+ struct cdnr_pktinfo *);
+{
+ struct cdnr_block *cb;
+ int size;
+
+ switch (type) {
+ case CBTYPE_TOP:
+ size = sizeof(struct top_cdnr);
+ break;
+ case CBTYPE_ELEMENT:
+ size = sizeof(struct cdnr_block);
+ break;
+ case CBTYPE_TBM:
+ size = sizeof(struct tbmeter);
+ break;
+ case CBTYPE_TCM:
+ size = sizeof(struct trtcm);
+ break;
+ default:
+ return (NULL);
+ }
+
+ MALLOC(cb, struct cdnr_block *, size, M_DEVBUF, M_WAITOK);
+ if (cb == NULL)
+ return (NULL);
+ bzero(cb, size);
+
+ cb->cb_len = size;
+ cb->cb_type = type;
+ cb->cb_ref = 0;
+ cb->cb_handle = (u_long)cb;
+ if (top == NULL)
+ cb->cb_top = (struct top_cdnr *)cb;
+ else
+ cb->cb_top = top;
+
+ if (input_func != NULL) {
+ /*
+ * if this cdnr has an action function,
+ * make tc_action to call itself.
+ */
+ cb->cb_action.tca_code = TCACODE_NEXT;
+ cb->cb_action.tca_next = cb;
+ cb->cb_input = input_func;
+ }
+ else
+ cb->cb_action.tca_code = TCACODE_NONE;
+
+ if (top != NULL)
+ LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
+
+ return ((void *)cb);
+}
+
+static void
+cdnr_cbdestroy(cblock)
+ void *cblock;
+{
+ struct cdnr_block *cb = cblock;
+
+ /* delete filters referencing to this cdnr */
+ acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
+
+ if (cb->cb_top != cblock)
+ LIST_REMOVE(cb, cb_next);
+
+ FREE(cb, M_DEVBUF);
+}
+
+/*
+ * conditioner common destroy routine
+ */
+static int
+generic_element_destroy(cb)
+ struct cdnr_block *cb;
+{
+ int error = 0;
+
+ switch (cb->cb_type) {
+ case CBTYPE_TOP:
+ error = top_destroy((struct top_cdnr *)cb);
+ break;
+ case CBTYPE_ELEMENT:
+ error = element_destroy(cb);
+ break;
+ case CBTYPE_TBM:
+ error = tbm_destroy((struct tbmeter *)cb);
+ break;
+ case CBTYPE_TCM:
+ error = trtcm_destroy((struct trtcm *)cb);
+ break;
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+static int
+tca_verify_action(utca)
+ struct tc_action *utca;
+{
+ switch (utca->tca_code) {
+ case TCACODE_PASS:
+ case TCACODE_DROP:
+ case TCACODE_MARK:
+ /* these are ok */
+ break;
+
+ case TCACODE_HANDLE:
+ /* verify handle value */
+ if (cdnr_handle2cb(utca->tca_handle) == NULL)
+ return (-1);
+ break;
+
+ case TCACODE_NONE:
+ case TCACODE_RETURN:
+ case TCACODE_NEXT:
+ default:
+ /* should not be passed from a user */
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+tca_import_action(ktca, utca)
+ struct tc_action *ktca, *utca;
+{
+ struct cdnr_block *cb;
+
+ *ktca = *utca;
+ if (ktca->tca_code == TCACODE_HANDLE) {
+ cb = cdnr_handle2cb(ktca->tca_handle);
+ if (cb == NULL) {
+ ktca->tca_code = TCACODE_NONE;
+ return;
+ }
+ ktca->tca_code = TCACODE_NEXT;
+ ktca->tca_next = cb;
+ cb->cb_ref++;
+ }
+ else if (ktca->tca_code == TCACODE_MARK) {
+ ktca->tca_dscp &= DSCP_MASK;
+ }
+ return;
+}
+
+static void
+tca_invalidate_action(tca)
+ struct tc_action *tca;
+{
+ struct cdnr_block *cb;
+
+ if (tca->tca_code == TCACODE_NEXT) {
+ cb = tca->tca_next;
+ if (cb == NULL)
+ return;
+ cb->cb_ref--;
+ }
+ tca->tca_code = TCACODE_NONE;
+}
+
+/*
+ * top level traffic conditioner
+ */
+static struct top_cdnr *
+top_create(ifp)
+ struct ifnet *ifp;
+{
+ struct top_cdnr *top;
+
+ if ((top = cdnr_cballoc(NULL, CBTYPE_TOP, NULL)) == NULL)
+ return (NULL);
+
+ top->tc_ifp = ifp;
+ /* set default action for the top level conditioner */
+ top->tc_block.cb_action.tca_code = TCACODE_PASS;
+
+ LIST_INSERT_HEAD(&tcb_list, top, tc_next);
+
+ ifp->if_altqcdnr = top;
+
+ return (top);
+}
+
+static int
+top_destroy(top)
+ struct top_cdnr *top;
+{
+ struct cdnr_block *cb;
+
+ if (ALTQ_IS_CNDTNING(top->tc_ifp))
+ CLEAR_CNDTNING(top->tc_ifp);
+ top->tc_ifp->if_altqcdnr = NULL;
+
+ /*
+ * destroy all the conditioner elements belonging to this interface
+ */
+ while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
+ while (cb != NULL && cb->cb_ref > 0)
+ cb = LIST_NEXT(cb, cb_next);
+ if (cb != NULL)
+ generic_element_destroy(cb);
+ }
+
+ LIST_REMOVE(top, tc_next);
+
+ cdnr_cbdestroy(top);
+
+ /* if there is no active conditioner, remove the input hook */
+ if (altq_input != NULL) {
+ LIST_FOREACH(top, &tcb_list, tc_next)
+ if (ALTQ_IS_CNDTNING(top->tc_ifp))
+ break;
+ if (top == NULL)
+ altq_input = NULL;
+ }
+
+ return (0);
+}
+
+/*
+ * simple tc elements without input function (e.g., dropper and makers).
+ */
+static struct cdnr_block *
+element_create(top, action)
+ struct top_cdnr *top;
+ struct tc_action *action;
+{
+ struct cdnr_block *cb;
+
+ if ((cb = cdnr_cballoc(top, CBTYPE_ELEMENT, NULL)) == NULL)
+ return (NULL);
+
+ tca_import_action(&cb->cb_action, action);
+
+ return (cb);
+}
+
+static int
+element_destroy(cb)
+ struct cdnr_block *cb;
+{
+ if (cb->cb_ref > 0)
+ return (EBUSY);
+
+ tca_invalidate_action(&cb->cb_action);
+
+ cdnr_cbdestroy(cb);
+ return (0);
+}
+
+/*
+ * internal representation of token bucket parameters
+ * rate: byte_per_unittime << 32
+ * (((bits_per_sec) / 8) << 32) / machclk_freq
+ * depth: byte << 32
+ *
+ */
+#define TB_SHIFT 32
+#define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT)
+#define TB_UNSCALE(x) ((x) >> TB_SHIFT)
+
+static void
+tb_import_profile(tb, profile)
+ struct tbe *tb;
+ struct tb_profile *profile;
+{
+ tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
+ tb->depth = TB_SCALE(profile->depth);
+ if (tb->rate > 0)
+ tb->filluptime = tb->depth / tb->rate;
+ else
+ tb->filluptime = 0xffffffffffffffffLL;
+ tb->token = tb->depth;
+ tb->last = read_machclk();
+}
+
+/*
+ * simple token bucket meter
+ */
+static struct tbmeter *
+tbm_create(top, profile, in_action, out_action)
+ struct top_cdnr *top;
+ struct tb_profile *profile;
+ struct tc_action *in_action, *out_action;
+{
+ struct tbmeter *tbm = NULL;
+
+ if (tca_verify_action(in_action) < 0
+ || tca_verify_action(out_action) < 0)
+ return (NULL);
+
+ if ((tbm = cdnr_cballoc(top, CBTYPE_TBM,
+ tbm_input)) == NULL)
+ return (NULL);
+
+ tb_import_profile(&tbm->tb, profile);
+
+ tca_import_action(&tbm->in_action, in_action);
+ tca_import_action(&tbm->out_action, out_action);
+
+ return (tbm);
+}
+
+static int
+tbm_destroy(tbm)
+ struct tbmeter *tbm;
+{
+ if (tbm->cdnrblk.cb_ref > 0)
+ return (EBUSY);
+
+ tca_invalidate_action(&tbm->in_action);
+ tca_invalidate_action(&tbm->out_action);
+
+ cdnr_cbdestroy(tbm);
+ return (0);
+}
+
+static struct tc_action *
+tbm_input(cb, pktinfo)
+ struct cdnr_block *cb;
+ struct cdnr_pktinfo *pktinfo;
+{
+ struct tbmeter *tbm = (struct tbmeter *)cb;
+ u_int64_t len;
+ u_int64_t interval, now;
+
+ len = TB_SCALE(pktinfo->pkt_len);
+
+ if (tbm->tb.token < len) {
+ now = read_machclk();
+ interval = now - tbm->tb.last;
+ if (interval >= tbm->tb.filluptime)
+ tbm->tb.token = tbm->tb.depth;
+ else {
+ tbm->tb.token += interval * tbm->tb.rate;
+ if (tbm->tb.token > tbm->tb.depth)
+ tbm->tb.token = tbm->tb.depth;
+ }
+ tbm->tb.last = now;
+ }
+
+ if (tbm->tb.token < len) {
+ tbm->out_stats.packets++;
+ tbm->out_stats.bytes += len;
+ return (&tbm->out_action);
+ }
+
+ tbm->tb.token -= len;
+ tbm->in_stats.packets++;
+ tbm->in_stats.bytes += len;
+ return (&tbm->in_action);
+}
+
+/*
+ * two rate three color marker
+ * as described in draft-heinanen-diffserv-trtcm-01.txt
+ */
+static struct trtcm *
+trtcm_create(top, cmtd_profile, peak_profile,
+ green_action, yellow_action, red_action, coloraware)
+ struct top_cdnr *top;
+ struct tb_profile *cmtd_profile, *peak_profile;
+ struct tc_action *green_action, *yellow_action, *red_action;
+ int coloraware;
+{
+ struct trtcm *tcm = NULL;
+
+ if (tca_verify_action(green_action) < 0
+ || tca_verify_action(yellow_action) < 0
+ || tca_verify_action(red_action) < 0)
+ return (NULL);
+
+ if ((tcm = cdnr_cballoc(top, CBTYPE_TCM,
+ trtcm_input)) == NULL)
+ return (NULL);
+
+ tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
+ tb_import_profile(&tcm->peak_tb, peak_profile);
+
+ tca_import_action(&tcm->green_action, green_action);
+ tca_import_action(&tcm->yellow_action, yellow_action);
+ tca_import_action(&tcm->red_action, red_action);
+
+ tcm->coloraware = coloraware;
+
+ return (tcm);
+}
+
+static int
+trtcm_destroy(tcm)
+ struct trtcm *tcm;
+{
+ if (tcm->cdnrblk.cb_ref > 0)
+ return (EBUSY);
+
+ tca_invalidate_action(&tcm->green_action);
+ tca_invalidate_action(&tcm->yellow_action);
+ tca_invalidate_action(&tcm->red_action);
+
+ cdnr_cbdestroy(tcm);
+ return (0);
+}
+
+static struct tc_action *
+trtcm_input(cb, pktinfo)
+ struct cdnr_block *cb;
+ struct cdnr_pktinfo *pktinfo;
+{
+ struct trtcm *tcm = (struct trtcm *)cb;
+ u_int64_t len;
+ u_int64_t interval, now;
+ u_int8_t color;
+
+ len = TB_SCALE(pktinfo->pkt_len);
+ if (tcm->coloraware) {
+ color = pktinfo->pkt_dscp;
+ if (color != tcm->green_action.tca_dscp &&
+ color != tcm->yellow_action.tca_dscp)
+ color = tcm->red_action.tca_dscp;
+ }
+ else {
+ /* if color-blind, precolor it as green */
+ color = tcm->green_action.tca_dscp;
+ }
+
+ now = read_machclk();
+ if (tcm->cmtd_tb.token < len) {
+ interval = now - tcm->cmtd_tb.last;
+ if (interval >= tcm->cmtd_tb.filluptime)
+ tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
+ else {
+ tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
+ if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
+ tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
+ }
+ tcm->cmtd_tb.last = now;
+ }
+ if (tcm->peak_tb.token < len) {
+ interval = now - tcm->peak_tb.last;
+ if (interval >= tcm->peak_tb.filluptime)
+ tcm->peak_tb.token = tcm->peak_tb.depth;
+ else {
+ tcm->peak_tb.token += interval * tcm->peak_tb.rate;
+ if (tcm->peak_tb.token > tcm->peak_tb.depth)
+ tcm->peak_tb.token = tcm->peak_tb.depth;
+ }
+ tcm->peak_tb.last = now;
+ }
+
+ if (color == tcm->red_action.tca_dscp || tcm->peak_tb.token < len) {
+ tcm->red_stats.packets++;
+ tcm->red_stats.bytes += len;
+ return (&tcm->red_action);
+ }
+
+ if (color == tcm->yellow_action.tca_dscp || tcm->cmtd_tb.token < len) {
+ tcm->peak_tb.token -= len;
+ tcm->yellow_stats.packets++;
+ tcm->yellow_stats.bytes += len;
+ return (&tcm->yellow_action);
+ }
+
+ tcm->cmtd_tb.token -= len;
+ tcm->peak_tb.token -= len;
+ tcm->green_stats.packets++;
+ tcm->green_stats.bytes += len;
+ return (&tcm->green_action);
+}
+
+/*
+ * ioctl requests
+ */
+static int
+cdnrcmd_if_attach(ifname)
+ char *ifname;
+{
+ struct ifnet *ifp;
+ struct top_cdnr *top;
+
+ if ((ifp = ifunit(ifname)) == NULL)
+ return (EBADF);
+
+ if (ifp->if_altqcdnr != NULL)
+ return (EBUSY);
+
+ if ((top = top_create(ifp)) == NULL)
+ return (ENOMEM);
+ return (0);
+}
+
+static int
+cdnrcmd_if_detach(ifname)
+ char *ifname;
+{
+ struct top_cdnr *top;
+
+ if ((top = tcb_lookup(ifname)) == NULL)
+ return (EBADF);
+
+ return top_destroy(top);
+}
+
+static int
+cdnrcmd_add_element(ap)
+ struct cdnr_add_element *ap;
+{
+ struct top_cdnr *top;
+ struct cdnr_block *cb;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ cb = element_create(top, &ap->action);
+
+ /* return a class handle to the user */
+ ap->cdnr_handle = cdnr_cb2handle(cb);
+ return (0);
+}
+
+static int
+cdnrcmd_delete_element(ap)
+ struct cdnr_delete_element *ap;
+{
+ struct top_cdnr *top;
+ struct cdnr_block *cb;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ if (cb->cb_type != CBTYPE_ELEMENT)
+ return generic_element_destroy(cb);
+
+ return element_destroy(cb);
+}
+
+static int
+cdnrcmd_add_filter(ap)
+ struct cdnr_add_filter *ap;
+{
+ struct top_cdnr *top;
+ struct cdnr_block *cb;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ return acc_add_filter(&top->tc_classifier, &ap->filter,
+ cb, &ap->filter_handle);
+}
+
+static int
+cdnrcmd_delete_filter(ap)
+ struct cdnr_delete_filter *ap;
+{
+ struct top_cdnr *top;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
+}
+
+static int
+cdnrcmd_add_tbm(ap)
+ struct cdnr_add_tbmeter *ap;
+{
+ struct top_cdnr *top;
+ struct tbmeter *tbm;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
+
+ /* return a class handle to the user */
+ ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
+ return (0);
+}
+
+static int
+cdnrcmd_modify_tbm(ap)
+ struct cdnr_modify_tbmeter *ap;
+{
+ struct tbmeter *tbm;
+
+ if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ tb_import_profile(&tbm->tb, &ap->profile);
+
+ return (0);
+}
+
+static int
+cdnrcmd_tbm_stats(ap)
+ struct cdnr_tbmeter_stats *ap;
+{
+ struct tbmeter *tbm;
+
+ if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ ap->in_stats = tbm->in_stats;
+ ap->out_stats = tbm->out_stats;
+
+ return (0);
+}
+
+static int
+cdnrcmd_add_trtcm(ap)
+ struct cdnr_add_trtcm *ap;
+{
+ struct top_cdnr *top;
+ struct trtcm *tcm;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
+ &ap->green_action, &ap->yellow_action,
+ &ap->red_action, ap->coloraware);
+
+ /* return a class handle to the user */
+ ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
+ return (0);
+}
+
+static int
+cdnrcmd_modify_trtcm(ap)
+ struct cdnr_modify_trtcm *ap;
+{
+ struct trtcm *tcm;
+
+ if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
+ tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
+
+ return (0);
+}
+
+static int
+cdnrcmd_trtcm_stats(ap)
+ struct cdnr_trtcm_stats *ap;
+{
+ struct trtcm *tcm;
+
+ if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
+ return (EINVAL);
+
+ ap->green_stats = tcm->green_stats;
+ ap->yellow_stats = tcm->yellow_stats;
+ ap->red_stats = tcm->red_stats;
+
+ return (0);
+}
+
+static int
+cdnrcmd_get_stats(ap)
+ struct cdnr_get_stats *ap;
+{
+ struct top_cdnr *top;
+
+ if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
+ return (EBADF);
+
+ bcopy(top->tc_stats, ap->stats, sizeof(ap->stats));
+ return (0);
+}
+
+/*
+ * conditioner device interface
+ */
+int
+cdnropen(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ if (machclk_freq == 0)
+ init_machclk();
+
+ if (machclk_freq == 0) {
+ printf("cdnr: no cpu clock available!\n");
+ return (ENXIO);
+ }
+
+ /* everything will be done when the queueing scheme is attached. */
+ return 0;
+}
+
+int
+cdnrclose(dev, flag, fmt, p)
+ dev_t dev;
+ int flag, fmt;
+ struct proc *p;
+{
+ struct top_cdnr *top;
+ int err, error = 0;
+
+ while ((top = LIST_FIRST(&tcb_list)) != NULL) {
+ /* destroy all */
+ err = top_destroy(top);
+ if (err != 0 && error == 0)
+ error = err;
+ }
+ altq_input = NULL;
+
+ return (error);
+}
+
+int
+cdnrioctl(dev, cmd, addr, flag, p)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct top_cdnr *top;
+ struct cdnr_interface *ifacep;
+ int s, error = 0;
+
+ /* check super-user privilege */
+ switch (cmd) {
+ case CDNR_GETSTATS:
+ break;
+ default:
+ if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+ return (error);
+ break;
+ }
+
+ s = splimp();
+ switch (cmd) {
+
+ case CDNR_IF_ATTACH:
+ ifacep = (struct cdnr_interface *)addr;
+ error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
+ break;
+
+ case CDNR_IF_DETACH:
+ ifacep = (struct cdnr_interface *)addr;
+ error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
+ break;
+
+ case CDNR_ENABLE:
+ case CDNR_DISABLE:
+ ifacep = (struct cdnr_interface *)addr;
+ if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
+ error = EBADF;
+ break;
+ }
+
+ switch (cmd) {
+
+ case CDNR_ENABLE:
+ SET_CNDTNING(top->tc_ifp);
+ if (altq_input == NULL)
+ altq_input = altq_cdnr_input;
+ break;
+
+ case CDNR_DISABLE:
+ CLEAR_CNDTNING(top->tc_ifp);
+ LIST_FOREACH(top, &tcb_list, tc_next)
+ if (ALTQ_IS_CNDTNING(top->tc_ifp))
+ break;
+ if (top == NULL)
+ altq_input = NULL;
+ break;
+ }
+ break;
+
+ case CDNR_ADD_ELEM:
+ error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
+ break;
+
+ case CDNR_DEL_ELEM:
+ error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
+ break;
+
+ case CDNR_ADD_TBM:
+ error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
+ break;
+
+ case CDNR_MOD_TBM:
+ error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
+ break;
+
+ case CDNR_TBM_STATS:
+ error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
+ break;
+
+ case CDNR_ADD_TCM:
+ error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
+ break;
+
+ case CDNR_MOD_TCM:
+ error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
+ break;
+
+ case CDNR_TCM_STATS:
+ error = cdnrcmd_trtcm_stats((struct cdnr_trtcm_stats *)addr);
+ break;
+
+ case CDNR_ADD_FILTER:
+ error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
+ break;
+
+ case CDNR_DEL_FILTER:
+ error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
+ break;
+
+ case CDNR_GETSTATS:
+ error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ splx(s);
+
+ return error;
+}
+
+#ifdef KLD_MODULE
+
+#include <net/altq_conf.h>
+
+static struct altqsw cdnr_sw =
+ {"cdnr", cdnropen, cdnrclose, cdnrioctl};
+
+ALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
+
+#endif /* KLD_MODULE */
+
+#endif /* CDNR */
View
284 kame/sys/netinet/altq_cdnr.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 1999
+ * Sony Computer Science Laboratories Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: altq_cdnr.h,v 1.1 1999/10/01 04:38:05 kjc Exp $
+ */
+
+#ifndef _NETINET_ALTQ_CDNR_H_
+#define _NETINET_ALTQ_CDNR_H_
+
+#include <netinet/altq.h>
+
+/*
+ * traffic conditioner action
+ */
+struct cdnr_block;
+
+struct tc_action {
+ int tca_code; /* e.g., TCACODE_PASS */
+ /* tca_code dependent variable */
+ union {
+ u_long un_value; /* template */
+ u_int8_t un_dscp; /* diffserv code point */
+ u_long un_handle; /* tc action handle */
+ struct cdnr_block *un_next; /* next tc element block */
+ } tca_un;
+};
+#define tca_value tca_un.un_value
+#define tca_dscp tca_un.un_dscp
+#define tca_handle tca_un.un_handle
+#define tca_next tca_un.un_next
+
+#define TCACODE_NONE 0 /* action is not set */
+#define TCACODE_PASS 1 /* pass this packet */
+#define TCACODE_DROP 2 /* discard this packet */
+#define TCACODE_RETURN 3 /* do not process this packet */
+#define TCACODE_MARK 4 /* mark dscp */
+#define TCACODE_HANDLE 5 /* take action specified by handle */
+#define TCACODE_NEXT 6 /* take action in the next tc element */
+#define TCACODE_MAX 6
+
+#define CDNR_NULL_HANDLE 0
+
+struct cdnr_interface {
+ char cdnr_ifname[IFNAMSIZ]; /* interface name (e.g., fxp0) */
+};
+
+/* simple token backet meter profile */
+struct tb_profile {
+ u_int rate; /* rate in bit-per-sec */
+ u_int depth; /* depth in bytes */
+};
+
+/* conditioner statistics */
+struct cdnr_stats {
+ u_int packets;
+ u_quad_t bytes;
+};
+
+struct cdnr_add_element {
+ struct cdnr_interface iface;
+ struct tc_action action;
+
+ u_long cdnr_handle; /* return value */
+};
+
+struct cdnr_delete_element {
+ struct cdnr_interface iface;
+ u_long cdnr_handle;
+};
+
+struct cdnr_add_tbmeter {
+ struct cdnr_interface iface;
+ struct tb_profile profile;
+ struct tc_action in_action;
+ struct tc_action out_action;
+