aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--net/netfilter/nf_tables_api.c33
-rw-r--r--net/netfilter/nft_chain_filter.c33
2 files changed, 48 insertions, 18 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 713ea0e48772..452f8a42d5e6 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -9690,16 +9690,20 @@ struct nf_hook_ops *nft_hook_find_ops_rcu(const struct nft_hook *hook,
EXPORT_SYMBOL_GPL(nft_hook_find_ops_rcu);
static int nft_flowtable_event(unsigned long event, struct net_device *dev,
- struct nft_flowtable *flowtable)
+ struct nft_flowtable *flowtable, bool changename)
{
struct nf_hook_ops *ops;
struct nft_hook *hook;
+ bool match;
list_for_each_entry(hook, &flowtable->hook_list, list) {
+ ops = nft_hook_find_ops(hook, dev);
+ match = !strcmp(hook->ifname, dev->name);
+
switch (event) {
case NETDEV_UNREGISTER:
- ops = nft_hook_find_ops(hook, dev);
- if (!ops)
+ /* NOP if not found or new name still matching */
+ if (!ops || (changename && match))
continue;
/* flow_offload_netdev_event() cleans up entries for us. */
@@ -9709,7 +9713,8 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
kfree_rcu(ops, rcu);
break;
case NETDEV_REGISTER:
- if (strcmp(hook->ifname, dev->name))
+ /* NOP if not matching or already registered */
+ if (!match || (changename && ops))
continue;
ops = kzalloc(sizeof(struct nf_hook_ops),
@@ -9737,7 +9742,8 @@ static int nft_flowtable_event(unsigned long event, struct net_device *dev,
}
static int __nf_tables_flowtable_event(unsigned long event,
- struct net_device *dev)
+ struct net_device *dev,
+ bool changename)
{
struct nftables_pernet *nft_net = nft_pernet(dev_net(dev));
struct nft_flowtable *flowtable;
@@ -9745,7 +9751,8 @@ static int __nf_tables_flowtable_event(unsigned long event,
list_for_each_entry(table, &nft_net->tables, list) {
list_for_each_entry(flowtable, &table->flowtables, list) {
- if (nft_flowtable_event(event, dev, flowtable))
+ if (nft_flowtable_event(event, dev,
+ flowtable, changename))
return 1;
}
}
@@ -9761,16 +9768,24 @@ static int nf_tables_flowtable_event(struct notifier_block *this,
struct net *net;
if (event != NETDEV_REGISTER &&
- event != NETDEV_UNREGISTER)
+ event != NETDEV_UNREGISTER &&
+ event != NETDEV_CHANGENAME)
return NOTIFY_DONE;
net = dev_net(dev);
nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex);
- if (__nf_tables_flowtable_event(event, dev))
+ if (event == NETDEV_CHANGENAME) {
+ if (__nf_tables_flowtable_event(NETDEV_REGISTER, dev, true)) {
+ ret = NOTIFY_BAD;
+ goto out_unlock;
+ }
+ __nf_tables_flowtable_event(NETDEV_UNREGISTER, dev, true);
+ } else if (__nf_tables_flowtable_event(event, dev, false)) {
ret = NOTIFY_BAD;
-
+ }
+out_unlock:
mutex_unlock(&nft_net->commit_mutex);
return ret;
}
diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c
index 7795dff13408..b59f8be6370e 100644
--- a/net/netfilter/nft_chain_filter.c
+++ b/net/netfilter/nft_chain_filter.c
@@ -319,17 +319,21 @@ static const struct nft_chain_type nft_chain_filter_netdev = {
};
static int nft_netdev_event(unsigned long event, struct net_device *dev,
- struct nft_base_chain *basechain)
+ struct nft_base_chain *basechain, bool changename)
{
struct nft_table *table = basechain->chain.table;
struct nf_hook_ops *ops;
struct nft_hook *hook;
+ bool match;
list_for_each_entry(hook, &basechain->hook_list, list) {
+ ops = nft_hook_find_ops(hook, dev);
+ match = !strcmp(hook->ifname, dev->name);
+
switch (event) {
case NETDEV_UNREGISTER:
- ops = nft_hook_find_ops(hook, dev);
- if (!ops)
+ /* NOP if not found or new name still matching */
+ if (!ops || (changename && match))
continue;
if (!(table->flags & NFT_TABLE_F_DORMANT))
@@ -339,7 +343,8 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
kfree_rcu(ops, rcu);
break;
case NETDEV_REGISTER:
- if (strcmp(hook->ifname, dev->name))
+ /* NOP if not matching or already registered */
+ if (!match || (changename && ops))
continue;
ops = kmemdup(&basechain->ops,
@@ -363,7 +368,9 @@ static int nft_netdev_event(unsigned long event, struct net_device *dev,
return 0;
}
-static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev)
+static int __nf_tables_netdev_event(unsigned long event,
+ struct net_device *dev,
+ bool changename)
{
struct nft_base_chain *basechain;
struct nftables_pernet *nft_net;
@@ -385,7 +392,7 @@ static int __nf_tables_netdev_event(unsigned long event, struct net_device *dev)
basechain->ops.hooknum != NF_INET_INGRESS)
continue;
- if (nft_netdev_event(event, dev, basechain))
+ if (nft_netdev_event(event, dev, basechain, changename))
return 1;
}
}
@@ -400,15 +407,23 @@ static int nf_tables_netdev_event(struct notifier_block *this,
int ret = NOTIFY_DONE;
if (event != NETDEV_REGISTER &&
- event != NETDEV_UNREGISTER)
+ event != NETDEV_UNREGISTER &&
+ event != NETDEV_CHANGENAME)
return NOTIFY_DONE;
nft_net = nft_pernet(dev_net(dev));
mutex_lock(&nft_net->commit_mutex);
- if (__nf_tables_netdev_event(event, dev))
+ if (event == NETDEV_CHANGENAME) {
+ if (__nf_tables_netdev_event(NETDEV_REGISTER, dev, true)) {
+ ret = NOTIFY_BAD;
+ goto out_unlock;
+ }
+ __nf_tables_netdev_event(NETDEV_UNREGISTER, dev, true);
+ } else if (__nf_tables_netdev_event(event, dev, false)) {
ret = NOTIFY_BAD;
-
+ }
+out_unlock:
mutex_unlock(&nft_net->commit_mutex);
return ret;
}