pflow: show socket status in verbose mode

Introduce a verbose output mode to pflowctl, and expose the status of
the socket to userspace. This can be helpful in debugging configuration
errors.

Sponsored by:	Rubicon Communications, LLC ("Netgate")
This commit is contained in:
Kristof Provost 2024-01-25 17:37:51 +01:00
parent b8a484ec34
commit e95025ed93
4 changed files with 53 additions and 8 deletions

View File

@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 08 2024 $ .Dd $Mdocdate: January 25 2024 $
.Dt PFLOWCTL 8 .Dt PFLOWCTL 8
.Os .Os
.Sh NAME .Sh NAME
@ -24,6 +24,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm pflowctl .Nm pflowctl
.Bk -words .Bk -words
.Op Fl v
.Op Fl lc .Op Fl lc
.Op Fl d Ar id .Op Fl d Ar id
.Op Fl s Ar id ... .Op Fl s Ar id ...
@ -40,6 +41,8 @@ The
utility provides several commands. utility provides several commands.
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl v
Produce verbose output.
.It Fl c .It Fl c
Create a new Create a new
.Xr pflow 4 .Xr pflow 4

View File

@ -47,13 +47,15 @@
static int get(int id); static int get(int id);
static bool verbose = false;
extern char *__progname; extern char *__progname;
static void static void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: %s [-lc] [-d id] [-s id ...]\n", "usage: %s [-lc] [-d id] [-s id ...] [-v]\n",
__progname); __progname);
exit(1); exit(1);
@ -253,6 +255,7 @@ struct pflowctl_get {
struct pflowctl_sockaddr src; struct pflowctl_sockaddr src;
struct pflowctl_sockaddr dst; struct pflowctl_sockaddr dst;
uint32_t obs_dom; uint32_t obs_dom;
uint8_t so_status;
}; };
#define _IN(_field) offsetof(struct genlmsghdr, _field) #define _IN(_field) offsetof(struct genlmsghdr, _field)
#define _OUT(_field) offsetof(struct pflowctl_get, _field) #define _OUT(_field) offsetof(struct pflowctl_get, _field)
@ -262,6 +265,7 @@ static struct snl_attr_parser ap_get[] = {
{ .type = PFLOWNL_GET_SRC, .off = _OUT(src), .arg = &sockaddr_parser, .cb = snl_attr_get_nested }, { .type = PFLOWNL_GET_SRC, .off = _OUT(src), .arg = &sockaddr_parser, .cb = snl_attr_get_nested },
{ .type = PFLOWNL_GET_DST, .off = _OUT(dst), .arg = &sockaddr_parser, .cb = snl_attr_get_nested }, { .type = PFLOWNL_GET_DST, .off = _OUT(dst), .arg = &sockaddr_parser, .cb = snl_attr_get_nested },
{ .type = PFLOWNL_GET_OBSERVATION_DOMAIN, .off = _OUT(obs_dom), .cb = snl_attr_get_uint32 }, { .type = PFLOWNL_GET_OBSERVATION_DOMAIN, .off = _OUT(obs_dom), .cb = snl_attr_get_uint32 },
{ .type = PFLOWNL_GET_SOCKET_STATUS, .off = _OUT(so_status), .cb = snl_attr_get_uint8 },
}; };
static struct snl_field_parser fp_get[] = {}; static struct snl_field_parser fp_get[] = {};
#undef _IN #undef _IN
@ -344,6 +348,10 @@ get(int id)
print_sockaddr(" src ", &g.src.storage); print_sockaddr(" src ", &g.src.storage);
print_sockaddr(" dst ", &g.dst.storage); print_sockaddr(" dst ", &g.dst.storage);
printf("\n"); printf("\n");
if (verbose) {
printf("\tsocket: %s\n",
g.so_status ? "connected" : "disconnected");
}
} }
if (e.error) if (e.error)
@ -533,10 +541,20 @@ static const struct snl_hdr_parser *all_parsers[] = {
&get_parser, &get_parser,
}; };
enum pflowctl_op_t {
OP_HELP,
OP_LIST,
OP_CREATE,
OP_DELETE,
OP_SET,
};
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int ch; int ch;
enum pflowctl_op_t op = OP_HELP;
char **set_args = NULL;
size_t set_arg_count = 0;
SNL_VERIFY_PARSERS(all_parsers); SNL_VERIFY_PARSERS(all_parsers);
@ -544,18 +562,40 @@ main(int argc, char *argv[])
usage(); usage();
while ((ch = getopt(argc, argv, while ((ch = getopt(argc, argv,
"lcd:s:")) != -1) { "lcd:s:v")) != -1) {
switch (ch) { switch (ch) {
case 'l': case 'l':
return (list()); op = OP_LIST;
break;
case 'c': case 'c':
return (create()); op = OP_CREATE;
break;
case 'd': case 'd':
return (del(optarg)); op = OP_DELETE;
break;
case 's': case 's':
return (set(optarg, argc - optind, argv + optind)); op = OP_SET;
set_arg_count = argc - optind;
set_args = argv + optind;
case 'v':
verbose = true;
break;
} }
} }
switch (op) {
case OP_LIST:
return (list());
case OP_CREATE:
return (create());
case OP_DELETE:
return (del(optarg));
case OP_SET:
return (set(optarg, set_arg_count, set_args));
case OP_HELP:
usage();
break;
}
return (0); return (0);
} }

View File

@ -362,7 +362,8 @@ enum pflow_get_type_t {
PFLOWNL_GET_VERSION = 2, /* u16 */ PFLOWNL_GET_VERSION = 2, /* u16 */
PFLOWNL_GET_SRC = 3, /* struct sockaddr_storage */ PFLOWNL_GET_SRC = 3, /* struct sockaddr_storage */
PFLOWNL_GET_DST = 4, /* struct sockaddr_storage */ PFLOWNL_GET_DST = 4, /* struct sockaddr_storage */
PFLOWNL_GET_OBSERVATION_DOMAIN = 5, /* u32 */ PFLOWNL_GET_OBSERVATION_DOMAIN = 5, /* u32 */
PFLOWNL_GET_SOCKET_STATUS = 6, /* u8 */
}; };
enum pflow_set_type_t { enum pflow_set_type_t {

View File

@ -1485,6 +1485,7 @@ pflow_nl_get(struct nlmsghdr *hdr, struct nl_pstate *npt)
nlattr_add_sockaddr(nw, PFLOWNL_GET_DST, sc->sc_flowdst); nlattr_add_sockaddr(nw, PFLOWNL_GET_DST, sc->sc_flowdst);
nlattr_add_u32(nw, PFLOWNL_GET_OBSERVATION_DOMAIN, nlattr_add_u32(nw, PFLOWNL_GET_OBSERVATION_DOMAIN,
sc->sc_observation_dom); sc->sc_observation_dom);
nlattr_add_u8(nw, PFLOWNL_GET_SOCKET_STATUS, sc->so != NULL);
if (! nlmsg_end(nw)) { if (! nlmsg_end(nw)) {
nlmsg_abort(nw); nlmsg_abort(nw);