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