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 *ifinfo); 54 static int rio_detach(struct ifinfo *ifinfo); 55 static int rio_enable(struct ifinfo *ifinfo); 56 static int rio_disable(struct ifinfo *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