1 /* $KAME: qop_wfq.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_wfq.h> 49 #include "altq_qop.h" 50 #include "qop_wfq.h" 51 52 static int wfq_attach(struct ifinfo *ifinfo); 53 static int wfq_detach(struct ifinfo *ifinfo); 54 static int wfq_enable(struct ifinfo *ifinfo); 55 static int wfq_disable(struct ifinfo *ifinfo); 56 57 #define WFQ_DEVICE "/dev/altq/wfq" 58 59 static int wfq_fd = -1; 60 static int wfq_refcount = 0; 61 62 static struct qdisc_ops wfq_qdisc = { 63 ALTQT_WFQ, 64 "wfq", 65 wfq_attach, 66 wfq_detach, 67 NULL, /* clear */ 68 wfq_enable, 69 wfq_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 wfq_interface_parser(const char *ifname, int argc, char **argv) 84 { 85 u_int bandwidth = 100000000; /* 100Mbps */ 86 u_int tbrsize = 0; 87 int hash_policy = 0; /* 0: use default */ 88 int nqueues = 0; /* 0: use default */ 89 int qsize = 0; /* 0: use default */ 90 91 /* 92 * process options 93 */ 94 while (argc > 0) { 95 if (EQUAL(*argv, "bandwidth")) { 96 argc--; argv++; 97 if (argc > 0) 98 bandwidth = atobps(*argv); 99 } else if (EQUAL(*argv, "tbrsize")) { 100 argc--; argv++; 101 if (argc > 0) 102 tbrsize = atobytes(*argv); 103 } else if (EQUAL(*argv, "nqueues")) { 104 argc--; argv++; 105 if (argc > 0) 106 nqueues = (int)strtol(*argv, NULL, 0); 107 } else if (EQUAL(*argv, "qsize")) { 108 argc--; argv++; 109 if (argc > 0) 110 qsize = atobytes(*argv); 111 } else if (EQUAL(*argv, "hash")) { 112 argc--; argv++; 113 if (argc > 0) { 114 if (EQUAL(*argv, "dstaddr")) 115 hash_policy = WFQ_HASH_DSTADDR; 116 else if (EQUAL(*argv, "full")) 117 hash_policy = WFQ_HASH_FULL; 118 else if (EQUAL(*argv, "srcport")) 119 hash_policy = WFQ_HASH_SRCPORT; 120 else { 121 LOG(LOG_ERR, 0, 122 "Unknown hash policy '%s'\n", 123 argv); 124 return (0); 125 } 126 } 127 } else if (EQUAL(*argv, "wfq")) { 128 /* just skip */ 129 } else { 130 LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv); 131 return (0); 132 } 133 argc--; argv++; 134 } 135 136 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0) 137 return (0); 138 139 if (qsize != 0 && qsize < 1500) { 140 LOG(LOG_ERR, 0, "qsize too small: %d bytes", qsize); 141 return (0); 142 } 143 144 if (qcmd_wfq_add_if(ifname, bandwidth, 145 hash_policy, nqueues, qsize) != 0) 146 return (0); 147 return (1); 148 } 149 150 /* 151 * qcmd api 152 */ 153 int 154 qcmd_wfq_add_if(const char *ifname, u_int bandwidth, int hash_policy, 155 int nqueues, int qsize) 156 { 157 int error; 158 159 error = qop_wfq_add_if(NULL, ifname, bandwidth, 160 hash_policy, nqueues, qsize); 161 if (error != 0) 162 LOG(LOG_ERR, errno, "%s: can't add wfq on interface '%s'\n", 163 qoperror(error), ifname); 164 return (error); 165 } 166 167 /* 168 * qop api 169 */ 170 int 171 qop_wfq_add_if(struct ifinfo **rp, const char *ifname, u_int bandwidth, 172 int hash_policy, int nqueues, int qsize) 173 { 174 struct ifinfo *ifinfo = NULL; 175 struct wfq_ifinfo *wfq_ifinfo; 176 int error; 177 178 if ((wfq_ifinfo = calloc(1, sizeof(*wfq_ifinfo))) == NULL) 179 return (QOPERR_NOMEM); 180 wfq_ifinfo->hash_policy = hash_policy; 181 wfq_ifinfo->nqueues = nqueues; 182 wfq_ifinfo->qsize = qsize; 183 184 error = qop_add_if(&ifinfo, ifname, bandwidth, 185 &wfq_qdisc, wfq_ifinfo); 186 if (error != 0) { 187 free(wfq_ifinfo); 188 return (error); 189 } 190 191 if (rp != NULL) 192 *rp = ifinfo; 193 return (0); 194 } 195 196 /* 197 * system call interfaces for qdisc_ops 198 */ 199 static int 200 wfq_attach(struct ifinfo *ifinfo) 201 { 202 struct wfq_interface iface; 203 struct wfq_ifinfo *wfq_ifinfo; 204 struct wfq_conf conf; 205 206 if (wfq_fd < 0 && 207 (wfq_fd = open(WFQ_DEVICE, O_RDWR)) < 0 && 208 (wfq_fd = open_module(WFQ_DEVICE, O_RDWR)) < 0) { 209 LOG(LOG_ERR, errno, "WFQ open\n"); 210 return (QOPERR_SYSCALL); 211 } 212 213 wfq_refcount++; 214 memset(&iface, 0, sizeof(iface)); 215 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 216 217 if (ioctl(wfq_fd, WFQ_IF_ATTACH, &iface) < 0) 218 return (QOPERR_SYSCALL); 219 220 /* set wfq parameters */ 221 wfq_ifinfo = (struct wfq_ifinfo *)ifinfo->private; 222 if (wfq_ifinfo->hash_policy != 0 || wfq_ifinfo->nqueues != 0 || 223 wfq_ifinfo->qsize != 0) { 224 memset(&conf, 0, sizeof(conf)); 225 strncpy(conf.iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 226 conf.hash_policy = wfq_ifinfo->hash_policy; 227 conf.nqueues = wfq_ifinfo->nqueues; 228 conf.qlimit = wfq_ifinfo->qsize; 229 if (ioctl(wfq_fd, WFQ_CONFIG, &conf) < 0) { 230 LOG(LOG_ERR, errno, "WFQ_CONFIG\n"); 231 return (QOPERR_SYSCALL); 232 } 233 } 234 #if 1 235 LOG(LOG_INFO, 0, "wfq attached to %s\n", iface.wfq_ifacename); 236 #endif 237 return (0); 238 } 239 240 static int 241 wfq_detach(struct ifinfo *ifinfo) 242 { 243 struct wfq_interface iface; 244 245 memset(&iface, 0, sizeof(iface)); 246 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 247 248 if (ioctl(wfq_fd, WFQ_IF_DETACH, &iface) < 0) 249 return (QOPERR_SYSCALL); 250 251 if (--wfq_refcount == 0) { 252 close(wfq_fd); 253 wfq_fd = -1; 254 } 255 return (0); 256 } 257 258 static int 259 wfq_enable(struct ifinfo *ifinfo) 260 { 261 struct wfq_interface iface; 262 263 memset(&iface, 0, sizeof(iface)); 264 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 265 266 if (ioctl(wfq_fd, WFQ_ENABLE, &iface) < 0) 267 return (QOPERR_SYSCALL); 268 return (0); 269 } 270 271 static int 272 wfq_disable(struct ifinfo *ifinfo) 273 { 274 struct wfq_interface iface; 275 276 memset(&iface, 0, sizeof(iface)); 277 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 278 279 if (ioctl(wfq_fd, WFQ_DISABLE, &iface) < 0) 280 return (QOPERR_SYSCALL); 281 return (0); 282 } 283