]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ggate/shared/ggate.c
MFC r326276:
[FreeBSD/FreeBSD.git] / sbin / ggate / shared / ggate.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * 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 THE AUTHORS 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 THE AUTHORS 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  * $FreeBSD$
29  */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/param.h>
36 #include <sys/disk.h>
37 #include <sys/stat.h>
38 #include <sys/endian.h>
39 #include <sys/socket.h>
40 #include <sys/linker.h>
41 #include <sys/module.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
45 #include <signal.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <libgen.h>
51 #include <libutil.h>
52 #include <netdb.h>
53 #include <syslog.h>
54 #include <stdarg.h>
55 #include <stdint.h>
56 #include <libgeom.h>
57
58 #include <geom/gate/g_gate.h>
59 #include "ggate.h"
60
61
62 int g_gate_devfd = -1;
63 int g_gate_verbose = 0;
64
65
66 void
67 g_gate_vlog(int priority, const char *message, va_list ap)
68 {
69
70         if (g_gate_verbose) {
71                 const char *prefix;
72
73                 switch (priority) {
74                 case LOG_ERR:
75                         prefix = "error";
76                         break;
77                 case LOG_WARNING:
78                         prefix = "warning";
79                         break;
80                 case LOG_NOTICE:
81                         prefix = "notice";
82                         break;
83                 case LOG_INFO:
84                         prefix = "info";
85                         break;
86                 case LOG_DEBUG:
87                         prefix = "debug";
88                         break;
89                 default:
90                         prefix = "unknown";
91                 }
92
93                 printf("%s: ", prefix);
94                 vprintf(message, ap);
95                 printf("\n");
96         } else {
97                 if (priority != LOG_DEBUG)
98                         vsyslog(priority, message, ap);
99         }
100 }
101
102 void
103 g_gate_log(int priority, const char *message, ...)
104 {
105         va_list ap;
106
107         va_start(ap, message);
108         g_gate_vlog(priority, message, ap);
109         va_end(ap);
110 }
111
112 void
113 g_gate_xvlog(const char *message, va_list ap)
114 {
115
116         g_gate_vlog(LOG_ERR, message, ap);
117         g_gate_vlog(LOG_ERR, "Exiting.", ap);
118         exit(EXIT_FAILURE);
119 }
120
121 void
122 g_gate_xlog(const char *message, ...)
123 {
124         va_list ap;
125
126         va_start(ap, message);
127         g_gate_xvlog(message, ap);
128         /* NOTREACHED */
129         va_end(ap);
130         exit(EXIT_FAILURE);
131 }
132
133 off_t
134 g_gate_mediasize(int fd)
135 {
136         off_t mediasize;
137         struct stat sb;
138
139         if (fstat(fd, &sb) == -1)
140                 g_gate_xlog("fstat(): %s.", strerror(errno));
141         if (S_ISCHR(sb.st_mode)) {
142                 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) {
143                         g_gate_xlog("Can't get media size: %s.",
144                             strerror(errno));
145                 }
146         } else if (S_ISREG(sb.st_mode)) {
147                 mediasize = sb.st_size;
148         } else {
149                 g_gate_xlog("Unsupported file system object.");
150         }
151         return (mediasize);
152 }
153
154 unsigned
155 g_gate_sectorsize(int fd)
156 {
157         unsigned secsize;
158         struct stat sb;
159
160         if (fstat(fd, &sb) == -1)
161                 g_gate_xlog("fstat(): %s.", strerror(errno));
162         if (S_ISCHR(sb.st_mode)) {
163                 if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) {
164                         g_gate_xlog("Can't get sector size: %s.",
165                             strerror(errno));
166                 }
167         } else if (S_ISREG(sb.st_mode)) {
168                 secsize = 512;
169         } else {
170                 g_gate_xlog("Unsupported file system object.");
171         }
172         return (secsize);
173 }
174
175 void
176 g_gate_open_device(void)
177 {
178
179         g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR);
180         if (g_gate_devfd == -1)
181                 err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME);
182 }
183
184 void
185 g_gate_close_device(void)
186 {
187
188         close(g_gate_devfd);
189 }
190
191 void
192 g_gate_ioctl(unsigned long req, void *data)
193 {
194
195         if (ioctl(g_gate_devfd, req, data) == -1) {
196                 g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(),
197                     G_GATE_CTL_NAME, strerror(errno));
198         }
199 }
200
201 void
202 g_gate_destroy(int unit, int force)
203 {
204         struct g_gate_ctl_destroy ggio;
205
206         ggio.gctl_version = G_GATE_VERSION;
207         ggio.gctl_unit = unit;
208         ggio.gctl_force = force;
209         g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio);
210 }
211
212 void
213 g_gate_load_module(void)
214 {
215
216         if (modfind("g_gate") == -1) {
217                 /* Not present in kernel, try loading it. */
218                 if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) {
219                         if (errno != EEXIST) {
220                                 errx(EXIT_FAILURE,
221                                     "geom_gate module not available!");
222                         }
223                 }
224         }
225 }
226
227 /*
228  * When we send from ggatec packets larger than 32kB, performance drops
229  * significantly (eg. to 256kB/s over 1Gbit/s link). This is not a problem
230  * when data is send from ggated. I don't know why, so for now I limit
231  * size of packets send from ggatec to 32kB by defining MAX_SEND_SIZE
232  * in ggatec Makefile.
233  */
234 #ifndef MAX_SEND_SIZE
235 #define MAX_SEND_SIZE   MAXPHYS
236 #endif
237 ssize_t
238 g_gate_send(int s, const void *buf, size_t len, int flags)
239 {
240         ssize_t done = 0, done2;
241         const unsigned char *p = buf;
242
243         while (len > 0) {
244                 done2 = send(s, p, MIN(len, MAX_SEND_SIZE), flags);
245                 if (done2 == 0)
246                         break;
247                 else if (done2 == -1) {
248                         if (errno == EAGAIN) {
249                                 printf("%s: EAGAIN\n", __func__);
250                                 continue;
251                         }
252                         done = -1;
253                         break;
254                 }
255                 done += done2;
256                 p += done2;
257                 len -= done2;
258         }
259         return (done);
260 }
261
262 ssize_t
263 g_gate_recv(int s, void *buf, size_t len, int flags)
264 {
265         ssize_t done;
266
267         do {
268                 done = recv(s, buf, len, flags);
269         } while (done == -1 && errno == EAGAIN);
270         return (done);
271 }
272
273 int nagle = 1;
274 unsigned rcvbuf = G_GATE_RCVBUF;
275 unsigned sndbuf = G_GATE_SNDBUF;
276
277 void
278 g_gate_socket_settings(int sfd)
279 {
280         struct timeval tv;
281         int bsize, on;
282
283         /* Socket settings. */
284         on = 1;
285         if (nagle) {
286                 if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on,
287                     sizeof(on)) == -1) {
288                         g_gate_xlog("setsockopt() error: %s.", strerror(errno));
289                 }
290         }
291         if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
292                 g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno));
293         bsize = rcvbuf;
294         if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1)
295                 g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno));
296         bsize = sndbuf;
297         if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1)
298                 g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno));
299         tv.tv_sec = 8;
300         tv.tv_usec = 0;
301         if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
302                 g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.",
303                     strerror(errno));
304         }
305         if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
306                 g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.",
307                     strerror(errno));
308         }
309 }
310
311 #ifdef LIBGEOM
312 static struct gclass *
313 find_class(struct gmesh *mesh, const char *name)
314 {
315         struct gclass *class;
316
317         LIST_FOREACH(class, &mesh->lg_class, lg_class) {
318                 if (strcmp(class->lg_name, name) == 0)
319                         return (class);
320         }
321         return (NULL);
322 }
323
324 static const char *
325 get_conf(struct ggeom *gp, const char *name)
326 {
327         struct gconfig *conf;
328
329         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
330                 if (strcmp(conf->lg_name, name) == 0)
331                         return (conf->lg_val);
332         }
333         return (NULL);
334 }
335
336 static void
337 show_config(struct ggeom *gp, int verbose)
338 {
339         struct gprovider *pp;
340         char buf[5];
341
342         pp = LIST_FIRST(&gp->lg_provider);
343         if (pp == NULL)
344                 return;
345         if (!verbose) {
346                 printf("%s\n", pp->lg_name);
347                 return;
348         }
349         printf("       NAME: %s\n", pp->lg_name);
350         printf("       info: %s\n", get_conf(gp, "info"));
351         printf("     access: %s\n", get_conf(gp, "access"));
352         printf("    timeout: %s\n", get_conf(gp, "timeout"));
353         printf("queue_count: %s\n", get_conf(gp, "queue_count"));
354         printf(" queue_size: %s\n", get_conf(gp, "queue_size"));
355         printf(" references: %s\n", get_conf(gp, "ref"));
356         humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
357             HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
358         printf("  mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf);
359         printf(" sectorsize: %u\n", pp->lg_sectorsize);
360         printf("       mode: %s\n", pp->lg_mode);
361         printf("\n");
362 }
363
364 void
365 g_gate_list(int unit, int verbose)
366 {
367         struct gmesh mesh;
368         struct gclass *class;
369         struct ggeom *gp;
370         char name[64];
371         int error;
372
373         error = geom_gettree(&mesh);
374         if (error != 0)
375                 exit(EXIT_FAILURE);
376         class = find_class(&mesh, G_GATE_CLASS_NAME);
377         if (class == NULL) {
378                 geom_deletetree(&mesh);
379                 exit(EXIT_SUCCESS);
380         }
381         if (unit >= 0) {
382                 snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
383                     unit);
384         }
385         LIST_FOREACH(gp, &class->lg_geom, lg_geom) {
386                 if (unit != -1 && strcmp(gp->lg_name, name) != 0)
387                         continue;
388                 show_config(gp, verbose);
389         }
390         geom_deletetree(&mesh);
391         exit(EXIT_SUCCESS);
392 }
393 #endif  /* LIBGEOM */
394
395 in_addr_t
396 g_gate_str2ip(const char *str)
397 {
398         struct hostent *hp;
399         in_addr_t ip;
400
401         ip = inet_addr(str);
402         if (ip != INADDR_NONE) {
403                 /* It is a valid IP address. */
404                 return (ip);
405         }
406         /* Check if it is a valid host name. */
407         hp = gethostbyname(str);
408         if (hp == NULL)
409                 return (INADDR_NONE);
410         return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
411 }