]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/netfilter/nf_tables_api.c
netfilter: add helper function to set up the nfnetlink header and use it
[mirror_ubuntu-jammy-kernel.git] / net / netfilter / nf_tables_api.c
index bd5e8122ea5e771d96ffd33f85c7b336092d36a2..005f1c620fc0c4cd240301f961bd5d05b006ff8c 100644 (file)
@@ -66,6 +66,41 @@ static const struct rhashtable_params nft_objname_ht_params = {
        .automatic_shrinking    = true,
 };
 
+struct nft_audit_data {
+       struct nft_table *table;
+       int entries;
+       int op;
+       struct list_head list;
+};
+
+static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
+       [NFT_MSG_NEWTABLE]      = AUDIT_NFT_OP_TABLE_REGISTER,
+       [NFT_MSG_GETTABLE]      = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELTABLE]      = AUDIT_NFT_OP_TABLE_UNREGISTER,
+       [NFT_MSG_NEWCHAIN]      = AUDIT_NFT_OP_CHAIN_REGISTER,
+       [NFT_MSG_GETCHAIN]      = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELCHAIN]      = AUDIT_NFT_OP_CHAIN_UNREGISTER,
+       [NFT_MSG_NEWRULE]       = AUDIT_NFT_OP_RULE_REGISTER,
+       [NFT_MSG_GETRULE]       = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELRULE]       = AUDIT_NFT_OP_RULE_UNREGISTER,
+       [NFT_MSG_NEWSET]        = AUDIT_NFT_OP_SET_REGISTER,
+       [NFT_MSG_GETSET]        = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELSET]        = AUDIT_NFT_OP_SET_UNREGISTER,
+       [NFT_MSG_NEWSETELEM]    = AUDIT_NFT_OP_SETELEM_REGISTER,
+       [NFT_MSG_GETSETELEM]    = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELSETELEM]    = AUDIT_NFT_OP_SETELEM_UNREGISTER,
+       [NFT_MSG_NEWGEN]        = AUDIT_NFT_OP_GEN_REGISTER,
+       [NFT_MSG_GETGEN]        = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_TRACE]         = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_NEWOBJ]        = AUDIT_NFT_OP_OBJ_REGISTER,
+       [NFT_MSG_GETOBJ]        = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELOBJ]        = AUDIT_NFT_OP_OBJ_UNREGISTER,
+       [NFT_MSG_GETOBJ_RESET]  = AUDIT_NFT_OP_OBJ_RESET,
+       [NFT_MSG_NEWFLOWTABLE]  = AUDIT_NFT_OP_FLOWTABLE_REGISTER,
+       [NFT_MSG_GETFLOWTABLE]  = AUDIT_NFT_OP_INVALID,
+       [NFT_MSG_DELFLOWTABLE]  = AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
+};
+
 static void nft_validate_state_update(struct net *net, u8 new_validate_state)
 {
        switch (net->nft.validate_state) {
@@ -586,8 +621,8 @@ struct nft_module_request {
 };
 
 #ifdef CONFIG_MODULES
-static __printf(2, 3) int nft_request_module(struct net *net, const char *fmt,
-                                            ...)
+__printf(2, 3) int nft_request_module(struct net *net, const char *fmt,
+                                     ...)
 {
        char module_name[MODULE_NAME_LEN];
        struct nft_module_request *req;
@@ -620,6 +655,7 @@ static __printf(2, 3) int nft_request_module(struct net *net, const char *fmt,
 
        return -EAGAIN;
 }
+EXPORT_SYMBOL_GPL(nft_request_module);
 #endif
 
 static void lockdep_nfnl_nft_mutex_not_held(void)
@@ -652,6 +688,11 @@ nf_tables_chain_type_lookup(struct net *net, const struct nlattr *nla,
        return ERR_PTR(-ENOENT);
 }
 
+static __be16 nft_base_seq(const struct net *net)
+{
+       return htons(net->nft.base_seq & 0xffff);
+}
+
 static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
        [NFTA_TABLE_NAME]       = { .type = NLA_STRING,
                                    .len = NFT_TABLE_MAXNAMELEN - 1 },
@@ -666,18 +707,13 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
                                     int family, const struct nft_table *table)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+                          NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
            nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
            nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
@@ -717,17 +753,6 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
 {
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(GFP_KERNEL, "%s:%llu;?:0",
-                             ctx->table->name, ctx->table->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       ctx->table->use,
-                       event == NFT_MSG_NEWTABLE ?
-                               AUDIT_NFT_OP_TABLE_REGISTER :
-                               AUDIT_NFT_OP_TABLE_UNREGISTER,
-                       GFP_KERNEL);
-       kfree(buf);
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
@@ -1438,18 +1463,13 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
                                     const struct nft_chain *chain)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+                          NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
                goto nla_put_failure;
        if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle),
@@ -1501,18 +1521,6 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
 {
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu",
-                             ctx->table->name, ctx->table->handle,
-                             ctx->chain->name, ctx->chain->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       ctx->chain->use,
-                       event == NFT_MSG_NEWCHAIN ?
-                               AUDIT_NFT_OP_CHAIN_REGISTER :
-                               AUDIT_NFT_OP_CHAIN_UNREGISTER,
-                       GFP_KERNEL);
-       kfree(buf);
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
@@ -2807,20 +2815,15 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
                                    const struct nft_rule *prule)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        const struct nft_expr *expr, *next;
        struct nlattr *list;
        u16 type = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
 
-       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, type, flags, family, NFNETLINK_V0,
+                          nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
@@ -2865,18 +2868,6 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
 {
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu",
-                             ctx->table->name, ctx->table->handle,
-                             ctx->chain->name, ctx->chain->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       rule->handle,
-                       event == NFT_MSG_NEWRULE ?
-                               AUDIT_NFT_OP_RULE_REGISTER :
-                               AUDIT_NFT_OP_RULE_UNREGISTER,
-                       GFP_KERNEL);
-       kfree(buf);
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
@@ -3803,7 +3794,6 @@ static int nf_tables_fill_set_concat(struct sk_buff *skb,
 static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
                              const struct nft_set *set, u16 event, u16 flags)
 {
-       struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
        u32 portid = ctx->portid;
        struct nlattr *nest;
@@ -3811,16 +3801,11 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
        int i;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
-                       flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
+                          NFNETLINK_V0, nft_base_seq(ctx->net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = ctx->family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(ctx->net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_SET_NAME, set->name))
@@ -3911,18 +3896,6 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
        struct sk_buff *skb;
        u32 portid = ctx->portid;
        int err;
-       char *buf = kasprintf(gfp_flags, "%s:%llu;%s:%llu",
-                             ctx->table->name, ctx->table->handle,
-                             set->name, set->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       set->field_count,
-                       event == NFT_MSG_NEWSET ?
-                               AUDIT_NFT_OP_SET_REGISTER :
-                               AUDIT_NFT_OP_SET_UNREGISTER,
-                       gfp_flags);
-       kfree(buf);
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
@@ -4801,7 +4774,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        struct nft_set *set;
        struct nft_set_dump_args args;
        bool set_found = false;
-       struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
        struct nlattr *nest;
        u32 portid, seq;
@@ -4834,16 +4806,11 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        portid = NETLINK_CB(cb->skb).portid;
        seq    = cb->nlh->nlmsg_seq;
 
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
-                       NLM_F_MULTI);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, NLM_F_MULTI,
+                          table->family, NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = table->family;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, table->name))
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
@@ -4900,22 +4867,16 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb,
                                       const struct nft_set *set,
                                       const struct nft_set_elem *elem)
 {
-       struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
        struct nlattr *nest;
        int err;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
-                       flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
+                          NFNETLINK_V0, nft_base_seq(ctx->net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = ctx->family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(ctx->net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_SET_NAME, set->name))
@@ -5107,18 +5068,6 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
        u32 portid = ctx->portid;
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu",
-                             ctx->table->name, ctx->table->handle,
-                             set->name, set->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       set->handle,
-                       event == NFT_MSG_NEWSETELEM ?
-                               AUDIT_NFT_OP_SETELEM_REGISTER :
-                               AUDIT_NFT_OP_SETELEM_UNREGISTER,
-                       GFP_KERNEL);
-       kfree(buf);
 
        if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
                return;
@@ -6245,19 +6194,14 @@ static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
                                   int family, const struct nft_table *table,
                                   struct nft_object *obj, bool reset)
 {
-       struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+                          NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_OBJ_TABLE, table->name) ||
            nla_put_string(skb, NFTA_OBJ_NAME, obj->key.name) ||
            nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
@@ -6320,12 +6264,11 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
                            filter->type != NFT_OBJECT_UNSPEC &&
                            obj->ops->type->type != filter->type)
                                goto cont;
-
                        if (reset) {
                                char *buf = kasprintf(GFP_ATOMIC,
-                                                     "%s:%llu;?:0",
+                                                     "%s:%u",
                                                      table->name,
-                                                     table->handle);
+                                                     net->nft.base_seq);
 
                                audit_log_nfcfg(buf,
                                                family,
@@ -6446,8 +6389,8 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
                reset = true;
 
        if (reset) {
-               char *buf = kasprintf(GFP_ATOMIC, "%s:%llu;?:0",
-                                     table->name, table->handle);
+               char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
+                                     table->name, net->nft.base_seq);
 
                audit_log_nfcfg(buf,
                                family,
@@ -6535,15 +6478,15 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
 {
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(gfp, "%s:%llu;?:0",
-                             table->name, table->handle);
+       char *buf = kasprintf(gfp, "%s:%u",
+                             table->name, net->nft.base_seq);
 
        audit_log_nfcfg(buf,
                        family,
                        obj->handle,
                        event == NFT_MSG_NEWOBJ ?
-                               AUDIT_NFT_OP_OBJ_REGISTER :
-                               AUDIT_NFT_OP_OBJ_UNREGISTER,
+                                AUDIT_NFT_OP_OBJ_REGISTER :
+                                AUDIT_NFT_OP_OBJ_UNREGISTER,
                        gfp);
        kfree(buf);
 
@@ -6787,6 +6730,9 @@ static int nft_register_flowtable_net_hooks(struct net *net,
 
        list_for_each_entry(hook, hook_list, list) {
                list_for_each_entry(ft, &table->flowtables, list) {
+                       if (!nft_is_active_next(net, ft))
+                               continue;
+
                        list_for_each_entry(hook2, &ft->hook_list, list) {
                                if (hook->ops.dev == hook2->ops.dev &&
                                    hook->ops.pf == hook2->ops.pf) {
@@ -6846,6 +6792,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
        struct nft_hook *hook, *next;
        struct nft_trans *trans;
        bool unregister = false;
+       u32 flags;
        int err;
 
        err = nft_flowtable_parse_hook(ctx, nla[NFTA_FLOWTABLE_HOOK],
@@ -6860,6 +6807,17 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
                }
        }
 
+       if (nla[NFTA_FLOWTABLE_FLAGS]) {
+               flags = ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
+               if (flags & ~NFT_FLOWTABLE_MASK)
+                       return -EOPNOTSUPP;
+               if ((flowtable->data.flags & NFT_FLOWTABLE_HW_OFFLOAD) ^
+                   (flags & NFT_FLOWTABLE_HW_OFFLOAD))
+                       return -EOPNOTSUPP;
+       } else {
+               flags = flowtable->data.flags;
+       }
+
        err = nft_register_flowtable_net_hooks(ctx->net, ctx->table,
                                               &flowtable_hook.list, flowtable);
        if (err < 0)
@@ -6873,6 +6831,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
                goto err_flowtable_update_hook;
        }
 
+       nft_trans_flowtable_flags(trans) = flags;
        nft_trans_flowtable(trans) = flowtable;
        nft_trans_flowtable_update(trans) = true;
        INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans));
@@ -6967,8 +6926,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
        if (nla[NFTA_FLOWTABLE_FLAGS]) {
                flowtable->data.flags =
                        ntohl(nla_get_be32(nla[NFTA_FLOWTABLE_FLAGS]));
-               if (flowtable->data.flags & ~NFT_FLOWTABLE_MASK)
+               if (flowtable->data.flags & ~NFT_FLOWTABLE_MASK) {
+                       err = -EOPNOTSUPP;
                        goto err3;
+               }
        }
 
        write_pnet(&flowtable->data.net, net);
@@ -7140,20 +7101,15 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
                                         struct list_head *hook_list)
 {
        struct nlattr *nest, *nest_devs;
-       struct nfgenmsg *nfmsg;
        struct nft_hook *hook;
        struct nlmsghdr *nlh;
 
        event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
+                          NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = family;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
            nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
            nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
@@ -7343,18 +7299,6 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
 {
        struct sk_buff *skb;
        int err;
-       char *buf = kasprintf(GFP_KERNEL, "%s:%llu;%s:%llu",
-                             flowtable->table->name, flowtable->table->handle,
-                             flowtable->name, flowtable->handle);
-
-       audit_log_nfcfg(buf,
-                       ctx->family,
-                       flowtable->hooknum,
-                       event == NFT_MSG_NEWFLOWTABLE ?
-                               AUDIT_NFT_OP_FLOWTABLE_REGISTER :
-                               AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
-                       GFP_KERNEL);
-       kfree(buf);
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
@@ -7398,19 +7342,14 @@ static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
                                   u32 portid, u32 seq)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        char buf[TASK_COMM_LEN];
        int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
 
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, 0, AF_UNSPEC,
+                          NFNETLINK_V0, nft_base_seq(net));
+       if (!nlh)
                goto nla_put_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family     = AF_UNSPEC;
-       nfmsg->version          = NFNETLINK_V0;
-       nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
-
        if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)) ||
            nla_put_be32(skb, NFTA_GEN_PROC_PID, htonl(task_pid_nr(current))) ||
            nla_put_string(skb, NFTA_GEN_PROC_NAME, get_task_comm(buf, current)))
@@ -7475,9 +7414,6 @@ static void nf_tables_gen_notify(struct net *net, struct sk_buff *skb,
        struct sk_buff *skb2;
        int err;
 
-       audit_log_nfcfg("?:0;?:0", 0, net->nft.base_seq,
-                       AUDIT_NFT_OP_GEN_REGISTER, GFP_KERNEL);
-
        if (!nlmsg_report(nlh) &&
            !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
                return;
@@ -8016,12 +7952,64 @@ new_batch:
        WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
 }
 
+static int nf_tables_commit_audit_alloc(struct list_head *adl,
+                                       struct nft_table *table)
+{
+       struct nft_audit_data *adp;
+
+       list_for_each_entry(adp, adl, list) {
+               if (adp->table == table)
+                       return 0;
+       }
+       adp = kzalloc(sizeof(*adp), GFP_KERNEL);
+       if (!adp)
+               return -ENOMEM;
+       adp->table = table;
+       list_add(&adp->list, adl);
+       return 0;
+}
+
+static void nf_tables_commit_audit_collect(struct list_head *adl,
+                                          struct nft_table *table, u32 op)
+{
+       struct nft_audit_data *adp;
+
+       list_for_each_entry(adp, adl, list) {
+               if (adp->table == table)
+                       goto found;
+       }
+       WARN_ONCE("table=%s not expected in commit list", table->name);
+       return;
+found:
+       adp->entries++;
+       if (!adp->op || adp->op > op)
+               adp->op = op;
+}
+
+#define AUNFTABLENAMELEN (NFT_TABLE_MAXNAMELEN + 22)
+
+static void nf_tables_commit_audit_log(struct list_head *adl, u32 generation)
+{
+       struct nft_audit_data *adp, *adn;
+       char aubuf[AUNFTABLENAMELEN];
+
+       list_for_each_entry_safe(adp, adn, adl, list) {
+               snprintf(aubuf, AUNFTABLENAMELEN, "%s:%u", adp->table->name,
+                        generation);
+               audit_log_nfcfg(aubuf, adp->table->family, adp->entries,
+                               nft2audit_op[adp->op], GFP_KERNEL);
+               list_del(&adp->list);
+               kfree(adp);
+       }
+}
+
 static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 {
        struct nft_trans *trans, *next;
        struct nft_trans_elem *te;
        struct nft_chain *chain;
        struct nft_table *table;
+       LIST_HEAD(adl);
        int err;
 
        if (list_empty(&net->nft.commit_list)) {
@@ -8041,6 +8029,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
                int ret;
 
+               ret = nf_tables_commit_audit_alloc(&adl, trans->ctx.table);
+               if (ret) {
+                       nf_tables_commit_chain_prepare_cancel(net);
+                       return ret;
+               }
                if (trans->msg_type == NFT_MSG_NEWRULE ||
                    trans->msg_type == NFT_MSG_DELRULE) {
                        chain = trans->ctx.chain;
@@ -8069,6 +8062,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
        net->nft.gencursor = nft_gencursor_next(net);
 
        list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+               nf_tables_commit_audit_collect(&adl, trans->ctx.table,
+                                              trans->msg_type);
                switch (trans->msg_type) {
                case NFT_MSG_NEWTABLE:
                        if (nft_trans_table_update(trans)) {
@@ -8179,6 +8174,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                        break;
                case NFT_MSG_NEWFLOWTABLE:
                        if (nft_trans_flowtable_update(trans)) {
+                               nft_trans_flowtable(trans)->data.flags =
+                                       nft_trans_flowtable_flags(trans);
                                nf_tables_flowtable_notify(&trans->ctx,
                                                           nft_trans_flowtable(trans),
                                                           &nft_trans_flowtable_hooks(trans),
@@ -8219,6 +8216,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 
        nft_commit_notify(net, NETLINK_CB(skb).portid);
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
+       nf_tables_commit_audit_log(&adl, net->nft.base_seq);
        nf_tables_commit_release(net);
 
        return 0;
@@ -9173,7 +9171,6 @@ static int __init nf_tables_module_init(void)
 {
        int err;
 
-       spin_lock_init(&nf_tables_destroy_list_lock);
        err = register_pernet_subsys(&nf_tables_net_ops);
        if (err < 0)
                return err;