diff options
-rw-r--r-- | include/net/netfilter/nf_tables.h | 5 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 31 | ||||
-rw-r--r-- | net/netfilter/nf_tables_netdev.c | 45 |
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 | ||
824 | int nft_register_basechain(struct nft_base_chain *basechain, | 824 | int __nft_release_basechain(struct nft_ctx *ctx); |
825 | unsigned int hook_nops); | ||
826 | void nft_unregister_basechain(struct nft_base_chain *basechain, | ||
827 | unsigned int hook_nops); | ||
828 | 825 | ||
829 | unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv); | 826 | unsigned 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 | ||
134 | int nft_register_basechain(struct nft_base_chain *basechain, | 134 | static 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 | } |
144 | EXPORT_SYMBOL_GPL(nft_register_basechain); | ||
145 | 144 | ||
146 | void nft_unregister_basechain(struct nft_base_chain *basechain, | 145 | static 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 | } |
156 | EXPORT_SYMBOL_GPL(nft_unregister_basechain); | ||
157 | 155 | ||
158 | static int nf_tables_register_hooks(const struct nft_table *table, | 156 | static 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 | ||
4591 | int __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 | } | ||
4610 | EXPORT_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. */ |
4594 | static void __nft_release_afinfo(struct net *net, struct nft_af_info *afi) | 4613 | static 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 | ||
159 | static void nft_netdev_event(unsigned long event, struct nft_af_info *afi, | 159 | static 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 | } |