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
40 int _sockconfig(int, void *, void *, void *, void *);
45 * Reads input from files in dir.
48 * Reads input from file. The file is structured as
49 * <fam> <type> <protocol> <path|module>
50 * <fam> <type> <protocol>
51 * with the first line registering and the second line
54 * soconfig <fam> <type> <protocol> <path|module>
57 * soconfig <fam> <type> <protocol>
61 * print the in-kernel socket configuration table
63 * Filter Operations (Consolidation Private):
65 * soconfig -F <name> <modname> {auto [top | bottom | before:filter |
66 * after:filter] | prog} <fam>:<type>:<proto>,...
73 static int parse_files_in_dir(const char *dir
);
75 static int parse_file(char *filename
);
77 static int split_line(char *line
, char *argvec
[], int maxargvec
);
79 static int parse_params(char *famstr
, char *typestr
, char *protostr
,
80 char *path
, const char *file
, int line
);
82 static int parse_int(char *str
);
84 static void usage(void);
86 static int parse_filter_params(int argc
, char **argv
);
88 static int print_socktable();
99 (void) setlocale(LC_ALL
, "");
100 #if !defined(TEXT_DOMAIN)
101 #define TEXT_DOMAIN "SYS_TEST"
103 (void) textdomain(TEXT_DOMAIN
);
105 if (argc
== 1 && strcmp(argv
[0], "-l") == 0) {
106 ret
= print_socktable();
110 if (argc
>= 2 && strcmp(argv
[0], "-F") == 0) {
112 ret
= parse_filter_params(argc
, argv
);
115 if (argc
== 2 && strcmp(argv
[0], "-d") == 0) {
116 ret
= parse_files_in_dir(argv
[1]);
119 if (argc
== 2 && strcmp(argv
[0], "-f") == 0) {
120 ret
= parse_file(argv
[1]);
124 ret
= parse_params(argv
[0], argv
[1], argv
[2], NULL
, NULL
, -1);
128 ret
= parse_params(argv
[0], argv
[1], argv
[2], argv
[3],
140 fprintf(stderr
, gettext(
141 "Usage: soconfig -d <dir>\n"
142 "\tsoconfig -f <file>\n"
143 "\tsoconfig <fam> <type> <protocol> <path|module>\n"
144 "\tsoconfig <fam> <type> <protocol>\n"
149 * Parse all files in the given directory.
152 parse_files_in_dir(const char *dirname
)
157 char buf
[MAXPATHLEN
];
159 if ((dp
= opendir(dirname
)) == NULL
) {
160 fprintf(stderr
, gettext("failed to open directory '%s': %s\n"),
161 dirname
, strerror(errno
));
165 while ((dirp
= readdir(dp
)) != NULL
) {
166 if (dirp
->d_name
[0] == '.')
169 if (snprintf(buf
, sizeof (buf
), "%s/%s", dirname
,
170 dirp
->d_name
) >= sizeof (buf
)) {
172 gettext("path name is too long: %s/%s\n"),
173 dirname
, dirp
->d_name
);
176 if (stat(buf
, &stats
) == -1) {
178 gettext("failed to stat '%s': %s\n"), buf
,
182 if (!S_ISREG(stats
.st_mode
))
185 (void) parse_file(buf
);
194 * Open the specified file and parse each line. Skip comments (everything
195 * after a '#'). Return 1 if at least one error was encountered; otherwise 0.
198 parse_file(char *filename
)
200 char line
[MAXLINELEN
];
201 char pline
[MAXLINELEN
];
208 fp
= fopen(filename
, "r");
210 perror("soconfig: open");
211 fprintf(stderr
, "\n");
216 while (fgets(line
, sizeof (line
) - 1, fp
) != NULL
) {
219 argcount
= split_line(pline
, argvec
,
220 sizeof (argvec
) / sizeof (argvec
[0]));
225 printf("scanned %d args\n", argcount
);
226 for (i
= 0; i
< argcount
; i
++)
227 printf("arg[%d]: %s\n", i
, argvec
[i
]);
232 /* Empty line - or comment only line */
235 numerror
+= parse_params(argvec
[0], argvec
[1],
236 argvec
[2], NULL
, filename
, linecount
);
239 numerror
+= parse_params(argvec
[0], argvec
[1],
240 argvec
[2], argvec
[3], filename
, linecount
);
245 gettext("Malformed line: <%s>\n"), line
);
247 gettext("\ton line %d in %s\n"), linecount
,
261 * Parse a line splitting it off at whitspace characters.
262 * Modifies the content of the string by inserting NULLs.
265 split_line(char *line
, char *argvec
[], int maxargvec
)
270 /* Truncate at the beginning of a comment */
271 cp
= strchr(line
, '#');
277 /* Skip any whitespace */
278 while (isspace(*line
) && *line
!= '\0')
288 /* Skip until next whitespace */
289 while (!isspace(*line
) && *line
!= '\0')
292 /* Break off argument */
300 * Parse the set of parameters and issues the sockconfig syscall.
301 * If line is not -1 it is assumed to be the line number in the file.
304 parse_params(char *famstr
, char *typestr
, char *protostr
, char *path
,
305 const char *file
, int line
)
307 int cmd
, fam
, type
, protocol
;
309 fam
= parse_int(famstr
);
311 fprintf(stderr
, gettext("Bad family number: %s\n"), famstr
);
314 gettext("\ton line %d in %s\n"), line
, file
);
316 fprintf(stderr
, "\n");
322 type
= parse_int(typestr
);
325 gettext("Bad socket type number: %s\n"), typestr
);
328 gettext("\ton line %d in %s\n"), line
, file
);
330 fprintf(stderr
, "\n");
336 protocol
= parse_int(protostr
);
337 if (protocol
== -1) {
339 gettext("Bad protocol number: %s\n"), protostr
);
342 gettext("\ton line %d in %s\n"), line
, file
);
344 fprintf(stderr
, "\n");
354 if (strncmp(path
, "/dev", strlen("/dev")) == 0 &&
355 stat(path
, &stats
) == -1) {
359 gettext("\ton line %d in %s\n"), line
,
362 fprintf(stderr
, "\n");
368 cmd
= SOCKCONFIG_ADD_SOCK
;
370 cmd
= SOCKCONFIG_REMOVE_SOCK
;
374 printf("not calling sockconfig(%d, %d, %d, %d, %s)\n",
375 cmd
, fam
, type
, protocol
, path
== NULL
? "(null)" : path
);
377 if (_sockconfig(cmd
, (void *)fam
, (void *)type
, (void *)protocol
, (void *)path
) == -1) {
382 s
= gettext("Mapping exists");
390 gettext("warning: socket configuration failed "
391 "for family %d type %d protocol %d: %s\n"),
392 fam
, type
, protocol
, s
);
395 gettext("\ton line %d in %s\n"), line
, file
);
409 res
= strtol(str
, &end
, 0);
416 * Add and remove socket filters.
419 parse_filter_params(int argc
, char **argv
)
421 struct sockconfig_filter_props filprop
;
422 sof_socktuple_t
*socktuples
;
423 size_t tupcnt
, nalloc
;
424 char *hintarg
, *socktup
, *tupstr
;
428 if (_sockconfig(SOCKCONFIG_REMOVE_FILTER
, argv
[0], NULL
,
433 gettext("socket filter is not configured "
437 perror("sockconfig");
445 if (argc
< 4 || argc
> 5)
449 if (strlen(argv
[1]) >= MODMAXNAMELEN
) {
451 gettext("invalid module name '%s': name too long\n"),
455 filprop
.sfp_modname
= argv
[1];
457 /* Check the attach semantics */
458 if (strcmp(argv
[2], "auto") == 0) {
459 filprop
.sfp_autoattach
= B_TRUE
;
462 if (strcmp(argv
[3], "top") == 0) {
463 filprop
.sfp_hint
= SOF_HINT_TOP
;
464 } else if (strcmp(argv
[3], "bottom") == 0) {
465 filprop
.sfp_hint
= SOF_HINT_BOTTOM
;
467 if (strncmp(argv
[3], "before", 6) == 0) {
468 filprop
.sfp_hint
= SOF_HINT_BEFORE
;
469 } else if (strncmp(argv
[3], "after", 5) == 0) {
470 filprop
.sfp_hint
= SOF_HINT_AFTER
;
473 gettext("invalid placement hint "
478 hintarg
= strchr(argv
[3], ':');
479 if (hintarg
== NULL
||
480 (strlen(++hintarg
) == 0) ||
481 (strlen(hintarg
) >= FILNAME_MAX
)) {
483 gettext("invalid placement hint "
484 "argument '%s': name too long\n"),
489 filprop
.sfp_hintarg
= hintarg
;
492 filprop
.sfp_hint
= SOF_HINT_NONE
;
494 } else if (strcmp(argv
[2], "prog") == 0) {
495 filprop
.sfp_autoattach
= B_FALSE
;
496 filprop
.sfp_hint
= SOF_HINT_NONE
;
497 /* cannot specify placement hint for programmatic filter */
500 gettext("placement hint specified for programmatic "
505 fprintf(stderr
, gettext("invalid attach semantic '%s'\n"),
510 /* parse the socket tuples */
512 socktuples
= calloc(nalloc
, sizeof (sof_socktuple_t
));
513 if (socktuples
== NULL
) {
519 tupstr
= argv
[(argc
== 4) ? 3 : 4];
520 while ((socktup
= strsep(&tupstr
, ",")) != NULL
) {
524 if (tupcnt
== nalloc
) {
525 sof_socktuple_t
*new;
528 new = reallocarray(socktuples
, nalloc
,
529 sizeof (sof_socktuple_t
));
538 while ((valstr
= strsep(&socktup
, ":")) != NULL
&& i
< 3) {
539 val
= parse_int(valstr
);
541 fprintf(stderr
, gettext("bad socket tuple\n"));
546 case 0: socktuples
[tupcnt
].sofst_family
= val
; break;
547 case 1: socktuples
[tupcnt
].sofst_type
= val
; break;
548 case 2: socktuples
[tupcnt
].sofst_protocol
= val
; break;
553 fprintf(stderr
, gettext("bad socket tuple\n"));
560 fprintf(stderr
, gettext("no socket tuples specified\n"));
564 filprop
.sfp_socktuple_cnt
= tupcnt
;
565 filprop
.sfp_socktuple
= socktuples
;
567 if (_sockconfig(SOCKCONFIG_ADD_FILTER
, argv
[0], &filprop
, NULL
, NULL
) < 0) {
571 gettext("invalid socket filter configuration\n"));
575 gettext("socket filter is already configured "
579 fprintf(stderr
, gettext("unable to satisfy placement "
583 perror("sockconfig");
594 * Print the in-kernel socket configuration table
600 sockconfig_socktable_t sc_table
;
603 (void) memset(&sc_table
, 0, sizeof (sockconfig_socktable_t
));
605 /* get number of entries */
606 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE
, &sc_table
, NULL
, NULL
, NULL
) == -1) {
608 gettext("cannot get in-kernel socket table: %s\n"),
612 if (sc_table
.num_of_entries
== 0)
615 sc_table
.st_entries
= calloc(sc_table
.num_of_entries
,
616 sizeof (sockconfig_socktable_entry_t
));
617 if (sc_table
.st_entries
== NULL
) {
618 fprintf(stderr
, gettext("out of memory\n"));
622 /* get socket table entries */
623 if (_sockconfig(SOCKCONFIG_GET_SOCKTABLE
, &sc_table
, NULL
, NULL
, NULL
) == -1) {
625 gettext("cannot get in-kernel socket table: %s\n"),
630 printf("%6s %4s %5s %15s %15s %6s %6s\n",
631 "FAMILY", "TYPE", "PROTO", "STRDEV", "SOCKMOD",
633 for (i
= 0; i
< sc_table
.num_of_entries
; i
++) {
634 printf("%6u %4u %5u %15s %15s %6u %#6x\n",
635 sc_table
.st_entries
[i
].se_family
,
636 sc_table
.st_entries
[i
].se_type
,
637 sc_table
.st_entries
[i
].se_protocol
,
638 (strcmp(sc_table
.st_entries
[i
].se_modname
,
640 sc_table
.st_entries
[i
].se_strdev
: "-",
641 sc_table
.st_entries
[i
].se_modname
,
642 sc_table
.st_entries
[i
].se_refcnt
,
643 sc_table
.st_entries
[i
].se_flags
);
645 free(sc_table
.st_entries
);