Print this page
4770 soconfig(1M) needs an option to print the in-kernel socket configuration table
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cmd-inet/usr.sbin/soconfig.c
+++ new/usr/src/cmd/cmd-inet/usr.sbin/soconfig.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <ctype.h>
26 27 #include <dirent.h>
27 28 #include <errno.h>
28 29 #include <locale.h>
29 30 #include <stdio.h>
30 31 #include <stdlib.h>
31 32 #include <string.h>
32 33 #include <sys/socket.h>
33 34 #include <sys/socketvar.h>
34 35 #include <sys/stat.h>
35 36 #include <unistd.h>
36 37
37 38 #define MAXLINELEN 4096
38 39
39 40 /*
40 41 * Usage:
41 42 * soconfig -d <dir>
42 43 * Reads input from files in dir.
43 44 *
44 45 * soconfig -f <file>
45 46 * Reads input from file. The file is structured as
46 47 * <fam> <type> <protocol> <path|module>
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
47 48 * <fam> <type> <protocol>
48 49 * with the first line registering and the second line
49 50 * deregistering.
50 51 *
51 52 * soconfig <fam> <type> <protocol> <path|module>
52 53 * registers
53 54 *
54 55 * soconfig <fam> <type> <protocol>
55 56 * deregisters
56 57 *
58 + * soconfig -l
59 + * print the in-kernel socket configuration table
60 + *
57 61 * Filter Operations (Consolidation Private):
58 62 *
59 63 * soconfig -F <name> <modname> {auto [top | bottom | before:filter |
60 64 * after:filter] | prog} <fam>:<type>:<proto>,...
61 65 * configure filter
62 66 *
63 67 * soconfig -F <name>
64 68 * unconfigures filter
65 69 */
66 70
67 71 static int parse_files_in_dir(const char *dir);
68 72
69 73 static int parse_file(char *filename);
70 74
71 75 static int split_line(char *line, char *argvec[], int maxargvec);
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
72 76
73 77 static int parse_params(char *famstr, char *typestr, char *protostr,
74 78 char *path, const char *file, int line);
75 79
76 80 static int parse_int(char *str);
77 81
78 82 static void usage(void);
79 83
80 84 static int parse_filter_params(int argc, char **argv);
81 85
86 +static int print_socktable();
87 +
82 88 int
83 89 main(argc, argv)
84 90 int argc;
85 91 char *argv[];
86 92 {
87 93 int ret;
88 94
89 95 argc--; argv++;
90 96
91 97 (void) setlocale(LC_ALL, "");
92 98 #if !defined(TEXT_DOMAIN)
93 99 #define TEXT_DOMAIN "SYS_TEST"
94 100 #endif
95 101 (void) textdomain(TEXT_DOMAIN);
96 102
103 + if (argc == 1 && strcmp(argv[0], "-l") == 0) {
104 + ret = print_socktable();
105 + exit(ret);
106 + }
107 +
97 108 if (argc >= 2 && strcmp(argv[0], "-F") == 0) {
98 109 argc--; argv++;
99 110 ret = parse_filter_params(argc, argv);
100 111 exit(ret);
101 112 }
102 113 if (argc == 2 && strcmp(argv[0], "-d") == 0) {
103 114 ret = parse_files_in_dir(argv[1]);
104 115 exit(ret);
105 116 }
106 117 if (argc == 2 && strcmp(argv[0], "-f") == 0) {
107 118 ret = parse_file(argv[1]);
108 119 exit(ret);
109 120 }
110 121 if (argc == 3) {
111 122 ret = parse_params(argv[0], argv[1], argv[2], NULL, NULL, -1);
112 123 exit(ret);
113 124 }
114 125 if (argc == 4) {
115 126 ret = parse_params(argv[0], argv[1], argv[2], argv[3],
116 127 NULL, -1);
117 128 exit(ret);
118 129 }
119 130 usage();
120 131 exit(1);
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
121 132 /* NOTREACHED */
122 133 }
123 134
124 135 static void
125 136 usage(void)
126 137 {
127 138 fprintf(stderr, gettext(
128 139 "Usage: soconfig -d <dir>\n"
129 140 "\tsoconfig -f <file>\n"
130 141 "\tsoconfig <fam> <type> <protocol> <path|module>\n"
131 - "\tsoconfig <fam> <type> <protocol>\n"));
142 + "\tsoconfig <fam> <type> <protocol>\n"
143 + "\tsoconfig -l\n"));
132 144 }
133 145
134 146 /*
135 147 * Parse all files in the given directory.
136 148 */
137 149 static int
138 150 parse_files_in_dir(const char *dirname)
139 151 {
140 152 DIR *dp;
141 153 struct dirent *dirp;
142 154 struct stat stats;
143 155 char buf[MAXPATHLEN];
144 156
145 157 if ((dp = opendir(dirname)) == NULL) {
146 158 fprintf(stderr, gettext("failed to open directory '%s': %s\n"),
147 159 dirname, strerror(errno));
148 160 return (1);
149 161 }
150 162
151 163 while ((dirp = readdir(dp)) != NULL) {
152 164 if (dirp->d_name[0] == '.')
153 165 continue;
154 166
155 167 if (snprintf(buf, sizeof (buf), "%s/%s", dirname,
156 168 dirp->d_name) >= sizeof (buf)) {
157 169 fprintf(stderr,
158 170 gettext("path name is too long: %s/%s\n"),
159 171 dirname, dirp->d_name);
160 172 continue;
161 173 }
162 174 if (stat(buf, &stats) == -1) {
163 175 fprintf(stderr,
164 176 gettext("failed to stat '%s': %s\n"), buf,
165 177 strerror(errno));
166 178 continue;
167 179 }
168 180 if (!S_ISREG(stats.st_mode))
169 181 continue;
170 182
171 183 (void) parse_file(buf);
172 184 }
173 185
174 186 closedir(dp);
175 187
176 188 return (0);
177 189 }
178 190
179 191 /*
180 192 * Open the specified file and parse each line. Skip comments (everything
181 193 * after a '#'). Return 1 if at least one error was encountered; otherwise 0.
182 194 */
183 195 static int
184 196 parse_file(char *filename)
185 197 {
186 198 char line[MAXLINELEN];
187 199 char pline[MAXLINELEN];
188 200 int argcount;
189 201 char *argvec[20];
190 202 FILE *fp;
191 203 int linecount = 0;
192 204 int numerror = 0;
193 205
194 206 fp = fopen(filename, "r");
195 207 if (fp == NULL) {
196 208 perror("soconfig: open");
197 209 fprintf(stderr, "\n");
198 210 usage();
199 211 return (1);
200 212 }
201 213
202 214 while (fgets(line, sizeof (line) - 1, fp) != NULL) {
203 215 linecount++;
204 216 strcpy(pline, line);
205 217 argcount = split_line(pline, argvec,
206 218 sizeof (argvec) / sizeof (argvec[0]));
207 219 #ifdef DEBUG
208 220 {
209 221 int i;
210 222
211 223 printf("scanned %d args\n", argcount);
212 224 for (i = 0; i < argcount; i++)
213 225 printf("arg[%d]: %s\n", i, argvec[i]);
214 226 }
215 227 #endif /* DEBUG */
216 228 switch (argcount) {
217 229 case 0:
218 230 /* Empty line - or comment only line */
219 231 break;
220 232 case 3:
221 233 numerror += parse_params(argvec[0], argvec[1],
222 234 argvec[2], NULL, filename, linecount);
223 235 break;
224 236 case 4:
225 237 numerror += parse_params(argvec[0], argvec[1],
226 238 argvec[2], argvec[3], filename, linecount);
227 239 break;
228 240 default:
229 241 numerror++;
230 242 fprintf(stderr,
231 243 gettext("Malformed line: <%s>\n"), line);
232 244 fprintf(stderr,
233 245 gettext("\ton line %d in %s\n"), linecount,
234 246 filename);
235 247 break;
236 248 }
237 249 }
238 250 (void) fclose(fp);
239 251
240 252 if (numerror > 0)
241 253 return (1);
242 254 else
243 255 return (0);
244 256 }
245 257
246 258 /*
247 259 * Parse a line splitting it off at whitspace characters.
248 260 * Modifies the content of the string by inserting NULLs.
249 261 */
250 262 static int
251 263 split_line(char *line, char *argvec[], int maxargvec)
252 264 {
253 265 int i = 0;
254 266 char *cp;
255 267
256 268 /* Truncate at the beginning of a comment */
257 269 cp = strchr(line, '#');
258 270 if (cp != NULL)
259 271 *cp = NULL;
260 272
261 273 /* CONSTCOND */
262 274 while (1) {
263 275 /* Skip any whitespace */
264 276 while (isspace(*line) && *line != NULL)
265 277 line++;
266 278
267 279 if (i >= maxargvec)
268 280 return (i);
269 281
270 282 argvec[i] = line;
271 283 if (*line == NULL)
272 284 return (i);
273 285 i++;
274 286 /* Skip until next whitespace */
275 287 while (!isspace(*line) && *line != NULL)
276 288 line++;
277 289 if (*line != NULL) {
278 290 /* Break off argument */
279 291 *line++ = NULL;
280 292 }
281 293 }
282 294 /* NOTREACHED */
283 295 }
284 296
285 297 /*
286 298 * Parse the set of parameters and issues the sockconfig syscall.
287 299 * If line is not -1 it is assumed to be the line number in the file.
288 300 */
289 301 static int
290 302 parse_params(char *famstr, char *typestr, char *protostr, char *path,
291 303 const char *file, int line)
292 304 {
293 305 int cmd, fam, type, protocol;
294 306
295 307 fam = parse_int(famstr);
296 308 if (fam == -1) {
297 309 fprintf(stderr, gettext("Bad family number: %s\n"), famstr);
298 310 if (line != -1)
299 311 fprintf(stderr,
300 312 gettext("\ton line %d in %s\n"), line, file);
301 313 else {
302 314 fprintf(stderr, "\n");
303 315 usage();
304 316 }
305 317 return (1);
306 318 }
307 319
308 320 type = parse_int(typestr);
309 321 if (type == -1) {
310 322 fprintf(stderr,
311 323 gettext("Bad socket type number: %s\n"), typestr);
312 324 if (line != -1)
313 325 fprintf(stderr,
314 326 gettext("\ton line %d in %s\n"), line, file);
315 327 else {
316 328 fprintf(stderr, "\n");
317 329 usage();
318 330 }
319 331 return (1);
320 332 }
321 333
322 334 protocol = parse_int(protostr);
323 335 if (protocol == -1) {
324 336 fprintf(stderr,
325 337 gettext("Bad protocol number: %s\n"), protostr);
326 338 if (line != -1)
327 339 fprintf(stderr,
328 340 gettext("\ton line %d in %s\n"), line, file);
329 341 else {
330 342 fprintf(stderr, "\n");
331 343 usage();
332 344 }
333 345 return (1);
334 346 }
335 347
336 348
337 349 if (path != NULL) {
338 350 struct stat stats;
339 351
340 352 if (strncmp(path, "/dev", strlen("/dev")) == 0 &&
341 353 stat(path, &stats) == -1) {
342 354 perror(path);
343 355 if (line != -1)
344 356 fprintf(stderr,
345 357 gettext("\ton line %d in %s\n"), line,
346 358 file);
347 359 else {
348 360 fprintf(stderr, "\n");
349 361 usage();
350 362 }
351 363 return (1);
352 364 }
353 365
354 366 cmd = SOCKCONFIG_ADD_SOCK;
355 367 } else {
356 368 cmd = SOCKCONFIG_REMOVE_SOCK;
357 369 }
358 370
359 371 #ifdef DEBUG
360 372 printf("not calling sockconfig(%d, %d, %d, %d, %s)\n",
361 373 cmd, fam, type, protocol, path == NULL ? "(null)" : path);
362 374 #else
363 375 if (_sockconfig(cmd, fam, type, protocol, path) == -1) {
364 376 char *s;
365 377
366 378 switch (errno) {
367 379 case EEXIST:
368 380 s = gettext("Mapping exists");
369 381 break;
370 382 default:
371 383 s = strerror(errno);
372 384 break;
373 385 }
374 386
375 387 fprintf(stderr,
376 388 gettext("warning: socket configuration failed "
377 389 "for family %d type %d protocol %d: %s\n"),
378 390 fam, type, protocol, s);
379 391 if (line != -1) {
380 392 fprintf(stderr,
381 393 gettext("\ton line %d in %s\n"), line, file);
382 394 }
383 395 return (1);
384 396 }
385 397 #endif
386 398 return (0);
387 399 }
388 400
389 401 static int
390 402 parse_int(char *str)
391 403 {
392 404 char *end;
393 405 int res;
394 406
395 407 res = strtol(str, &end, 0);
396 408 if (end == str)
397 409 return (-1);
398 410 return (res);
399 411 }
400 412
401 413 /*
402 414 * Add and remove socket filters.
403 415 */
404 416 static int
405 417 parse_filter_params(int argc, char **argv)
406 418 {
407 419 struct sockconfig_filter_props filprop;
408 420 sof_socktuple_t *socktuples;
409 421 size_t tupcnt, nalloc;
410 422 char *hintarg, *socktup, *tupstr;
411 423 int i;
412 424
413 425 if (argc == 1) {
414 426 if (_sockconfig(SOCKCONFIG_REMOVE_FILTER, argv[0], 0,
415 427 0, 0) < 0) {
416 428 switch (errno) {
417 429 case ENXIO:
418 430 fprintf(stderr,
419 431 gettext("socket filter is not configured "
420 432 "'%s'\n"), argv[0]);
421 433 break;
422 434 default:
423 435 perror("sockconfig");
424 436 break;
425 437 }
426 438 return (1);
427 439 }
428 440 return (0);
429 441 }
430 442
431 443 if (argc < 4 || argc > 5)
432 444 return (1);
433 445
434 446
435 447 if (strlen(argv[1]) >= MODMAXNAMELEN) {
436 448 fprintf(stderr,
437 449 gettext("invalid module name '%s': name too long\n"),
438 450 argv[1]);
439 451 return (1);
440 452 }
441 453 filprop.sfp_modname = argv[1];
442 454
443 455 /* Check the attach semantics */
444 456 if (strcmp(argv[2], "auto") == 0) {
445 457 filprop.sfp_autoattach = B_TRUE;
446 458 if (argc == 5) {
447 459 /* placement hint */
448 460 if (strcmp(argv[3], "top") == 0) {
449 461 filprop.sfp_hint = SOF_HINT_TOP;
450 462 } else if (strcmp(argv[3], "bottom") == 0) {
451 463 filprop.sfp_hint = SOF_HINT_BOTTOM;
452 464 } else {
453 465 if (strncmp(argv[3], "before", 6) == 0) {
454 466 filprop.sfp_hint = SOF_HINT_BEFORE;
455 467 } else if (strncmp(argv[3], "after", 5) == 0) {
456 468 filprop.sfp_hint = SOF_HINT_AFTER;
457 469 } else {
458 470 fprintf(stderr,
459 471 gettext("invalid placement hint "
460 472 "'%s'\n"), argv[3]);
461 473 return (1);
462 474 }
463 475
464 476 hintarg = strchr(argv[3], ':');
465 477 if (hintarg == NULL ||
466 478 (strlen(++hintarg) == 0) ||
467 479 (strlen(hintarg) >= FILNAME_MAX)) {
468 480 fprintf(stderr,
469 481 gettext("invalid placement hint "
470 482 "argument '%s': name too long\n"),
471 483 argv[3]);
472 484 return (1);
473 485 }
474 486
475 487 filprop.sfp_hintarg = hintarg;
476 488 }
477 489 } else {
478 490 filprop.sfp_hint = SOF_HINT_NONE;
479 491 }
480 492 } else if (strcmp(argv[2], "prog") == 0) {
481 493 filprop.sfp_autoattach = B_FALSE;
482 494 filprop.sfp_hint = SOF_HINT_NONE;
483 495 /* cannot specify placement hint for programmatic filter */
484 496 if (argc == 5) {
485 497 fprintf(stderr,
486 498 gettext("placement hint specified for programmatic "
487 499 "filter\n"));
488 500 return (1);
489 501 }
490 502 } else {
491 503 fprintf(stderr, gettext("invalid attach semantic '%s'\n"),
492 504 argv[2]);
493 505 return (1);
494 506 }
495 507
496 508 /* parse the socket tuples */
497 509 nalloc = 4;
498 510 socktuples = calloc(nalloc, sizeof (sof_socktuple_t));
499 511 if (socktuples == NULL) {
500 512 perror("calloc");
501 513 return (1);
502 514 }
503 515
504 516 tupcnt = 0;
505 517 tupstr = argv[(argc == 4) ? 3 : 4];
506 518 while ((socktup = strsep(&tupstr, ",")) != NULL) {
507 519 int val;
508 520 char *valstr;
509 521
510 522 if (tupcnt == nalloc) {
511 523 sof_socktuple_t *new;
512 524
513 525 nalloc *= 2;
514 526 new = realloc(socktuples,
515 527 nalloc * sizeof (sof_socktuple_t));
516 528 if (new == NULL) {
517 529 perror("realloc");
518 530 free(socktuples);
519 531 return (1);
520 532 }
521 533 socktuples = new;
522 534 }
523 535 i = 0;
524 536 while ((valstr = strsep(&socktup, ":")) != NULL && i < 3) {
525 537 val = parse_int(valstr);
526 538 if (val == -1) {
527 539 fprintf(stderr, gettext("bad socket tuple\n"));
528 540 free(socktuples);
529 541 return (1);
530 542 }
531 543 switch (i) {
532 544 case 0: socktuples[tupcnt].sofst_family = val; break;
533 545 case 1: socktuples[tupcnt].sofst_type = val; break;
534 546 case 2: socktuples[tupcnt].sofst_protocol = val; break;
535 547 }
536 548 i++;
537 549 }
538 550 if (i != 3) {
539 551 fprintf(stderr, gettext("bad socket tuple\n"));
540 552 free(socktuples);
541 553 return (1);
542 554 }
543 555 tupcnt++;
544 556 }
545 557 if (tupcnt == 0) {
546 558 fprintf(stderr, gettext("no socket tuples specified\n"));
547 559 free(socktuples);
548 560 return (1);
549 561 }
550 562 filprop.sfp_socktuple_cnt = tupcnt;
551 563 filprop.sfp_socktuple = socktuples;
552 564
553 565 if (_sockconfig(SOCKCONFIG_ADD_FILTER, argv[0], &filprop, 0, 0) < 0) {
554 566 switch (errno) {
555 567 case EINVAL:
556 568 fprintf(stderr,
557 569 gettext("invalid socket filter configuration\n"));
558 570 break;
559 571 case EEXIST:
560 572 fprintf(stderr,
561 573 gettext("socket filter is already configured "
562 574 "'%s'\n"), argv[0]);
563 575 break;
564 576 case ENOSPC:
565 577 fprintf(stderr, gettext("unable to satisfy placement "
566 578 "constraint\n"));
567 579 break;
↓ open down ↓ |
426 lines elided |
↑ open up ↑ |
568 580 default:
569 581 perror("sockconfig");
570 582 break;
571 583 }
572 584 free(socktuples);
573 585 return (1);
574 586 }
575 587 free(socktuples);
576 588 return (0);
577 589 }
590 +
591 +/*
592 + * Print the in-kernel socket configuration table
593 + */
594 +
595 +static int
596 +print_socktable()
597 +{
598 + sockconfig_socktable_t sc_table;
599 + int i;
600 +
601 + (void) memset(&sc_table, 0, sizeof (sockconfig_socktable_t));
602 +
603 + /* get number of entries */
604 + if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table) == -1) {
605 + fprintf(stderr,
606 + gettext("cannot get in-kernel socket table: %s\n"),
607 + strerror(errno));
608 + return (-1);
609 + }
610 + if (sc_table.num_of_entries == 0)
611 + return (0);
612 +
613 + sc_table.st_entries = calloc(sc_table.num_of_entries,
614 + sizeof (sockconfig_socktable_entry_t));
615 + if (sc_table.st_entries == NULL) {
616 + fprintf(stderr, gettext("out of memory\n"));
617 + return (-1);
618 + }
619 +
620 + /* get socket table entries */
621 + if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE, &sc_table) == -1) {
622 + fprintf(stderr,
623 + gettext("cannot get in-kernel socket table: %s\n"),
624 + strerror(errno));
625 + return (-1);
626 + }
627 +
628 + printf("%6s %4s %5s %15s %15s %6s %6s\n",
629 + "FAMILY", "TYPE", "PROTO", "STRDEV", "SOCKMOD",
630 + "REFS", "FLAGS");
631 + for (i = 0; i < sc_table.num_of_entries; i++) {
632 + printf("%6u %4u %5u %15s %15s %6u %#6x\n",
633 + sc_table.st_entries[i].se_family,
634 + sc_table.st_entries[i].se_type,
635 + sc_table.st_entries[i].se_protocol,
636 + (strcmp(sc_table.st_entries[i].se_modname,
637 + "socktpi") == 0) ?
638 + sc_table.st_entries[i].se_strdev : "-",
639 + sc_table.st_entries[i].se_modname,
640 + sc_table.st_entries[i].se_refcnt,
641 + sc_table.st_entries[i].se_flags);
642 + }
643 + free(sc_table.st_entries);
644 + return (0);
645 +}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX