#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_offload.h>
#include <net/net_namespace.h>
+#include <net/netns/generic.h>
#include <net/sock.h>
#define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-"))
+unsigned int nf_tables_net_id __read_mostly;
+
static LIST_HEAD(nf_tables_expressions);
static LIST_HEAD(nf_tables_objects);
static LIST_HEAD(nf_tables_flowtables);
static void nft_validate_state_update(struct net *net, u8 new_validate_state)
{
- switch (net->nft.validate_state) {
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+
+ switch (nft_net->validate_state) {
case NFT_VALIDATE_SKIP:
WARN_ON_ONCE(new_validate_state == NFT_VALIDATE_DO);
break;
return;
}
- net->nft.validate_state = new_validate_state;
+ nft_net->validate_state = new_validate_state;
}
static void nf_tables_trans_destroy_work(struct work_struct *w);
static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work);
static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
{
+ struct nftables_pernet *nft_net;
struct net *net = ctx->net;
struct nft_trans *trans;
if (!nft_set_is_anonymous(set))
return;
- list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_for_each_entry_reverse(trans, &nft_net->commit_list, list) {
switch (trans->msg_type) {
case NFT_MSG_NEWSET:
if (nft_trans_set(trans) == set)
nf_unregister_net_hook(net, &basechain->ops);
}
+static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
+{
+ struct nftables_pernet *nft_net;
+
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_add_tail(&trans->list, &nft_net->commit_list);
+}
+
static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
{
struct nft_trans *trans;
if (msg_type == NFT_MSG_NEWTABLE)
nft_activate_next(ctx->net, ctx->table);
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
}
}
}
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return trans;
}
ntohl(nla_get_be32(ctx->nla[NFTA_RULE_ID]));
}
nft_trans_rule(trans) = rule;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return trans;
}
nft_activate_next(ctx->net, set);
}
nft_trans_set(trans) = set;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
}
nft_activate_next(ctx->net, obj);
nft_trans_obj(trans) = obj;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
}
nft_activate_next(ctx->net, flowtable);
nft_trans_flowtable(trans) = flowtable;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
}
const struct nlattr *nla,
u8 family, u8 genmask, u32 nlpid)
{
+ struct nftables_pernet *nft_net;
struct nft_table *table;
if (nla == NULL)
return ERR_PTR(-EINVAL);
- list_for_each_entry_rcu(table, &net->nft.tables, list,
- lockdep_is_held(&net->nft.commit_mutex)) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_for_each_entry_rcu(table, &nft_net->tables, list,
+ lockdep_is_held(&nft_net->commit_mutex)) {
if (!nla_strcmp(nla, table->name) &&
table->family == family &&
nft_active_genmask(table, genmask)) {
const struct nlattr *nla,
u8 genmask)
{
+ struct nftables_pernet *nft_net;
struct nft_table *table;
- list_for_each_entry(table, &net->nft.tables, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_for_each_entry(table, &nft_net->tables, list) {
if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
nft_active_genmask(table, genmask))
return table;
...)
{
char module_name[MODULE_NAME_LEN];
+ struct nftables_pernet *nft_net;
struct nft_module_request *req;
va_list args;
int ret;
if (ret >= MODULE_NAME_LEN)
return 0;
- list_for_each_entry(req, &net->nft.module_list, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_for_each_entry(req, &nft_net->module_list, list) {
if (!strcmp(req->module, module_name)) {
if (req->done)
return 0;
req->done = false;
strlcpy(req->module, module_name, MODULE_NAME_LEN);
- list_add_tail(&req->list, &net->nft.module_list);
+ list_add_tail(&req->list, &nft_net->module_list);
return -EAGAIN;
}
static __be16 nft_base_seq(const struct net *net)
{
- return htons(net->nft.base_seq & 0xffff);
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+
+ return htons(nft_net->base_seq & 0xffff);
}
static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
{
+ struct nftables_pernet *nft_net;
struct sk_buff *skb;
int err;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_net = net_generic(ctx->net, nf_tables_net_id);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
struct netlink_callback *cb)
{
const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
+ struct nftables_pernet *nft_net;
const struct nft_table *table;
unsigned int idx = 0, s_idx = cb->args[0];
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
continue;
nft_trans_table_flags(trans) = flags;
nft_trans_table_update(trans) = true;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
err:
nft_trans_destroy(trans);
const struct nlattr * const nla[],
struct netlink_ext_ack *extack)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
u32 flags = 0;
int err;
- lockdep_assert_held(&net->nft.commit_mutex);
+ lockdep_assert_held(&nft_net->commit_mutex);
attr = nla[NFTA_TABLE_NAME];
table = nft_table_lookup(net, attr, family, genmask,
NETLINK_CB(skb).portid);
if (err < 0)
goto err_trans;
- list_add_tail_rcu(&table->list, &net->nft.tables);
+ list_add_tail_rcu(&table->list, &nft_net->tables);
return 0;
err_trans:
rhltable_destroy(&table->chains_ht);
static int nft_flush(struct nft_ctx *ctx, int family)
{
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
struct nft_table *table, *nt;
const struct nlattr * const *nla = ctx->nla;
int err = 0;
- list_for_each_entry_safe(table, nt, &ctx->net->nft.tables, list) {
+ list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
if (family != AF_UNSPEC && table->family != family)
continue;
static bool lockdep_commit_lock_is_held(const struct net *net)
{
#ifdef CONFIG_PROVE_LOCKING
- return lockdep_is_held(&net->nft.commit_mutex);
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+
+ return lockdep_is_held(&nft_net->commit_mutex);
#else
return true;
#endif
static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
{
+ struct nftables_pernet *nft_net;
struct sk_buff *skb;
int err;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_net = net_generic(ctx->net, nf_tables_net_id);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
unsigned int idx = 0, s_idx = cb->args[0];
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
+ struct nftables_pernet *nft_net;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
continue;
struct nft_chain_hook *hook, u8 family,
bool autoload)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nlattr *ha[NFTA_HOOK_MAX + 1];
const struct nft_chain_type *type;
int err;
- lockdep_assert_held(&net->nft.commit_mutex);
+ lockdep_assert_held(&nft_net->commit_mutex);
lockdep_nfnl_nft_mutex_not_held();
err = nla_parse_nested_deprecated(ha, NFTA_HOOK_MAX,
if (nla[NFTA_CHAIN_HANDLE] &&
nla[NFTA_CHAIN_NAME]) {
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
struct nft_trans *tmp;
char *name;
goto err;
err = -EEXIST;
- list_for_each_entry(tmp, &ctx->net->nft.commit_list, list) {
+ list_for_each_entry(tmp, &nft_net->commit_list, list) {
if (tmp->msg_type == NFT_MSG_NEWCHAIN &&
tmp->ctx.table == table &&
nft_trans_chain_update(tmp) &&
nft_trans_chain_name(trans) = name;
}
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
err:
static struct nft_chain *nft_chain_lookup_byid(const struct net *net,
const struct nlattr *nla)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
u32 id = ntohl(nla_get_be32(nla));
struct nft_trans *trans;
- list_for_each_entry(trans, &net->nft.commit_list, list) {
+ list_for_each_entry(trans, &nft_net->commit_list, list) {
struct nft_chain *chain = trans->ctx.chain;
if (trans->msg_type == NFT_MSG_NEWCHAIN &&
const struct nlattr * const nla[],
struct netlink_ext_ack *extack)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
u64 handle = 0;
u32 flags = 0;
- lockdep_assert_held(&net->nft.commit_mutex);
+ lockdep_assert_held(&nft_net->commit_mutex);
table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask,
NETLINK_CB(skb).portid);
static void nf_tables_rule_notify(const struct nft_ctx *ctx,
const struct nft_rule *rule, int event)
{
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
struct sk_buff *skb;
int err;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
unsigned int idx = 0;
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
+ struct nftables_pernet *nft_net;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
continue;
const struct nlattr * const nla[],
struct netlink_ext_ack *extack)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u8 genmask = nft_genmask_next(net);
struct nft_expr_info *info = NULL;
int err, rem;
u64 handle, pos_handle;
- lockdep_assert_held(&net->nft.commit_mutex);
+ lockdep_assert_held(&nft_net->commit_mutex);
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask,
NETLINK_CB(skb).portid);
kvfree(info);
chain->use++;
- if (net->nft.validate_state == NFT_VALIDATE_DO)
+ if (nft_net->validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, table);
if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
const struct nlattr *nla)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
u32 id = ntohl(nla_get_be32(nla));
struct nft_trans *trans;
- list_for_each_entry(trans, &net->nft.commit_list, list) {
+ list_for_each_entry(trans, &nft_net->commit_list, list) {
struct nft_rule *rule = nft_trans_rule(trans);
if (trans->msg_type == NFT_MSG_NEWRULE &&
const struct nft_set_desc *desc,
enum nft_set_policies policy)
{
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
const struct nft_set_ops *ops, *bops;
struct nft_set_estimate est, best;
const struct nft_set_type *type;
u32 flags = 0;
int i;
- lockdep_assert_held(&ctx->net->nft.commit_mutex);
+ lockdep_assert_held(&nft_net->commit_mutex);
lockdep_nfnl_nft_mutex_not_held();
if (nla[NFTA_SET_FLAGS] != NULL)
static struct nft_set *nft_set_lookup_byid(const struct net *net,
const struct nlattr *nla, u8 genmask)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_trans *trans;
u32 id = ntohl(nla_get_be32(nla));
- list_for_each_entry(trans, &net->nft.commit_list, list) {
+ list_for_each_entry(trans, &nft_net->commit_list, list) {
if (trans->msg_type == NFT_MSG_NEWSET) {
struct nft_set *set = nft_trans_set(trans);
const struct nft_set *set, int event,
gfp_t gfp_flags)
{
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
struct sk_buff *skb;
u32 portid = ctx->portid;
int err;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
struct net *net = sock_net(skb->sk);
struct nft_ctx *ctx = cb->data, ctx_set;
+ struct nftables_pernet *nft_net;
if (cb->args[1])
return skb->len;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (ctx->family != NFPROTO_UNSPEC &&
ctx->family != table->family)
continue;
{
struct nft_set_dump_ctx *dump_ctx = cb->data;
struct net *net = sock_net(skb->sk);
+ struct nftables_pernet *nft_net;
struct nft_table *table;
struct nft_set *set;
struct nft_set_dump_args args;
int event;
rcu_read_lock();
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
dump_ctx->ctx.family != table->family)
continue;
const struct nft_set_elem *elem,
int event, u16 flags)
{
+ struct nftables_pernet *nft_net;
struct net *net = ctx->net;
u32 portid = ctx->portid;
struct sk_buff *skb;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_net = net_generic(net, nf_tables_net_id);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
}
nft_trans_elem(trans) = elem;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
err_set_full:
const struct nlattr * const nla[],
struct netlink_ext_ack *extack)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
u8 genmask = nft_genmask_next(net);
const struct nlattr *attr;
struct nft_set *set;
return err;
}
- if (net->nft.validate_state == NFT_VALIDATE_DO)
+ if (nft_net->validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, ctx.table);
return 0;
nft_set_elem_deactivate(ctx->net, set, &elem);
nft_trans_elem(trans) = elem;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
fail_ops:
nft_set_elem_deactivate(ctx->net, set, elem);
nft_trans_elem_set(trans) = set;
nft_trans_elem(trans) = *elem;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
err1:
nft_trans_obj(trans) = obj;
nft_trans_obj_update(trans) = true;
nft_trans_obj_newobj(trans) = newobj;
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
struct nft_obj_filter *filter = cb->data;
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
+ struct nftables_pernet *nft_net;
struct nft_object *obj;
bool reset = false;
reset = true;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
continue;
char *buf = kasprintf(GFP_ATOMIC,
"%s:%u",
table->name,
- net->nft.base_seq);
+ nft_net->base_seq);
audit_log_nfcfg(buf,
family,
reset = true;
if (reset) {
- char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
- table->name, net->nft.base_seq);
+ const struct nftables_pernet *nft_net;
+ char *buf;
+
+ nft_net = net_generic(net, nf_tables_net_id);
+ buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, nft_net->base_seq);
audit_log_nfcfg(buf,
family,
struct nft_object *obj, u32 portid, u32 seq, int event,
int family, int report, gfp_t gfp)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct sk_buff *skb;
int err;
char *buf = kasprintf(gfp, "%s:%u",
- table->name, net->nft.base_seq);
+ table->name, nft_net->base_seq);
audit_log_nfcfg(buf,
family,
goto err;
}
- nft_notify_enqueue(skb, report, &net->nft.notify_list);
+ nft_notify_enqueue(skb, report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans));
list_splice(&flowtable_hook.list, &nft_trans_flowtable_hooks(trans));
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans));
nft_flowtable_hook_release(&flowtable_hook);
- list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+ nft_trans_commit_list_add_tail(ctx->net, trans);
return 0;
struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
struct nft_flowtable *flowtable;
+ struct nftables_pernet *nft_net;
const struct nft_table *table;
rcu_read_lock();
- cb->seq = net->nft.base_seq;
+ nft_net = net_generic(net, nf_tables_net_id);
+ cb->seq = nft_net->base_seq;
- list_for_each_entry_rcu(table, &net->nft.tables, list) {
+ list_for_each_entry_rcu(table, &nft_net->tables, list) {
if (family != NFPROTO_UNSPEC && family != table->family)
continue;
struct list_head *hook_list,
int event)
{
+ struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
struct sk_buff *skb;
int err;
goto err;
}
- nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
+ nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
return;
err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
u32 portid, u32 seq)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nlmsghdr *nlh;
char buf[TASK_COMM_LEN];
int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
if (!nlh)
goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)) ||
+ if (nla_put_be32(skb, NFTA_GEN_ID, htonl(nft_net->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)))
goto nla_put_failure;
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct nft_flowtable *flowtable;
+ struct nftables_pernet *nft_net;
struct nft_table *table;
struct net *net;
return 0;
net = dev_net(dev);
- mutex_lock(&net->nft.commit_mutex);
- list_for_each_entry(table, &net->nft.tables, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ mutex_lock(&nft_net->commit_mutex);
+ list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(flowtable, &table->flowtables, list) {
nft_flowtable_event(event, dev, flowtable);
}
}
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
return NOTIFY_DONE;
}
static int nf_tables_validate(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_table *table;
- switch (net->nft.validate_state) {
+ switch (nft_net->validate_state) {
case NFT_VALIDATE_SKIP:
break;
case NFT_VALIDATE_NEED:
nft_validate_state_update(net, NFT_VALIDATE_DO);
fallthrough;
case NFT_VALIDATE_DO:
- list_for_each_entry(table, &net->nft.tables, list) {
+ list_for_each_entry(table, &nft_net->tables, list) {
if (nft_table_validate(net, table) < 0)
return -EAGAIN;
}
static void nf_tables_commit_chain_prepare_cancel(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_trans *trans, *next;
- list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+ list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
struct nft_chain *chain = trans->ctx.chain;
if (trans->msg_type == NFT_MSG_NEWRULE ||
static void nf_tables_module_autoload_cleanup(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_module_request *req, *next;
- WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
- list_for_each_entry_safe(req, next, &net->nft.module_list, list) {
+ WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
+ list_for_each_entry_safe(req, next, &nft_net->module_list, list) {
WARN_ON_ONCE(!req->done);
list_del(&req->list);
kfree(req);
static void nf_tables_commit_release(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_trans *trans;
/* all side effects have to be made visible.
* Memory reclaim happens asynchronously from work queue
* to prevent expensive synchronize_rcu() in commit phase.
*/
- if (list_empty(&net->nft.commit_list)) {
+ if (list_empty(&nft_net->commit_list)) {
nf_tables_module_autoload_cleanup(net);
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
return;
}
- trans = list_last_entry(&net->nft.commit_list,
+ trans = list_last_entry(&nft_net->commit_list,
struct nft_trans, list);
get_net(trans->ctx.net);
WARN_ON_ONCE(trans->put_net);
trans->put_net = true;
spin_lock(&nf_tables_destroy_list_lock);
- list_splice_tail_init(&net->nft.commit_list, &nf_tables_destroy_list);
+ list_splice_tail_init(&nft_net->commit_list, &nf_tables_destroy_list);
spin_unlock(&nf_tables_destroy_list_lock);
nf_tables_module_autoload_cleanup(net);
schedule_work(&trans_destroy_work);
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
}
static void nft_commit_notify(struct net *net, u32 portid)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct sk_buff *batch_skb = NULL, *nskb, *skb;
unsigned char *data;
int len;
- list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) {
+ list_for_each_entry_safe(skb, nskb, &nft_net->notify_list, list) {
if (!batch_skb) {
new_batch:
batch_skb = skb;
NFT_CB(batch_skb).report, GFP_KERNEL);
}
- WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
+ WARN_ON_ONCE(!list_empty(&nft_net->notify_list));
}
static int nf_tables_commit_audit_alloc(struct list_head *adl,
static int nf_tables_commit(struct net *net, struct sk_buff *skb)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
struct nft_chain *chain;
LIST_HEAD(adl);
int err;
- if (list_empty(&net->nft.commit_list)) {
- mutex_unlock(&net->nft.commit_mutex);
+ if (list_empty(&nft_net->commit_list)) {
+ mutex_unlock(&nft_net->commit_mutex);
return 0;
}
return err;
/* 1. Allocate space for next generation rules_gen_X[] */
- list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+ list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
int ret;
ret = nf_tables_commit_audit_alloc(&adl, trans->ctx.table);
}
/* step 2. Make rules_gen_X visible to packet path */
- list_for_each_entry(table, &net->nft.tables, list) {
+ list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(chain, &table->chains, list)
nf_tables_commit_chain(net, chain);
}
* Bump generation counter, invalidate any dump in progress.
* Cannot fail after this point.
*/
- while (++net->nft.base_seq == 0);
+ while (++nft_net->base_seq == 0)
+ ;
/* step 3. Start new generation, rules_gen_X now in use. */
net->nft.gencursor = nft_gencursor_next(net);
- list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+ list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
nf_tables_commit_audit_collect(&adl, trans->ctx.table,
trans->msg_type);
switch (trans->msg_type) {
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_audit_log(&adl, nft_net->base_seq);
nf_tables_commit_release(net);
return 0;
static void nf_tables_module_autoload(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_module_request *req, *next;
LIST_HEAD(module_list);
- list_splice_init(&net->nft.module_list, &module_list);
- mutex_unlock(&net->nft.commit_mutex);
+ list_splice_init(&nft_net->module_list, &module_list);
+ mutex_unlock(&nft_net->commit_mutex);
list_for_each_entry_safe(req, next, &module_list, list) {
request_module("%s", req->module);
req->done = true;
}
- mutex_lock(&net->nft.commit_mutex);
- list_splice(&module_list, &net->nft.module_list);
+ mutex_lock(&nft_net->commit_mutex);
+ list_splice(&module_list, &nft_net->module_list);
}
static void nf_tables_abort_release(struct nft_trans *trans)
static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
struct nft_hook *hook;
nf_tables_validate(net) < 0)
return -EAGAIN;
- list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
+ list_for_each_entry_safe_reverse(trans, next, &nft_net->commit_list,
list) {
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
synchronize_rcu();
list_for_each_entry_safe_reverse(trans, next,
- &net->nft.commit_list, list) {
+ &nft_net->commit_list, list) {
list_del(&trans->list);
nf_tables_abort_release(trans);
}
static int nf_tables_abort(struct net *net, struct sk_buff *skb,
enum nfnl_abort_action action)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
int ret = __nf_tables_abort(net, action);
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
return ret;
}
static bool nf_tables_valid_genid(struct net *net, u32 genid)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
bool genid_ok;
- mutex_lock(&net->nft.commit_mutex);
+ mutex_lock(&nft_net->commit_mutex);
- genid_ok = genid == 0 || net->nft.base_seq == genid;
+ genid_ok = genid == 0 || nft_net->base_seq == genid;
if (!genid_ok)
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
/* else, commit mutex has to be released by commit or abort function */
return genid_ok;
static void __nft_release_hooks(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_table *table;
- list_for_each_entry(table, &net->nft.tables, list) {
+ list_for_each_entry(table, &nft_net->tables, list) {
if (nft_table_has_owner(table))
continue;
static void __nft_release_tables(struct net *net)
{
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
struct nft_table *table, *nt;
- list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
+ list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
if (nft_table_has_owner(table))
continue;
static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
+ struct nftables_pernet *nft_net;
struct netlink_notify *n = ptr;
struct nft_table *table, *nt;
struct net *net = n->net;
if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
return NOTIFY_DONE;
- mutex_lock(&net->nft.commit_mutex);
- list_for_each_entry(table, &net->nft.tables, list) {
+ nft_net = net_generic(net, nf_tables_net_id);
+ mutex_lock(&nft_net->commit_mutex);
+ list_for_each_entry(table, &nft_net->tables, list) {
if (nft_table_has_owner(table) &&
n->portid == table->nlpid) {
__nft_release_hook(net, table);
}
if (release) {
synchronize_rcu();
- list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
+ list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
if (nft_table_has_owner(table) &&
n->portid == table->nlpid)
__nft_release_table(net, table);
}
}
- mutex_unlock(&net->nft.commit_mutex);
+ mutex_unlock(&nft_net->commit_mutex);
return NOTIFY_DONE;
}
static int __net_init nf_tables_init_net(struct net *net)
{
- INIT_LIST_HEAD(&net->nft.tables);
- INIT_LIST_HEAD(&net->nft.commit_list);
- INIT_LIST_HEAD(&net->nft.module_list);
- INIT_LIST_HEAD(&net->nft.notify_list);
- mutex_init(&net->nft.commit_mutex);
- net->nft.base_seq = 1;
- net->nft.validate_state = NFT_VALIDATE_SKIP;
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+
+ INIT_LIST_HEAD(&nft_net->tables);
+ INIT_LIST_HEAD(&nft_net->commit_list);
+ INIT_LIST_HEAD(&nft_net->module_list);
+ INIT_LIST_HEAD(&nft_net->notify_list);
+ mutex_init(&nft_net->commit_mutex);
+ nft_net->base_seq = 1;
+ nft_net->validate_state = NFT_VALIDATE_SKIP;
return 0;
}
static void __net_exit nf_tables_exit_net(struct net *net)
{
- mutex_lock(&net->nft.commit_mutex);
- if (!list_empty(&net->nft.commit_list))
+ struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+
+ mutex_lock(&nft_net->commit_mutex);
+ if (!list_empty(&nft_net->commit_list))
__nf_tables_abort(net, NFNL_ABORT_NONE);
__nft_release_tables(net);
- mutex_unlock(&net->nft.commit_mutex);
- WARN_ON_ONCE(!list_empty(&net->nft.tables));
- WARN_ON_ONCE(!list_empty(&net->nft.module_list));
- WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
+ mutex_unlock(&nft_net->commit_mutex);
+ WARN_ON_ONCE(!list_empty(&nft_net->tables));
+ WARN_ON_ONCE(!list_empty(&nft_net->module_list));
+ WARN_ON_ONCE(!list_empty(&nft_net->notify_list));
}
static struct pernet_operations nf_tables_net_ops = {
.init = nf_tables_init_net,
.pre_exit = nf_tables_pre_exit_net,
.exit = nf_tables_exit_net,
+ .id = &nf_tables_net_id,
+ .size = sizeof(struct nftables_pernet),
};
static int __init nf_tables_module_init(void)