1 /* $KAME: qop_fifoq.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_fifoq.h> 49 #include "altq_qop.h" 50 #include "qop_fifoq.h" 51 52 static int fifoq_attach(struct ifinfo *ifinfo); 53 static int fifoq_detach(struct ifinfo *ifinfo); 54 static int fifoq_enable(struct ifinfo *ifinfo); 55 static int fifoq_disable(struct ifinfo *ifinfo); 56 57 #define FIFOQ_DEVICE "/dev/altq/fifoq" 58 59 static int fifoq_fd = -1; 60 static int fifoq_refcount = 0; 61 62 static struct qdisc_ops fifoq_qdisc = { 63 ALTQT_FIFOQ, 64 "fifoq", 65 fifoq_attach, 66 fifoq_detach, 67 NULL, /* clear */ 68 fifoq_enable, 69 fifoq_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 fifoq_interface_parser(const char *ifname, int argc, char **argv) 84 { 85 u_int bandwidth = 100000000; /* 100Mbps */ 86 u_int tbrsize = 0; 87 int qlimit = 50; 88 89 /* 90 * process options 91 */ 92 while (argc > 0) { 93 if (EQUAL(*argv, "bandwidth")) { 94 argc--; argv++; 95 if (argc > 0) 96 bandwidth = atobps(*argv); 97 } else if (EQUAL(*argv, "tbrsize")) { 98 argc--; argv++; 99 if (argc > 0) 100 tbrsize = atobytes(*argv); 101 } else if (EQUAL(*argv, "qlimit")) { 102 argc--; argv++; 103 if (argc > 0) 104 qlimit = (int)strtol(*argv, NULL, 0); 105 } else if (EQUAL(*argv, "fifoq")) { 106 /* just skip */ 107 } else { 108 LOG(LOG_ERR, 0, "Unknown keyword '%s'\n", argv); 109 return (0); 110 } 111 argc--; argv++; 112 } 113 114 if (qcmd_tbr_register(ifname, bandwidth, tbrsize) != 0) 115 return (0); 116 117 if (qcmd_fifoq_add_if(ifname, bandwidth, qlimit) != 0) 118 return (0); 119 return (1); 120 } 121 122 /* 123 * qcmd api 124 */ 125 int 126 qcmd_fifoq_add_if(const char *ifname, u_int bandwidth, int qlimit) 127 { 128 int error; 129 130 error = qop_fifoq_add_if(NULL, ifname, bandwidth, qlimit); 131 if (error != 0) 132 LOG(LOG_ERR, errno, "%s: can't add fifoq on interface '%s'\n", 133 qoperror(error), ifname); 134 return (error); 135 } 136 137 /* 138 * qop api 139 */ 140 int 141 qop_fifoq_add_if(struct ifinfo **rp, const char *ifname, 142 u_int bandwidth, int qlimit) 143 { 144 struct ifinfo *ifinfo = NULL; 145 struct fifoq_ifinfo *fifoq_ifinfo; 146 int error; 147 148 if ((fifoq_ifinfo = calloc(1, sizeof(*fifoq_ifinfo))) == NULL) 149 return (QOPERR_NOMEM); 150 fifoq_ifinfo->qlimit = qlimit; 151 152 error = qop_add_if(&ifinfo, ifname, bandwidth, 153 &fifoq_qdisc, fifoq_ifinfo); 154 if (error != 0) { 155 free(fifoq_ifinfo); 156 return (error); 157 } 158 159 if (rp != NULL) 160 *rp = ifinfo; 161 return (0); 162 } 163 164 /* 165 * system call interfaces for qdisc_ops 166 */ 167 static int 168 fifoq_attach(struct ifinfo *ifinfo) 169 { 170 struct fifoq_interface iface; 171 struct fifoq_ifinfo *fifoq_ifinfo; 172 struct fifoq_conf conf; 173 174 if (fifoq_fd < 0 && 175 (fifoq_fd = open(FIFOQ_DEVICE, O_RDWR)) < 0 && 176 (fifoq_fd = open_module(FIFOQ_DEVICE, O_RDWR)) < 0) { 177 LOG(LOG_ERR, errno, "FIFOQ open\n"); 178 return (QOPERR_SYSCALL); 179 } 180 181 fifoq_refcount++; 182 memset(&iface, 0, sizeof(iface)); 183 strncpy(iface.fifoq_ifname, ifinfo->ifname, IFNAMSIZ); 184 185 if (ioctl(fifoq_fd, FIFOQ_IF_ATTACH, &iface) < 0) 186 return (QOPERR_SYSCALL); 187 188 /* set fifoq parameters */ 189 fifoq_ifinfo = (struct fifoq_ifinfo *)ifinfo->private; 190 if (fifoq_ifinfo->qlimit > 0) { 191 memset(&conf, 0, sizeof(conf)); 192 strncpy(conf.iface.fifoq_ifname, ifinfo->ifname, IFNAMSIZ); 193 conf.fifoq_limit = fifoq_ifinfo->qlimit; 194 if (ioctl(fifoq_fd, FIFOQ_CONFIG, &conf) < 0) 195 return (QOPERR_SYSCALL); 196 } 197 #if 1 198 LOG(LOG_INFO, 0, "fifoq attached to %s\n", iface.fifoq_ifname); 199 #endif 200 return (0); 201 } 202 203 static int 204 fifoq_detach(struct ifinfo *ifinfo) 205 { 206 struct fifoq_interface iface; 207 208 memset(&iface, 0, sizeof(iface)); 209 strncpy(iface.fifoq_ifname, ifinfo->ifname, IFNAMSIZ); 210 211 if (ioctl(fifoq_fd, FIFOQ_IF_DETACH, &iface) < 0) 212 return (QOPERR_SYSCALL); 213 214 if (--fifoq_refcount == 0) { 215 close(fifoq_fd); 216 fifoq_fd = -1; 217 } 218 return (0); 219 } 220 221 static int 222 fifoq_enable(struct ifinfo *ifinfo) 223 { 224 struct fifoq_interface iface; 225 226 memset(&iface, 0, sizeof(iface)); 227 strncpy(iface.fifoq_ifname, ifinfo->ifname, IFNAMSIZ); 228 229 if (ioctl(fifoq_fd, FIFOQ_ENABLE, &iface) < 0) 230 return (QOPERR_SYSCALL); 231 return (0); 232 } 233 234 static int 235 fifoq_disable(struct ifinfo *ifinfo) 236 { 237 struct fifoq_interface iface; 238 239 memset(&iface, 0, sizeof(iface)); 240 strncpy(iface.fifoq_ifname, ifinfo->ifname, IFNAMSIZ); 241 242 if (ioctl(fifoq_fd, FIFOQ_DISABLE, &iface) < 0) 243 return (QOPERR_SYSCALL); 244 return (0); 245 } 246