1 /* $NetBSD: qop_wfq.c,v 1.5 2002/03/05 04:11:53 itojun Exp $ */ 2 /* $KAME: qop_wfq.c,v 1.6 2001/12/03 08:20:56 kjc Exp $ */ 3 /* 4 * Copyright (C) 1999-2000 5 * Sony Computer Science Laboratories, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/sockio.h> 32 #include <sys/ioctl.h> 33 #include <sys/fcntl.h> 34 #include <net/if.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <stddef.h> 42 #include <string.h> 43 #include <ctype.h> 44 #include <errno.h> 45 #include <syslog.h> 46 #include <netdb.h> 47 48 #include <altq/altq.h> 49 #include <altq/altq_wfq.h> 50 #include "altq_qop.h" 51 #include "qop_wfq.h" 52 53 static int wfq_attach(struct ifinfo *); 54 static int wfq_detach(struct ifinfo *); 55 static int wfq_enable(struct ifinfo *); 56 static int wfq_disable(struct ifinfo *); 57 58 #define WFQ_DEVICE "/dev/altq/wfq" 59 60 static int wfq_fd = -1; 61 static int wfq_refcount = 0; 62 63 static struct qdisc_ops wfq_qdisc = { 64 ALTQT_WFQ, 65 "wfq", 66 wfq_attach, 67 wfq_detach, 68 NULL, /* clear */ 69 wfq_enable, 70 wfq_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 wfq_interface_parser(const char *ifname, int argc, char **argv) 85 { 86 u_int bandwidth = 100000000; /* 100Mbps */ 87 u_int tbrsize = 0; 88 int hash_policy = 0; /* 0: use default */ 89 int nqueues = 0; /* 0: use default */ 90 int qsize = 0; /* 0: use default */ 91 92 /* 93 * process options 94 */ 95 while (argc > 0) { 96 if (EQUAL(*argv, "bandwidth")) { 97 argc--; argv++; 98 if (argc > 0) 99 bandwidth = atobps(*argv); 100 } else if (EQUAL(*argv, "tbrsize")) { 101 argc--; argv++; 102 if (argc > 0) 103 tbrsize = atobytes(*argv); 104 } else if (EQUAL(*argv, "nqueues")) { 105 argc--; argv++; 106 if (argc > 0) 107 nqueues = (int)strtol(*argv, NULL, 0); 108 } else if (EQUAL(*argv, "qsize")) { 109 argc--; argv++; 110 if (argc > 0) 111 qsize = atobytes(*argv); 112 } else if (EQUAL(*argv, "hash")) { 113 argc--; argv++; 114 if (argc > 0) { 115 if (EQUAL(*argv, "dstaddr")) 116 hash_policy = WFQ_HASH_DSTADDR; 117 else if (EQUAL(*argv, "full")) 118 hash_policy = WFQ_HASH_FULL; 119 else if (EQUAL(*argv, "srcport")) 120 hash_policy = WFQ_HASH_SRCPORT; 121 else { 122 LOG(LOG_ERR, 0, 123 "Unknown hash policy '%s'", *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'", *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'", 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"); 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"); 231 return (QOPERR_SYSCALL); 232 } 233 } 234 #if 1 235 LOG(LOG_INFO, 0, "wfq attached to %s", 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