aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netfilter/nf_tables.h5
-rw-r--r--net/netfilter/nf_tables_api.c31
-rw-r--r--net/netfilter/nf_tables_netdev.c45
3 files changed, 44 insertions, 37 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index a50f139ce087..0191fbb33a2f 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -821,10 +821,7 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
821 return container_of(chain, struct nft_base_chain, chain); 821 return container_of(chain, struct nft_base_chain, chain);
822} 822}
823 823
824int nft_register_basechain(struct nft_base_chain *basechain, 824int __nft_release_basechain(struct nft_ctx *ctx);
825 unsigned int hook_nops);
826void nft_unregister_basechain(struct nft_base_chain *basechain,
827 unsigned int hook_nops);
828 825
829unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv); 826unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
830 827
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 852273110275..5729844e1d46 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -131,8 +131,8 @@ static void nft_trans_destroy(struct nft_trans *trans)
131 kfree(trans); 131 kfree(trans);
132} 132}
133 133
134int nft_register_basechain(struct nft_base_chain *basechain, 134static int nft_register_basechain(struct nft_base_chain *basechain,
135 unsigned int hook_nops) 135 unsigned int hook_nops)
136{ 136{
137 struct net *net = read_pnet(&basechain->pnet); 137 struct net *net = read_pnet(&basechain->pnet);
138 138
@@ -141,10 +141,9 @@ int nft_register_basechain(struct nft_base_chain *basechain,
141 141
142 return nf_register_net_hooks(net, basechain->ops, hook_nops); 142 return nf_register_net_hooks(net, basechain->ops, hook_nops);
143} 143}
144EXPORT_SYMBOL_GPL(nft_register_basechain);
145 144
146void nft_unregister_basechain(struct nft_base_chain *basechain, 145static void nft_unregister_basechain(struct nft_base_chain *basechain,
147 unsigned int hook_nops) 146 unsigned int hook_nops)
148{ 147{
149 struct net *net = read_pnet(&basechain->pnet); 148 struct net *net = read_pnet(&basechain->pnet);
150 149
@@ -153,7 +152,6 @@ void nft_unregister_basechain(struct nft_base_chain *basechain,
153 152
154 nf_unregister_net_hooks(net, basechain->ops, hook_nops); 153 nf_unregister_net_hooks(net, basechain->ops, hook_nops);
155} 154}
156EXPORT_SYMBOL_GPL(nft_unregister_basechain);
157 155
158static int nf_tables_register_hooks(const struct nft_table *table, 156static int nf_tables_register_hooks(const struct nft_table *table,
159 struct nft_chain *chain, 157 struct nft_chain *chain,
@@ -4590,6 +4588,27 @@ static int __net_init nf_tables_init_net(struct net *net)
4590 return 0; 4588 return 0;
4591} 4589}
4592 4590
4591int __nft_release_basechain(struct nft_ctx *ctx)
4592{
4593 struct nft_rule *rule, *nr;
4594
4595 BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
4596
4597 nf_tables_unregister_hooks(ctx->chain->table, ctx->chain,
4598 ctx->afi->nops);
4599 list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
4600 list_del(&rule->list);
4601 ctx->chain->use--;
4602 nf_tables_rule_destroy(ctx, rule);
4603 }
4604 list_del(&ctx->chain->list);
4605 ctx->table->use--;
4606 nf_tables_chain_destroy(ctx->chain);
4607
4608 return 0;
4609}
4610EXPORT_SYMBOL_GPL(__nft_release_basechain);
4611
4593/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */ 4612/* Called by nft_unregister_afinfo() from __net_exit path, nfnl_lock is held. */
4594static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) 4613static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi)
4595{ 4614{
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
index 2bfd1fbccec8..3e9c87b961ba 100644
--- a/net/netfilter/nf_tables_netdev.c
+++ b/net/netfilter/nf_tables_netdev.c
@@ -156,35 +156,17 @@ static const struct nf_chain_type nft_filter_chain_netdev = {
156 .hook_mask = (1 << NF_NETDEV_INGRESS), 156 .hook_mask = (1 << NF_NETDEV_INGRESS),
157}; 157};
158 158
159static void nft_netdev_event(unsigned long event, struct nft_af_info *afi, 159static void nft_netdev_event(unsigned long event, struct net_device *dev,
160 struct net_device *dev, struct nft_table *table, 160 struct nft_ctx *ctx)
161 struct nft_base_chain *basechain)
162{ 161{
163 switch (event) { 162 struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
164 case NETDEV_REGISTER:
165 if (strcmp(basechain->dev_name, dev->name) != 0)
166 return;
167 163
168 BUG_ON(!(basechain->flags & NFT_BASECHAIN_DISABLED)); 164 switch (event) {
169
170 dev_hold(dev);
171 basechain->ops[0].dev = dev;
172 basechain->flags &= ~NFT_BASECHAIN_DISABLED;
173 if (!(table->flags & NFT_TABLE_F_DORMANT))
174 nft_register_basechain(basechain, afi->nops);
175 break;
176 case NETDEV_UNREGISTER: 165 case NETDEV_UNREGISTER:
177 if (strcmp(basechain->dev_name, dev->name) != 0) 166 if (strcmp(basechain->dev_name, dev->name) != 0)
178 return; 167 return;
179 168
180 BUG_ON(basechain->flags & NFT_BASECHAIN_DISABLED); 169 __nft_release_basechain(ctx);
181
182 if (!(table->flags & NFT_TABLE_F_DORMANT))
183 nft_unregister_basechain(basechain, afi->nops);
184
185 dev_put(basechain->ops[0].dev);
186 basechain->ops[0].dev = NULL;
187 basechain->flags |= NFT_BASECHAIN_DISABLED;
188 break; 170 break;
189 case NETDEV_CHANGENAME: 171 case NETDEV_CHANGENAME:
190 if (dev->ifindex != basechain->ops[0].dev->ifindex) 172 if (dev->ifindex != basechain->ops[0].dev->ifindex)
@@ -201,20 +183,29 @@ static int nf_tables_netdev_event(struct notifier_block *this,
201 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 183 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
202 struct nft_af_info *afi; 184 struct nft_af_info *afi;
203 struct nft_table *table; 185 struct nft_table *table;
204 struct nft_chain *chain; 186 struct nft_chain *chain, *nr;
187 struct nft_ctx ctx = {
188 .net = dev_net(dev),
189 };
190
191 if (event != NETDEV_UNREGISTER &&
192 event != NETDEV_CHANGENAME)
193 return NOTIFY_DONE;
205 194
206 nfnl_lock(NFNL_SUBSYS_NFTABLES); 195 nfnl_lock(NFNL_SUBSYS_NFTABLES);
207 list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) { 196 list_for_each_entry(afi, &dev_net(dev)->nft.af_info, list) {
197 ctx.afi = afi;
208 if (afi->family != NFPROTO_NETDEV) 198 if (afi->family != NFPROTO_NETDEV)
209 continue; 199 continue;
210 200
211 list_for_each_entry(table, &afi->tables, list) { 201 list_for_each_entry(table, &afi->tables, list) {
212 list_for_each_entry(chain, &table->chains, list) { 202 ctx.table = table;
203 list_for_each_entry_safe(chain, nr, &table->chains, list) {
213 if (!(chain->flags & NFT_BASE_CHAIN)) 204 if (!(chain->flags & NFT_BASE_CHAIN))
214 continue; 205 continue;
215 206
216 nft_netdev_event(event, afi, dev, table, 207 ctx.chain = chain;
217 nft_base_chain(chain)); 208 nft_netdev_event(event, dev, &ctx);
218 } 209 }
219 } 210 }
220 } 211 }