Hi Pablo,

On Wed, Apr 11, 2018 at 09:39:01AM +0200, Pablo Neira Ayuso wrote:
> Two comments, both related to 'struct cookie':
> * How is 'struct cookie' going to be used? Do you have follow up
>   patches to update the codebase to use this?

It's already there, please have a look at
nft_ctx_{un,}buffer_{output,error} functions and those they call
(init_cookie, exit_cookie). The API interface they establish can be used
as such:

| struct nft_ctx *ctx;
| const char *cmd;
| int rc;
| ctx = nft_ctx_new(0);
| nft_buffer_output(ctx);
| nft_buffer_error(ctx);
| cmd = "list ruleset";
| rc = nft_run_cmd_from_buffer(ctx, cmd, sizeof(cmd));
| if (rc) {
|       printf("FAIL: nftables says: %s\n",
|              nft_ctx_get_error_buffer(ctx));
| } else {
|       /* this prints 'list ruleset' output */
|       printf("%s\n", nft_ctx_get_output_buffer(ctx));
| }
| nft_ctx_free(ctx);

So these nft_ctx_buffer_* and nft_ctx_get_*_buffer functions are an
alternative to nft_ctx_set_{output,error} functions for cases where it
is more convenient to have all output available in a char buffer instead
of being written to an open FILE pointer.

> * Can we avoid the union around struct cookie and FILE *fp? I mean, I
>   don't think it makes sense to start exposing lots of toggles through
>   the API, the more we expose, the more combinations are possible and
>   then more chances we get to support all kind of strange combinations
>   in the future.

That union is simply for convenience: {init,exit}_cookie functions take
a pointer to struct cookie as parameter and since it is part of that
union they get access to the "standard" FILE pointer which is used if
no buffering was requested.

That union is introduced by commit 4885331de84cb ("libnftables: Simplify
cookie integration"), a followup to 40d94ca1dcd8e ("libnftables: Support
buffering output and error") - please have a look at the latter to see
how things were without it.

>   So what I'm suggesting is: Can we turn 'struct cookie' into the
>   default way to print messages?

Sure, we could do that. OTOH there is e.g. nft cli, which doesn't care
about what's printed to stdout and stderr. Changing the default would
mean cli has to manually print to stdout and stderr after each command.

Internally, this buffering infrastructure is an add-on to FILE pointer
output we already have (which was introduced as the quickest path from
plain printf's everywhere to giving API users control over library

I really think we should keep the FILE pointer output (i.e. nft_print())
internally, simply because changing everything to snprintf() is tedious
due to buffer length checks everywhere (I'm having libnftnl's
SNPRINTF_BUFFER_SIZE macro in mind ;).

The buffering add-on doesn't necessarily add complexity to API users'
implementations - prior to it, there were two options:

* Don't care and go with the default, i.e. output goes to stdout and

* Provide a FILE pointer to print into, i.e. call nft_ctx_set_output().

The add-on adds a third, completely separate option to them:

* Get output in a buffer, i.e. call nft_ctx_buffer_output() and use
  nft_ctx_get_output_buffer() afterwards to receive a pointer to the

>   Regarding the name 'struct cookie', is this refering to something
>   related to Python? I mean, this name tells me very little. What I
>   can see there is a new class that allows us to do buffering, so
>   probably using 'struct nft_buffer' or such sound more convenient to
>   me?

I chose it simply because it all evolves around fopencookie(3), which
provides the needed functionality (create a FILE pointer with
customizable write() backend). In the documentation, the opaque data
pointer passed around to callbacks is referred to as 'cookie'.

On Wed, Apr 11, 2018 at 09:48:25AM +0200, Pablo Neira Ayuso wrote:
> On Tue, Apr 10, 2018 at 07:00:21PM +0200, Phil Sutter wrote:
> > diff --git a/src/libnftables.c b/src/libnftables.c
> > index 8bf989b08cc54..d6622d51aba33 100644
> > --- a/src/libnftables.c
> > +++ b/src/libnftables.c
> > @@ -169,6 +169,7 @@ struct nft_ctx *nft_ctx_new(uint32_t flags)
> >     init_list_head(&ctx->cache.list);
> >     ctx->flags = flags;
> >     ctx->output.output_fp = stdout;
> > +   ctx->output.error_fp = stderr;
> I understand you may need this new toggle. But can we probably
> reasonable defaults? I mean, if no error_fp is specified, then use the
> one set by output_fp.

This was already the default, see this chunk from commit 4176e24e14f07
("libnftables: Introduce nft_ctx_set_error()"):

| @@ -297,9 +309,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, char 
*buf, size_t buflen)
|         if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0)
|                 rc = -1;
| -       fp = nft_ctx_set_output(nft, stderr);
|         erec_print_list(&nft->output, &msgs, nft->debug_mask);
| -       nft_ctx_set_output(nft, fp);
|         scanner_destroy(scanner);
|         iface_cache_release();
|         free(nlbuf);

So for printing error records, output_fp was temporarily changed to
stderr. So error_fp defaulting to stderr is backwards compatible.

> As said, it would be good if you can review the existing toggles and
> see if we can stop exposing some of those through API if possible. I
> would just expose the bare minimum and provide reasonable defaults so
> we most people in the world will not need to call n+1 different setter
> functions.

Understood. In this case though, I think the combination of possible
FILE pointer output and output buffering into a library managed buffer
is worth keeping. Looking at nftables.h though, I guess we could reduce
more complexity by combining all the nft_ctx_output_* toggles into a
single one which accepts a bit field. With bits being: stateless,
ip2name, handle, echo and maybe also dry-run, although that's strictly
not the same category. What do you think?

Thanks, Phil
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to