geom_gate userland utility improvements
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

417 lines
9.2 KiB

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