Hi, On Wed, Jun 05, 2019 at 06:46:52PM +0200, Pablo Neira Ayuso wrote: [...] > diff --git a/src/cache.c b/src/cache.c > new file mode 100644 > index 000000000000..89a884012a90 > --- /dev/null > +++ b/src/cache.c > @@ -0,0 +1,123 @@ > +/* > + * Copyright (c) 2019 Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include <expression.h> > +#include <statement.h> > +#include <rule.h> > +#include <erec.h> > +#include <utils.h> > + > +static void evaluate_cache_add(struct cmd *cmd, unsigned int *completeness) > +{ > + switch (cmd->obj) { > + case CMD_OBJ_SETELEM: > + case CMD_OBJ_SET: > + case CMD_OBJ_CHAIN: > + case CMD_OBJ_FLOWTABLE: > + if (*completeness < cmd->op) > + *completeness = cmd->op; > + break; > + case CMD_OBJ_RULE: > + /* XXX index is set to zero unless this handle_merge() call is > + * invoked, this handle_merge() call is done from the > + * evaluation, which is too late. > + */ Using the right handle was somehow tricky. IIRC, getting it right was part of the work on v5 of my series. Maybe you were working around a bug in my code? > + handle_merge(&cmd->rule->handle, &cmd->handle); > + > + if (cmd->rule->handle.index.id && > + *completeness < CMD_LIST) > + *completeness = CMD_LIST; > + break; > + default: > + break; > + } > +} > + > +static void evaluate_cache_del(struct cmd *cmd, unsigned int *completeness) > +{ > + switch (cmd->obj) { > + case CMD_OBJ_SETELEM: > + if (*completeness < cmd->op) > + *completeness = cmd->op; This manual max() thing seems to be a common pattern. Maybe make these functions return cmd->op (or the desired completeness) and handle the max() check in caller? [...] > +int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds) > +{ > + unsigned int completeness = CMD_INVALID; > + struct cmd *cmd; > + > + list_for_each_entry(cmd, cmds, list) { > + switch (cmd->op) { > + case CMD_ADD: > + case CMD_INSERT: > + case CMD_REPLACE: > + if (nft_output_echo(&nft->output) && > + completeness < cmd->op) > + return cmd->op; Is 'return' correct here? That would abort cmd list processing. > + > + /* Fall through */ > + case CMD_CREATE: > + evaluate_cache_add(cmd, &completeness); > + break; > + case CMD_DELETE: > + evaluate_cache_del(cmd, &completeness); > + break; > + case CMD_GET: > + case CMD_LIST: > + case CMD_RESET: > + case CMD_EXPORT: > + case CMD_MONITOR: > + if (completeness < cmd->op) > + completeness = cmd->op; > + break; > + case CMD_FLUSH: > + evaluate_cache_flush(cmd, &completeness); > + break; > + case CMD_RENAME: > + evaluate_cache_rename(cmd, &completeness); As suggested above, I would do (also in the other cases): tmp = evaluate_cache_rename(cmd); > + break; > + case CMD_DESCRIBE: > + case CMD_IMPORT: > + break; > + default: > + break; > + } And here: completeness = max(tmp, completeness); > + } > + > + return completeness; > +} Cheers, Phil