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