1128763Spjd/*- 2128763Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3128763Spjd * All rights reserved. 4128763Spjd * 5128763Spjd * Redistribution and use in source and binary forms, with or without 6128763Spjd * modification, are permitted provided that the following conditions 7128763Spjd * are met: 8128763Spjd * 1. Redistributions of source code must retain the above copyright 9128763Spjd * notice, this list of conditions and the following disclaimer. 10128763Spjd * 2. Redistributions in binary form must reproduce the above copyright 11128763Spjd * notice, this list of conditions and the following disclaimer in the 12128763Spjd * documentation and/or other materials provided with the distribution. 13204075Spjd * 14128763Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15128763Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16128763Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17128763Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18128763Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19128763Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20128763Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21128763Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22128763Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23128763Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24128763Spjd * SUCH DAMAGE. 25128763Spjd * 26128763Spjd * $FreeBSD$ 27128763Spjd */ 28128763Spjd 29128763Spjd#include <stdio.h> 30128763Spjd#include <stdlib.h> 31128763Spjd#include <unistd.h> 32128763Spjd#include <fcntl.h> 33128763Spjd#include <sys/param.h> 34128763Spjd#include <sys/disk.h> 35128763Spjd#include <sys/stat.h> 36128763Spjd#include <sys/endian.h> 37128763Spjd#include <sys/socket.h> 38128763Spjd#include <sys/linker.h> 39128763Spjd#include <sys/module.h> 40128763Spjd#include <netinet/in.h> 41147844Spjd#include <netinet/tcp.h> 42128763Spjd#include <arpa/inet.h> 43128763Spjd#include <signal.h> 44128763Spjd#include <err.h> 45128763Spjd#include <errno.h> 46128763Spjd#include <string.h> 47128763Spjd#include <strings.h> 48128763Spjd#include <libgen.h> 49130837Spjd#include <libutil.h> 50128763Spjd#include <netdb.h> 51128763Spjd#include <syslog.h> 52128763Spjd#include <stdarg.h> 53130837Spjd#include <stdint.h> 54128763Spjd#include <libgeom.h> 55128763Spjd 56128763Spjd#include <geom/gate/g_gate.h> 57128763Spjd#include "ggate.h" 58128763Spjd 59128763Spjd 60128763Spjdint g_gate_devfd = -1; 61128763Spjdint g_gate_verbose = 0; 62128763Spjd 63128763Spjd 64128763Spjdvoid 65128763Spjdg_gate_vlog(int priority, const char *message, va_list ap) 66128763Spjd{ 67128763Spjd 68128763Spjd if (g_gate_verbose) { 69128763Spjd const char *prefix; 70128763Spjd 71128763Spjd switch (priority) { 72128763Spjd case LOG_ERR: 73128763Spjd prefix = "error"; 74128763Spjd break; 75128763Spjd case LOG_WARNING: 76128763Spjd prefix = "warning"; 77128763Spjd break; 78128763Spjd case LOG_NOTICE: 79128763Spjd prefix = "notice"; 80128763Spjd break; 81128763Spjd case LOG_INFO: 82128763Spjd prefix = "info"; 83128763Spjd break; 84128763Spjd case LOG_DEBUG: 85128763Spjd prefix = "debug"; 86128763Spjd break; 87128763Spjd default: 88128763Spjd prefix = "unknown"; 89128763Spjd } 90128763Spjd 91128763Spjd printf("%s: ", prefix); 92128763Spjd vprintf(message, ap); 93128763Spjd printf("\n"); 94128763Spjd } else { 95128763Spjd if (priority != LOG_DEBUG) 96128763Spjd vsyslog(priority, message, ap); 97128763Spjd } 98128763Spjd} 99128763Spjd 100128763Spjdvoid 101128763Spjdg_gate_log(int priority, const char *message, ...) 102128763Spjd{ 103128763Spjd va_list ap; 104128763Spjd 105128763Spjd va_start(ap, message); 106128763Spjd g_gate_vlog(priority, message, ap); 107128763Spjd va_end(ap); 108128763Spjd} 109128763Spjd 110128763Spjdvoid 111128763Spjdg_gate_xvlog(const char *message, va_list ap) 112128763Spjd{ 113128763Spjd 114128763Spjd g_gate_vlog(LOG_ERR, message, ap); 115128763Spjd g_gate_vlog(LOG_ERR, "Exiting.", ap); 116128763Spjd exit(EXIT_FAILURE); 117128763Spjd} 118128763Spjd 119128763Spjdvoid 120128763Spjdg_gate_xlog(const char *message, ...) 121128763Spjd{ 122128763Spjd va_list ap; 123128763Spjd 124128763Spjd va_start(ap, message); 125128763Spjd g_gate_xvlog(message, ap); 126128763Spjd /* NOTREACHED */ 127128763Spjd va_end(ap); 128128763Spjd exit(EXIT_FAILURE); 129128763Spjd} 130128763Spjd 131128763Spjdoff_t 132128763Spjdg_gate_mediasize(int fd) 133128763Spjd{ 134128763Spjd off_t mediasize; 135128763Spjd struct stat sb; 136128763Spjd 137134937Spjd if (fstat(fd, &sb) == -1) 138128763Spjd g_gate_xlog("fstat(): %s.", strerror(errno)); 139128763Spjd if (S_ISCHR(sb.st_mode)) { 140134937Spjd if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) { 141128763Spjd g_gate_xlog("Can't get media size: %s.", 142128763Spjd strerror(errno)); 143128763Spjd } 144128763Spjd } else if (S_ISREG(sb.st_mode)) { 145128763Spjd mediasize = sb.st_size; 146128763Spjd } else { 147128763Spjd g_gate_xlog("Unsupported file system object."); 148128763Spjd } 149128763Spjd return (mediasize); 150128763Spjd} 151128763Spjd 152165327Spjdunsigned 153128763Spjdg_gate_sectorsize(int fd) 154128763Spjd{ 155165327Spjd unsigned secsize; 156128763Spjd struct stat sb; 157128763Spjd 158134937Spjd if (fstat(fd, &sb) == -1) 159128763Spjd g_gate_xlog("fstat(): %s.", strerror(errno)); 160128763Spjd if (S_ISCHR(sb.st_mode)) { 161134937Spjd if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) { 162204075Spjd g_gate_xlog("Can't get sector size: %s.", 163128763Spjd strerror(errno)); 164128763Spjd } 165128763Spjd } else if (S_ISREG(sb.st_mode)) { 166128763Spjd secsize = 512; 167128763Spjd } else { 168128763Spjd g_gate_xlog("Unsupported file system object."); 169128763Spjd } 170128763Spjd return (secsize); 171128763Spjd} 172128763Spjd 173128763Spjdvoid 174128763Spjdg_gate_open_device(void) 175128763Spjd{ 176128763Spjd 177204075Spjd g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR); 178134937Spjd if (g_gate_devfd == -1) 179128763Spjd err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME); 180128763Spjd} 181128763Spjd 182128763Spjdvoid 183128763Spjdg_gate_close_device(void) 184128763Spjd{ 185128763Spjd 186128763Spjd close(g_gate_devfd); 187128763Spjd} 188128763Spjd 189128763Spjdvoid 190128763Spjdg_gate_ioctl(unsigned long req, void *data) 191128763Spjd{ 192128763Spjd 193134937Spjd if (ioctl(g_gate_devfd, req, data) == -1) { 194128763Spjd g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(), 195128763Spjd G_GATE_CTL_NAME, strerror(errno)); 196128763Spjd } 197128763Spjd} 198128763Spjd 199128763Spjdvoid 200128763Spjdg_gate_destroy(int unit, int force) 201128763Spjd{ 202128763Spjd struct g_gate_ctl_destroy ggio; 203128763Spjd 204128763Spjd ggio.gctl_version = G_GATE_VERSION; 205128763Spjd ggio.gctl_unit = unit; 206128763Spjd ggio.gctl_force = force; 207128763Spjd g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio); 208128763Spjd} 209128763Spjd 210128763Spjdvoid 211128763Spjdg_gate_load_module(void) 212128763Spjd{ 213128763Spjd 214134937Spjd if (modfind("g_gate") == -1) { 215128763Spjd /* Not present in kernel, try loading it. */ 216134937Spjd if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) { 217128763Spjd if (errno != EEXIST) { 218128763Spjd errx(EXIT_FAILURE, 219128763Spjd "geom_gate module not available!"); 220128763Spjd } 221128763Spjd } 222128763Spjd } 223128763Spjd} 224128763Spjd 225168422Spjd/* 226168422Spjd * When we send from ggatec packets larger than 32kB, performance drops 227168422Spjd * significantly (eg. to 256kB/s over 1Gbit/s link). This is not a problem 228168422Spjd * when data is send from ggated. I don't know why, so for now I limit 229168422Spjd * size of packets send from ggatec to 32kB by defining MAX_SEND_SIZE 230168422Spjd * in ggatec Makefile. 231168422Spjd */ 232168422Spjd#ifndef MAX_SEND_SIZE 233168422Spjd#define MAX_SEND_SIZE MAXPHYS 234168422Spjd#endif 235147844Spjdssize_t 236147844Spjdg_gate_send(int s, const void *buf, size_t len, int flags) 237147844Spjd{ 238147844Spjd ssize_t done = 0, done2; 239147844Spjd const unsigned char *p = buf; 240147844Spjd 241147844Spjd while (len > 0) { 242168422Spjd done2 = send(s, p, MIN(len, MAX_SEND_SIZE), flags); 243147844Spjd if (done2 == 0) 244147844Spjd break; 245147844Spjd else if (done2 == -1) { 246147844Spjd if (errno == EAGAIN) { 247147844Spjd printf("%s: EAGAIN\n", __func__); 248147844Spjd continue; 249147844Spjd } 250147844Spjd done = -1; 251147844Spjd break; 252147844Spjd } 253147844Spjd done += done2; 254147844Spjd p += done2; 255147844Spjd len -= done2; 256147844Spjd } 257147844Spjd return (done); 258147844Spjd} 259147844Spjd 260147844Spjdssize_t 261147844Spjdg_gate_recv(int s, void *buf, size_t len, int flags) 262147844Spjd{ 263163804Spjd ssize_t done; 264147844Spjd 265163804Spjd do { 266163804Spjd done = recv(s, buf, len, flags); 267163804Spjd } while (done == -1 && errno == EAGAIN); 268163804Spjd return (done); 269147844Spjd} 270147844Spjd 271147844Spjdint nagle = 1; 272147844Spjdunsigned rcvbuf = G_GATE_RCVBUF; 273147844Spjdunsigned sndbuf = G_GATE_SNDBUF; 274147844Spjd 275147844Spjdvoid 276147844Spjdg_gate_socket_settings(int sfd) 277147844Spjd{ 278147844Spjd struct timeval tv; 279147844Spjd int bsize, on; 280147844Spjd 281147844Spjd /* Socket settings. */ 282147844Spjd on = 1; 283147844Spjd if (nagle) { 284204075Spjd if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, 285147844Spjd sizeof(on)) == -1) { 286147844Spjd g_gate_xlog("setsockopt() error: %s.", strerror(errno)); 287147844Spjd } 288147844Spjd } 289147844Spjd if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) 290147844Spjd g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno)); 291147844Spjd bsize = rcvbuf; 292147844Spjd if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1) 293147844Spjd g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno)); 294147844Spjd bsize = sndbuf; 295147844Spjd if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1) 296147844Spjd g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno)); 297163804Spjd tv.tv_sec = 8; 298147844Spjd tv.tv_usec = 0; 299147844Spjd if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { 300147844Spjd g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.", 301147844Spjd strerror(errno)); 302147844Spjd } 303147844Spjd if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { 304147844Spjd g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.", 305147844Spjd strerror(errno)); 306147844Spjd } 307147844Spjd} 308147844Spjd 309128763Spjd#ifdef LIBGEOM 310128763Spjdstatic struct gclass * 311128763Spjdfind_class(struct gmesh *mesh, const char *name) 312128763Spjd{ 313128763Spjd struct gclass *class; 314128763Spjd 315128763Spjd LIST_FOREACH(class, &mesh->lg_class, lg_class) { 316128763Spjd if (strcmp(class->lg_name, name) == 0) 317128763Spjd return (class); 318128763Spjd } 319128763Spjd return (NULL); 320128763Spjd} 321128763Spjd 322128763Spjdstatic const char * 323128763Spjdget_conf(struct ggeom *gp, const char *name) 324128763Spjd{ 325128763Spjd struct gconfig *conf; 326128763Spjd 327128763Spjd LIST_FOREACH(conf, &gp->lg_config, lg_config) { 328128763Spjd if (strcmp(conf->lg_name, name) == 0) 329128763Spjd return (conf->lg_val); 330128763Spjd } 331128763Spjd return (NULL); 332128763Spjd} 333128763Spjd 334128763Spjdstatic void 335128763Spjdshow_config(struct ggeom *gp, int verbose) 336128763Spjd{ 337128763Spjd struct gprovider *pp; 338130837Spjd char buf[5]; 339128763Spjd 340128763Spjd pp = LIST_FIRST(&gp->lg_provider); 341128763Spjd if (pp == NULL) 342128763Spjd return; 343128763Spjd if (!verbose) { 344128763Spjd printf("%s\n", pp->lg_name); 345128763Spjd return; 346128763Spjd } 347128763Spjd printf(" NAME: %s\n", pp->lg_name); 348128763Spjd printf(" info: %s\n", get_conf(gp, "info")); 349128763Spjd printf(" access: %s\n", get_conf(gp, "access")); 350128763Spjd printf(" timeout: %s\n", get_conf(gp, "timeout")); 351128763Spjd printf("queue_count: %s\n", get_conf(gp, "queue_count")); 352128763Spjd printf(" queue_size: %s\n", get_conf(gp, "queue_size")); 353128763Spjd printf(" references: %s\n", get_conf(gp, "ref")); 354130837Spjd humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 355130837Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 356130837Spjd printf(" mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf); 357128763Spjd printf(" sectorsize: %u\n", pp->lg_sectorsize); 358128763Spjd printf(" mode: %s\n", pp->lg_mode); 359128763Spjd printf("\n"); 360128763Spjd} 361128763Spjd 362128763Spjdvoid 363128763Spjdg_gate_list(int unit, int verbose) 364128763Spjd{ 365128763Spjd struct gmesh mesh; 366128763Spjd struct gclass *class; 367128763Spjd struct ggeom *gp; 368128763Spjd char name[64]; 369128763Spjd int error; 370128763Spjd 371128763Spjd error = geom_gettree(&mesh); 372128763Spjd if (error != 0) 373128763Spjd exit(EXIT_FAILURE); 374128763Spjd class = find_class(&mesh, G_GATE_CLASS_NAME); 375128763Spjd if (class == NULL) { 376128763Spjd geom_deletetree(&mesh); 377128763Spjd exit(EXIT_SUCCESS); 378128763Spjd } 379128763Spjd if (unit >= 0) { 380128763Spjd snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, 381128763Spjd unit); 382128763Spjd } 383128763Spjd LIST_FOREACH(gp, &class->lg_geom, lg_geom) { 384128763Spjd if (unit != -1 && strcmp(gp->lg_name, name) != 0) 385128763Spjd continue; 386128763Spjd show_config(gp, verbose); 387128763Spjd } 388128763Spjd geom_deletetree(&mesh); 389128763Spjd exit(EXIT_SUCCESS); 390128763Spjd} 391128763Spjd#endif /* LIBGEOM */ 392128763Spjd 393128763Spjdin_addr_t 394128763Spjdg_gate_str2ip(const char *str) 395128763Spjd{ 396128763Spjd struct hostent *hp; 397128763Spjd in_addr_t ip; 398128763Spjd 399128763Spjd ip = inet_addr(str); 400128763Spjd if (ip != INADDR_NONE) { 401128763Spjd /* It is a valid IP address. */ 402128763Spjd return (ip); 403128763Spjd } 404128763Spjd /* Check if it is a valid host name. */ 405128763Spjd hp = gethostbyname(str); 406128763Spjd if (hp == NULL) 407128763Spjd return (INADDR_NONE); 408128836Spjd return (((struct in_addr *)(void *)hp->h_addr)->s_addr); 409128763Spjd} 410