Home | History | Annotate | Line # | Download | only in libaltq
qop_rio.c revision 1.2
      1 /*	$KAME: qop_rio.c,v 1.3 2000/10/18 09:15:20 kjc Exp $	*/
      2 /*
      3  * Copyright (C) 1999-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_red.h>
     49 #include <altq/altq_rio.h>
     50 #include "altq_qop.h"
     51 #include "qop_rio.h"
     52 
     53 static int rio_attach(struct ifinfo *);
     54 static int rio_detach(struct ifinfo *);
     55 static int rio_enable(struct ifinfo *);
     56 static int rio_disable(struct ifinfo *);
     57 
     58 #define RIO_DEVICE	"/dev/altq/rio"
     59 
     60 static int rio_fd = -1;
     61 static int rio_refcount = 0;
     62 
     63 static struct qdisc_ops rio_qdisc = {
     64 	ALTQT_RIO,
     65 	"rio",
     66 	rio_attach,
     67 	rio_detach,
     68 	NULL,			/* clear */
     69 	rio_enable,
     70 	rio_disable,
     71 	NULL,			/* add class */
     72 	NULL,			/* modify class */
     73 	NULL,			/* delete class */
     74 	NULL,			/* add filter */
     75 	NULL			/* delete filter */
     76 };
     77 
     78 /*
     79  * parser interface
     80  */
     81 #define EQUAL(s1, s2)	(strcmp((s1), (s2)) == 0)
     82 
     83 int
     84 rio_interface_parser(const char *ifname, int argc, char **argv)
     85 {
     86 	u_int  	bandwidth = 100000000;	/* 100Mbps */
     87 	u_int	tbrsize = 0;
     88 	int	weight = 0;		/* 0: use default */
     89 	int	lo_inv_pmax = 0;	/* 0: use default */
     90 	int	lo_th_min = 0;		/* 0: use default */
     91 	int	lo_th_max = 0;		/* 0: use default */
     92 	int	med_inv_pmax = 0;	/* 0: use default */
     93 	int	med_th_min = 0;		/* 0: use default */
     94 	int	med_th_max = 0;		/* 0: use default */
     95 	int	hi_inv_pmax = 0;	/* 0: use default */
     96 	int	hi_th_min = 0;		/* 0: use default */
     97 	int	hi_th_max = 0;		/* 0: use default */
     98 	int	qlimit = 60;
     99 	int	pkttime = 0;
    100 	int	flags = 0;
    101 	int	packet_size = 1000;
    102 
    103 	/*
    104 	 * process options
    105 	 */
    106 	while (argc > 0) {
    107 		if (EQUAL(*argv, "bandwidth")) {
    108 			argc--; argv++;
    109 			if (argc > 0)
    110 				bandwidth = atobps(*argv);
    111 		} else if (EQUAL(*argv, "tbrsize")) {
    112 			argc--; argv++;
    113 			if (argc > 0)
    114 				tbrsize = atobytes(*argv);
    115 		} else if (EQUAL(*argv, "packetsize")) {
    116 			argc--; argv++;
    117 			if (argc > 0)
    118 				packet_size = atobytes(*argv);
    119 		} else if (EQUAL(*argv, "weight")) {
    120 			argc--; argv++;
    121 			if (argc > 0)
    122 				weight = (int)strtol(*argv, NULL, 0);
    123 		} else if (EQUAL(*argv, "qlimit")) {
    124 			argc--; argv++;
    125 			if (argc > 0)
    126 				qlimit = (int)strtol(*argv, NULL, 0);
    127 		} else if (EQUAL(*argv, "lo_thmin")) {
    128 			argc--; argv++;
    129 			if (argc > 0)
    130 				lo_th_min = (int)strtol(*argv, NULL, 0);
    131 		} else if (EQUAL(*argv, "lo_thmax")) {
    132 			argc--; argv++;
    133 			if (argc > 0)
    134 				lo_th_max = (int)strtol(*argv, NULL, 0);
    135 		} else if (EQUAL(*argv, "lo_invpmax")) {
    136 			argc--; argv++;
    137 			if (argc > 0)
    138 				lo_inv_pmax = (int)strtol(*argv, NULL, 0);
    139 		} else if (EQUAL(*argv, "med_thmin")) {
    140 			argc--; argv++;
    141 			if (argc > 0)
    142 				med_th_min = (int)strtol(*argv, NULL, 0);
    143 		} else if (EQUAL(*argv, "med_thmax")) {
    144 			argc--; argv++;
    145 			if (argc > 0)
    146 				med_th_max = (int)strtol(*argv, NULL, 0);
    147 		} else if (EQUAL(*argv, "med_invpmax")) {
    148 			argc--; argv++;
    149 			if (argc > 0)
    150 				med_inv_pmax = (int)strtol(*argv, NULL, 0);
    151 		} else if (EQUAL(*argv, "hi_thmin")) {
    152 			argc--; argv++;
    153 			if (argc > 0)
    154 				hi_th_min = (int)strtol(*argv, NULL, 0);
    155 		} else if (EQUAL(*argv, "hi_thmax")) {
    156 			argc--; argv++;
    157 			if (argc > 0)
    158 				hi_th_max = (int)strtol(*argv, NULL, 0);
    159 		} else if (EQUAL(*argv, "hi_invpmax")) {
    160 			argc--; argv++;
    161 			if (argc > 0)
    162 				hi_inv_pmax = (int)strtol(*argv, NULL, 0);
    163 		} else if (EQUAL(*argv, "rio")) {
    164 			/* just skip */
    165 		} else if (EQUAL(*argv, "ecn")) {
    166 			flags |= RIOF_ECN;
    167 		} else {
    168 			LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv);
    169 			return (0);
    170 		}
    171 		argc--; argv++;
    172 	}
    173 
    174 	if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0)
    175 		return (0);
    176 
    177 	pkttime = packet_size * 8 * 1000 / (bandwidth / 1000);
    178 	if (weight != 0) {
    179 		/* check if weight is power of 2 */
    180 		int i, w;
    181 
    182 		w = weight;
    183 		for (i = 0; w > 1; i++)
    184 			w = w >> 1;
    185 		w = 1 << i;
    186 		if (weight != w) {
    187 			LOG(LOG_ERR, 0, "weight %d: should be power of 2",
    188 			    weight);
    189 			return (0);
    190 		}
    191 	}
    192 
    193 	if (qcmd_rio_add_if(ifname, bandwidth, weight,
    194 			    lo_inv_pmax, lo_th_min, lo_th_max,
    195 			    med_inv_pmax, med_th_min, med_th_max,
    196 			    hi_inv_pmax, hi_th_min, hi_th_max,
    197 			    qlimit, pkttime, flags) != 0)
    198 		return (0);
    199 	return (1);
    200 }
    201 
    202 /*
    203  * qcmd api
    204  */
    205 int
    206 qcmd_rio_add_if(const char *ifname, u_int bandwidth, int weight,
    207 		int lo_inv_pmax, int lo_th_min, int lo_th_max,
    208 		int med_inv_pmax, int med_th_min, int med_th_max,
    209 		int hi_inv_pmax, int hi_th_min, int hi_th_max,
    210 		int qlimit, int pkttime, int flags)
    211 {
    212 	struct redparams red_params[RIO_NDROPPREC];
    213 	int error;
    214 
    215 	red_params[0].inv_pmax = lo_inv_pmax;
    216 	red_params[0].th_min   = lo_th_min;
    217 	red_params[0].th_max   = lo_th_max;
    218 	red_params[1].inv_pmax = med_inv_pmax;
    219 	red_params[1].th_min   = med_th_min;
    220 	red_params[1].th_max   = med_th_max;
    221 	red_params[2].inv_pmax = hi_inv_pmax;
    222 	red_params[2].th_min   = hi_th_min;
    223 	red_params[2].th_max   = hi_th_max;
    224 
    225 	error = qop_rio_add_if(NULL, ifname, bandwidth, weight, red_params,
    226 			       qlimit, pkttime, flags);
    227 	if (error != 0)
    228 		LOG(LOG_ERR, errno, "%s: can't add rio on interface '%s'\n",
    229 		    qoperror(error), ifname);
    230 	return (error);
    231 }
    232 
    233 /*
    234  * qop api
    235  */
    236 int
    237 qop_rio_add_if(struct ifinfo **rp, const char *ifname,
    238 	       u_int bandwidth, int weight, struct redparams *red_params,
    239 	       int qlimit, int pkttime, int flags)
    240 {
    241 	struct ifinfo *ifinfo = NULL;
    242 	struct rio_ifinfo *rio_ifinfo;
    243 	int i, error;
    244 
    245 	if ((rio_ifinfo = calloc(1, sizeof(*rio_ifinfo))) == NULL)
    246 		return (QOPERR_NOMEM);
    247 	for (i = 0; i < RIO_NDROPPREC; i++)
    248 		rio_ifinfo->red_params[i] = red_params[i];
    249 	rio_ifinfo->weight   = weight;
    250 	rio_ifinfo->qlimit   = qlimit;
    251 	rio_ifinfo->pkttime  = pkttime;
    252 	rio_ifinfo->flags    = flags;
    253 
    254 	error = qop_add_if(&ifinfo, ifname, bandwidth,
    255 			   &rio_qdisc, rio_ifinfo);
    256 	if (error != 0) {
    257 		free(rio_ifinfo);
    258 		return (error);
    259 	}
    260 
    261 	if (rp != NULL)
    262 		*rp = ifinfo;
    263 	return (0);
    264 }
    265 
    266 /*
    267  *  system call interfaces for qdisc_ops
    268  */
    269 static int
    270 rio_attach(struct ifinfo *ifinfo)
    271 {
    272 	struct rio_interface iface;
    273 	struct rio_ifinfo *rio_ifinfo;
    274 	struct rio_conf conf;
    275 	int i;
    276 
    277 	if (rio_fd < 0 &&
    278 	    (rio_fd = open(RIO_DEVICE, O_RDWR)) < 0 &&
    279 	    (rio_fd = open_module(RIO_DEVICE, O_RDWR)) < 0) {
    280 		LOG(LOG_ERR, errno, "RIO open\n");
    281 		return (QOPERR_SYSCALL);
    282 	}
    283 
    284 	rio_refcount++;
    285 	memset(&iface, 0, sizeof(iface));
    286 	strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
    287 
    288 	if (ioctl(rio_fd, RIO_IF_ATTACH, &iface) < 0)
    289 		return (QOPERR_SYSCALL);
    290 
    291 	/* set rio parameters */
    292 	rio_ifinfo = (struct rio_ifinfo *)ifinfo->private;
    293 	memset(&conf, 0, sizeof(conf));
    294 	strncpy(conf.iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
    295 	for (i = 0; i < RIO_NDROPPREC; i++)
    296 		conf.q_params[i] = rio_ifinfo->red_params[i];
    297 	conf.rio_weight	  = rio_ifinfo->weight;
    298 	conf.rio_limit    = rio_ifinfo->qlimit;
    299 	conf.rio_flags    = rio_ifinfo->flags;
    300 	if (ioctl(rio_fd, RIO_CONFIG, &conf) < 0)
    301 		return (QOPERR_SYSCALL);
    302 
    303 #if 1
    304 	LOG(LOG_INFO, 0, "rio attached to %s\n", iface.rio_ifname);
    305 #endif
    306 	return (0);
    307 }
    308 
    309 static int
    310 rio_detach(struct ifinfo *ifinfo)
    311 {
    312 	struct rio_interface iface;
    313 
    314 	memset(&iface, 0, sizeof(iface));
    315 	strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
    316 
    317 	if (ioctl(rio_fd, RIO_IF_DETACH, &iface) < 0)
    318 		return (QOPERR_SYSCALL);
    319 
    320 	if (--rio_refcount == 0) {
    321 		close(rio_fd);
    322 		rio_fd = -1;
    323 	}
    324 	return (0);
    325 }
    326 
    327 static int
    328 rio_enable(struct ifinfo *ifinfo)
    329 {
    330 	struct rio_interface iface;
    331 
    332 	memset(&iface, 0, sizeof(iface));
    333 	strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
    334 
    335 	if (ioctl(rio_fd, RIO_ENABLE, &iface) < 0)
    336 		return (QOPERR_SYSCALL);
    337 	return (0);
    338 }
    339 
    340 static int
    341 rio_disable(struct ifinfo *ifinfo)
    342 {
    343 	struct rio_interface iface;
    344 
    345 	memset(&iface, 0, sizeof(iface));
    346 	strncpy(iface.rio_ifname, ifinfo->ifname, IFNAMSIZ);
    347 
    348 	if (ioctl(rio_fd, RIO_DISABLE, &iface) < 0)
    349 		return (QOPERR_SYSCALL);
    350 	return (0);
    351 }
    352