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 53static int wfq_attach(struct ifinfo *); 54static int wfq_detach(struct ifinfo *); 55static int wfq_enable(struct ifinfo *); 56static int wfq_disable(struct ifinfo *); 57 58#define WFQ_DEVICE "/dev/altq/wfq" 59 60static int wfq_fd = -1; 61static int wfq_refcount = 0; 62 63static 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 83int 84wfq_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 if (EQUAL(*argv, "srcaddr")) 122 hash_policy = WFQ_HASH_SRCADDR; 123 else { 124 LOG(LOG_ERR, 0, 125 "Unknown hash policy '%s'", *argv); 126 return (0); 127 } 128 } 129 } else if (EQUAL(*argv, "wfq")) { 130 /* just skip */ 131 } else { 132 LOG(LOG_ERR, 0, "Unknown keyword '%s'", *argv); 133 return (0); 134 } 135 argc--; argv++; 136 } 137 138 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0) 139 return (0); 140 141 if (qsize != 0 && qsize < 1500) { 142 LOG(LOG_ERR, 0, "qsize too small: %d bytes", qsize); 143 return (0); 144 } 145 146 if (qcmd_wfq_add_if(ifname, bandwidth, 147 hash_policy, nqueues, qsize) != 0) 148 return (0); 149 return (1); 150} 151 152/* 153 * qcmd api 154 */ 155int 156qcmd_wfq_add_if(const char *ifname, u_int bandwidth, int hash_policy, 157 int nqueues, int qsize) 158{ 159 int error; 160 161 error = qop_wfq_add_if(NULL, ifname, bandwidth, 162 hash_policy, nqueues, qsize); 163 if (error != 0) 164 LOG(LOG_ERR, errno, "%s: can't add wfq on interface '%s'", 165 qoperror(error), ifname); 166 return (error); 167} 168 169/* 170 * qop api 171 */ 172int 173qop_wfq_add_if(struct ifinfo **rp, const char *ifname, u_int bandwidth, 174 int hash_policy, int nqueues, int qsize) 175{ 176 struct ifinfo *ifinfo = NULL; 177 struct wfq_ifinfo *wfq_ifinfo; 178 int error; 179 180 if ((wfq_ifinfo = calloc(1, sizeof(*wfq_ifinfo))) == NULL) 181 return (QOPERR_NOMEM); 182 wfq_ifinfo->hash_policy = hash_policy; 183 wfq_ifinfo->nqueues = nqueues; 184 wfq_ifinfo->qsize = qsize; 185 186 error = qop_add_if(&ifinfo, ifname, bandwidth, 187 &wfq_qdisc, wfq_ifinfo); 188 if (error != 0) { 189 free(wfq_ifinfo); 190 return (error); 191 } 192 193 if (rp != NULL) 194 *rp = ifinfo; 195 return (0); 196} 197 198/* 199 * system call interfaces for qdisc_ops 200 */ 201static int 202wfq_attach(struct ifinfo *ifinfo) 203{ 204 struct wfq_interface iface; 205 struct wfq_ifinfo *wfq_ifinfo; 206 struct wfq_conf conf; 207 208 if (wfq_fd < 0 && 209 (wfq_fd = open(WFQ_DEVICE, O_RDWR)) < 0 && 210 (wfq_fd = open_module(WFQ_DEVICE, O_RDWR)) < 0) { 211 LOG(LOG_ERR, errno, "WFQ open"); 212 return (QOPERR_SYSCALL); 213 } 214 215 wfq_refcount++; 216 memset(&iface, 0, sizeof(iface)); 217 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 218 219 if (ioctl(wfq_fd, WFQ_IF_ATTACH, &iface) < 0) 220 return (QOPERR_SYSCALL); 221 222 /* set wfq parameters */ 223 wfq_ifinfo = (struct wfq_ifinfo *)ifinfo->private; 224 if (wfq_ifinfo->hash_policy != 0 || wfq_ifinfo->nqueues != 0 || 225 wfq_ifinfo->qsize != 0) { 226 memset(&conf, 0, sizeof(conf)); 227 strncpy(conf.iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 228 conf.hash_policy = wfq_ifinfo->hash_policy; 229 conf.nqueues = wfq_ifinfo->nqueues; 230 conf.qlimit = wfq_ifinfo->qsize; 231 if (ioctl(wfq_fd, WFQ_CONFIG, &conf) < 0) { 232 LOG(LOG_ERR, errno, "WFQ_CONFIG"); 233 return (QOPERR_SYSCALL); 234 } 235 } 236#if 1 237 LOG(LOG_INFO, 0, "wfq attached to %s", iface.wfq_ifacename); 238#endif 239 return (0); 240} 241 242static int 243wfq_detach(struct ifinfo *ifinfo) 244{ 245 struct wfq_interface iface; 246 247 memset(&iface, 0, sizeof(iface)); 248 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 249 250 if (ioctl(wfq_fd, WFQ_IF_DETACH, &iface) < 0) 251 return (QOPERR_SYSCALL); 252 253 if (--wfq_refcount == 0) { 254 close(wfq_fd); 255 wfq_fd = -1; 256 } 257 return (0); 258} 259 260static int 261wfq_enable(struct ifinfo *ifinfo) 262{ 263 struct wfq_interface iface; 264 265 memset(&iface, 0, sizeof(iface)); 266 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 267 268 if (ioctl(wfq_fd, WFQ_ENABLE, &iface) < 0) 269 return (QOPERR_SYSCALL); 270 return (0); 271} 272 273static int 274wfq_disable(struct ifinfo *ifinfo) 275{ 276 struct wfq_interface iface; 277 278 memset(&iface, 0, sizeof(iface)); 279 strncpy(iface.wfq_ifacename, ifinfo->ifname, IFNAMSIZ); 280 281 if (ioctl(wfq_fd, WFQ_DISABLE, &iface) < 0) 282 return (QOPERR_SYSCALL); 283 return (0); 284} 285