This switches 'nft monitor' JSON output from using libnftnl's to libnftables' implementation. Signed-off-by: Phil Sutter <phil@xxxxxx> --- include/json.h | 51 +++++++++ src/json.c | 57 ++++++++++ src/monitor.c | 281 +++++++++++++++++++++++++------------------------ src/rule.c | 2 - 4 files changed, 251 insertions(+), 140 deletions(-) diff --git a/include/json.h b/include/json.h index 663375489bc51..d2dc92d963693 100644 --- a/include/json.h +++ b/include/json.h @@ -9,9 +9,11 @@ struct expr; struct netlink_ctx; struct rule; struct set; +struct obj; struct stmt; struct symbol_table; struct table; +struct netlink_mon_handler; #ifdef HAVE_LIBJANSSON @@ -88,6 +90,19 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf, int nft_parse_json_filename(struct nft_ctx *nft, const char *filename, struct list_head *msgs, struct list_head *cmds); +void monitor_print_table_json(struct netlink_mon_handler *monh, + const char *cmd, struct table *t); +void monitor_print_chain_json(struct netlink_mon_handler *monh, + const char *cmd, struct chain *c); +void monitor_print_set_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s); +void monitor_print_element_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s); +void monitor_print_obj_json(struct netlink_mon_handler *monh, + const char *cmd, struct obj *o); +void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r); + #else /* ! HAVE_LIBJANSSON */ typedef void json_t; @@ -183,6 +198,42 @@ nft_parse_json_filename(struct nft_ctx *nft, const char *filename, return -EINVAL; } +static inline void monitor_print_table_json(struct netlink_mon_handler *monh, + const char *cmd, struct table *t) +{ + /* empty */ +} + +static inline void monitor_print_chain_json(struct netlink_mon_handler *monh, + const char *cmd, struct chain *c) +{ + /* empty */ +} + +static inline void monitor_print_set_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s) +{ + /* empty */ +} + +static inline void monitor_print_element_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s) +{ + /* empty */ +} + +static inline void monitor_print_obj_json(struct netlink_mon_handler *monh, + const char *cmd, struct obj *o) +{ + /* empty */ +} + +static inline void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r) +{ + /* empty */ +} + #endif /* HAVE_LIBJANSSON */ #endif /* NFTABLES_JSON_H */ diff --git a/src/json.c b/src/json.c index a0a2b9db65b0b..f5d97c623fb3a 100644 --- a/src/json.c +++ b/src/json.c @@ -148,6 +148,19 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set) return json_pack("{s:o}", type, root); } +/* XXX: Merge with set_print_json()? */ +static json_t *element_print_json(struct output_ctx *octx, + const struct set *set) +{ + json_t *root = expr_print_json(set->init, octx); + + return json_pack("{s: {s:s, s:s, s:s, s:o}}", "element", + "family", family2str(set->handle.family), + "table", set->handle.table.name, + "name", set->handle.set.name, + "elem", root); +} + static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx) { char buf[1024]; @@ -1714,3 +1727,47 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd) json_decref(root); return 0; } + +static void monitor_print_json(struct netlink_mon_handler *monh, + const char *cmd, json_t *obj) +{ + obj = json_pack("{s:o}", cmd, obj); + json_dumpf(obj, monh->ctx->octx->output_fp, 0); + json_decref(obj); +} + +void monitor_print_table_json(struct netlink_mon_handler *monh, + const char *cmd, struct table *t) +{ + monitor_print_json(monh, cmd, table_print_json(monh->ctx->octx, t)); +} + +void monitor_print_chain_json(struct netlink_mon_handler *monh, + const char *cmd, struct chain *c) +{ + monitor_print_json(monh, cmd, chain_print_json(monh->ctx->octx, c)); +} + +void monitor_print_set_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s) +{ + monitor_print_json(monh, cmd, set_print_json(monh->ctx->octx, s)); +} + +void monitor_print_element_json(struct netlink_mon_handler *monh, + const char *cmd, struct set *s) +{ + monitor_print_json(monh, cmd, element_print_json(monh->ctx->octx, s)); +} + +void monitor_print_obj_json(struct netlink_mon_handler *monh, + const char *cmd, struct obj *o) +{ + monitor_print_json(monh, cmd, obj_print_json(monh->ctx->octx, o)); +} + +void monitor_print_rule_json(struct netlink_mon_handler *monh, + const char *cmd, struct rule *r) +{ + monitor_print_json(monh, cmd, rule_print_json(monh->ctx->octx, r)); +} diff --git a/src/monitor.c b/src/monitor.c index 3e70b89f0b2ab..213c40d119b4c 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -38,6 +38,7 @@ #include <utils.h> #include <erec.h> #include <iface.h> +#include <json.h> #define nft_mon_print(monh, ...) nft_print(monh->ctx->octx, __VA_ARGS__) @@ -127,18 +128,39 @@ static uint32_t netlink_msg2nftnl_of(uint32_t msg) case NFT_MSG_NEWSET: case NFT_MSG_NEWSETELEM: case NFT_MSG_NEWRULE: + case NFT_MSG_NEWOBJ: + case NFT_MSG_NEWFLOWTABLE: return NFTNL_OF_EVENT_NEW; case NFT_MSG_DELTABLE: case NFT_MSG_DELCHAIN: case NFT_MSG_DELSET: case NFT_MSG_DELSETELEM: case NFT_MSG_DELRULE: + case NFT_MSG_DELOBJ: + case NFT_MSG_DELFLOWTABLE: return NFTNL_OF_EVENT_DEL; } return 0; } +static const char *nftnl_of2cmd(uint32_t of) +{ + switch (of) { + case NFTNL_OF_EVENT_NEW: + return "add"; + case NFTNL_OF_EVENT_DEL: + return "delete"; + default: + return "???"; + } +} + +static const char *netlink_msg2cmd(uint32_t msg) +{ + return nftnl_of2cmd(netlink_msg2nftnl_of(msg)); +} + static void nlr_for_each_set(struct nftnl_rule *nlr, void (*cb)(struct set *s, void *data), void *data, struct nft_cache *cache) @@ -179,34 +201,29 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { struct nftnl_table *nlt; - uint32_t family; + struct table *t; + const char *cmd; nlt = netlink_table_alloc(nlh); + t = netlink_delinearize_table(monh->ctx, nlt); + cmd = netlink_msg2cmd(type); switch (monh->format) { case NFTNL_OUTPUT_DEFAULT: - if (type == NFT_MSG_NEWTABLE) { - nft_mon_print(monh, "add table "); - } else { - nft_mon_print(monh, "delete table "); - } + nft_mon_print(monh, "%s table ", cmd); - family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY); - - nft_mon_print(monh, "%s %s", family2str(family), - nftnl_table_get_str(nlt, NFTNL_TABLE_NAME)); + nft_mon_print(monh, "%s %s", family2str(t->handle.family), + t->handle.table.name); if (monh->ctx->octx->handle > 0) nft_mon_print(monh, " # handle %" PRIu64 "", - nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE)); - nft_mon_print(monh, "\n"); + t->handle.handle.id); break; case NFTNL_OUTPUT_JSON: - nftnl_table_fprintf(monh->ctx->octx->output_fp, nlt, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + monitor_print_table_json(monh, cmd, t); break; } - + nft_mon_print(monh, "\n"); + table_free(t); nftnl_table_free(nlt); return MNL_CB_OK; } @@ -216,35 +233,34 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type, { struct nftnl_chain *nlc; struct chain *c; - uint32_t family; + const char *cmd; nlc = netlink_chain_alloc(nlh); + c = netlink_delinearize_chain(monh->ctx, nlc); + cmd = netlink_msg2cmd(type); switch (monh->format) { case NFTNL_OUTPUT_DEFAULT: + nft_mon_print(monh, "%s ", cmd); + switch (type) { case NFT_MSG_NEWCHAIN: - nft_mon_print(monh, "add "); - - c = netlink_delinearize_chain(monh->ctx, nlc); chain_print_plain(c, monh->ctx->octx); - chain_free(c); break; case NFT_MSG_DELCHAIN: - family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY); - nft_mon_print(monh, "delete chain %s %s %s\n", family2str(family), - nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE), - nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); + nft_mon_print(monh, "chain %s %s %s", + family2str(c->handle.family), + c->handle.table.name, + c->handle.chain.name); break; } break; case NFTNL_OUTPUT_JSON: - nftnl_chain_fprintf(monh->ctx->octx->output_fp, nlc, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + monitor_print_chain_json(monh, cmd, c); break; } - + nft_mon_print(monh, "\n"); + chain_free(c); nftnl_chain_free(nlc); return MNL_CB_OK; } @@ -253,43 +269,44 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { struct nftnl_set *nls; + const char *family, *cmd; struct set *set; - uint32_t family, flags; + uint32_t flags; nls = netlink_set_alloc(nlh); flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS); if (flags & NFT_SET_ANONYMOUS) goto out; + set = netlink_delinearize_set(monh->ctx, nls); + if (set == NULL) { + nftnl_set_free(nls); + return MNL_CB_ERROR; + } + family = family2str(set->handle.family); + cmd = netlink_msg2cmd(type); + switch (monh->format) { case NFTNL_OUTPUT_DEFAULT: + nft_mon_print(monh, "%s ", cmd); + switch (type) { case NFT_MSG_NEWSET: - nft_mon_print(monh, "add "); - set = netlink_delinearize_set(monh->ctx, nls); - if (set == NULL) { - nftnl_set_free(nls); - return MNL_CB_ERROR; - } set_print_plain(set, monh->ctx->octx); - set_free(set); - nft_mon_print(monh, "\n"); break; case NFT_MSG_DELSET: - family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY); - nft_mon_print(monh, "delete set %s %s %s\n", - family2str(family), - nftnl_set_get_str(nls, NFTNL_SET_TABLE), - nftnl_set_get_str(nls, NFTNL_SET_NAME)); + nft_mon_print(monh, "set %s %s %s", family, + set->handle.table.name, + set->handle.set.name); break; } break; case NFTNL_OUTPUT_JSON: - nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + monitor_print_set_json(monh, cmd, set); break; } + nft_mon_print(monh, "\n"); + set_free(set); out: nftnl_set_free(nls); return MNL_CB_OK; @@ -360,13 +377,14 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, struct nftnl_set *nls; struct set *dummyset; struct set *set; - const char *setname, *table; + const char *setname, *table, *cmd; uint32_t family; nls = netlink_setelem_alloc(nlh); table = nftnl_set_get_str(nls, NFTNL_SET_TABLE); setname = nftnl_set_get_str(nls, NFTNL_SET_NAME); family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY); + cmd = netlink_msg2cmd(type); set = set_lookup_global(family, table, setname, monh->cache); if (set == NULL) { @@ -374,70 +392,63 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type, goto out; } - switch (monh->format) { - case NFTNL_OUTPUT_DEFAULT: - if (set->flags & NFT_SET_ANONYMOUS) - goto out; - - /* we want to 'delinearize' the set_elem, but don't - * modify the original cached set. This path is only - * used by named sets, so use a dummy set. - */ - dummyset = set_alloc(monh->loc); - dummyset->key = expr_clone(set->key); - dummyset->datatype = set->datatype; - dummyset->flags = set->flags; - dummyset->init = set_expr_alloc(monh->loc, set); + if (set->flags & NFT_SET_ANONYMOUS) + goto out; - nlsei = nftnl_set_elems_iter_create(nls); - if (nlsei == NULL) - memory_allocation_error(); + /* we want to 'delinearize' the set_elem, but don't + * modify the original cached set. This path is only + * used by named sets, so use a dummy set. + */ + dummyset = set_alloc(monh->loc); + dummyset->key = expr_clone(set->key); + dummyset->datatype = set->datatype; + dummyset->flags = set->flags; + dummyset->init = set_expr_alloc(monh->loc, set); - nlse = nftnl_set_elems_iter_next(nlsei); - while (nlse != NULL) { - if (netlink_event_ignore_range_event(nlse)) { - set_free(dummyset); - nftnl_set_elems_iter_destroy(nlsei); - goto out; - } - if (netlink_delinearize_setelem(nlse, dummyset, - monh->cache) < 0) { - set_free(dummyset); - nftnl_set_elems_iter_destroy(nlsei); - goto out; - } - nlse = nftnl_set_elems_iter_next(nlsei); - } - nftnl_set_elems_iter_destroy(nlsei); + nlsei = nftnl_set_elems_iter_create(nls); + if (nlsei == NULL) + memory_allocation_error(); - if (netlink_event_range_cache(set, dummyset)) { + nlse = nftnl_set_elems_iter_next(nlsei); + while (nlse != NULL) { + if (netlink_event_ignore_range_event(nlse)) { set_free(dummyset); + nftnl_set_elems_iter_destroy(nlsei); goto out; } - - switch (type) { - case NFT_MSG_NEWSETELEM: - nft_mon_print(monh, "add "); - break; - case NFT_MSG_DELSETELEM: - nft_mon_print(monh, "delete "); - break; - default: + if (netlink_delinearize_setelem(nlse, dummyset, + monh->cache) < 0) { set_free(dummyset); + nftnl_set_elems_iter_destroy(nlsei); goto out; } - nft_mon_print(monh, "element %s %s %s ", family2str(family), table, setname); - expr_print(dummyset->init, monh->ctx->octx); - nft_mon_print(monh, "\n"); + nlse = nftnl_set_elems_iter_next(nlsei); + } + nftnl_set_elems_iter_destroy(nlsei); + if (netlink_event_range_cache(set, dummyset)) { set_free(dummyset); + goto out; + } + + switch (monh->format) { + case NFTNL_OUTPUT_DEFAULT: + nft_mon_print(monh, "%s element %s %s %s ", + cmd, family2str(family), table, setname); + expr_print(dummyset->init, monh->ctx->octx); break; case NFTNL_OUTPUT_JSON: - nftnl_set_fprintf(monh->ctx->octx->output_fp, nls, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + dummyset->handle.family = family; + dummyset->handle.set.name = setname; + dummyset->handle.table.name = table; + monitor_print_element_json(monh, cmd, dummyset); + /* prevent set_free() from trying to free those */ + dummyset->handle.set.name = NULL; + dummyset->handle.table.name = NULL; break; } + nft_mon_print(monh, "\n"); + set_free(dummyset); out: nftnl_set_free(nls); return MNL_CB_OK; @@ -446,43 +457,43 @@ out: static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { + const char *family, *cmd; struct nftnl_obj *nlo; - uint32_t family; struct obj *obj; nlo = netlink_obj_alloc(nlh); + obj = netlink_delinearize_obj(monh->ctx, nlo); + if (obj == NULL) { + nftnl_obj_free(nlo); + return MNL_CB_ERROR; + } + family = family2str(obj->handle.family); + cmd = netlink_msg2cmd(type); + switch (monh->format) { case NFTNL_OUTPUT_DEFAULT: + nft_mon_print(monh, "%s ", cmd); + switch (type) { case NFT_MSG_NEWOBJ: - nft_mon_print(monh, "add "); - obj = netlink_delinearize_obj(monh->ctx, nlo); - if (obj == NULL) { - nftnl_obj_free(nlo); - return MNL_CB_ERROR; - } obj_print_plain(obj, monh->ctx->octx); - obj_free(obj); - nft_mon_print(monh, "\n"); break; case NFT_MSG_DELOBJ: - family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY); - nft_mon_print(monh, "delete %s %s %s %s\n", - obj_type_name(nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE)), - family2str(family), - nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE), - nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME)); + nft_mon_print(monh, "%s %s %s %s", + obj_type_name(obj->type), + family, + obj->handle.table.name, + obj->handle.obj.name); break; } break; case NFTNL_OUTPUT_JSON: - nftnl_obj_fprintf(monh->ctx->octx->output_fp, nlo, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + monitor_print_obj_json(monh, cmd, obj); break; } - + nft_mon_print(monh, "\n"); + obj_free(obj); nftnl_obj_free(nlo); return MNL_CB_OK; } @@ -496,48 +507,42 @@ static void rule_map_decompose_cb(struct set *s, void *data) static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type, struct netlink_mon_handler *monh) { + const char *family, *cmd; struct nftnl_rule *nlr; - const char *family; - const char *table; - const char *chain; struct rule *r; - uint64_t handle; - uint32_t fam; nlr = netlink_rule_alloc(nlh); + r = netlink_delinearize_rule(monh->ctx, nlr); + nlr_for_each_set(nlr, rule_map_decompose_cb, NULL, monh->cache); + cmd = netlink_msg2cmd(type); + switch (monh->format) { case NFTNL_OUTPUT_DEFAULT: - fam = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY); - family = family2str(fam); - table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE); - chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN); - handle = nftnl_rule_get_u64(nlr, NFTNL_RULE_HANDLE); + family = family2str(r->handle.family); + + nft_mon_print(monh, "%s rule %s %s %s ", + cmd, + family, + r->handle.table.name, + r->handle.chain.name); switch (type) { case NFT_MSG_NEWRULE: - r = netlink_delinearize_rule(monh->ctx, nlr); - nlr_for_each_set(nlr, rule_map_decompose_cb, NULL, - monh->cache); - - nft_mon_print(monh, "add rule %s %s %s ", family, table, chain); rule_print(r, monh->ctx->octx); - nft_mon_print(monh, "\n"); - rule_free(r); break; case NFT_MSG_DELRULE: - nft_mon_print(monh, "delete rule %s %s %s handle %u\n", - family, table, chain, (unsigned int)handle); + nft_mon_print(monh, "handle %" PRIu64, + r->handle.handle.id); break; } break; case NFTNL_OUTPUT_JSON: - nftnl_rule_fprintf(monh->ctx->octx->output_fp, nlr, - monh->format, netlink_msg2nftnl_of(type)); - nft_mon_print(monh, "\n"); + monitor_print_rule_json(monh, cmd, r); break; } - + nft_mon_print(monh, "\n"); + rule_free(r); nftnl_rule_free(nlr); return MNL_CB_OK; } diff --git a/src/rule.c b/src/rule.c index 58ac94f6716ca..bf626854279b4 100644 --- a/src/rule.c +++ b/src/rule.c @@ -1049,8 +1049,6 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx) } if (octx->handle > 0) nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id); - - nft_print(octx, "\n"); } struct table *table_alloc(void) -- 2.19.0