4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
38 #define MAXLINELEN 4096
43 * Reads input from files in dir.
46 * Reads input from file. The file is structured as
47 * <fam> <type> <protocol> <path|module>
48 * <fam> <type> <protocol>
49 * with the first line registering and the second line
52 * soconfig <fam> <type> <protocol> <path|module>
55 * soconfig <fam> <type> <protocol>
59 * print the in-kernel socket configuration table
61 * Filter Operations (Consolidation Private):
63 * soconfig -F <name> <modname> {auto [top | bottom | before:filter |
64 * after:filter] | prog} <fam>:<type>:<proto>,...
71 static int parse_files_in_dir(const char *dir
);
73 static int parse_file(char *filename
);
75 static int split_line(char *line
, char *argvec
[], int maxargvec
);
77 static int parse_params(char *famstr
, char *typestr
, char *protostr
,
78 char *path
, const char *file
, int line
);
80 static int parse_int(char *str
);
82 static void usage(void);
84 static int parse_filter_params(int argc
, char **argv
);
86 static int print_socktable();
97 (void) setlocale(LC_ALL
, "");
98 #if !defined(TEXT_DOMAIN)
99 #define TEXT_DOMAIN "SYS_TEST"
101 (void) textdomain(TEXT_DOMAIN
);
103 if (argc
== 1 && strcmp(argv
[0], "-l") == 0) {
104 ret
= print_socktable();
108 if (argc
>= 2 && strcmp(argv
[0], "-F") == 0) {
110 ret
= parse_filter_params(argc
, argv
);
113 if (argc
== 2 && strcmp(argv
[0], "-d") == 0) {
114 ret
= parse_files_in_dir(argv
[1]);
117 if (argc
== 2 && strcmp(argv
[0], "-f") == 0) {
118 ret
= parse_file(argv
[1]);
122 ret
= parse_params(argv
[0], argv
[1], argv
[2], NULL
, NULL
, -1);
126 ret
= parse_params(argv
[0], argv
[1], argv
[2], argv
[3],
138 fprintf(stderr
, gettext(
139 "Usage: soconfig -d <dir>\n"
140 "\tsoconfig -f <file>\n"
141 "\tsoconfig <fam> <type> <protocol> <path|module>\n"
142 "\tsoconfig <fam> <type> <protocol>\n"
147 * Parse all files in the given directory.
150 parse_files_in_dir(const char *dirname
)
155 char buf
[MAXPATHLEN
];
157 if ((dp
= opendir(dirname
)) == NULL
) {
158 fprintf(stderr
, gettext("failed to open directory '%s': %s\n"),
159 dirname
, strerror(errno
));
163 while ((dirp
= readdir(dp
)) != NULL
) {
164 if (dirp
->d_name
[0] == '.')
167 if (snprintf(buf
, sizeof (buf
), "%s/%s", dirname
,
168 dirp
->d_name
) >= sizeof (buf
)) {
170 gettext("path name is too long: %s/%s\n"),
171 dirname
, dirp
->d_name
);
174 if (stat(buf
, &stats
) == -1) {
176 gettext("failed to stat '%s': %s\n"), buf
,
180 if (!S_ISREG(stats
.st_mode
))
183 (void) parse_file(buf
);
192 * Open the specified file and parse each line. Skip comments (everything
193 * after a '#'). Return 1 if at least one error was encountered; otherwise 0.
196 parse_file(char *filename
)
198 char line
[MAXLINELEN
];
199 char pline
[MAXLINELEN
];
206 fp
= fopen(filename
, "r");
208 perror("soconfig: open");
209 fprintf(stderr
, "\n");
214 while (fgets(line
, sizeof (line
) - 1, fp
) != NULL
) {
217 argcount
= split_line(pline
, argvec
,
218 sizeof (argvec
) / sizeof (argvec
[0]));
223 printf("scanned %d args\n", argcount
);
224 for (i
= 0; i
< argcount
; i
++)
225 printf("arg[%d]: %s\n", i
, argvec
[i
]);
230 /* Empty line - or comment only line */
233 numerror
+= parse_params(argvec
[0], argvec
[1],
234 argvec
[2], NULL
, filename
, linecount
);
237 numerror
+= parse_params(argvec
[0], argvec
[1],
238 argvec
[2], argvec
[3], filename
, linecount
);
243 gettext("Malformed line: <%s>\n"), line
);
245 gettext("\ton line %d in %s\n"), linecount
,
259 * Parse a line splitting it off at whitspace characters.
260 * Modifies the content of the string by inserting NULLs.
263 split_line(char *line
, char *argvec
[], int maxargvec
)
268 /* Truncate at the beginning of a comment */
269 cp
= strchr(line
, '#');
275 /* Skip any whitespace */
276 while (isspace(*line
) && *line
!= '\0')
286 /* Skip until next whitespace */
287 while (!isspace(*line
) && *line
!= '\0')
290 /* Break off argument */
298 * Parse the set of parameters and issues the sockconfig syscall.
299 * If line is not -1 it is assumed to be the line number in the file.
302 parse_params(char *famstr
, char *typestr
, char *protostr
, char *path
,
303 const char *file
, int line
)
305 int cmd
, fam
, type
, protocol
;
307 fam
= parse_int(famstr
);
309 fprintf(stderr
, gettext("Bad family number: %s\n"), famstr
);
312 gettext("\ton line %d in %s\n"), line
, file
);
314 fprintf(stderr
, "\n");
320 type
= parse_int(typestr
);
323 gettext("Bad socket type number: %s\n"), typestr
);
326 gettext("\ton line %d in %s\n"), line
, file
);
328 fprintf(stderr
, "\n");
334 protocol
= parse_int(protostr
);
335 if (protocol
== -1) {
337 gettext("Bad protocol number: %s\n"), protostr
);
340 gettext("\ton line %d in %s\n"), line
, file
);
342 fprintf(stderr
, "\n");
352 if (strncmp(path
, "/dev", strlen("/dev")) == 0 &&
353 stat(path
, &stats
) == -1) {
357 gettext("\ton line %d in %s\n"), line
,
360 fprintf(stderr
, "\n");
366 cmd
= SOCKCONFIG_ADD_SOCK
;
368 cmd
= SOCKCONFIG_REMOVE_SOCK
;
372 printf("not calling sockconfig(%d, %d, %d, %d, %s)\n",
373 cmd
, fam
, type
, protocol
, path
== NULL
? "(null)" : path
);
375 if (_sockconfig(cmd
, fam
, type
, protocol
, path
) == -1) {
380 s
= gettext("Mapping exists");
388 gettext("warning: socket configuration failed "
389 "for family %d type %d protocol %d: %s\n"),
390 fam
, type
, protocol
, s
);
393 gettext("\ton line %d in %s\n"), line
, file
);
407 res
= strtol(str
, &end
, 0);
414 * Add and remove socket filters.
417 parse_filter_params(int argc
, char **argv
)
419 struct sockconfig_filter_props filprop
;
420 sof_socktuple_t
*socktuples
;
421 size_t tupcnt
, nalloc
;
422 char *hintarg
, *socktup
, *tupstr
;
426 if (_sockconfig(SOCKCONFIG_REMOVE_FILTER
, argv
[0], 0,
431 gettext("socket filter is not configured "
435 perror("sockconfig");
443 if (argc
< 4 || argc
> 5)
447 if (strlen(argv
[1]) >= MODMAXNAMELEN
) {
449 gettext("invalid module name '%s': name too long\n"),
453 filprop
.sfp_modname
= argv
[1];
455 /* Check the attach semantics */
456 if (strcmp(argv
[2], "auto") == 0) {
457 filprop
.sfp_autoattach
= B_TRUE
;
460 if (strcmp(argv
[3], "top") == 0) {
461 filprop
.sfp_hint
= SOF_HINT_TOP
;
462 } else if (strcmp(argv
[3], "bottom") == 0) {
463 filprop
.sfp_hint
= SOF_HINT_BOTTOM
;
465 if (strncmp(argv
[3], "before", 6) == 0) {
466 filprop
.sfp_hint
= SOF_HINT_BEFORE
;
467 } else if (strncmp(argv
[3], "after", 5) == 0) {
468 filprop
.sfp_hint
= SOF_HINT_AFTER
;
471 gettext("invalid placement hint "
476 hintarg
= strchr(argv
[3], ':');
477 if (hintarg
== NULL
||
478 (strlen(++hintarg
) == 0) ||
479 (strlen(hintarg
) >= FILNAME_MAX
)) {
481 gettext("invalid placement hint "
482 "argument '%s': name too long\n"),
487 filprop
.sfp_hintarg
= hintarg
;
490 filprop
.sfp_hint
= SOF_HINT_NONE
;
492 } else if (strcmp(argv
[2], "prog") == 0) {
493 filprop
.sfp_autoattach
= B_FALSE
;
494 filprop
.sfp_hint
= SOF_HINT_NONE
;
495 /* cannot specify placement hint for programmatic filter */
498 gettext("placement hint specified for programmatic "
503 fprintf(stderr
, gettext("invalid attach semantic '%s'\n"),
508 /* parse the socket tuples */
510 socktuples
= calloc(nalloc
, sizeof (sof_socktuple_t
));
511 if (socktuples
== NULL
) {
517 tupstr
= argv
[(argc
== 4) ? 3 : 4];
518 while ((socktup
= strsep(&tupstr
, ",")) != NULL
) {
522 if (tupcnt
== nalloc
) {
523 sof_socktuple_t
*new;
526 new = reallocarray(socktuples
, nalloc
,
527 sizeof (sof_socktuple_t
));
536 while ((valstr
= strsep(&socktup
, ":")) != NULL
&& i
< 3) {
537 val
= parse_int(valstr
);
539 fprintf(stderr
, gettext("bad socket tuple\n"));
544 case 0: socktuples
[tupcnt
].sofst_family
= val
; break;
545 case 1: socktuples
[tupcnt
].sofst_type
= val
; break;
546 case 2: socktuples
[tupcnt
].sofst_protocol
= val
; break;
551 fprintf(stderr
, gettext("bad socket tuple\n"));
558 fprintf(stderr
, gettext("no socket tuples specified\n"));
562 filprop
.sfp_socktuple_cnt
= tupcnt
;
563 filprop
.sfp_socktuple
= socktuples
;
565 if (_sockconfig(SOCKCONFIG_ADD_FILTER
, argv
[0], &filprop
, 0, 0) < 0) {
569 gettext("invalid socket filter configuration\n"));
573 gettext("socket filter is already configured "
577 fprintf(stderr
, gettext("unable to satisfy placement "
581 perror("sockconfig");
592 * Print the in-kernel socket configuration table
598 sockconfig_socktable_t sc_table
;
601 (void) memset(&sc_table
, 0, sizeof (sockconfig_socktable_t
));
603 /* get number of entries */
604 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE
, &sc_table
) == -1) {
606 gettext("cannot get in-kernel socket table: %s\n"),
610 if (sc_table
.num_of_entries
== 0)
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"));
620 /* get socket table entries */
621 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE
, &sc_table
) == -1) {
623 gettext("cannot get in-kernel socket table: %s\n"),
628 printf("%6s %4s %5s %15s %15s %6s %6s\n",
629 "FAMILY", "TYPE", "PROTO", "STRDEV", "SOCKMOD",
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
,
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
);
643 free(sc_table
.st_entries
);