Home | History | Annotate | Line # | Download | only in libaltq
qop_priq.c revision 1.5
      1 /*	$NetBSD: qop_priq.c,v 1.5 2002/03/05 04:11:53 itojun Exp $	*/
      2 /*	$KAME: qop_priq.c,v 1.4 2001/12/03 08:20:55 kjc Exp $	*/
      3 /*
      4  * Copyright (C) 2000
      5  *	Sony Computer Science Laboratories, Inc.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/param.h>
     30 #include <sys/socket.h>
     31 #include <sys/sockio.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/fcntl.h>
     34 #include <net/if.h>
     35 #include <netinet/in.h>
     36 #include <arpa/inet.h>
     37 
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <unistd.h>
     41 #include <stddef.h>
     42 #include <string.h>
     43 #include <ctype.h>
     44 #include <errno.h>
     45 #include <syslog.h>
     46 #include <netdb.h>
     47 
     48 #include <altq/altq.h>
     49 #include <altq/altq_priq.h>
     50 #include "altq_qop.h"
     51 #include "qop_priq.h"
     52 
     53 static int qop_priq_enable_hook(struct ifinfo *);
     54 
     55 static int priq_attach(struct ifinfo *);
     56 static int priq_detach(struct ifinfo *);
     57 static int priq_clear(struct ifinfo *);
     58 static int priq_enable(struct ifinfo *);
     59 static int priq_disable(struct ifinfo *);
     60 static int priq_add_class(struct classinfo *);
     61 static int priq_modify_class(struct classinfo *, void *);
     62 static int priq_delete_class(struct classinfo *);
     63 static int priq_add_filter(struct fltrinfo *);
     64 static int priq_delete_filter(struct fltrinfo *);
     65 
     66 #define PRIQ_DEVICE	"/dev/altq/priq"
     67 
     68 static int priq_fd = -1;
     69 static int priq_refcount = 0;
     70 
     71 static struct qdisc_ops priq_qdisc = {
     72 	ALTQT_PRIQ,
     73 	"priq",
     74 	priq_attach,
     75 	priq_detach,
     76 	priq_clear,
     77 	priq_enable,
     78 	priq_disable,
     79 	priq_add_class,
     80 	priq_modify_class,
     81 	priq_delete_class,
     82 	priq_add_filter,
     83 	priq_delete_filter,
     84 };
     85 
     86 #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
     87 
     88 /*
     89  * parser interface
     90  */
     91 int
     92 priq_interface_parser(const char *ifname, int argc, char **argv)
     93 {
     94 	u_int  	bandwidth = 100000000;	/* 100Mbps */
     95 	u_int	tbrsize = 0;
     96 	int	flags = 0;
     97 
     98 	/*
     99 	 * process options
    100 	 */
    101 	while (argc > 0) {
    102 		if (EQUAL(*argv, "bandwidth")) {
    103 			argc--; argv++;
    104 			if (argc > 0)
    105 				bandwidth = atobps(*argv);
    106 		} else if (EQUAL(*argv, "tbrsize")) {
    107 			argc--; argv++;
    108 			if (argc > 0)
    109 				tbrsize = atobytes(*argv);
    110 		} else if (EQUAL(*argv, "priq")) {
    111 			/* just skip */
    112 		} else {
    113 			LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv);
    114 			return (0);
    115 		}
    116 		argc--; argv++;
    117 	}
    118 
    119 	if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
    120 		return (0);
    121 
    122 	if (qcmd_priq_add_if(ifname, bandwidth, flags) != 0)
    123 		return (0);
    124 	return (1);
    125 }
    126 
    127 int
    128 priq_class_parser(const char *ifname, const char *class_name,
    129 		  const char *parent_name, int argc, char **argv)
    130 {
    131 	int	pri = 0, qlimit = 50;
    132 	int	flags = 0, error;
    133 
    134 	while (argc > 0) {
    135 		if (EQUAL(*argv, "priority")) {
    136 			argc--; argv++;
    137 			if (argc > 0)
    138 				pri = strtoul(*argv, NULL, 0);
    139 		} else if (EQUAL(*argv, "qlimit")) {
    140 			argc--; argv++;
    141 			if (argc > 0)
    142 				qlimit = strtoul(*argv, NULL, 0);
    143 		} else if (EQUAL(*argv, "default")) {
    144 			flags |= PRCF_DEFAULTCLASS;
    145 		} else if (EQUAL(*argv, "red")) {
    146 			flags |= PRCF_RED;
    147 		} else if (EQUAL(*argv, "ecn")) {
    148 			flags |= PRCF_ECN;
    149 		} else if (EQUAL(*argv, "rio")) {
    150 			flags |= PRCF_RIO;
    151 		} else if (EQUAL(*argv, "cleardscp")) {
    152 			flags |= PRCF_CLEARDSCP;
    153 		} else {
    154 			LOG(LOG_ERR, 0,
    155 			    "Unknown keyword '%s' in %s, line %d",
    156 			    *argv, altqconfigfile, line_no);
    157 			return (0);
    158 		}
    159 
    160 		argc--; argv++;
    161 	}
    162 
    163 	if ((flags & PRCF_ECN) && (flags & (PRCF_RED|PRCF_RIO)) == 0)
    164 		flags |= PRCF_RED;
    165 
    166 	error = qcmd_priq_add_class(ifname, class_name, pri, qlimit, flags);
    167 
    168 	if (error) {
    169 		LOG(LOG_ERR, errno, "priq_class_parser: %s",
    170 		    qoperror(error));
    171 		return (0);
    172 	}
    173 	return (1);
    174 }
    175 
    176 /*
    177  * qcmd api
    178  */
    179 int
    180 qcmd_priq_add_if(const char *ifname, u_int bandwidth, int flags)
    181 {
    182 	int error;
    183 
    184 	error = qop_priq_add_if(NULL, ifname, bandwidth, flags);
    185 	if (error != 0)
    186 		LOG(LOG_ERR, errno, "%s: can't add priq on interface '%s'",
    187 		    qoperror(error), ifname);
    188 	return (error);
    189 }
    190 
    191 int
    192 qcmd_priq_add_class(const char *ifname, const char *class_name,
    193 		    int pri, int qlimit, int flags)
    194 {
    195 	struct ifinfo *ifinfo;
    196 	int error = 0;
    197 
    198 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
    199 		error = QOPERR_BADIF;
    200 
    201 	if (error == 0)
    202 		error = qop_priq_add_class(NULL, class_name, ifinfo,
    203 					   pri, qlimit, flags);
    204 	if (error != 0)
    205 		LOG(LOG_ERR, errno,
    206 		    "priq: %s: can't add class '%s' on interface '%s'",
    207 		    qoperror(error), class_name, ifname);
    208 	return (error);
    209 }
    210 
    211 int
    212 qcmd_priq_modify_class(const char *ifname, const char *class_name,
    213 		       int pri, int qlimit, int flags)
    214 {
    215 	struct ifinfo *ifinfo;
    216 	struct classinfo *clinfo;
    217 
    218 	if ((ifinfo = ifname2ifinfo(ifname)) == NULL)
    219 		return (QOPERR_BADIF);
    220 
    221 	if ((clinfo = clname2clinfo(ifinfo, class_name)) == NULL)
    222 		return (QOPERR_BADCLASS);
    223 
    224 	return qop_priq_modify_class(clinfo, pri, qlimit, flags);
    225 }
    226 
    227 /*
    228  * qop api
    229  */
    230 int
    231 qop_priq_add_if(struct ifinfo **rp, const char *ifname,
    232 		u_int bandwidth, int flags)
    233 {
    234 	struct ifinfo *ifinfo = NULL;
    235 	struct priq_ifinfo *priq_ifinfo = NULL;
    236 	int error;
    237 
    238 	if ((priq_ifinfo = calloc(1, sizeof(*priq_ifinfo))) == NULL)
    239 		return (QOPERR_NOMEM);
    240 
    241 	error = qop_add_if(&ifinfo, ifname, bandwidth,
    242 			   &priq_qdisc, priq_ifinfo);
    243 	if (error != 0)
    244 		goto err_ret;
    245 
    246 	/* set enable hook */
    247 	ifinfo->enable_hook = qop_priq_enable_hook;
    248 
    249 	if (rp != NULL)
    250 		*rp = ifinfo;
    251 	return (0);
    252 
    253  err_ret:
    254 	if (priq_ifinfo != NULL) {
    255 		free(priq_ifinfo);
    256 		if (ifinfo != NULL)
    257 			ifinfo->private = NULL;
    258 	}
    259 	return (error);
    260 }
    261 
    262 int
    263 qop_priq_add_class(struct classinfo **rp, const char *class_name,
    264 		   struct ifinfo *ifinfo, int pri, int qlimit, int flags)
    265 {
    266 	struct classinfo *clinfo;
    267 	struct priq_ifinfo *priq_ifinfo;
    268 	struct priq_classinfo *priq_clinfo = NULL;
    269 	int error;
    270 
    271 	priq_ifinfo = ifinfo->private;
    272 	if ((flags & PRCF_DEFAULTCLASS) && priq_ifinfo->default_class != NULL)
    273 		return (QOPERR_CLASS_INVAL);
    274 
    275 	if ((priq_clinfo = calloc(1, sizeof(*priq_clinfo))) == NULL) {
    276 		error = QOPERR_NOMEM;
    277 		goto err_ret;
    278 	}
    279 
    280 	priq_clinfo->pri = pri;
    281 	priq_clinfo->qlimit = qlimit;
    282 	priq_clinfo->flags = flags;
    283 
    284 	if ((error = qop_add_class(&clinfo, class_name, ifinfo, NULL,
    285 				   priq_clinfo)) != 0)
    286 		goto err_ret;
    287 
    288 	if (flags & PRCF_DEFAULTCLASS)
    289 		priq_ifinfo->default_class = clinfo;
    290 
    291 	if (rp != NULL)
    292 		*rp = clinfo;
    293 	return (0);
    294 
    295  err_ret:
    296 	if (priq_clinfo != NULL) {
    297 		free(priq_clinfo);
    298 		clinfo->private = NULL;
    299 	}
    300 
    301 	return (error);
    302 }
    303 
    304 int
    305 qop_priq_modify_class(struct classinfo *clinfo,
    306 		      int pri, int qlimit, int flags)
    307 {
    308 	struct priq_classinfo *priq_clinfo, *parent_clinfo;
    309 	int error;
    310 
    311 	priq_clinfo = clinfo->private;
    312 	if (clinfo->parent == NULL)
    313 		return (QOPERR_CLASS_INVAL);
    314 	parent_clinfo = clinfo->parent->private;
    315 
    316 	priq_clinfo->pri = pri;
    317 	priq_clinfo->qlimit = qlimit;
    318 	priq_clinfo->flags = flags;
    319 
    320 	error = qop_modify_class(clinfo, NULL);
    321 	if (error == 0)
    322 		return (0);
    323 	return (error);
    324 }
    325 
    326 /*
    327  * sanity check at enabling priq:
    328  *  1. there must one default class for an interface
    329  */
    330 static int
    331 qop_priq_enable_hook(struct ifinfo *ifinfo)
    332 {
    333 	struct priq_ifinfo *priq_ifinfo;
    334 
    335 	priq_ifinfo = ifinfo->private;
    336 	if (priq_ifinfo->default_class == NULL) {
    337 		LOG(LOG_ERR, 0, "priq: no default class on interface %s!",
    338 		    ifinfo->ifname);
    339 		return (QOPERR_CLASS);
    340 	}
    341 	return (0);
    342 }
    343 
    344 /*
    345  *  system call interfaces for qdisc_ops
    346  */
    347 static int
    348 priq_attach(struct ifinfo *ifinfo)
    349 {
    350 	struct priq_interface iface;
    351 
    352 	memset(&iface, 0, sizeof(iface));
    353 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    354 
    355 	if (priq_fd < 0 &&
    356 	    (priq_fd = open(PRIQ_DEVICE, O_RDWR)) < 0 &&
    357 	    (priq_fd = open_module(PRIQ_DEVICE, O_RDWR)) < 0) {
    358 		LOG(LOG_ERR, errno, "PRIQ open");
    359 		return (QOPERR_SYSCALL);
    360 	}
    361 
    362 	priq_refcount++;
    363 	memset(&iface, 0, sizeof(iface));
    364 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    365 	iface.arg = ifinfo->bandwidth;
    366 
    367 	if (ioctl(priq_fd, PRIQ_IF_ATTACH, &iface) < 0)
    368 		return (QOPERR_SYSCALL);
    369 	return (0);
    370 }
    371 
    372 static int
    373 priq_detach(struct ifinfo *ifinfo)
    374 {
    375 	struct priq_interface iface;
    376 
    377 	memset(&iface, 0, sizeof(iface));
    378 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    379 
    380 	if (ioctl(priq_fd, PRIQ_IF_DETACH, &iface) < 0)
    381 		return (QOPERR_SYSCALL);
    382 
    383 	if (--priq_refcount == 0) {
    384 		close(priq_fd);
    385 		priq_fd = -1;
    386 	}
    387 	return (0);
    388 }
    389 
    390 static int
    391 priq_clear(struct ifinfo *ifinfo)
    392 {
    393 	struct priq_interface iface;
    394 
    395 	memset(&iface, 0, sizeof(iface));
    396 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    397 
    398 	if (ioctl(priq_fd, PRIQ_CLEAR, &iface) < 0)
    399 		return (QOPERR_SYSCALL);
    400 	return (0);
    401 }
    402 
    403 static int
    404 priq_enable(struct ifinfo *ifinfo)
    405 {
    406 	struct priq_interface iface;
    407 
    408 	memset(&iface, 0, sizeof(iface));
    409 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    410 
    411 	if (ioctl(priq_fd, PRIQ_ENABLE, &iface) < 0)
    412 		return (QOPERR_SYSCALL);
    413 	return (0);
    414 }
    415 
    416 static int
    417 priq_disable(struct ifinfo *ifinfo)
    418 {
    419 	struct priq_interface iface;
    420 
    421 	memset(&iface, 0, sizeof(iface));
    422 	strncpy(iface.ifname, ifinfo->ifname, IFNAMSIZ);
    423 
    424 	if (ioctl(priq_fd, PRIQ_DISABLE, &iface) < 0)
    425 		return (QOPERR_SYSCALL);
    426 	return (0);
    427 }
    428 
    429 static int
    430 priq_add_class(struct classinfo *clinfo)
    431 {
    432 	struct priq_add_class class_add;
    433 	struct priq_classinfo *priq_clinfo;
    434 	struct priq_ifinfo *priq_ifinfo;
    435 
    436 	priq_ifinfo = clinfo->ifinfo->private;
    437 	priq_clinfo = clinfo->private;
    438 
    439 	memset(&class_add, 0, sizeof(class_add));
    440 	strncpy(class_add.iface.ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
    441 
    442 	class_add.pri = priq_clinfo->pri;
    443 	class_add.qlimit = priq_clinfo->qlimit;
    444 	class_add.flags = priq_clinfo->flags;
    445 	if (ioctl(priq_fd, PRIQ_ADD_CLASS, &class_add) < 0) {
    446 		clinfo->handle = PRIQ_NULLCLASS_HANDLE;
    447 		return (QOPERR_SYSCALL);
    448 	}
    449 	clinfo->handle = class_add.class_handle;
    450 	return (0);
    451 }
    452 
    453 static int
    454 priq_modify_class(struct classinfo *clinfo, void *arg)
    455 {
    456 	struct priq_modify_class class_mod;
    457 	struct priq_classinfo *priq_clinfo;
    458 
    459 	priq_clinfo = clinfo->private;
    460 
    461 	memset(&class_mod, 0, sizeof(class_mod));
    462 	strncpy(class_mod.iface.ifname, clinfo->ifinfo->ifname, IFNAMSIZ);
    463 	class_mod.class_handle = clinfo->handle;
    464 
    465 	class_mod.pri = priq_clinfo->pri;
    466 	class_mod.qlimit = priq_clinfo->qlimit;
    467 	class_mod.flags = priq_clinfo->flags;
    468 
    469 	if (ioctl(priq_fd, PRIQ_MOD_CLASS, &class_mod) < 0)
    470 		return (QOPERR_SYSCALL);
    471 	return (0);
    472 }
    473 
    474 static int
    475 priq_delete_class(struct classinfo *clinfo)
    476 {
    477 	struct priq_delete_class class_delete;
    478 
    479 	if (clinfo->handle == PRIQ_NULLCLASS_HANDLE)
    480 		return (0);
    481 
    482 	memset(&class_delete, 0, sizeof(class_delete));
    483 	strncpy(class_delete.iface.ifname, clinfo->ifinfo->ifname,
    484 		IFNAMSIZ);
    485 	class_delete.class_handle = clinfo->handle;
    486 
    487 	if (ioctl(priq_fd, PRIQ_DEL_CLASS, &class_delete) < 0)
    488 		return (QOPERR_SYSCALL);
    489 	return (0);
    490 }
    491 
    492 static int
    493 priq_add_filter(struct fltrinfo *fltrinfo)
    494 {
    495 	struct priq_add_filter fltr_add;
    496 
    497 	memset(&fltr_add, 0, sizeof(fltr_add));
    498 	strncpy(fltr_add.iface.ifname, fltrinfo->clinfo->ifinfo->ifname,
    499 		IFNAMSIZ);
    500 	fltr_add.class_handle = fltrinfo->clinfo->handle;
    501 	fltr_add.filter = fltrinfo->fltr;
    502 
    503 	if (ioctl(priq_fd, PRIQ_ADD_FILTER, &fltr_add) < 0)
    504 		return (QOPERR_SYSCALL);
    505 	fltrinfo->handle = fltr_add.filter_handle;
    506 	return (0);
    507 }
    508 
    509 static int
    510 priq_delete_filter(struct fltrinfo *fltrinfo)
    511 {
    512 	struct priq_delete_filter fltr_del;
    513 
    514 	memset(&fltr_del, 0, sizeof(fltr_del));
    515 	strncpy(fltr_del.iface.ifname, fltrinfo->clinfo->ifinfo->ifname,
    516 		IFNAMSIZ);
    517 	fltr_del.filter_handle = fltrinfo->handle;
    518 
    519 	if (ioctl(priq_fd, PRIQ_DEL_FILTER, &fltr_del) < 0)
    520 		return (QOPERR_SYSCALL);
    521 	return (0);
    522 }
    523 
    524 
    525