1 /* $KAME: qop_red.c,v 1.3 2000/10/18 09:15:19 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_qop.h" 50 #include "qop_red.h" 51 52 static int red_attach(struct ifinfo *ifinfo); 53 static int red_detach(struct ifinfo *ifinfo); 54 static int red_enable(struct ifinfo *ifinfo); 55 static int red_disable(struct ifinfo *ifinfo); 56 57 #define RED_DEVICE "/dev/altq/red" 58 59 static int red_fd = -1; 60 static int red_refcount = 0; 61 62 static struct qdisc_ops red_qdisc = { 63 ALTQT_RED, 64 "red", 65 red_attach, 66 red_detach, 67 NULL, /* clear */ 68 red_enable, 69 red_disable, 70 NULL, /* add class */ 71 NULL, /* modify class */ 72 NULL, /* delete class */ 73 NULL, /* add filter */ 74 NULL /* delete filter */ 75 }; 76 77 /* 78 * parser interface 79 */ 80 #define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0) 81 82 int 83 red_interface_parser(const char *ifname, int argc, char **argv) 84 { 85 u_int bandwidth = 100000000; /* 100Mbps */ 86 u_int tbrsize = 0; 87 int weight = 0; /* 0: use default */ 88 int inv_pmax = 0; /* 0: use default */ 89 int th_min = 0; /* 0: use default */ 90 int th_max = 0; /* 0: use default */ 91 int qlimit = 60; 92 int pkttime = 0; 93 int flags = 0; 94 int packet_size = 1000; 95 96 /* 97 * process options 98 */ 99 while (argc > 0) { 100 if (EQUAL(*argv, "bandwidth")) { 101 argc--; argv++; 102 if (argc > 0) 103 bandwidth = atobps(*argv); 104 } else if (EQUAL(*argv, "tbrsize")) { 105 argc--; argv++; 106 if (argc > 0) 107 tbrsize = atobytes(*argv); 108 } else if (EQUAL(*argv, "packetsize")) { 109 argc--; argv++; 110 if (argc > 0) 111 packet_size = atobytes(*argv); 112 } else if (EQUAL(*argv, "weight")) { 113 argc--; argv++; 114 if (argc > 0) 115 weight = (int)strtol(*argv, NULL, 0); 116 } else if (EQUAL(*argv, "qlimit")) { 117 argc--; argv++; 118 if (argc > 0) 119 qlimit = (int)strtol(*argv, NULL, 0); 120 } else if (EQUAL(*argv, "thmin")) { 121 argc--; argv++; 122 if (argc > 0) 123 th_min = (int)strtol(*argv, NULL, 0); 124 } else if (EQUAL(*argv, "thmax")) { 125 argc--; argv++; 126 if (argc > 0) 127 th_max = (int)strtol(*argv, NULL, 0); 128 } else if (EQUAL(*argv, "invpmax")) { 129 argc--; argv++; 130 if (argc > 0) 131 inv_pmax = (int)strtol(*argv, NULL, 0); 132 } else if (EQUAL(*argv, "red")) { 133 /* just skip */ 134 } else if (EQUAL(*argv, "ecn")) { 135 flags |= REDF_ECN; 136 } else if (EQUAL(*argv, "flowvalve")) { 137 flags |= REDF_FLOWVALVE; 138 } else { 139 LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv); 140 return (0); 141 } 142 argc--; argv++; 143 } 144 145 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0) 146 return (0); 147 148 pkttime = packet_size * 8 * 1000 / (bandwidth / 1000); 149 if (weight != 0) { 150 /* check if weight is power of 2 */ 151 int i, w; 152 153 w = weight; 154 for (i = 0; w > 1; i++) 155 w = w >> 1; 156 w = 1 << i; 157 if (weight != w) { 158 LOG(LOG_ERR, 0, "weight %d: should be power of 2", 159 weight); 160 return (0); 161 } 162 } 163 164 if (qcmd_red_add_if(ifname, bandwidth, weight, inv_pmax, 165 th_min, th_max, qlimit, pkttime, flags) != 0) 166 return (0); 167 return (1); 168 } 169 170 /* 171 * qcmd api 172 */ 173 int 174 qcmd_red_add_if(const char *ifname, u_int bandwidth, int weight, 175 int inv_pmax, int th_min, int th_max, int qlimit, 176 int pkttime, int flags) 177 { 178 int error; 179 180 error = qop_red_add_if(NULL, ifname, bandwidth, weight, inv_pmax, 181 th_min, th_max, qlimit, pkttime, flags); 182 if (error != 0) 183 LOG(LOG_ERR, errno, "%s: can't add red on interface '%s'\n", 184 qoperror(error), ifname); 185 return (error); 186 } 187 188 /* 189 * qop api 190 */ 191 int 192 qop_red_add_if(struct ifinfo **rp, const char *ifname, 193 u_int bandwidth, int weight, int inv_pmax, int th_min, 194 int th_max, int qlimit, int pkttime, int flags) 195 { 196 struct ifinfo *ifinfo = NULL; 197 struct red_ifinfo *red_ifinfo; 198 int error; 199 200 if ((red_ifinfo = calloc(1, sizeof(*red_ifinfo))) == NULL) 201 return (QOPERR_NOMEM); 202 red_ifinfo->weight = weight; 203 red_ifinfo->inv_pmax = inv_pmax; 204 red_ifinfo->th_min = th_min; 205 red_ifinfo->th_max = th_max; 206 red_ifinfo->qlimit = qlimit; 207 red_ifinfo->pkttime = pkttime; 208 red_ifinfo->flags = flags; 209 210 error = qop_add_if(&ifinfo, ifname, bandwidth, 211 &red_qdisc, red_ifinfo); 212 if (error != 0) { 213 free(red_ifinfo); 214 return (error); 215 } 216 217 if (rp != NULL) 218 *rp = ifinfo; 219 return (0); 220 } 221 222 /* 223 * system call interfaces for qdisc_ops 224 */ 225 static int 226 red_attach(struct ifinfo *ifinfo) 227 { 228 struct red_interface iface; 229 struct red_ifinfo *red_ifinfo; 230 struct red_conf conf; 231 232 if (red_fd < 0 && 233 (red_fd = open(RED_DEVICE, O_RDWR)) < 0 && 234 (red_fd = open_module(RED_DEVICE, O_RDWR)) < 0) { 235 LOG(LOG_ERR, errno, "RED open\n"); 236 return (QOPERR_SYSCALL); 237 } 238 239 red_refcount++; 240 memset(&iface, 0, sizeof(iface)); 241 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ); 242 243 if (ioctl(red_fd, RED_IF_ATTACH, &iface) < 0) 244 return (QOPERR_SYSCALL); 245 246 /* set red parameters */ 247 red_ifinfo = (struct red_ifinfo *)ifinfo->private; 248 memset(&conf, 0, sizeof(conf)); 249 strncpy(conf.iface.red_ifname, ifinfo->ifname, IFNAMSIZ); 250 conf.red_weight = red_ifinfo->weight; 251 conf.red_inv_pmax = red_ifinfo->inv_pmax; 252 conf.red_thmin = red_ifinfo->th_min; 253 conf.red_thmax = red_ifinfo->th_max; 254 conf.red_limit = red_ifinfo->qlimit; 255 conf.red_flags = red_ifinfo->flags; 256 if (ioctl(red_fd, RED_CONFIG, &conf) < 0) 257 return (QOPERR_SYSCALL); 258 259 #if 1 260 LOG(LOG_INFO, 0, "red attached to %s\n", iface.red_ifname); 261 #endif 262 return (0); 263 } 264 265 static int 266 red_detach(struct ifinfo *ifinfo) 267 { 268 struct red_interface iface; 269 270 memset(&iface, 0, sizeof(iface)); 271 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ); 272 273 if (ioctl(red_fd, RED_IF_DETACH, &iface) < 0) 274 return (QOPERR_SYSCALL); 275 276 if (--red_refcount == 0) { 277 close(red_fd); 278 red_fd = -1; 279 } 280 return (0); 281 } 282 283 static int 284 red_enable(struct ifinfo *ifinfo) 285 { 286 struct red_interface iface; 287 288 memset(&iface, 0, sizeof(iface)); 289 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ); 290 291 if (ioctl(red_fd, RED_ENABLE, &iface) < 0) 292 return (QOPERR_SYSCALL); 293 return (0); 294 } 295 296 static int 297 red_disable(struct ifinfo *ifinfo) 298 { 299 struct red_interface iface; 300 301 memset(&iface, 0, sizeof(iface)); 302 strncpy(iface.red_ifname, ifinfo->ifname, IFNAMSIZ); 303 304 if (ioctl(red_fd, RED_DISABLE, &iface) < 0) 305 return (QOPERR_SYSCALL); 306 return (0); 307 } 308