blob: 78de717afddf01a16cc9eccdae5a8e9531f3d766 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * net/sched/cls_api.c Packet classifier API.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 * Changes:
12 *
13 * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support
14 *
15 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/module.h>
18#include <linux/types.h>
19#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/errno.h>
Jiri Pirko33a48922017-02-09 14:38:57 +010022#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/init.h>
25#include <linux/kmod.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Jiri Pirko48617382018-01-17 11:46:46 +010027#include <linux/idr.h>
John Hurley7f76fa32018-11-09 21:21:26 -080028#include <linux/rhashtable.h>
Denis V. Lunevb8542722007-12-01 00:21:31 +110029#include <net/net_namespace.h>
30#include <net/sock.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070031#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <net/pkt_sched.h>
33#include <net/pkt_cls.h>
Pablo Neira Ayusoe3ab7862019-02-02 12:50:45 +010034#include <net/tc_act/tc_pedit.h>
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +010035#include <net/tc_act/tc_mirred.h>
36#include <net/tc_act/tc_vlan.h>
37#include <net/tc_act/tc_tunnel_key.h>
38#include <net/tc_act/tc_csum.h>
39#include <net/tc_act/tc_gact.h>
40#include <net/tc_act/tc_skbedit.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Davide Carattie3314732018-10-10 22:00:58 +020042extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/* The list of all installed classifier types */
WANG Cong36272872013-12-15 20:15:11 -080045static LIST_HEAD(tcf_proto_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47/* Protects list of registered TC modules. It is pure SMP lock. */
48static DEFINE_RWLOCK(cls_mod_lock);
49
50/* Find classifier type by string name */
51
Jiri Pirkof34e8bf2018-07-23 09:23:04 +020052static const struct tcf_proto_ops *__tcf_proto_lookup_ops(const char *kind)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053{
Eric Dumazetdcd76082013-12-20 10:04:18 -080054 const struct tcf_proto_ops *t, *res = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56 if (kind) {
57 read_lock(&cls_mod_lock);
WANG Cong36272872013-12-15 20:15:11 -080058 list_for_each_entry(t, &tcf_proto_base, head) {
Jiri Pirko33a48922017-02-09 14:38:57 +010059 if (strcmp(kind, t->kind) == 0) {
Eric Dumazetdcd76082013-12-20 10:04:18 -080060 if (try_module_get(t->owner))
61 res = t;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 break;
63 }
64 }
65 read_unlock(&cls_mod_lock);
66 }
Eric Dumazetdcd76082013-12-20 10:04:18 -080067 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
Jiri Pirkof34e8bf2018-07-23 09:23:04 +020070static const struct tcf_proto_ops *
Vlad Buslov12db03b2019-02-11 10:55:45 +020071tcf_proto_lookup_ops(const char *kind, bool rtnl_held,
72 struct netlink_ext_ack *extack)
Jiri Pirkof34e8bf2018-07-23 09:23:04 +020073{
74 const struct tcf_proto_ops *ops;
75
76 ops = __tcf_proto_lookup_ops(kind);
77 if (ops)
78 return ops;
79#ifdef CONFIG_MODULES
Vlad Buslov12db03b2019-02-11 10:55:45 +020080 if (rtnl_held)
81 rtnl_unlock();
Jiri Pirkof34e8bf2018-07-23 09:23:04 +020082 request_module("cls_%s", kind);
Vlad Buslov12db03b2019-02-11 10:55:45 +020083 if (rtnl_held)
84 rtnl_lock();
Jiri Pirkof34e8bf2018-07-23 09:23:04 +020085 ops = __tcf_proto_lookup_ops(kind);
86 /* We dropped the RTNL semaphore in order to perform
87 * the module load. So, even if we succeeded in loading
88 * the module we have to replay the request. We indicate
89 * this using -EAGAIN.
90 */
91 if (ops) {
92 module_put(ops->owner);
93 return ERR_PTR(-EAGAIN);
94 }
95#endif
96 NL_SET_ERR_MSG(extack, "TC classifier not found");
97 return ERR_PTR(-ENOENT);
98}
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* Register(unregister) new classifier type */
101
102int register_tcf_proto_ops(struct tcf_proto_ops *ops)
103{
WANG Cong36272872013-12-15 20:15:11 -0800104 struct tcf_proto_ops *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 int rc = -EEXIST;
106
107 write_lock(&cls_mod_lock);
WANG Cong36272872013-12-15 20:15:11 -0800108 list_for_each_entry(t, &tcf_proto_base, head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if (!strcmp(ops->kind, t->kind))
110 goto out;
111
WANG Cong36272872013-12-15 20:15:11 -0800112 list_add_tail(&ops->head, &tcf_proto_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 rc = 0;
114out:
115 write_unlock(&cls_mod_lock);
116 return rc;
117}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800118EXPORT_SYMBOL(register_tcf_proto_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Cong Wang7aa00452017-10-26 18:24:28 -0700120static struct workqueue_struct *tc_filter_wq;
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
123{
WANG Cong36272872013-12-15 20:15:11 -0800124 struct tcf_proto_ops *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 int rc = -ENOENT;
126
Daniel Borkmannc78e1742015-05-20 17:13:33 +0200127 /* Wait for outstanding call_rcu()s, if any, from a
128 * tcf_proto_ops's destroy() handler.
129 */
130 rcu_barrier();
Cong Wang7aa00452017-10-26 18:24:28 -0700131 flush_workqueue(tc_filter_wq);
Daniel Borkmannc78e1742015-05-20 17:13:33 +0200132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 write_lock(&cls_mod_lock);
Eric Dumazetdcd76082013-12-20 10:04:18 -0800134 list_for_each_entry(t, &tcf_proto_base, head) {
135 if (t == ops) {
136 list_del(&t->head);
137 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 break;
Eric Dumazetdcd76082013-12-20 10:04:18 -0800139 }
140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 write_unlock(&cls_mod_lock);
142 return rc;
143}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800144EXPORT_SYMBOL(unregister_tcf_proto_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Cong Wangaaa908f2018-05-23 15:26:53 -0700146bool tcf_queue_work(struct rcu_work *rwork, work_func_t func)
Cong Wang7aa00452017-10-26 18:24:28 -0700147{
Cong Wangaaa908f2018-05-23 15:26:53 -0700148 INIT_RCU_WORK(rwork, func);
149 return queue_rcu_work(tc_filter_wq, rwork);
Cong Wang7aa00452017-10-26 18:24:28 -0700150}
151EXPORT_SYMBOL(tcf_queue_work);
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153/* Select new prio value from the range, managed by kernel. */
154
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800155static inline u32 tcf_auto_prio(struct tcf_proto *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800157 u32 first = TC_H_MAKE(0xC0000000U, 0U);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 if (tp)
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000160 first = tp->prio - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Jiri Pirko79619732017-05-17 11:07:58 +0200162 return TC_H_MAJ(first);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
Vlad Buslov470502d2019-02-11 10:55:48 +0200165static bool tcf_proto_is_unlocked(const char *kind)
166{
167 const struct tcf_proto_ops *ops;
168 bool ret;
169
170 ops = tcf_proto_lookup_ops(kind, false, NULL);
171 /* On error return false to take rtnl lock. Proto lookup/create
172 * functions will perform lookup again and properly handle errors.
173 */
174 if (IS_ERR(ops))
175 return false;
176
177 ret = !!(ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
178 module_put(ops->owner);
179 return ret;
180}
181
Jiri Pirko33a48922017-02-09 14:38:57 +0100182static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
Alexander Aringc35a4ac2018-01-18 11:20:50 -0500183 u32 prio, struct tcf_chain *chain,
Vlad Buslov12db03b2019-02-11 10:55:45 +0200184 bool rtnl_held,
Alexander Aringc35a4ac2018-01-18 11:20:50 -0500185 struct netlink_ext_ack *extack)
Jiri Pirko33a48922017-02-09 14:38:57 +0100186{
187 struct tcf_proto *tp;
188 int err;
189
190 tp = kzalloc(sizeof(*tp), GFP_KERNEL);
191 if (!tp)
192 return ERR_PTR(-ENOBUFS);
193
Vlad Buslov12db03b2019-02-11 10:55:45 +0200194 tp->ops = tcf_proto_lookup_ops(kind, rtnl_held, extack);
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200195 if (IS_ERR(tp->ops)) {
196 err = PTR_ERR(tp->ops);
Jiri Pirkod68d75f2018-05-11 17:45:32 +0200197 goto errout;
Jiri Pirko33a48922017-02-09 14:38:57 +0100198 }
199 tp->classify = tp->ops->classify;
200 tp->protocol = protocol;
201 tp->prio = prio;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200202 tp->chain = chain;
Vlad Buslov8b646782019-02-11 10:55:41 +0200203 spin_lock_init(&tp->lock);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200204 refcount_set(&tp->refcnt, 1);
Jiri Pirko33a48922017-02-09 14:38:57 +0100205
206 err = tp->ops->init(tp);
207 if (err) {
208 module_put(tp->ops->owner);
209 goto errout;
210 }
211 return tp;
212
213errout:
214 kfree(tp);
215 return ERR_PTR(err);
216}
217
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200218static void tcf_proto_get(struct tcf_proto *tp)
219{
220 refcount_inc(&tp->refcnt);
221}
222
223static void tcf_chain_put(struct tcf_chain *chain);
224
Vlad Buslov12db03b2019-02-11 10:55:45 +0200225static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
Jakub Kicinski715df5e2018-01-24 12:54:13 -0800226 struct netlink_ext_ack *extack)
Jiri Pirkocf1facd2017-02-09 14:38:56 +0100227{
Vlad Buslov12db03b2019-02-11 10:55:45 +0200228 tp->ops->destroy(tp, rtnl_held, extack);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200229 tcf_chain_put(tp->chain);
WANG Cong763dbf62017-04-19 14:21:21 -0700230 module_put(tp->ops->owner);
231 kfree_rcu(tp, rcu);
Jiri Pirkocf1facd2017-02-09 14:38:56 +0100232}
233
Vlad Buslov12db03b2019-02-11 10:55:45 +0200234static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held,
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200235 struct netlink_ext_ack *extack)
236{
237 if (refcount_dec_and_test(&tp->refcnt))
Vlad Buslov12db03b2019-02-11 10:55:45 +0200238 tcf_proto_destroy(tp, rtnl_held, extack);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200239}
240
Vlad Buslov268a3512019-02-26 17:34:40 +0200241static int walker_check_empty(struct tcf_proto *tp, void *fh,
Vlad Buslov6676d5e2019-02-25 17:38:31 +0200242 struct tcf_walker *arg)
Vlad Buslov8b646782019-02-11 10:55:41 +0200243{
Vlad Buslov268a3512019-02-26 17:34:40 +0200244 if (fh) {
Vlad Buslov6676d5e2019-02-25 17:38:31 +0200245 arg->nonempty = true;
246 return -1;
247 }
248 return 0;
Vlad Buslov8b646782019-02-11 10:55:41 +0200249}
250
Vlad Buslov12db03b2019-02-11 10:55:45 +0200251static bool tcf_proto_is_empty(struct tcf_proto *tp, bool rtnl_held)
Vlad Buslov8b646782019-02-11 10:55:41 +0200252{
Vlad Buslov6676d5e2019-02-25 17:38:31 +0200253 struct tcf_walker walker = { .fn = walker_check_empty, };
Vlad Buslov8b646782019-02-11 10:55:41 +0200254
255 if (tp->ops->walk) {
Vlad Buslov12db03b2019-02-11 10:55:45 +0200256 tp->ops->walk(tp, &walker, rtnl_held);
Vlad Buslov6676d5e2019-02-25 17:38:31 +0200257 return !walker.nonempty;
Vlad Buslov8b646782019-02-11 10:55:41 +0200258 }
259 return true;
260}
261
Vlad Buslov12db03b2019-02-11 10:55:45 +0200262static bool tcf_proto_check_delete(struct tcf_proto *tp, bool rtnl_held)
Vlad Buslov8b646782019-02-11 10:55:41 +0200263{
264 spin_lock(&tp->lock);
Vlad Buslov12db03b2019-02-11 10:55:45 +0200265 if (tcf_proto_is_empty(tp, rtnl_held))
Vlad Buslov8b646782019-02-11 10:55:41 +0200266 tp->deleting = true;
267 spin_unlock(&tp->lock);
268 return tp->deleting;
269}
270
271static void tcf_proto_mark_delete(struct tcf_proto *tp)
272{
273 spin_lock(&tp->lock);
274 tp->deleting = true;
275 spin_unlock(&tp->lock);
276}
277
278static bool tcf_proto_is_deleting(struct tcf_proto *tp)
279{
280 bool deleting;
281
282 spin_lock(&tp->lock);
283 deleting = tp->deleting;
284 spin_unlock(&tp->lock);
285
286 return deleting;
287}
288
Vlad Buslovc266f642019-02-11 10:55:32 +0200289#define ASSERT_BLOCK_LOCKED(block) \
290 lockdep_assert_held(&(block)->lock)
291
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100292struct tcf_filter_chain_list_item {
293 struct list_head list;
294 tcf_chain_head_change_t *chain_head_change;
295 void *chain_head_change_priv;
296};
297
Jiri Pirko5bc17012017-05-17 11:08:01 +0200298static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
299 u32 chain_index)
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200300{
Jiri Pirko5bc17012017-05-17 11:08:01 +0200301 struct tcf_chain *chain;
302
Vlad Buslovc266f642019-02-11 10:55:32 +0200303 ASSERT_BLOCK_LOCKED(block);
304
Jiri Pirko5bc17012017-05-17 11:08:01 +0200305 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
306 if (!chain)
307 return NULL;
308 list_add_tail(&chain->list, &block->chain_list);
Vlad Busloved76f5e2019-02-11 10:55:38 +0200309 mutex_init(&chain->filter_chain_lock);
Jiri Pirko5bc17012017-05-17 11:08:01 +0200310 chain->block = block;
311 chain->index = chain_index;
Cong Wange2ef7542017-09-11 16:33:31 -0700312 chain->refcnt = 1;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200313 if (!chain->index)
314 block->chain0.chain = chain;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200315 return chain;
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200316}
317
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100318static void tcf_chain_head_change_item(struct tcf_filter_chain_list_item *item,
319 struct tcf_proto *tp_head)
320{
321 if (item->chain_head_change)
322 item->chain_head_change(tp_head, item->chain_head_change_priv);
323}
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200324
325static void tcf_chain0_head_change(struct tcf_chain *chain,
326 struct tcf_proto *tp_head)
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100327{
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100328 struct tcf_filter_chain_list_item *item;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200329 struct tcf_block *block = chain->block;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100330
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200331 if (chain->index)
332 return;
Vlad Buslov165f0132019-02-11 10:55:35 +0200333
334 mutex_lock(&block->lock);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200335 list_for_each_entry(item, &block->chain0.filter_chain_list, list)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100336 tcf_chain_head_change_item(item, tp_head);
Vlad Buslov165f0132019-02-11 10:55:35 +0200337 mutex_unlock(&block->lock);
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100338}
339
Vlad Buslovc266f642019-02-11 10:55:32 +0200340/* Returns true if block can be safely freed. */
341
342static bool tcf_chain_detach(struct tcf_chain *chain)
Jiri Pirkof93e1cd2017-05-20 15:01:32 +0200343{
Cong Wangefbf7892017-12-04 10:48:18 -0800344 struct tcf_block *block = chain->block;
345
Vlad Buslovc266f642019-02-11 10:55:32 +0200346 ASSERT_BLOCK_LOCKED(block);
347
Cong Wange2ef7542017-09-11 16:33:31 -0700348 list_del(&chain->list);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200349 if (!chain->index)
350 block->chain0.chain = NULL;
Vlad Buslovc266f642019-02-11 10:55:32 +0200351
352 if (list_empty(&block->chain_list) &&
353 refcount_read(&block->refcnt) == 0)
354 return true;
355
356 return false;
357}
358
359static void tcf_block_destroy(struct tcf_block *block)
360{
361 mutex_destroy(&block->lock);
362 kfree_rcu(block, rcu);
363}
364
365static void tcf_chain_destroy(struct tcf_chain *chain, bool free_block)
366{
367 struct tcf_block *block = chain->block;
368
Vlad Busloved76f5e2019-02-11 10:55:38 +0200369 mutex_destroy(&chain->filter_chain_lock);
Davide Carattiee3bbfe2019-03-20 15:00:16 +0100370 kfree_rcu(chain, rcu);
Vlad Buslovc266f642019-02-11 10:55:32 +0200371 if (free_block)
372 tcf_block_destroy(block);
Cong Wange2ef7542017-09-11 16:33:31 -0700373}
Jiri Pirko744a4cf2017-08-22 22:46:49 +0200374
Cong Wange2ef7542017-09-11 16:33:31 -0700375static void tcf_chain_hold(struct tcf_chain *chain)
376{
Vlad Buslovc266f642019-02-11 10:55:32 +0200377 ASSERT_BLOCK_LOCKED(chain->block);
378
Cong Wange2ef7542017-09-11 16:33:31 -0700379 ++chain->refcnt;
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200380}
381
Jiri Pirko3d32f4c2018-08-01 12:36:55 +0200382static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain)
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200383{
Vlad Buslovc266f642019-02-11 10:55:32 +0200384 ASSERT_BLOCK_LOCKED(chain->block);
385
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200386 /* In case all the references are action references, this
Jiri Pirko3d32f4c2018-08-01 12:36:55 +0200387 * chain should not be shown to the user.
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200388 */
389 return chain->refcnt == chain->action_refcnt;
390}
391
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200392static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
393 u32 chain_index)
Jiri Pirko5bc17012017-05-17 11:08:01 +0200394{
395 struct tcf_chain *chain;
396
Vlad Buslovc266f642019-02-11 10:55:32 +0200397 ASSERT_BLOCK_LOCKED(block);
398
Jiri Pirko5bc17012017-05-17 11:08:01 +0200399 list_for_each_entry(chain, &block->chain_list, list) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200400 if (chain->index == chain_index)
Cong Wange2ef7542017-09-11 16:33:31 -0700401 return chain;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200402 }
403 return NULL;
404}
405
406static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
407 u32 seq, u16 flags, int event, bool unicast);
408
Jiri Pirko53681402018-08-01 12:36:56 +0200409static struct tcf_chain *__tcf_chain_get(struct tcf_block *block,
410 u32 chain_index, bool create,
411 bool by_act)
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200412{
Vlad Buslovc266f642019-02-11 10:55:32 +0200413 struct tcf_chain *chain = NULL;
414 bool is_first_reference;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200415
Vlad Buslovc266f642019-02-11 10:55:32 +0200416 mutex_lock(&block->lock);
417 chain = tcf_chain_lookup(block, chain_index);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200418 if (chain) {
419 tcf_chain_hold(chain);
Jiri Pirko53681402018-08-01 12:36:56 +0200420 } else {
421 if (!create)
Vlad Buslovc266f642019-02-11 10:55:32 +0200422 goto errout;
Jiri Pirko53681402018-08-01 12:36:56 +0200423 chain = tcf_chain_create(block, chain_index);
424 if (!chain)
Vlad Buslovc266f642019-02-11 10:55:32 +0200425 goto errout;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200426 }
Jiri Pirko80532382017-09-06 13:14:19 +0200427
Jiri Pirko53681402018-08-01 12:36:56 +0200428 if (by_act)
429 ++chain->action_refcnt;
Vlad Buslovc266f642019-02-11 10:55:32 +0200430 is_first_reference = chain->refcnt - chain->action_refcnt == 1;
431 mutex_unlock(&block->lock);
Jiri Pirko53681402018-08-01 12:36:56 +0200432
433 /* Send notification only in case we got the first
434 * non-action reference. Until then, the chain acts only as
435 * a placeholder for actions pointing to it and user ought
436 * not know about them.
437 */
Vlad Buslovc266f642019-02-11 10:55:32 +0200438 if (is_first_reference && !by_act)
Jiri Pirko53681402018-08-01 12:36:56 +0200439 tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
440 RTM_NEWCHAIN, false);
441
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200442 return chain;
Vlad Buslovc266f642019-02-11 10:55:32 +0200443
444errout:
445 mutex_unlock(&block->lock);
446 return chain;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200447}
Jiri Pirko53681402018-08-01 12:36:56 +0200448
Jiri Pirko290b1c82018-08-01 12:36:57 +0200449static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
450 bool create)
Jiri Pirko53681402018-08-01 12:36:56 +0200451{
452 return __tcf_chain_get(block, chain_index, create, false);
453}
Jiri Pirko5bc17012017-05-17 11:08:01 +0200454
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200455struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
456{
Jiri Pirko53681402018-08-01 12:36:56 +0200457 return __tcf_chain_get(block, chain_index, true, true);
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200458}
459EXPORT_SYMBOL(tcf_chain_get_by_act);
460
Vlad Buslova5654822019-02-11 10:55:37 +0200461static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
462 void *tmplt_priv);
463static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
464 void *tmplt_priv, u32 chain_index,
465 struct tcf_block *block, struct sk_buff *oskb,
466 u32 seq, u16 flags, bool unicast);
Jiri Pirko9f407f12018-07-23 09:23:07 +0200467
Vlad Buslov91052fa2019-02-11 10:55:33 +0200468static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
469 bool explicitly_created)
Jiri Pirko5bc17012017-05-17 11:08:01 +0200470{
Vlad Buslovc266f642019-02-11 10:55:32 +0200471 struct tcf_block *block = chain->block;
Vlad Buslova5654822019-02-11 10:55:37 +0200472 const struct tcf_proto_ops *tmplt_ops;
Vlad Buslovb62989f2019-03-06 17:50:43 +0200473 bool free_block = false;
Vlad Buslovc266f642019-02-11 10:55:32 +0200474 unsigned int refcnt;
Vlad Buslova5654822019-02-11 10:55:37 +0200475 void *tmplt_priv;
Vlad Buslovc266f642019-02-11 10:55:32 +0200476
477 mutex_lock(&block->lock);
Vlad Buslov91052fa2019-02-11 10:55:33 +0200478 if (explicitly_created) {
479 if (!chain->explicitly_created) {
480 mutex_unlock(&block->lock);
481 return;
482 }
483 chain->explicitly_created = false;
484 }
485
Jiri Pirko53681402018-08-01 12:36:56 +0200486 if (by_act)
487 chain->action_refcnt--;
Vlad Buslovc266f642019-02-11 10:55:32 +0200488
489 /* tc_chain_notify_delete can't be called while holding block lock.
490 * However, when block is unlocked chain can be changed concurrently, so
491 * save these to temporary variables.
492 */
493 refcnt = --chain->refcnt;
Vlad Buslova5654822019-02-11 10:55:37 +0200494 tmplt_ops = chain->tmplt_ops;
495 tmplt_priv = chain->tmplt_priv;
Jiri Pirko53681402018-08-01 12:36:56 +0200496
497 /* The last dropped non-action reference will trigger notification. */
Vlad Buslovb62989f2019-03-06 17:50:43 +0200498 if (refcnt - chain->action_refcnt == 0 && !by_act) {
499 tc_chain_notify_delete(tmplt_ops, tmplt_priv, chain->index,
Vlad Buslova5654822019-02-11 10:55:37 +0200500 block, NULL, 0, 0, false);
Vlad Buslov726d06122019-02-11 10:55:42 +0200501 /* Last reference to chain, no need to lock. */
502 chain->flushing = false;
503 }
Jiri Pirko53681402018-08-01 12:36:56 +0200504
Vlad Buslovb62989f2019-03-06 17:50:43 +0200505 if (refcnt == 0)
506 free_block = tcf_chain_detach(chain);
507 mutex_unlock(&block->lock);
508
Vlad Buslovc266f642019-02-11 10:55:32 +0200509 if (refcnt == 0) {
Vlad Buslova5654822019-02-11 10:55:37 +0200510 tc_chain_tmplt_del(tmplt_ops, tmplt_priv);
Vlad Buslovc266f642019-02-11 10:55:32 +0200511 tcf_chain_destroy(chain, free_block);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200512 }
Jiri Pirko5bc17012017-05-17 11:08:01 +0200513}
Jiri Pirko53681402018-08-01 12:36:56 +0200514
Jiri Pirko290b1c82018-08-01 12:36:57 +0200515static void tcf_chain_put(struct tcf_chain *chain)
Jiri Pirko53681402018-08-01 12:36:56 +0200516{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200517 __tcf_chain_put(chain, false, false);
Jiri Pirko53681402018-08-01 12:36:56 +0200518}
Jiri Pirko5bc17012017-05-17 11:08:01 +0200519
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200520void tcf_chain_put_by_act(struct tcf_chain *chain)
521{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200522 __tcf_chain_put(chain, true, false);
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200523}
524EXPORT_SYMBOL(tcf_chain_put_by_act);
525
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200526static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
527{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200528 __tcf_chain_put(chain, false, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200529}
530
Vlad Buslov12db03b2019-02-11 10:55:45 +0200531static void tcf_chain_flush(struct tcf_chain *chain, bool rtnl_held)
Jiri Pirko290b1c82018-08-01 12:36:57 +0200532{
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200533 struct tcf_proto *tp, *tp_next;
Jiri Pirko290b1c82018-08-01 12:36:57 +0200534
Vlad Busloved76f5e2019-02-11 10:55:38 +0200535 mutex_lock(&chain->filter_chain_lock);
536 tp = tcf_chain_dereference(chain->filter_chain, chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200537 RCU_INIT_POINTER(chain->filter_chain, NULL);
Jiri Pirko290b1c82018-08-01 12:36:57 +0200538 tcf_chain0_head_change(chain, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +0200539 chain->flushing = true;
Vlad Busloved76f5e2019-02-11 10:55:38 +0200540 mutex_unlock(&chain->filter_chain_lock);
541
Jiri Pirko290b1c82018-08-01 12:36:57 +0200542 while (tp) {
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200543 tp_next = rcu_dereference_protected(tp->next, 1);
Vlad Buslov12db03b2019-02-11 10:55:45 +0200544 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200545 tp = tp_next;
Jiri Pirko290b1c82018-08-01 12:36:57 +0200546 }
547}
548
John Hurley7f76fa32018-11-09 21:21:26 -0800549static struct tcf_block *tc_dev_ingress_block(struct net_device *dev)
550{
551 const struct Qdisc_class_ops *cops;
552 struct Qdisc *qdisc;
553
554 if (!dev_ingress_queue(dev))
555 return NULL;
556
557 qdisc = dev_ingress_queue(dev)->qdisc_sleeping;
558 if (!qdisc)
559 return NULL;
560
561 cops = qdisc->ops->cl_ops;
562 if (!cops)
563 return NULL;
564
565 if (!cops->tcf_block)
566 return NULL;
567
568 return cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL);
569}
570
571static struct rhashtable indr_setup_block_ht;
572
573struct tc_indr_block_dev {
574 struct rhash_head ht_node;
575 struct net_device *dev;
576 unsigned int refcnt;
577 struct list_head cb_list;
578 struct tcf_block *block;
579};
580
581struct tc_indr_block_cb {
582 struct list_head list;
583 void *cb_priv;
584 tc_indr_block_bind_cb_t *cb;
585 void *cb_ident;
586};
587
588static const struct rhashtable_params tc_indr_setup_block_ht_params = {
589 .key_offset = offsetof(struct tc_indr_block_dev, dev),
590 .head_offset = offsetof(struct tc_indr_block_dev, ht_node),
591 .key_len = sizeof(struct net_device *),
592};
593
594static struct tc_indr_block_dev *
595tc_indr_block_dev_lookup(struct net_device *dev)
596{
597 return rhashtable_lookup_fast(&indr_setup_block_ht, &dev,
598 tc_indr_setup_block_ht_params);
599}
600
601static struct tc_indr_block_dev *tc_indr_block_dev_get(struct net_device *dev)
602{
603 struct tc_indr_block_dev *indr_dev;
604
605 indr_dev = tc_indr_block_dev_lookup(dev);
606 if (indr_dev)
607 goto inc_ref;
608
609 indr_dev = kzalloc(sizeof(*indr_dev), GFP_KERNEL);
610 if (!indr_dev)
611 return NULL;
612
613 INIT_LIST_HEAD(&indr_dev->cb_list);
614 indr_dev->dev = dev;
615 indr_dev->block = tc_dev_ingress_block(dev);
616 if (rhashtable_insert_fast(&indr_setup_block_ht, &indr_dev->ht_node,
617 tc_indr_setup_block_ht_params)) {
618 kfree(indr_dev);
619 return NULL;
620 }
621
622inc_ref:
623 indr_dev->refcnt++;
624 return indr_dev;
625}
626
627static void tc_indr_block_dev_put(struct tc_indr_block_dev *indr_dev)
628{
629 if (--indr_dev->refcnt)
630 return;
631
632 rhashtable_remove_fast(&indr_setup_block_ht, &indr_dev->ht_node,
633 tc_indr_setup_block_ht_params);
634 kfree(indr_dev);
635}
636
637static struct tc_indr_block_cb *
638tc_indr_block_cb_lookup(struct tc_indr_block_dev *indr_dev,
639 tc_indr_block_bind_cb_t *cb, void *cb_ident)
640{
641 struct tc_indr_block_cb *indr_block_cb;
642
643 list_for_each_entry(indr_block_cb, &indr_dev->cb_list, list)
644 if (indr_block_cb->cb == cb &&
645 indr_block_cb->cb_ident == cb_ident)
646 return indr_block_cb;
647 return NULL;
648}
649
650static struct tc_indr_block_cb *
651tc_indr_block_cb_add(struct tc_indr_block_dev *indr_dev, void *cb_priv,
652 tc_indr_block_bind_cb_t *cb, void *cb_ident)
653{
654 struct tc_indr_block_cb *indr_block_cb;
655
656 indr_block_cb = tc_indr_block_cb_lookup(indr_dev, cb, cb_ident);
657 if (indr_block_cb)
658 return ERR_PTR(-EEXIST);
659
660 indr_block_cb = kzalloc(sizeof(*indr_block_cb), GFP_KERNEL);
661 if (!indr_block_cb)
662 return ERR_PTR(-ENOMEM);
663
664 indr_block_cb->cb_priv = cb_priv;
665 indr_block_cb->cb = cb;
666 indr_block_cb->cb_ident = cb_ident;
667 list_add(&indr_block_cb->list, &indr_dev->cb_list);
668
669 return indr_block_cb;
670}
671
672static void tc_indr_block_cb_del(struct tc_indr_block_cb *indr_block_cb)
673{
674 list_del(&indr_block_cb->list);
675 kfree(indr_block_cb);
676}
677
678static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
679 struct tc_indr_block_cb *indr_block_cb,
680 enum tc_block_command command)
681{
682 struct tc_block_offload bo = {
683 .command = command,
684 .binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
685 .block = indr_dev->block,
686 };
687
688 if (!indr_dev->block)
689 return;
690
691 indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
692 &bo);
693}
694
695int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
696 tc_indr_block_bind_cb_t *cb, void *cb_ident)
697{
698 struct tc_indr_block_cb *indr_block_cb;
699 struct tc_indr_block_dev *indr_dev;
700 int err;
701
702 indr_dev = tc_indr_block_dev_get(dev);
703 if (!indr_dev)
704 return -ENOMEM;
705
706 indr_block_cb = tc_indr_block_cb_add(indr_dev, cb_priv, cb, cb_ident);
707 err = PTR_ERR_OR_ZERO(indr_block_cb);
708 if (err)
709 goto err_dev_put;
710
711 tc_indr_block_ing_cmd(indr_dev, indr_block_cb, TC_BLOCK_BIND);
712 return 0;
713
714err_dev_put:
715 tc_indr_block_dev_put(indr_dev);
716 return err;
717}
718EXPORT_SYMBOL_GPL(__tc_indr_block_cb_register);
719
720int tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
721 tc_indr_block_bind_cb_t *cb, void *cb_ident)
722{
723 int err;
724
725 rtnl_lock();
726 err = __tc_indr_block_cb_register(dev, cb_priv, cb, cb_ident);
727 rtnl_unlock();
728
729 return err;
730}
731EXPORT_SYMBOL_GPL(tc_indr_block_cb_register);
732
733void __tc_indr_block_cb_unregister(struct net_device *dev,
734 tc_indr_block_bind_cb_t *cb, void *cb_ident)
735{
736 struct tc_indr_block_cb *indr_block_cb;
737 struct tc_indr_block_dev *indr_dev;
738
739 indr_dev = tc_indr_block_dev_lookup(dev);
740 if (!indr_dev)
741 return;
742
743 indr_block_cb = tc_indr_block_cb_lookup(indr_dev, cb, cb_ident);
744 if (!indr_block_cb)
745 return;
746
747 /* Send unbind message if required to free any block cbs. */
748 tc_indr_block_ing_cmd(indr_dev, indr_block_cb, TC_BLOCK_UNBIND);
749 tc_indr_block_cb_del(indr_block_cb);
750 tc_indr_block_dev_put(indr_dev);
751}
752EXPORT_SYMBOL_GPL(__tc_indr_block_cb_unregister);
753
754void tc_indr_block_cb_unregister(struct net_device *dev,
755 tc_indr_block_bind_cb_t *cb, void *cb_ident)
756{
757 rtnl_lock();
758 __tc_indr_block_cb_unregister(dev, cb, cb_ident);
759 rtnl_unlock();
760}
761EXPORT_SYMBOL_GPL(tc_indr_block_cb_unregister);
762
763static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
764 struct tcf_block_ext_info *ei,
765 enum tc_block_command command,
766 struct netlink_ext_ack *extack)
767{
768 struct tc_indr_block_cb *indr_block_cb;
769 struct tc_indr_block_dev *indr_dev;
770 struct tc_block_offload bo = {
771 .command = command,
772 .binder_type = ei->binder_type,
773 .block = block,
774 .extack = extack,
775 };
776
777 indr_dev = tc_indr_block_dev_lookup(dev);
778 if (!indr_dev)
779 return;
780
781 indr_dev->block = command == TC_BLOCK_BIND ? block : NULL;
782
783 list_for_each_entry(indr_block_cb, &indr_dev->cb_list, list)
784 indr_block_cb->cb(dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
785 &bo);
786}
787
Jiri Pirkocaa72602018-01-17 11:46:50 +0100788static bool tcf_block_offload_in_use(struct tcf_block *block)
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200789{
Jiri Pirkocaa72602018-01-17 11:46:50 +0100790 return block->offloadcnt;
791}
792
793static int tcf_block_offload_cmd(struct tcf_block *block,
794 struct net_device *dev,
795 struct tcf_block_ext_info *ei,
John Hurley60513bd2018-06-25 14:30:04 -0700796 enum tc_block_command command,
797 struct netlink_ext_ack *extack)
Jiri Pirkocaa72602018-01-17 11:46:50 +0100798{
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200799 struct tc_block_offload bo = {};
800
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200801 bo.command = command;
802 bo.binder_type = ei->binder_type;
803 bo.block = block;
John Hurley60513bd2018-06-25 14:30:04 -0700804 bo.extack = extack;
Jiri Pirkocaa72602018-01-17 11:46:50 +0100805 return dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200806}
807
Jiri Pirkocaa72602018-01-17 11:46:50 +0100808static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
John Hurley60513bd2018-06-25 14:30:04 -0700809 struct tcf_block_ext_info *ei,
810 struct netlink_ext_ack *extack)
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200811{
Jiri Pirkocaa72602018-01-17 11:46:50 +0100812 struct net_device *dev = q->dev_queue->dev;
813 int err;
814
815 if (!dev->netdev_ops->ndo_setup_tc)
816 goto no_offload_dev_inc;
817
818 /* If tc offload feature is disabled and the block we try to bind
819 * to already has some offloaded filters, forbid to bind.
820 */
John Hurley60513bd2018-06-25 14:30:04 -0700821 if (!tc_can_offload(dev) && tcf_block_offload_in_use(block)) {
822 NL_SET_ERR_MSG(extack, "Bind to offloaded block failed as dev has offload disabled");
Jiri Pirkocaa72602018-01-17 11:46:50 +0100823 return -EOPNOTSUPP;
John Hurley60513bd2018-06-25 14:30:04 -0700824 }
Jiri Pirkocaa72602018-01-17 11:46:50 +0100825
John Hurley60513bd2018-06-25 14:30:04 -0700826 err = tcf_block_offload_cmd(block, dev, ei, TC_BLOCK_BIND, extack);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100827 if (err == -EOPNOTSUPP)
828 goto no_offload_dev_inc;
John Hurley7f76fa32018-11-09 21:21:26 -0800829 if (err)
830 return err;
831
832 tc_indr_block_call(block, dev, ei, TC_BLOCK_BIND, extack);
833 return 0;
Jiri Pirkocaa72602018-01-17 11:46:50 +0100834
835no_offload_dev_inc:
836 if (tcf_block_offload_in_use(block))
837 return -EOPNOTSUPP;
838 block->nooffloaddevcnt++;
John Hurley7f76fa32018-11-09 21:21:26 -0800839 tc_indr_block_call(block, dev, ei, TC_BLOCK_BIND, extack);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100840 return 0;
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200841}
842
843static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
844 struct tcf_block_ext_info *ei)
845{
Jiri Pirkocaa72602018-01-17 11:46:50 +0100846 struct net_device *dev = q->dev_queue->dev;
847 int err;
848
John Hurley7f76fa32018-11-09 21:21:26 -0800849 tc_indr_block_call(block, dev, ei, TC_BLOCK_UNBIND, NULL);
850
Jiri Pirkocaa72602018-01-17 11:46:50 +0100851 if (!dev->netdev_ops->ndo_setup_tc)
852 goto no_offload_dev_dec;
John Hurley60513bd2018-06-25 14:30:04 -0700853 err = tcf_block_offload_cmd(block, dev, ei, TC_BLOCK_UNBIND, NULL);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100854 if (err == -EOPNOTSUPP)
855 goto no_offload_dev_dec;
856 return;
857
858no_offload_dev_dec:
859 WARN_ON(block->nooffloaddevcnt-- == 0);
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200860}
861
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100862static int
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200863tcf_chain0_head_change_cb_add(struct tcf_block *block,
864 struct tcf_block_ext_info *ei,
865 struct netlink_ext_ack *extack)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100866{
867 struct tcf_filter_chain_list_item *item;
Vlad Buslov165f0132019-02-11 10:55:35 +0200868 struct tcf_chain *chain0;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100869
870 item = kmalloc(sizeof(*item), GFP_KERNEL);
871 if (!item) {
872 NL_SET_ERR_MSG(extack, "Memory allocation for head change callback item failed");
873 return -ENOMEM;
874 }
875 item->chain_head_change = ei->chain_head_change;
876 item->chain_head_change_priv = ei->chain_head_change_priv;
Vlad Buslov165f0132019-02-11 10:55:35 +0200877
878 mutex_lock(&block->lock);
879 chain0 = block->chain0.chain;
Vlad Busloved76f5e2019-02-11 10:55:38 +0200880 if (chain0)
881 tcf_chain_hold(chain0);
882 else
883 list_add(&item->list, &block->chain0.filter_chain_list);
Vlad Buslov165f0132019-02-11 10:55:35 +0200884 mutex_unlock(&block->lock);
885
Vlad Busloved76f5e2019-02-11 10:55:38 +0200886 if (chain0) {
887 struct tcf_proto *tp_head;
888
889 mutex_lock(&chain0->filter_chain_lock);
890
891 tp_head = tcf_chain_dereference(chain0->filter_chain, chain0);
892 if (tp_head)
893 tcf_chain_head_change_item(item, tp_head);
894
895 mutex_lock(&block->lock);
896 list_add(&item->list, &block->chain0.filter_chain_list);
897 mutex_unlock(&block->lock);
898
899 mutex_unlock(&chain0->filter_chain_lock);
900 tcf_chain_put(chain0);
901 }
902
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100903 return 0;
904}
905
906static void
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200907tcf_chain0_head_change_cb_del(struct tcf_block *block,
908 struct tcf_block_ext_info *ei)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100909{
910 struct tcf_filter_chain_list_item *item;
911
Vlad Buslov165f0132019-02-11 10:55:35 +0200912 mutex_lock(&block->lock);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200913 list_for_each_entry(item, &block->chain0.filter_chain_list, list) {
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100914 if ((!ei->chain_head_change && !ei->chain_head_change_priv) ||
915 (item->chain_head_change == ei->chain_head_change &&
916 item->chain_head_change_priv == ei->chain_head_change_priv)) {
Vlad Buslov165f0132019-02-11 10:55:35 +0200917 if (block->chain0.chain)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200918 tcf_chain_head_change_item(item, NULL);
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100919 list_del(&item->list);
Vlad Buslov165f0132019-02-11 10:55:35 +0200920 mutex_unlock(&block->lock);
921
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100922 kfree(item);
923 return;
924 }
925 }
Vlad Buslov165f0132019-02-11 10:55:35 +0200926 mutex_unlock(&block->lock);
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100927 WARN_ON(1);
928}
929
Jiri Pirko48617382018-01-17 11:46:46 +0100930struct tcf_net {
Vlad Buslovab281622018-09-24 19:22:56 +0300931 spinlock_t idr_lock; /* Protects idr */
Jiri Pirko48617382018-01-17 11:46:46 +0100932 struct idr idr;
933};
934
935static unsigned int tcf_net_id;
936
937static int tcf_block_insert(struct tcf_block *block, struct net *net,
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100938 struct netlink_ext_ack *extack)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100939{
Jiri Pirko48617382018-01-17 11:46:46 +0100940 struct tcf_net *tn = net_generic(net, tcf_net_id);
Vlad Buslovab281622018-09-24 19:22:56 +0300941 int err;
Jiri Pirko48617382018-01-17 11:46:46 +0100942
Vlad Buslovab281622018-09-24 19:22:56 +0300943 idr_preload(GFP_KERNEL);
944 spin_lock(&tn->idr_lock);
945 err = idr_alloc_u32(&tn->idr, block, &block->index, block->index,
946 GFP_NOWAIT);
947 spin_unlock(&tn->idr_lock);
948 idr_preload_end();
949
950 return err;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100951}
952
Jiri Pirko48617382018-01-17 11:46:46 +0100953static void tcf_block_remove(struct tcf_block *block, struct net *net)
Jiri Pirko6529eab2017-05-17 11:07:55 +0200954{
Jiri Pirko48617382018-01-17 11:46:46 +0100955 struct tcf_net *tn = net_generic(net, tcf_net_id);
956
Vlad Buslovab281622018-09-24 19:22:56 +0300957 spin_lock(&tn->idr_lock);
Matthew Wilcox9c160942017-11-28 09:48:43 -0500958 idr_remove(&tn->idr, block->index);
Vlad Buslovab281622018-09-24 19:22:56 +0300959 spin_unlock(&tn->idr_lock);
Jiri Pirko48617382018-01-17 11:46:46 +0100960}
961
962static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100963 u32 block_index,
Jiri Pirko48617382018-01-17 11:46:46 +0100964 struct netlink_ext_ack *extack)
965{
966 struct tcf_block *block;
Jiri Pirko6529eab2017-05-17 11:07:55 +0200967
Jiri Pirko48617382018-01-17 11:46:46 +0100968 block = kzalloc(sizeof(*block), GFP_KERNEL);
Alexander Aring8d1a77f2017-12-20 12:35:19 -0500969 if (!block) {
970 NL_SET_ERR_MSG(extack, "Memory allocation for block failed");
Jiri Pirko48617382018-01-17 11:46:46 +0100971 return ERR_PTR(-ENOMEM);
Alexander Aring8d1a77f2017-12-20 12:35:19 -0500972 }
Vlad Buslovc266f642019-02-11 10:55:32 +0200973 mutex_init(&block->lock);
Jiri Pirko5bc17012017-05-17 11:08:01 +0200974 INIT_LIST_HEAD(&block->chain_list);
Jiri Pirkoacb67442017-10-19 15:50:31 +0200975 INIT_LIST_HEAD(&block->cb_list);
Jiri Pirkof36fe1c2018-01-17 11:46:48 +0100976 INIT_LIST_HEAD(&block->owner_list);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200977 INIT_LIST_HEAD(&block->chain0.filter_chain_list);
Jiri Pirkoacb67442017-10-19 15:50:31 +0200978
Vlad Buslovcfebd7e2018-09-24 19:22:54 +0300979 refcount_set(&block->refcnt, 1);
Jiri Pirko48617382018-01-17 11:46:46 +0100980 block->net = net;
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100981 block->index = block_index;
982
983 /* Don't store q pointer for blocks which are shared */
984 if (!tcf_block_shared(block))
985 block->q = q;
Jiri Pirko48617382018-01-17 11:46:46 +0100986 return block;
Jiri Pirko48617382018-01-17 11:46:46 +0100987}
988
989static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index)
990{
991 struct tcf_net *tn = net_generic(net, tcf_net_id);
992
Matthew Wilcox322d8842017-11-28 10:01:24 -0500993 return idr_find(&tn->idr, block_index);
Jiri Pirko48617382018-01-17 11:46:46 +0100994}
995
Vlad Buslov0607e432018-09-24 19:22:57 +0300996static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index)
997{
998 struct tcf_block *block;
999
1000 rcu_read_lock();
1001 block = tcf_block_lookup(net, block_index);
1002 if (block && !refcount_inc_not_zero(&block->refcnt))
1003 block = NULL;
1004 rcu_read_unlock();
1005
1006 return block;
1007}
1008
Vlad Buslovbbf73832019-02-11 10:55:36 +02001009static struct tcf_chain *
1010__tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
1011{
1012 mutex_lock(&block->lock);
1013 if (chain)
1014 chain = list_is_last(&chain->list, &block->chain_list) ?
1015 NULL : list_next_entry(chain, list);
1016 else
1017 chain = list_first_entry_or_null(&block->chain_list,
1018 struct tcf_chain, list);
1019
1020 /* skip all action-only chains */
1021 while (chain && tcf_chain_held_by_acts_only(chain))
1022 chain = list_is_last(&chain->list, &block->chain_list) ?
1023 NULL : list_next_entry(chain, list);
1024
1025 if (chain)
1026 tcf_chain_hold(chain);
1027 mutex_unlock(&block->lock);
1028
1029 return chain;
1030}
1031
1032/* Function to be used by all clients that want to iterate over all chains on
1033 * block. It properly obtains block->lock and takes reference to chain before
1034 * returning it. Users of this function must be tolerant to concurrent chain
1035 * insertion/deletion or ensure that no concurrent chain modification is
1036 * possible. Note that all netlink dump callbacks cannot guarantee to provide
1037 * consistent dump because rtnl lock is released each time skb is filled with
1038 * data and sent to user-space.
1039 */
1040
1041struct tcf_chain *
1042tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
1043{
1044 struct tcf_chain *chain_next = __tcf_get_next_chain(block, chain);
1045
1046 if (chain)
1047 tcf_chain_put(chain);
1048
1049 return chain_next;
1050}
1051EXPORT_SYMBOL(tcf_get_next_chain);
1052
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001053static struct tcf_proto *
1054__tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
1055{
Vlad Buslov8b646782019-02-11 10:55:41 +02001056 u32 prio = 0;
1057
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001058 ASSERT_RTNL();
1059 mutex_lock(&chain->filter_chain_lock);
1060
Vlad Buslov8b646782019-02-11 10:55:41 +02001061 if (!tp) {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001062 tp = tcf_chain_dereference(chain->filter_chain, chain);
Vlad Buslov8b646782019-02-11 10:55:41 +02001063 } else if (tcf_proto_is_deleting(tp)) {
1064 /* 'deleting' flag is set and chain->filter_chain_lock was
1065 * unlocked, which means next pointer could be invalid. Restart
1066 * search.
1067 */
1068 prio = tp->prio + 1;
1069 tp = tcf_chain_dereference(chain->filter_chain, chain);
1070
1071 for (; tp; tp = tcf_chain_dereference(tp->next, chain))
1072 if (!tp->deleting && tp->prio >= prio)
1073 break;
1074 } else {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001075 tp = tcf_chain_dereference(tp->next, chain);
Vlad Buslov8b646782019-02-11 10:55:41 +02001076 }
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001077
1078 if (tp)
1079 tcf_proto_get(tp);
1080
1081 mutex_unlock(&chain->filter_chain_lock);
1082
1083 return tp;
1084}
1085
1086/* Function to be used by all clients that want to iterate over all tp's on
1087 * chain. Users of this function must be tolerant to concurrent tp
1088 * insertion/deletion or ensure that no concurrent chain modification is
1089 * possible. Note that all netlink dump callbacks cannot guarantee to provide
1090 * consistent dump because rtnl lock is released each time skb is filled with
1091 * data and sent to user-space.
1092 */
1093
1094struct tcf_proto *
Vlad Buslov12db03b2019-02-11 10:55:45 +02001095tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp,
1096 bool rtnl_held)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001097{
1098 struct tcf_proto *tp_next = __tcf_get_next_proto(chain, tp);
1099
1100 if (tp)
Vlad Buslov12db03b2019-02-11 10:55:45 +02001101 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001102
1103 return tp_next;
1104}
1105EXPORT_SYMBOL(tcf_get_next_proto);
1106
Vlad Buslov12db03b2019-02-11 10:55:45 +02001107static void tcf_block_flush_all_chains(struct tcf_block *block, bool rtnl_held)
Vlad Buslovf0023432018-09-24 19:22:55 +03001108{
1109 struct tcf_chain *chain;
1110
Vlad Buslovbbf73832019-02-11 10:55:36 +02001111 /* Last reference to block. At this point chains cannot be added or
1112 * removed concurrently.
Vlad Buslovf0023432018-09-24 19:22:55 +03001113 */
Vlad Buslovbbf73832019-02-11 10:55:36 +02001114 for (chain = tcf_get_next_chain(block, NULL);
1115 chain;
1116 chain = tcf_get_next_chain(block, chain)) {
Vlad Buslovf0023432018-09-24 19:22:55 +03001117 tcf_chain_put_explicitly_created(chain);
Vlad Buslov12db03b2019-02-11 10:55:45 +02001118 tcf_chain_flush(chain, rtnl_held);
Vlad Buslovf0023432018-09-24 19:22:55 +03001119 }
1120}
1121
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001122/* Lookup Qdisc and increments its reference counter.
1123 * Set parent, if necessary.
1124 */
1125
1126static int __tcf_qdisc_find(struct net *net, struct Qdisc **q,
1127 u32 *parent, int ifindex, bool rtnl_held,
1128 struct netlink_ext_ack *extack)
1129{
1130 const struct Qdisc_class_ops *cops;
1131 struct net_device *dev;
1132 int err = 0;
1133
1134 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK)
1135 return 0;
1136
1137 rcu_read_lock();
1138
1139 /* Find link */
1140 dev = dev_get_by_index_rcu(net, ifindex);
1141 if (!dev) {
1142 rcu_read_unlock();
1143 return -ENODEV;
1144 }
1145
1146 /* Find qdisc */
1147 if (!*parent) {
1148 *q = dev->qdisc;
1149 *parent = (*q)->handle;
1150 } else {
1151 *q = qdisc_lookup_rcu(dev, TC_H_MAJ(*parent));
1152 if (!*q) {
1153 NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists");
1154 err = -EINVAL;
1155 goto errout_rcu;
1156 }
1157 }
1158
1159 *q = qdisc_refcount_inc_nz(*q);
1160 if (!*q) {
1161 NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists");
1162 err = -EINVAL;
1163 goto errout_rcu;
1164 }
1165
1166 /* Is it classful? */
1167 cops = (*q)->ops->cl_ops;
1168 if (!cops) {
1169 NL_SET_ERR_MSG(extack, "Qdisc not classful");
1170 err = -EINVAL;
1171 goto errout_qdisc;
1172 }
1173
1174 if (!cops->tcf_block) {
1175 NL_SET_ERR_MSG(extack, "Class doesn't support blocks");
1176 err = -EOPNOTSUPP;
1177 goto errout_qdisc;
1178 }
1179
1180errout_rcu:
1181 /* At this point we know that qdisc is not noop_qdisc,
1182 * which means that qdisc holds a reference to net_device
1183 * and we hold a reference to qdisc, so it is safe to release
1184 * rcu read lock.
1185 */
1186 rcu_read_unlock();
1187 return err;
1188
1189errout_qdisc:
1190 rcu_read_unlock();
1191
1192 if (rtnl_held)
1193 qdisc_put(*q);
1194 else
1195 qdisc_put_unlocked(*q);
1196 *q = NULL;
1197
1198 return err;
1199}
1200
1201static int __tcf_qdisc_cl_find(struct Qdisc *q, u32 parent, unsigned long *cl,
1202 int ifindex, struct netlink_ext_ack *extack)
1203{
1204 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK)
1205 return 0;
1206
1207 /* Do we search for filter, attached to class? */
1208 if (TC_H_MIN(parent)) {
1209 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1210
1211 *cl = cops->find(q, parent);
1212 if (*cl == 0) {
1213 NL_SET_ERR_MSG(extack, "Specified class doesn't exist");
1214 return -ENOENT;
1215 }
1216 }
1217
1218 return 0;
1219}
1220
1221static struct tcf_block *__tcf_block_find(struct net *net, struct Qdisc *q,
1222 unsigned long cl, int ifindex,
1223 u32 block_index,
1224 struct netlink_ext_ack *extack)
1225{
1226 struct tcf_block *block;
1227
1228 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
1229 block = tcf_block_refcnt_get(net, block_index);
1230 if (!block) {
1231 NL_SET_ERR_MSG(extack, "Block of given index was not found");
1232 return ERR_PTR(-EINVAL);
1233 }
1234 } else {
1235 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1236
1237 block = cops->tcf_block(q, cl, extack);
1238 if (!block)
1239 return ERR_PTR(-EINVAL);
1240
1241 if (tcf_block_shared(block)) {
1242 NL_SET_ERR_MSG(extack, "This filter block is shared. Please use the block index to manipulate the filters");
1243 return ERR_PTR(-EOPNOTSUPP);
1244 }
1245
1246 /* Always take reference to block in order to support execution
1247 * of rules update path of cls API without rtnl lock. Caller
1248 * must release block when it is finished using it. 'if' block
1249 * of this conditional obtain reference to block by calling
1250 * tcf_block_refcnt_get().
1251 */
1252 refcount_inc(&block->refcnt);
1253 }
1254
1255 return block;
1256}
1257
Vlad Buslov0607e432018-09-24 19:22:57 +03001258static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001259 struct tcf_block_ext_info *ei, bool rtnl_held)
Vlad Buslov0607e432018-09-24 19:22:57 +03001260{
Vlad Buslovc266f642019-02-11 10:55:32 +02001261 if (refcount_dec_and_mutex_lock(&block->refcnt, &block->lock)) {
Vlad Buslov0607e432018-09-24 19:22:57 +03001262 /* Flushing/putting all chains will cause the block to be
1263 * deallocated when last chain is freed. However, if chain_list
1264 * is empty, block has to be manually deallocated. After block
1265 * reference counter reached 0, it is no longer possible to
1266 * increment it or add new chains to block.
1267 */
1268 bool free_block = list_empty(&block->chain_list);
1269
Vlad Buslovc266f642019-02-11 10:55:32 +02001270 mutex_unlock(&block->lock);
Vlad Buslov0607e432018-09-24 19:22:57 +03001271 if (tcf_block_shared(block))
1272 tcf_block_remove(block, block->net);
Vlad Buslov0607e432018-09-24 19:22:57 +03001273
1274 if (q)
1275 tcf_block_offload_unbind(block, q, ei);
1276
1277 if (free_block)
Vlad Buslovc266f642019-02-11 10:55:32 +02001278 tcf_block_destroy(block);
Vlad Buslov0607e432018-09-24 19:22:57 +03001279 else
Vlad Buslov12db03b2019-02-11 10:55:45 +02001280 tcf_block_flush_all_chains(block, rtnl_held);
Vlad Buslov0607e432018-09-24 19:22:57 +03001281 } else if (q) {
1282 tcf_block_offload_unbind(block, q, ei);
1283 }
1284}
1285
Vlad Buslov12db03b2019-02-11 10:55:45 +02001286static void tcf_block_refcnt_put(struct tcf_block *block, bool rtnl_held)
Vlad Buslov0607e432018-09-24 19:22:57 +03001287{
Vlad Buslov12db03b2019-02-11 10:55:45 +02001288 __tcf_block_put(block, NULL, NULL, rtnl_held);
Vlad Buslov0607e432018-09-24 19:22:57 +03001289}
1290
Vlad Buslovc431f892018-05-31 09:52:53 +03001291/* Find tcf block.
1292 * Set q, parent, cl when appropriate.
1293 */
1294
1295static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q,
1296 u32 *parent, unsigned long *cl,
1297 int ifindex, u32 block_index,
1298 struct netlink_ext_ack *extack)
1299{
1300 struct tcf_block *block;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001301 int err = 0;
Vlad Buslovc431f892018-05-31 09:52:53 +03001302
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001303 ASSERT_RTNL();
Vlad Buslovc431f892018-05-31 09:52:53 +03001304
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001305 err = __tcf_qdisc_find(net, q, parent, ifindex, true, extack);
1306 if (err)
1307 goto errout;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001308
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001309 err = __tcf_qdisc_cl_find(*q, *parent, cl, ifindex, extack);
1310 if (err)
1311 goto errout_qdisc;
Vlad Buslovc431f892018-05-31 09:52:53 +03001312
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001313 block = __tcf_block_find(net, *q, *cl, ifindex, block_index, extack);
Dan Carpenteraf736bf2019-02-18 12:26:32 +03001314 if (IS_ERR(block)) {
1315 err = PTR_ERR(block);
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001316 goto errout_qdisc;
Dan Carpenteraf736bf2019-02-18 12:26:32 +03001317 }
Vlad Buslovc431f892018-05-31 09:52:53 +03001318
1319 return block;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001320
Vlad Buslove368fdb2018-09-24 19:22:53 +03001321errout_qdisc:
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001322 if (*q)
Vlad Buslove368fdb2018-09-24 19:22:53 +03001323 qdisc_put(*q);
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001324errout:
1325 *q = NULL;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001326 return ERR_PTR(err);
1327}
1328
Vlad Buslov12db03b2019-02-11 10:55:45 +02001329static void tcf_block_release(struct Qdisc *q, struct tcf_block *block,
1330 bool rtnl_held)
Vlad Buslove368fdb2018-09-24 19:22:53 +03001331{
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001332 if (!IS_ERR_OR_NULL(block))
Vlad Buslov12db03b2019-02-11 10:55:45 +02001333 tcf_block_refcnt_put(block, rtnl_held);
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001334
Vlad Buslov470502d2019-02-11 10:55:48 +02001335 if (q) {
1336 if (rtnl_held)
1337 qdisc_put(q);
1338 else
1339 qdisc_put_unlocked(q);
1340 }
Vlad Buslovc431f892018-05-31 09:52:53 +03001341}
1342
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001343struct tcf_block_owner_item {
1344 struct list_head list;
1345 struct Qdisc *q;
1346 enum tcf_block_binder_type binder_type;
1347};
1348
1349static void
1350tcf_block_owner_netif_keep_dst(struct tcf_block *block,
1351 struct Qdisc *q,
1352 enum tcf_block_binder_type binder_type)
1353{
1354 if (block->keep_dst &&
1355 binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
1356 binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
1357 netif_keep_dst(qdisc_dev(q));
1358}
1359
1360void tcf_block_netif_keep_dst(struct tcf_block *block)
1361{
1362 struct tcf_block_owner_item *item;
1363
1364 block->keep_dst = true;
1365 list_for_each_entry(item, &block->owner_list, list)
1366 tcf_block_owner_netif_keep_dst(block, item->q,
1367 item->binder_type);
1368}
1369EXPORT_SYMBOL(tcf_block_netif_keep_dst);
1370
1371static int tcf_block_owner_add(struct tcf_block *block,
1372 struct Qdisc *q,
1373 enum tcf_block_binder_type binder_type)
1374{
1375 struct tcf_block_owner_item *item;
1376
1377 item = kmalloc(sizeof(*item), GFP_KERNEL);
1378 if (!item)
1379 return -ENOMEM;
1380 item->q = q;
1381 item->binder_type = binder_type;
1382 list_add(&item->list, &block->owner_list);
1383 return 0;
1384}
1385
1386static void tcf_block_owner_del(struct tcf_block *block,
1387 struct Qdisc *q,
1388 enum tcf_block_binder_type binder_type)
1389{
1390 struct tcf_block_owner_item *item;
1391
1392 list_for_each_entry(item, &block->owner_list, list) {
1393 if (item->q == q && item->binder_type == binder_type) {
1394 list_del(&item->list);
1395 kfree(item);
1396 return;
1397 }
1398 }
1399 WARN_ON(1);
1400}
1401
Jiri Pirko48617382018-01-17 11:46:46 +01001402int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
1403 struct tcf_block_ext_info *ei,
1404 struct netlink_ext_ack *extack)
1405{
1406 struct net *net = qdisc_net(q);
1407 struct tcf_block *block = NULL;
Jiri Pirko48617382018-01-17 11:46:46 +01001408 int err;
1409
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001410 if (ei->block_index)
Jiri Pirko48617382018-01-17 11:46:46 +01001411 /* block_index not 0 means the shared block is requested */
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001412 block = tcf_block_refcnt_get(net, ei->block_index);
Jiri Pirko48617382018-01-17 11:46:46 +01001413
1414 if (!block) {
Jiri Pirkobb047dd2018-02-13 12:00:16 +01001415 block = tcf_block_create(net, q, ei->block_index, extack);
Jiri Pirko48617382018-01-17 11:46:46 +01001416 if (IS_ERR(block))
1417 return PTR_ERR(block);
Jiri Pirkobb047dd2018-02-13 12:00:16 +01001418 if (tcf_block_shared(block)) {
1419 err = tcf_block_insert(block, net, extack);
Jiri Pirko48617382018-01-17 11:46:46 +01001420 if (err)
1421 goto err_block_insert;
1422 }
1423 }
1424
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001425 err = tcf_block_owner_add(block, q, ei->binder_type);
1426 if (err)
1427 goto err_block_owner_add;
1428
1429 tcf_block_owner_netif_keep_dst(block, q, ei->binder_type);
1430
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001431 err = tcf_chain0_head_change_cb_add(block, ei, extack);
Jiri Pirkoa9b19442018-01-17 11:46:45 +01001432 if (err)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001433 goto err_chain0_head_change_cb_add;
Jiri Pirkocaa72602018-01-17 11:46:50 +01001434
John Hurley60513bd2018-06-25 14:30:04 -07001435 err = tcf_block_offload_bind(block, q, ei, extack);
Jiri Pirkocaa72602018-01-17 11:46:50 +01001436 if (err)
1437 goto err_block_offload_bind;
1438
Jiri Pirko6529eab2017-05-17 11:07:55 +02001439 *p_block = block;
1440 return 0;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001441
Jiri Pirkocaa72602018-01-17 11:46:50 +01001442err_block_offload_bind:
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001443 tcf_chain0_head_change_cb_del(block, ei);
1444err_chain0_head_change_cb_add:
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001445 tcf_block_owner_del(block, q, ei->binder_type);
1446err_block_owner_add:
Jiri Pirko48617382018-01-17 11:46:46 +01001447err_block_insert:
Vlad Buslov12db03b2019-02-11 10:55:45 +02001448 tcf_block_refcnt_put(block, true);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001449 return err;
Jiri Pirko6529eab2017-05-17 11:07:55 +02001450}
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001451EXPORT_SYMBOL(tcf_block_get_ext);
1452
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001453static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
1454{
1455 struct tcf_proto __rcu **p_filter_chain = priv;
1456
1457 rcu_assign_pointer(*p_filter_chain, tp_head);
1458}
1459
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001460int tcf_block_get(struct tcf_block **p_block,
Alexander Aring8d1a77f2017-12-20 12:35:19 -05001461 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
1462 struct netlink_ext_ack *extack)
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001463{
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001464 struct tcf_block_ext_info ei = {
1465 .chain_head_change = tcf_chain_head_change_dflt,
1466 .chain_head_change_priv = p_filter_chain,
1467 };
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001468
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001469 WARN_ON(!p_filter_chain);
Alexander Aring8d1a77f2017-12-20 12:35:19 -05001470 return tcf_block_get_ext(p_block, q, &ei, extack);
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001471}
Jiri Pirko6529eab2017-05-17 11:07:55 +02001472EXPORT_SYMBOL(tcf_block_get);
1473
Cong Wang7aa00452017-10-26 18:24:28 -07001474/* XXX: Standalone actions are not allowed to jump to any chain, and bound
Roman Kapla60b3f52017-11-24 12:27:58 +01001475 * actions should be all removed after flushing.
Cong Wang7aa00452017-10-26 18:24:28 -07001476 */
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001477void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
David S. Millere1ea2f92017-10-30 14:10:01 +09001478 struct tcf_block_ext_info *ei)
Cong Wang7aa00452017-10-26 18:24:28 -07001479{
David S. Millerc30abd52017-12-16 22:11:55 -05001480 if (!block)
1481 return;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001482 tcf_chain0_head_change_cb_del(block, ei);
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001483 tcf_block_owner_del(block, q, ei->binder_type);
Roman Kapla60b3f52017-11-24 12:27:58 +01001484
Vlad Buslov12db03b2019-02-11 10:55:45 +02001485 __tcf_block_put(block, q, ei, true);
Jiri Pirko6529eab2017-05-17 11:07:55 +02001486}
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001487EXPORT_SYMBOL(tcf_block_put_ext);
1488
1489void tcf_block_put(struct tcf_block *block)
1490{
1491 struct tcf_block_ext_info ei = {0, };
1492
Jiri Pirko4853f122017-12-21 13:13:59 +01001493 if (!block)
1494 return;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001495 tcf_block_put_ext(block, block->q, &ei);
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001496}
David S. Millere1ea2f92017-10-30 14:10:01 +09001497
Jiri Pirko6529eab2017-05-17 11:07:55 +02001498EXPORT_SYMBOL(tcf_block_put);
Jiri Pirkocf1facd2017-02-09 14:38:56 +01001499
Jiri Pirkoacb67442017-10-19 15:50:31 +02001500struct tcf_block_cb {
1501 struct list_head list;
1502 tc_setup_cb_t *cb;
1503 void *cb_ident;
1504 void *cb_priv;
1505 unsigned int refcnt;
1506};
1507
1508void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
1509{
1510 return block_cb->cb_priv;
1511}
1512EXPORT_SYMBOL(tcf_block_cb_priv);
1513
1514struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
1515 tc_setup_cb_t *cb, void *cb_ident)
1516{ struct tcf_block_cb *block_cb;
1517
1518 list_for_each_entry(block_cb, &block->cb_list, list)
1519 if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
1520 return block_cb;
1521 return NULL;
1522}
1523EXPORT_SYMBOL(tcf_block_cb_lookup);
1524
1525void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
1526{
1527 block_cb->refcnt++;
1528}
1529EXPORT_SYMBOL(tcf_block_cb_incref);
1530
1531unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
1532{
1533 return --block_cb->refcnt;
1534}
1535EXPORT_SYMBOL(tcf_block_cb_decref);
1536
John Hurley32636742018-06-25 14:30:10 -07001537static int
1538tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
1539 void *cb_priv, bool add, bool offload_in_use,
1540 struct netlink_ext_ack *extack)
1541{
Vlad Buslovbbf73832019-02-11 10:55:36 +02001542 struct tcf_chain *chain, *chain_prev;
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001543 struct tcf_proto *tp, *tp_prev;
John Hurley32636742018-06-25 14:30:10 -07001544 int err;
1545
Vlad Buslovbbf73832019-02-11 10:55:36 +02001546 for (chain = __tcf_get_next_chain(block, NULL);
1547 chain;
1548 chain_prev = chain,
1549 chain = __tcf_get_next_chain(block, chain),
1550 tcf_chain_put(chain_prev)) {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001551 for (tp = __tcf_get_next_proto(chain, NULL); tp;
1552 tp_prev = tp,
1553 tp = __tcf_get_next_proto(chain, tp),
Vlad Buslov12db03b2019-02-11 10:55:45 +02001554 tcf_proto_put(tp_prev, true, NULL)) {
John Hurley32636742018-06-25 14:30:10 -07001555 if (tp->ops->reoffload) {
1556 err = tp->ops->reoffload(tp, add, cb, cb_priv,
1557 extack);
1558 if (err && add)
1559 goto err_playback_remove;
1560 } else if (add && offload_in_use) {
1561 err = -EOPNOTSUPP;
1562 NL_SET_ERR_MSG(extack, "Filter HW offload failed - classifier without re-offloading support");
1563 goto err_playback_remove;
1564 }
1565 }
1566 }
1567
1568 return 0;
1569
1570err_playback_remove:
Vlad Buslov12db03b2019-02-11 10:55:45 +02001571 tcf_proto_put(tp, true, NULL);
Vlad Buslovbbf73832019-02-11 10:55:36 +02001572 tcf_chain_put(chain);
John Hurley32636742018-06-25 14:30:10 -07001573 tcf_block_playback_offloads(block, cb, cb_priv, false, offload_in_use,
1574 extack);
1575 return err;
1576}
1577
Jiri Pirkoacb67442017-10-19 15:50:31 +02001578struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
1579 tc_setup_cb_t *cb, void *cb_ident,
John Hurley60513bd2018-06-25 14:30:04 -07001580 void *cb_priv,
1581 struct netlink_ext_ack *extack)
Jiri Pirkoacb67442017-10-19 15:50:31 +02001582{
1583 struct tcf_block_cb *block_cb;
John Hurley32636742018-06-25 14:30:10 -07001584 int err;
Jiri Pirkoacb67442017-10-19 15:50:31 +02001585
John Hurley32636742018-06-25 14:30:10 -07001586 /* Replay any already present rules */
1587 err = tcf_block_playback_offloads(block, cb, cb_priv, true,
1588 tcf_block_offload_in_use(block),
1589 extack);
1590 if (err)
1591 return ERR_PTR(err);
Jiri Pirkocaa72602018-01-17 11:46:50 +01001592
Jiri Pirkoacb67442017-10-19 15:50:31 +02001593 block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
1594 if (!block_cb)
Jiri Pirkocaa72602018-01-17 11:46:50 +01001595 return ERR_PTR(-ENOMEM);
Jiri Pirkoacb67442017-10-19 15:50:31 +02001596 block_cb->cb = cb;
1597 block_cb->cb_ident = cb_ident;
1598 block_cb->cb_priv = cb_priv;
1599 list_add(&block_cb->list, &block->cb_list);
1600 return block_cb;
1601}
1602EXPORT_SYMBOL(__tcf_block_cb_register);
1603
1604int tcf_block_cb_register(struct tcf_block *block,
1605 tc_setup_cb_t *cb, void *cb_ident,
John Hurley60513bd2018-06-25 14:30:04 -07001606 void *cb_priv, struct netlink_ext_ack *extack)
Jiri Pirkoacb67442017-10-19 15:50:31 +02001607{
1608 struct tcf_block_cb *block_cb;
1609
John Hurley60513bd2018-06-25 14:30:04 -07001610 block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv,
1611 extack);
Gustavo A. R. Silvabaa2d2b2018-07-18 23:14:17 -05001612 return PTR_ERR_OR_ZERO(block_cb);
Jiri Pirkoacb67442017-10-19 15:50:31 +02001613}
1614EXPORT_SYMBOL(tcf_block_cb_register);
1615
John Hurley32636742018-06-25 14:30:10 -07001616void __tcf_block_cb_unregister(struct tcf_block *block,
1617 struct tcf_block_cb *block_cb)
Jiri Pirkoacb67442017-10-19 15:50:31 +02001618{
John Hurley32636742018-06-25 14:30:10 -07001619 tcf_block_playback_offloads(block, block_cb->cb, block_cb->cb_priv,
1620 false, tcf_block_offload_in_use(block),
1621 NULL);
Jiri Pirkoacb67442017-10-19 15:50:31 +02001622 list_del(&block_cb->list);
1623 kfree(block_cb);
1624}
1625EXPORT_SYMBOL(__tcf_block_cb_unregister);
1626
1627void tcf_block_cb_unregister(struct tcf_block *block,
1628 tc_setup_cb_t *cb, void *cb_ident)
1629{
1630 struct tcf_block_cb *block_cb;
1631
1632 block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
1633 if (!block_cb)
1634 return;
John Hurley32636742018-06-25 14:30:10 -07001635 __tcf_block_cb_unregister(block, block_cb);
Jiri Pirkoacb67442017-10-19 15:50:31 +02001636}
1637EXPORT_SYMBOL(tcf_block_cb_unregister);
1638
Jiri Pirko87d83092017-05-17 11:07:54 +02001639/* Main classifier routine: scans classifier chain attached
1640 * to this qdisc, (optionally) tests for protocol and asks
1641 * specific classifiers.
1642 */
1643int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1644 struct tcf_result *res, bool compat_mode)
1645{
Jiri Pirko87d83092017-05-17 11:07:54 +02001646#ifdef CONFIG_NET_CLS_ACT
1647 const int max_reclassify_loop = 4;
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001648 const struct tcf_proto *orig_tp = tp;
1649 const struct tcf_proto *first_tp;
Jiri Pirko87d83092017-05-17 11:07:54 +02001650 int limit = 0;
1651
1652reclassify:
1653#endif
1654 for (; tp; tp = rcu_dereference_bh(tp->next)) {
Cong Wangcd0c4e72019-01-11 18:55:42 -08001655 __be16 protocol = tc_skb_protocol(skb);
Jiri Pirko87d83092017-05-17 11:07:54 +02001656 int err;
1657
1658 if (tp->protocol != protocol &&
1659 tp->protocol != htons(ETH_P_ALL))
1660 continue;
1661
1662 err = tp->classify(skb, tp, res);
1663#ifdef CONFIG_NET_CLS_ACT
Jiri Pirkodb505142017-05-17 11:08:03 +02001664 if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001665 first_tp = orig_tp;
Jiri Pirko87d83092017-05-17 11:07:54 +02001666 goto reset;
Jiri Pirkodb505142017-05-17 11:08:03 +02001667 } else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001668 first_tp = res->goto_tp;
Jiri Pirkodb505142017-05-17 11:08:03 +02001669 goto reset;
1670 }
Jiri Pirko87d83092017-05-17 11:07:54 +02001671#endif
1672 if (err >= 0)
1673 return err;
1674 }
1675
1676 return TC_ACT_UNSPEC; /* signal: continue lookup */
1677#ifdef CONFIG_NET_CLS_ACT
1678reset:
1679 if (unlikely(limit++ >= max_reclassify_loop)) {
Jiri Pirko9d3aaff2018-01-17 11:46:47 +01001680 net_notice_ratelimited("%u: reclassify loop, rule prio %u, protocol %02x\n",
1681 tp->chain->block->index,
1682 tp->prio & 0xffff,
Jiri Pirko87d83092017-05-17 11:07:54 +02001683 ntohs(tp->protocol));
1684 return TC_ACT_SHOT;
1685 }
1686
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001687 tp = first_tp;
Jiri Pirko87d83092017-05-17 11:07:54 +02001688 goto reclassify;
1689#endif
1690}
1691EXPORT_SYMBOL(tcf_classify);
1692
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001693struct tcf_chain_info {
1694 struct tcf_proto __rcu **pprev;
1695 struct tcf_proto __rcu *next;
1696};
1697
Vlad Busloved76f5e2019-02-11 10:55:38 +02001698static struct tcf_proto *tcf_chain_tp_prev(struct tcf_chain *chain,
1699 struct tcf_chain_info *chain_info)
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001700{
Vlad Busloved76f5e2019-02-11 10:55:38 +02001701 return tcf_chain_dereference(*chain_info->pprev, chain);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001702}
1703
Vlad Buslov726d06122019-02-11 10:55:42 +02001704static int tcf_chain_tp_insert(struct tcf_chain *chain,
1705 struct tcf_chain_info *chain_info,
1706 struct tcf_proto *tp)
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001707{
Vlad Buslov726d06122019-02-11 10:55:42 +02001708 if (chain->flushing)
1709 return -EAGAIN;
1710
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001711 if (*chain_info->pprev == chain->filter_chain)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001712 tcf_chain0_head_change(chain, tp);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02001713 tcf_proto_get(tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02001714 RCU_INIT_POINTER(tp->next, tcf_chain_tp_prev(chain, chain_info));
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001715 rcu_assign_pointer(*chain_info->pprev, tp);
Vlad Buslov726d06122019-02-11 10:55:42 +02001716
1717 return 0;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001718}
1719
1720static void tcf_chain_tp_remove(struct tcf_chain *chain,
1721 struct tcf_chain_info *chain_info,
1722 struct tcf_proto *tp)
1723{
Vlad Busloved76f5e2019-02-11 10:55:38 +02001724 struct tcf_proto *next = tcf_chain_dereference(chain_info->next, chain);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001725
Vlad Buslov8b646782019-02-11 10:55:41 +02001726 tcf_proto_mark_delete(tp);
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001727 if (tp == chain->filter_chain)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001728 tcf_chain0_head_change(chain, next);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001729 RCU_INIT_POINTER(*chain_info->pprev, next);
1730}
1731
1732static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
1733 struct tcf_chain_info *chain_info,
1734 u32 protocol, u32 prio,
Vlad Buslov8b646782019-02-11 10:55:41 +02001735 bool prio_allocate);
1736
1737/* Try to insert new proto.
1738 * If proto with specified priority already exists, free new proto
1739 * and return existing one.
1740 */
1741
1742static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
1743 struct tcf_proto *tp_new,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001744 u32 protocol, u32 prio,
1745 bool rtnl_held)
Vlad Buslov8b646782019-02-11 10:55:41 +02001746{
1747 struct tcf_chain_info chain_info;
1748 struct tcf_proto *tp;
Vlad Buslov726d06122019-02-11 10:55:42 +02001749 int err = 0;
Vlad Buslov8b646782019-02-11 10:55:41 +02001750
1751 mutex_lock(&chain->filter_chain_lock);
1752
1753 tp = tcf_chain_tp_find(chain, &chain_info,
1754 protocol, prio, false);
1755 if (!tp)
Vlad Buslov726d06122019-02-11 10:55:42 +02001756 err = tcf_chain_tp_insert(chain, &chain_info, tp_new);
Vlad Buslov8b646782019-02-11 10:55:41 +02001757 mutex_unlock(&chain->filter_chain_lock);
1758
1759 if (tp) {
Vlad Buslov12db03b2019-02-11 10:55:45 +02001760 tcf_proto_destroy(tp_new, rtnl_held, NULL);
Vlad Buslov8b646782019-02-11 10:55:41 +02001761 tp_new = tp;
Vlad Buslov726d06122019-02-11 10:55:42 +02001762 } else if (err) {
Vlad Buslov12db03b2019-02-11 10:55:45 +02001763 tcf_proto_destroy(tp_new, rtnl_held, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +02001764 tp_new = ERR_PTR(err);
Vlad Buslov8b646782019-02-11 10:55:41 +02001765 }
1766
1767 return tp_new;
1768}
1769
1770static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001771 struct tcf_proto *tp, bool rtnl_held,
Vlad Buslov8b646782019-02-11 10:55:41 +02001772 struct netlink_ext_ack *extack)
1773{
1774 struct tcf_chain_info chain_info;
1775 struct tcf_proto *tp_iter;
1776 struct tcf_proto **pprev;
1777 struct tcf_proto *next;
1778
1779 mutex_lock(&chain->filter_chain_lock);
1780
1781 /* Atomically find and remove tp from chain. */
1782 for (pprev = &chain->filter_chain;
1783 (tp_iter = tcf_chain_dereference(*pprev, chain));
1784 pprev = &tp_iter->next) {
1785 if (tp_iter == tp) {
1786 chain_info.pprev = pprev;
1787 chain_info.next = tp_iter->next;
1788 WARN_ON(tp_iter->deleting);
1789 break;
1790 }
1791 }
1792 /* Verify that tp still exists and no new filters were inserted
1793 * concurrently.
1794 * Mark tp for deletion if it is empty.
1795 */
Vlad Buslov12db03b2019-02-11 10:55:45 +02001796 if (!tp_iter || !tcf_proto_check_delete(tp, rtnl_held)) {
Vlad Buslov8b646782019-02-11 10:55:41 +02001797 mutex_unlock(&chain->filter_chain_lock);
1798 return;
1799 }
1800
1801 next = tcf_chain_dereference(chain_info.next, chain);
1802 if (tp == chain->filter_chain)
1803 tcf_chain0_head_change(chain, next);
1804 RCU_INIT_POINTER(*chain_info.pprev, next);
1805 mutex_unlock(&chain->filter_chain_lock);
1806
Vlad Buslov12db03b2019-02-11 10:55:45 +02001807 tcf_proto_put(tp, rtnl_held, extack);
Vlad Buslov8b646782019-02-11 10:55:41 +02001808}
1809
1810static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
1811 struct tcf_chain_info *chain_info,
1812 u32 protocol, u32 prio,
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001813 bool prio_allocate)
1814{
1815 struct tcf_proto **pprev;
1816 struct tcf_proto *tp;
1817
1818 /* Check the chain for existence of proto-tcf with this priority */
1819 for (pprev = &chain->filter_chain;
Vlad Busloved76f5e2019-02-11 10:55:38 +02001820 (tp = tcf_chain_dereference(*pprev, chain));
1821 pprev = &tp->next) {
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001822 if (tp->prio >= prio) {
1823 if (tp->prio == prio) {
1824 if (prio_allocate ||
1825 (tp->protocol != protocol && protocol))
1826 return ERR_PTR(-EINVAL);
1827 } else {
1828 tp = NULL;
1829 }
1830 break;
1831 }
1832 }
1833 chain_info->pprev = pprev;
Vlad Buslov4dbfa762019-02-11 10:55:39 +02001834 if (tp) {
1835 chain_info->next = tp->next;
1836 tcf_proto_get(tp);
1837 } else {
1838 chain_info->next = NULL;
1839 }
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001840 return tp;
1841}
1842
WANG Cong71203712017-08-07 15:26:50 -07001843static int tcf_fill_node(struct net *net, struct sk_buff *skb,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001844 struct tcf_proto *tp, struct tcf_block *block,
1845 struct Qdisc *q, u32 parent, void *fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001846 u32 portid, u32 seq, u16 flags, int event,
1847 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001848{
1849 struct tcmsg *tcm;
1850 struct nlmsghdr *nlh;
1851 unsigned char *b = skb_tail_pointer(skb);
1852
1853 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
1854 if (!nlh)
1855 goto out_nlmsg_trim;
1856 tcm = nlmsg_data(nlh);
1857 tcm->tcm_family = AF_UNSPEC;
1858 tcm->tcm__pad1 = 0;
1859 tcm->tcm__pad2 = 0;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001860 if (q) {
1861 tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
1862 tcm->tcm_parent = parent;
1863 } else {
1864 tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
1865 tcm->tcm_block_index = block->index;
1866 }
WANG Cong71203712017-08-07 15:26:50 -07001867 tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
1868 if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
1869 goto nla_put_failure;
1870 if (nla_put_u32(skb, TCA_CHAIN, tp->chain->index))
1871 goto nla_put_failure;
1872 if (!fh) {
1873 tcm->tcm_handle = 0;
1874 } else {
Vlad Buslov12db03b2019-02-11 10:55:45 +02001875 if (tp->ops->dump &&
1876 tp->ops->dump(net, tp, fh, skb, tcm, rtnl_held) < 0)
WANG Cong71203712017-08-07 15:26:50 -07001877 goto nla_put_failure;
1878 }
1879 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1880 return skb->len;
1881
1882out_nlmsg_trim:
1883nla_put_failure:
1884 nlmsg_trim(skb, b);
1885 return -1;
1886}
1887
1888static int tfilter_notify(struct net *net, struct sk_buff *oskb,
1889 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001890 struct tcf_block *block, struct Qdisc *q,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001891 u32 parent, void *fh, int event, bool unicast,
1892 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001893{
1894 struct sk_buff *skb;
1895 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001896 int err = 0;
WANG Cong71203712017-08-07 15:26:50 -07001897
1898 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1899 if (!skb)
1900 return -ENOBUFS;
1901
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001902 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001903 n->nlmsg_seq, n->nlmsg_flags, event,
1904 rtnl_held) <= 0) {
WANG Cong71203712017-08-07 15:26:50 -07001905 kfree_skb(skb);
1906 return -EINVAL;
1907 }
1908
1909 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001910 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1911 else
1912 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1913 n->nlmsg_flags & NLM_F_ECHO);
WANG Cong71203712017-08-07 15:26:50 -07001914
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001915 if (err > 0)
1916 err = 0;
1917 return err;
WANG Cong71203712017-08-07 15:26:50 -07001918}
1919
1920static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
1921 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001922 struct tcf_block *block, struct Qdisc *q,
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001923 u32 parent, void *fh, bool unicast, bool *last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001924 bool rtnl_held, struct netlink_ext_ack *extack)
WANG Cong71203712017-08-07 15:26:50 -07001925{
1926 struct sk_buff *skb;
1927 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
1928 int err;
1929
1930 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1931 if (!skb)
1932 return -ENOBUFS;
1933
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001934 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001935 n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER,
1936 rtnl_held) <= 0) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001937 NL_SET_ERR_MSG(extack, "Failed to build del event notification");
WANG Cong71203712017-08-07 15:26:50 -07001938 kfree_skb(skb);
1939 return -EINVAL;
1940 }
1941
Vlad Buslov12db03b2019-02-11 10:55:45 +02001942 err = tp->ops->delete(tp, fh, last, rtnl_held, extack);
WANG Cong71203712017-08-07 15:26:50 -07001943 if (err) {
1944 kfree_skb(skb);
1945 return err;
1946 }
1947
1948 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001949 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1950 else
1951 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1952 n->nlmsg_flags & NLM_F_ECHO);
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001953 if (err < 0)
1954 NL_SET_ERR_MSG(extack, "Failed to send filter delete notification");
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001955
1956 if (err > 0)
1957 err = 0;
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001958 return err;
WANG Cong71203712017-08-07 15:26:50 -07001959}
1960
1961static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001962 struct tcf_block *block, struct Qdisc *q,
1963 u32 parent, struct nlmsghdr *n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001964 struct tcf_chain *chain, int event,
1965 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001966{
1967 struct tcf_proto *tp;
1968
Vlad Buslov12db03b2019-02-11 10:55:45 +02001969 for (tp = tcf_get_next_proto(chain, NULL, rtnl_held);
1970 tp; tp = tcf_get_next_proto(chain, tp, rtnl_held))
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001971 tfilter_notify(net, oskb, n, tp, block,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001972 q, parent, NULL, event, false, rtnl_held);
WANG Cong71203712017-08-07 15:26:50 -07001973}
1974
Vlad Buslov7d5509f2019-02-11 10:55:44 +02001975static void tfilter_put(struct tcf_proto *tp, void *fh)
1976{
1977 if (tp->ops->put && fh)
1978 tp->ops->put(tp, fh);
1979}
1980
Vlad Buslovc431f892018-05-31 09:52:53 +03001981static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
David Ahernc21ef3e2017-04-16 09:48:24 -07001982 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001984 struct net *net = sock_net(skb->sk);
Patrick McHardyadd93b62008-01-22 22:11:33 -08001985 struct nlattr *tca[TCA_MAX + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 struct tcmsg *t;
1987 u32 protocol;
1988 u32 prio;
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02001989 bool prio_allocate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02001991 u32 chain_index;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001992 struct Qdisc *q = NULL;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001993 struct tcf_chain_info chain_info;
Jiri Pirko5bc17012017-05-17 11:08:01 +02001994 struct tcf_chain *chain = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02001995 struct tcf_block *block;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 struct tcf_proto *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 unsigned long cl;
WANG Cong8113c092017-08-04 21:31:43 -07001998 void *fh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 int err;
Daniel Borkmann628185c2016-12-21 18:04:11 +01002000 int tp_created;
Vlad Buslov470502d2019-02-11 10:55:48 +02002001 bool rtnl_held = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
Vlad Buslovc431f892018-05-31 09:52:53 +03002003 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
Eric W. Biedermandfc47ef2012-11-16 03:03:00 +00002004 return -EPERM;
Hong zhi guode179c82013-03-25 17:36:33 +00002005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006replay:
Daniel Borkmann628185c2016-12-21 18:04:11 +01002007 tp_created = 0;
2008
Davide Carattie3314732018-10-10 22:00:58 +02002009 err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack);
Hong zhi guode179c82013-03-25 17:36:33 +00002010 if (err < 0)
2011 return err;
2012
David S. Miller942b8162012-06-26 21:48:50 -07002013 t = nlmsg_data(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 protocol = TC_H_MIN(t->tcm_info);
2015 prio = TC_H_MAJ(t->tcm_info);
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002016 prio_allocate = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 parent = t->tcm_parent;
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002018 tp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 cl = 0;
Vlad Buslov470502d2019-02-11 10:55:48 +02002020 block = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
2022 if (prio == 0) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002023 /* If no priority is provided by the user,
2024 * we allocate one.
2025 */
2026 if (n->nlmsg_flags & NLM_F_CREATE) {
2027 prio = TC_H_MAKE(0x80000000U, 0U);
2028 prio_allocate = true;
2029 } else {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002030 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 return -ENOENT;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 }
2034
2035 /* Find head of filter chain. */
2036
Vlad Buslov470502d2019-02-11 10:55:48 +02002037 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2038 if (err)
2039 return err;
2040
2041 /* Take rtnl mutex if rtnl_held was set to true on previous iteration,
2042 * block is shared (no qdisc found), qdisc is not unlocked, classifier
2043 * type is not specified, classifier is not unlocked.
2044 */
2045 if (rtnl_held ||
2046 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
2047 !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) {
2048 rtnl_held = true;
2049 rtnl_lock();
2050 }
2051
2052 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2053 if (err)
2054 goto errout;
2055
2056 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2057 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002058 if (IS_ERR(block)) {
2059 err = PTR_ERR(block);
2060 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002061 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002062
2063 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2064 if (chain_index > TC_ACT_EXT_VAL_MASK) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002065 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Jiri Pirko5bc17012017-05-17 11:08:01 +02002066 err = -EINVAL;
2067 goto errout;
2068 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002069 chain = tcf_chain_get(block, chain_index, true);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002070 if (!chain) {
Jiri Pirkod5ed72a2018-08-27 20:58:43 +02002071 NL_SET_ERR_MSG(extack, "Cannot create specified filter chain");
Vlad Buslovc431f892018-05-31 09:52:53 +03002072 err = -ENOMEM;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002073 goto errout;
2074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Vlad Busloved76f5e2019-02-11 10:55:38 +02002076 mutex_lock(&chain->filter_chain_lock);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002077 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2078 prio, prio_allocate);
2079 if (IS_ERR(tp)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002080 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002081 err = PTR_ERR(tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002082 goto errout_locked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 }
2084
2085 if (tp == NULL) {
Vlad Buslov8b646782019-02-11 10:55:41 +02002086 struct tcf_proto *tp_new = NULL;
2087
Vlad Buslov726d06122019-02-11 10:55:42 +02002088 if (chain->flushing) {
2089 err = -EAGAIN;
2090 goto errout_locked;
2091 }
2092
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 /* Proto-tcf does not exist, create new one */
2094
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002095 if (tca[TCA_KIND] == NULL || !protocol) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002096 NL_SET_ERR_MSG(extack, "Filter kind and protocol must be specified");
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002097 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002098 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Vlad Buslovc431f892018-05-31 09:52:53 +03002101 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002102 NL_SET_ERR_MSG(extack, "Need both RTM_NEWTFILTER and NLM_F_CREATE to create a new filter");
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002103 err = -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002104 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002107 if (prio_allocate)
Vlad Busloved76f5e2019-02-11 10:55:38 +02002108 prio = tcf_auto_prio(tcf_chain_tp_prev(chain,
2109 &chain_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Vlad Busloved76f5e2019-02-11 10:55:38 +02002111 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslov8b646782019-02-11 10:55:41 +02002112 tp_new = tcf_proto_create(nla_data(tca[TCA_KIND]),
Vlad Buslov12db03b2019-02-11 10:55:45 +02002113 protocol, prio, chain, rtnl_held,
2114 extack);
Vlad Buslov8b646782019-02-11 10:55:41 +02002115 if (IS_ERR(tp_new)) {
2116 err = PTR_ERR(tp_new);
Vlad Buslov726d06122019-02-11 10:55:42 +02002117 goto errout_tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002119
Minoru Usui12186be2009-06-02 02:17:34 -07002120 tp_created = 1;
Vlad Buslov12db03b2019-02-11 10:55:45 +02002121 tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio,
2122 rtnl_held);
Vlad Buslov726d06122019-02-11 10:55:42 +02002123 if (IS_ERR(tp)) {
2124 err = PTR_ERR(tp);
2125 goto errout_tp;
2126 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002127 } else {
2128 mutex_unlock(&chain->filter_chain_lock);
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
Vlad Buslov8b646782019-02-11 10:55:41 +02002131 if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2132 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2133 err = -EINVAL;
2134 goto errout;
2135 }
2136
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 fh = tp->ops->get(tp, t->tcm_handle);
2138
WANG Cong8113c092017-08-04 21:31:43 -07002139 if (!fh) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002140 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002141 NL_SET_ERR_MSG(extack, "Need both RTM_NEWTFILTER and NLM_F_CREATE to create a new filter");
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002142 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002144 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002145 } else if (n->nlmsg_flags & NLM_F_EXCL) {
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002146 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002147 NL_SET_ERR_MSG(extack, "Filter already exists");
2148 err = -EEXIST;
2149 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 }
2151
Jiri Pirko9f407f12018-07-23 09:23:07 +02002152 if (chain->tmplt_ops && chain->tmplt_ops != tp->ops) {
2153 NL_SET_ERR_MSG(extack, "Chain template is set to a different filter kind");
2154 err = -EINVAL;
2155 goto errout;
2156 }
2157
Cong Wang2f7ef2f2014-04-25 13:54:06 -07002158 err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
Alexander Aring7306db32018-01-18 11:20:51 -05002159 n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002160 rtnl_held, extack);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002161 if (err == 0) {
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002162 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002163 RTM_NEWTFILTER, false, rtnl_held);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002164 tfilter_put(tp, fh);
2165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167errout:
Vlad Buslov8b646782019-02-11 10:55:41 +02002168 if (err && tp_created)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002169 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +02002170errout_tp:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002171 if (chain) {
2172 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002173 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002174 if (!tp_created)
2175 tcf_chain_put(chain);
2176 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002177 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002178
2179 if (rtnl_held)
2180 rtnl_unlock();
2181
2182 if (err == -EAGAIN) {
2183 /* Take rtnl lock in case EAGAIN is caused by concurrent flush
2184 * of target chain.
2185 */
2186 rtnl_held = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 /* Replay the request. */
2188 goto replay;
Vlad Buslov470502d2019-02-11 10:55:48 +02002189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002191
2192errout_locked:
2193 mutex_unlock(&chain->filter_chain_lock);
2194 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195}
2196
Vlad Buslovc431f892018-05-31 09:52:53 +03002197static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2198 struct netlink_ext_ack *extack)
2199{
2200 struct net *net = sock_net(skb->sk);
2201 struct nlattr *tca[TCA_MAX + 1];
2202 struct tcmsg *t;
2203 u32 protocol;
2204 u32 prio;
2205 u32 parent;
2206 u32 chain_index;
2207 struct Qdisc *q = NULL;
2208 struct tcf_chain_info chain_info;
2209 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002210 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002211 struct tcf_proto *tp = NULL;
2212 unsigned long cl = 0;
2213 void *fh = NULL;
2214 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002215 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002216
2217 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2218 return -EPERM;
2219
Davide Carattie3314732018-10-10 22:00:58 +02002220 err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002221 if (err < 0)
2222 return err;
2223
2224 t = nlmsg_data(n);
2225 protocol = TC_H_MIN(t->tcm_info);
2226 prio = TC_H_MAJ(t->tcm_info);
2227 parent = t->tcm_parent;
2228
2229 if (prio == 0 && (protocol || t->tcm_handle || tca[TCA_KIND])) {
2230 NL_SET_ERR_MSG(extack, "Cannot flush filters with protocol, handle or kind set");
2231 return -ENOENT;
2232 }
2233
2234 /* Find head of filter chain. */
2235
Vlad Buslov470502d2019-02-11 10:55:48 +02002236 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2237 if (err)
2238 return err;
2239
2240 /* Take rtnl mutex if flushing whole chain, block is shared (no qdisc
2241 * found), qdisc is not unlocked, classifier type is not specified,
2242 * classifier is not unlocked.
2243 */
2244 if (!prio ||
2245 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
2246 !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) {
2247 rtnl_held = true;
2248 rtnl_lock();
2249 }
2250
2251 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2252 if (err)
2253 goto errout;
2254
2255 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2256 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002257 if (IS_ERR(block)) {
2258 err = PTR_ERR(block);
2259 goto errout;
2260 }
2261
2262 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2263 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2264 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2265 err = -EINVAL;
2266 goto errout;
2267 }
2268 chain = tcf_chain_get(block, chain_index, false);
2269 if (!chain) {
Jiri Pirko5ca8a252018-08-03 11:08:47 +02002270 /* User requested flush on non-existent chain. Nothing to do,
2271 * so just return success.
2272 */
2273 if (prio == 0) {
2274 err = 0;
2275 goto errout;
2276 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002277 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Jiri Pirkob7b42472018-08-27 20:58:44 +02002278 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002279 goto errout;
2280 }
2281
2282 if (prio == 0) {
2283 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002284 chain, RTM_DELTFILTER, rtnl_held);
2285 tcf_chain_flush(chain, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002286 err = 0;
2287 goto errout;
2288 }
2289
Vlad Busloved76f5e2019-02-11 10:55:38 +02002290 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002291 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2292 prio, false);
2293 if (!tp || IS_ERR(tp)) {
2294 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002295 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002296 goto errout_locked;
Vlad Buslovc431f892018-05-31 09:52:53 +03002297 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2298 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2299 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002300 goto errout_locked;
2301 } else if (t->tcm_handle == 0) {
2302 tcf_chain_tp_remove(chain, &chain_info, tp);
2303 mutex_unlock(&chain->filter_chain_lock);
2304
Vlad Buslov12db03b2019-02-11 10:55:45 +02002305 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002306 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002307 RTM_DELTFILTER, false, rtnl_held);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002308 err = 0;
Vlad Buslovc431f892018-05-31 09:52:53 +03002309 goto errout;
2310 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002311 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002312
2313 fh = tp->ops->get(tp, t->tcm_handle);
2314
2315 if (!fh) {
Vlad Busloved76f5e2019-02-11 10:55:38 +02002316 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2317 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002318 } else {
2319 bool last;
2320
2321 err = tfilter_del_notify(net, skb, n, tp, block,
2322 q, parent, fh, false, &last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002323 rtnl_held, extack);
2324
Vlad Buslovc431f892018-05-31 09:52:53 +03002325 if (err)
2326 goto errout;
Vlad Buslov8b646782019-02-11 10:55:41 +02002327 if (last)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002328 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002329 }
2330
2331errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002332 if (chain) {
2333 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002334 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002335 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002336 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002337 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002338
2339 if (rtnl_held)
2340 rtnl_unlock();
2341
Vlad Buslovc431f892018-05-31 09:52:53 +03002342 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002343
2344errout_locked:
2345 mutex_unlock(&chain->filter_chain_lock);
2346 goto errout;
Vlad Buslovc431f892018-05-31 09:52:53 +03002347}
2348
2349static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2350 struct netlink_ext_ack *extack)
2351{
2352 struct net *net = sock_net(skb->sk);
2353 struct nlattr *tca[TCA_MAX + 1];
2354 struct tcmsg *t;
2355 u32 protocol;
2356 u32 prio;
2357 u32 parent;
2358 u32 chain_index;
2359 struct Qdisc *q = NULL;
2360 struct tcf_chain_info chain_info;
2361 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002362 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002363 struct tcf_proto *tp = NULL;
2364 unsigned long cl = 0;
2365 void *fh = NULL;
2366 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002367 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002368
Davide Carattie3314732018-10-10 22:00:58 +02002369 err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002370 if (err < 0)
2371 return err;
2372
2373 t = nlmsg_data(n);
2374 protocol = TC_H_MIN(t->tcm_info);
2375 prio = TC_H_MAJ(t->tcm_info);
2376 parent = t->tcm_parent;
2377
2378 if (prio == 0) {
2379 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
2380 return -ENOENT;
2381 }
2382
2383 /* Find head of filter chain. */
2384
Vlad Buslov470502d2019-02-11 10:55:48 +02002385 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2386 if (err)
2387 return err;
2388
2389 /* Take rtnl mutex if block is shared (no qdisc found), qdisc is not
2390 * unlocked, classifier type is not specified, classifier is not
2391 * unlocked.
2392 */
2393 if ((q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
2394 !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) {
2395 rtnl_held = true;
2396 rtnl_lock();
2397 }
2398
2399 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2400 if (err)
2401 goto errout;
2402
2403 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2404 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002405 if (IS_ERR(block)) {
2406 err = PTR_ERR(block);
2407 goto errout;
2408 }
2409
2410 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2411 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2412 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2413 err = -EINVAL;
2414 goto errout;
2415 }
2416 chain = tcf_chain_get(block, chain_index, false);
2417 if (!chain) {
2418 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
2419 err = -EINVAL;
2420 goto errout;
2421 }
2422
Vlad Busloved76f5e2019-02-11 10:55:38 +02002423 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002424 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2425 prio, false);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002426 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002427 if (!tp || IS_ERR(tp)) {
2428 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002429 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002430 goto errout;
2431 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2432 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2433 err = -EINVAL;
2434 goto errout;
2435 }
2436
2437 fh = tp->ops->get(tp, t->tcm_handle);
2438
2439 if (!fh) {
2440 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2441 err = -ENOENT;
2442 } else {
2443 err = tfilter_notify(net, skb, n, tp, block, q, parent,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002444 fh, RTM_NEWTFILTER, true, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002445 if (err < 0)
2446 NL_SET_ERR_MSG(extack, "Failed to send filter notify message");
2447 }
2448
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002449 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002450errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002451 if (chain) {
2452 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002453 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002454 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002455 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002456 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002457
2458 if (rtnl_held)
2459 rtnl_unlock();
2460
Vlad Buslovc431f892018-05-31 09:52:53 +03002461 return err;
2462}
2463
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002464struct tcf_dump_args {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 struct tcf_walker w;
2466 struct sk_buff *skb;
2467 struct netlink_callback *cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002468 struct tcf_block *block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002469 struct Qdisc *q;
2470 u32 parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471};
2472
WANG Cong8113c092017-08-04 21:31:43 -07002473static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474{
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002475 struct tcf_dump_args *a = (void *)arg;
WANG Cong832d1d52014-01-09 16:14:01 -08002476 struct net *net = sock_net(a->skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002478 return tcf_fill_node(net, a->skb, tp, a->block, a->q, a->parent,
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002479 n, NETLINK_CB(a->cb->skb).portid,
Jamal Hadi Salim5a7a5552016-09-18 08:45:33 -04002480 a->cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002481 RTM_NEWTFILTER, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482}
2483
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002484static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
2485 struct sk_buff *skb, struct netlink_callback *cb,
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002486 long index_start, long *p_index)
2487{
2488 struct net *net = sock_net(skb->sk);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002489 struct tcf_block *block = chain->block;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002490 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002491 struct tcf_proto *tp, *tp_prev;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002492 struct tcf_dump_args arg;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002493
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002494 for (tp = __tcf_get_next_proto(chain, NULL);
2495 tp;
2496 tp_prev = tp,
2497 tp = __tcf_get_next_proto(chain, tp),
Vlad Buslov12db03b2019-02-11 10:55:45 +02002498 tcf_proto_put(tp_prev, true, NULL),
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002499 (*p_index)++) {
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002500 if (*p_index < index_start)
2501 continue;
2502 if (TC_H_MAJ(tcm->tcm_info) &&
2503 TC_H_MAJ(tcm->tcm_info) != tp->prio)
2504 continue;
2505 if (TC_H_MIN(tcm->tcm_info) &&
2506 TC_H_MIN(tcm->tcm_info) != tp->protocol)
2507 continue;
2508 if (*p_index > index_start)
2509 memset(&cb->args[1], 0,
2510 sizeof(cb->args) - sizeof(cb->args[0]));
2511 if (cb->args[1] == 0) {
YueHaibing53189182018-07-17 20:58:14 +08002512 if (tcf_fill_node(net, skb, tp, block, q, parent, NULL,
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002513 NETLINK_CB(cb->skb).portid,
2514 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002515 RTM_NEWTFILTER, true) <= 0)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002516 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002517 cb->args[1] = 1;
2518 }
2519 if (!tp->ops->walk)
2520 continue;
2521 arg.w.fn = tcf_node_dump;
2522 arg.skb = skb;
2523 arg.cb = cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002524 arg.block = block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002525 arg.q = q;
2526 arg.parent = parent;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002527 arg.w.stop = 0;
2528 arg.w.skip = cb->args[1] - 1;
2529 arg.w.count = 0;
Vlad Buslov01683a12018-07-09 13:29:11 +03002530 arg.w.cookie = cb->args[2];
Vlad Buslov12db03b2019-02-11 10:55:45 +02002531 tp->ops->walk(tp, &arg.w, true);
Vlad Buslov01683a12018-07-09 13:29:11 +03002532 cb->args[2] = arg.w.cookie;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002533 cb->args[1] = arg.w.count + 1;
2534 if (arg.w.stop)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002535 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002536 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002537 return true;
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002538
2539errout:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002540 tcf_proto_put(tp, true, NULL);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002541 return false;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002542}
2543
Eric Dumazetbd27a872009-11-05 20:57:26 -08002544/* called with RTNL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
2546{
Vlad Buslovbbf73832019-02-11 10:55:36 +02002547 struct tcf_chain *chain, *chain_prev;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002548 struct net *net = sock_net(skb->sk);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002549 struct nlattr *tca[TCA_MAX + 1];
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002550 struct Qdisc *q = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02002551 struct tcf_block *block;
David S. Miller942b8162012-06-26 21:48:50 -07002552 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002553 long index_start;
2554 long index;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002555 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002556 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
Hong zhi guo573ce262013-03-27 06:47:04 +00002558 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return skb->len;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002560
David Aherndac9c972018-10-07 20:16:24 -07002561 err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL,
2562 cb->extack);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002563 if (err)
2564 return err;
2565
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002566 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002567 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002568 if (!block)
WANG Cong143976c2017-08-24 16:51:29 -07002569 goto out;
Jiri Pirkod680b352018-01-18 16:14:49 +01002570 /* If we work with block index, q is NULL and parent value
2571 * will never be used in the following code. The check
2572 * in tcf_fill_node prevents it. However, compiler does not
2573 * see that far, so set parent to zero to silence the warning
2574 * about parent being uninitialized.
2575 */
2576 parent = 0;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002577 } else {
2578 const struct Qdisc_class_ops *cops;
2579 struct net_device *dev;
2580 unsigned long cl = 0;
2581
2582 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
2583 if (!dev)
2584 return skb->len;
2585
2586 parent = tcm->tcm_parent;
2587 if (!parent) {
2588 q = dev->qdisc;
2589 parent = q->handle;
2590 } else {
2591 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
2592 }
2593 if (!q)
2594 goto out;
2595 cops = q->ops->cl_ops;
2596 if (!cops)
2597 goto out;
2598 if (!cops->tcf_block)
2599 goto out;
2600 if (TC_H_MIN(tcm->tcm_parent)) {
2601 cl = cops->find(q, tcm->tcm_parent);
2602 if (cl == 0)
2603 goto out;
2604 }
2605 block = cops->tcf_block(q, cl, NULL);
2606 if (!block)
2607 goto out;
2608 if (tcf_block_shared(block))
2609 q = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002612 index_start = cb->args[0];
2613 index = 0;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002614
Vlad Buslovbbf73832019-02-11 10:55:36 +02002615 for (chain = __tcf_get_next_chain(block, NULL);
2616 chain;
2617 chain_prev = chain,
2618 chain = __tcf_get_next_chain(block, chain),
2619 tcf_chain_put(chain_prev)) {
Jiri Pirko5bc17012017-05-17 11:08:01 +02002620 if (tca[TCA_CHAIN] &&
2621 nla_get_u32(tca[TCA_CHAIN]) != chain->index)
2622 continue;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002623 if (!tcf_chain_dump(chain, q, parent, skb, cb,
Roman Kapl5ae437a2018-02-19 21:32:51 +01002624 index_start, &index)) {
Vlad Buslovbbf73832019-02-11 10:55:36 +02002625 tcf_chain_put(chain);
Roman Kapl5ae437a2018-02-19 21:32:51 +01002626 err = -EMSGSIZE;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002627 break;
Roman Kapl5ae437a2018-02-19 21:32:51 +01002628 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002629 }
2630
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002631 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002632 tcf_block_refcnt_put(block, true);
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002633 cb->args[0] = index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635out:
Roman Kapl5ae437a2018-02-19 21:32:51 +01002636 /* If we did no progress, the error (EMSGSIZE) is real */
2637 if (skb->len == 0 && err)
2638 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 return skb->len;
2640}
2641
Vlad Buslova5654822019-02-11 10:55:37 +02002642static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
2643 void *tmplt_priv, u32 chain_index,
2644 struct net *net, struct sk_buff *skb,
2645 struct tcf_block *block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002646 u32 portid, u32 seq, u16 flags, int event)
2647{
2648 unsigned char *b = skb_tail_pointer(skb);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002649 const struct tcf_proto_ops *ops;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002650 struct nlmsghdr *nlh;
2651 struct tcmsg *tcm;
Jiri Pirko9f407f12018-07-23 09:23:07 +02002652 void *priv;
2653
Vlad Buslova5654822019-02-11 10:55:37 +02002654 ops = tmplt_ops;
2655 priv = tmplt_priv;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002656
2657 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
2658 if (!nlh)
2659 goto out_nlmsg_trim;
2660 tcm = nlmsg_data(nlh);
2661 tcm->tcm_family = AF_UNSPEC;
2662 tcm->tcm__pad1 = 0;
2663 tcm->tcm__pad2 = 0;
2664 tcm->tcm_handle = 0;
2665 if (block->q) {
2666 tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
2667 tcm->tcm_parent = block->q->handle;
2668 } else {
2669 tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
2670 tcm->tcm_block_index = block->index;
2671 }
2672
Vlad Buslova5654822019-02-11 10:55:37 +02002673 if (nla_put_u32(skb, TCA_CHAIN, chain_index))
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002674 goto nla_put_failure;
2675
Jiri Pirko9f407f12018-07-23 09:23:07 +02002676 if (ops) {
2677 if (nla_put_string(skb, TCA_KIND, ops->kind))
2678 goto nla_put_failure;
2679 if (ops->tmplt_dump(skb, net, priv) < 0)
2680 goto nla_put_failure;
2681 }
2682
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002683 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
2684 return skb->len;
2685
2686out_nlmsg_trim:
2687nla_put_failure:
2688 nlmsg_trim(skb, b);
2689 return -EMSGSIZE;
2690}
2691
2692static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
2693 u32 seq, u16 flags, int event, bool unicast)
2694{
2695 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2696 struct tcf_block *block = chain->block;
2697 struct net *net = block->net;
2698 struct sk_buff *skb;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002699 int err = 0;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002700
2701 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2702 if (!skb)
2703 return -ENOBUFS;
2704
Vlad Buslova5654822019-02-11 10:55:37 +02002705 if (tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
2706 chain->index, net, skb, block, portid,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002707 seq, flags, event) <= 0) {
2708 kfree_skb(skb);
2709 return -EINVAL;
2710 }
2711
2712 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002713 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2714 else
2715 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
2716 flags & NLM_F_ECHO);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002717
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002718 if (err > 0)
2719 err = 0;
2720 return err;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002721}
2722
Vlad Buslova5654822019-02-11 10:55:37 +02002723static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
2724 void *tmplt_priv, u32 chain_index,
2725 struct tcf_block *block, struct sk_buff *oskb,
2726 u32 seq, u16 flags, bool unicast)
2727{
2728 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2729 struct net *net = block->net;
2730 struct sk_buff *skb;
2731
2732 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2733 if (!skb)
2734 return -ENOBUFS;
2735
2736 if (tc_chain_fill_node(tmplt_ops, tmplt_priv, chain_index, net, skb,
2737 block, portid, seq, flags, RTM_DELCHAIN) <= 0) {
2738 kfree_skb(skb);
2739 return -EINVAL;
2740 }
2741
2742 if (unicast)
2743 return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2744
2745 return rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
2746}
2747
Jiri Pirko9f407f12018-07-23 09:23:07 +02002748static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
2749 struct nlattr **tca,
2750 struct netlink_ext_ack *extack)
2751{
2752 const struct tcf_proto_ops *ops;
2753 void *tmplt_priv;
2754
2755 /* If kind is not set, user did not specify template. */
2756 if (!tca[TCA_KIND])
2757 return 0;
2758
Vlad Buslov12db03b2019-02-11 10:55:45 +02002759 ops = tcf_proto_lookup_ops(nla_data(tca[TCA_KIND]), true, extack);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002760 if (IS_ERR(ops))
2761 return PTR_ERR(ops);
2762 if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
2763 NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier");
2764 return -EOPNOTSUPP;
2765 }
2766
2767 tmplt_priv = ops->tmplt_create(net, chain, tca, extack);
2768 if (IS_ERR(tmplt_priv)) {
2769 module_put(ops->owner);
2770 return PTR_ERR(tmplt_priv);
2771 }
2772 chain->tmplt_ops = ops;
2773 chain->tmplt_priv = tmplt_priv;
2774 return 0;
2775}
2776
Vlad Buslova5654822019-02-11 10:55:37 +02002777static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
2778 void *tmplt_priv)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002779{
Jiri Pirko9f407f12018-07-23 09:23:07 +02002780 /* If template ops are set, no work to do for us. */
Vlad Buslova5654822019-02-11 10:55:37 +02002781 if (!tmplt_ops)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002782 return;
2783
Vlad Buslova5654822019-02-11 10:55:37 +02002784 tmplt_ops->tmplt_destroy(tmplt_priv);
2785 module_put(tmplt_ops->owner);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002786}
2787
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002788/* Add/delete/get a chain */
2789
2790static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
2791 struct netlink_ext_ack *extack)
2792{
2793 struct net *net = sock_net(skb->sk);
2794 struct nlattr *tca[TCA_MAX + 1];
2795 struct tcmsg *t;
2796 u32 parent;
2797 u32 chain_index;
2798 struct Qdisc *q = NULL;
2799 struct tcf_chain *chain = NULL;
2800 struct tcf_block *block;
2801 unsigned long cl;
2802 int err;
2803
2804 if (n->nlmsg_type != RTM_GETCHAIN &&
2805 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2806 return -EPERM;
2807
2808replay:
Davide Carattie3314732018-10-10 22:00:58 +02002809 err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, rtm_tca_policy, extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002810 if (err < 0)
2811 return err;
2812
2813 t = nlmsg_data(n);
2814 parent = t->tcm_parent;
2815 cl = 0;
2816
2817 block = tcf_block_find(net, &q, &parent, &cl,
2818 t->tcm_ifindex, t->tcm_block_index, extack);
2819 if (IS_ERR(block))
2820 return PTR_ERR(block);
2821
2822 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2823 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2824 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002825 err = -EINVAL;
2826 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002827 }
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002828
2829 mutex_lock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002830 chain = tcf_chain_lookup(block, chain_index);
2831 if (n->nlmsg_type == RTM_NEWCHAIN) {
2832 if (chain) {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002833 if (tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002834 /* The chain exists only because there is
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002835 * some action referencing it.
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002836 */
2837 tcf_chain_hold(chain);
2838 } else {
2839 NL_SET_ERR_MSG(extack, "Filter chain already exists");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002840 err = -EEXIST;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002841 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002842 }
2843 } else {
2844 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
2845 NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002846 err = -ENOENT;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002847 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002848 }
2849 chain = tcf_chain_create(block, chain_index);
2850 if (!chain) {
2851 NL_SET_ERR_MSG(extack, "Failed to create filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002852 err = -ENOMEM;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002853 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002854 }
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002855 }
2856 } else {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002857 if (!chain || tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002858 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002859 err = -EINVAL;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002860 goto errout_block_locked;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002861 }
2862 tcf_chain_hold(chain);
2863 }
2864
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002865 if (n->nlmsg_type == RTM_NEWCHAIN) {
2866 /* Modifying chain requires holding parent block lock. In case
2867 * the chain was successfully added, take a reference to the
2868 * chain. This ensures that an empty chain does not disappear at
2869 * the end of this function.
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002870 */
2871 tcf_chain_hold(chain);
2872 chain->explicitly_created = true;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002873 }
2874 mutex_unlock(&block->lock);
2875
2876 switch (n->nlmsg_type) {
2877 case RTM_NEWCHAIN:
2878 err = tc_chain_tmplt_add(chain, net, tca, extack);
2879 if (err) {
2880 tcf_chain_put_explicitly_created(chain);
2881 goto errout;
2882 }
2883
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002884 tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
2885 RTM_NEWCHAIN, false);
2886 break;
2887 case RTM_DELCHAIN:
Cong Wangf5b9bac2018-09-11 14:22:23 -07002888 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002889 chain, RTM_DELTFILTER, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002890 /* Flush the chain first as the user requested chain removal. */
Vlad Buslov12db03b2019-02-11 10:55:45 +02002891 tcf_chain_flush(chain, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002892 /* In case the chain was successfully deleted, put a reference
2893 * to the chain previously taken during addition.
2894 */
2895 tcf_chain_put_explicitly_created(chain);
2896 break;
2897 case RTM_GETCHAIN:
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002898 err = tc_chain_notify(chain, skb, n->nlmsg_seq,
2899 n->nlmsg_seq, n->nlmsg_type, true);
2900 if (err < 0)
2901 NL_SET_ERR_MSG(extack, "Failed to send chain notify message");
2902 break;
2903 default:
2904 err = -EOPNOTSUPP;
2905 NL_SET_ERR_MSG(extack, "Unsupported message type");
2906 goto errout;
2907 }
2908
2909errout:
2910 tcf_chain_put(chain);
Vlad Buslove368fdb2018-09-24 19:22:53 +03002911errout_block:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002912 tcf_block_release(q, block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002913 if (err == -EAGAIN)
2914 /* Replay the request. */
2915 goto replay;
2916 return err;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002917
2918errout_block_locked:
2919 mutex_unlock(&block->lock);
2920 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002921}
2922
2923/* called with RTNL */
2924static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
2925{
2926 struct net *net = sock_net(skb->sk);
2927 struct nlattr *tca[TCA_MAX + 1];
2928 struct Qdisc *q = NULL;
2929 struct tcf_block *block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002930 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovace4a262019-02-25 17:45:44 +02002931 struct tcf_chain *chain;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002932 long index_start;
2933 long index;
2934 u32 parent;
2935 int err;
2936
2937 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
2938 return skb->len;
2939
Davide Carattie3314732018-10-10 22:00:58 +02002940 err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, rtm_tca_policy,
David Aherndac9c972018-10-07 20:16:24 -07002941 cb->extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002942 if (err)
2943 return err;
2944
2945 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002946 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002947 if (!block)
2948 goto out;
2949 /* If we work with block index, q is NULL and parent value
2950 * will never be used in the following code. The check
2951 * in tcf_fill_node prevents it. However, compiler does not
2952 * see that far, so set parent to zero to silence the warning
2953 * about parent being uninitialized.
2954 */
2955 parent = 0;
2956 } else {
2957 const struct Qdisc_class_ops *cops;
2958 struct net_device *dev;
2959 unsigned long cl = 0;
2960
2961 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
2962 if (!dev)
2963 return skb->len;
2964
2965 parent = tcm->tcm_parent;
2966 if (!parent) {
2967 q = dev->qdisc;
2968 parent = q->handle;
2969 } else {
2970 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
2971 }
2972 if (!q)
2973 goto out;
2974 cops = q->ops->cl_ops;
2975 if (!cops)
2976 goto out;
2977 if (!cops->tcf_block)
2978 goto out;
2979 if (TC_H_MIN(tcm->tcm_parent)) {
2980 cl = cops->find(q, tcm->tcm_parent);
2981 if (cl == 0)
2982 goto out;
2983 }
2984 block = cops->tcf_block(q, cl, NULL);
2985 if (!block)
2986 goto out;
2987 if (tcf_block_shared(block))
2988 q = NULL;
2989 }
2990
2991 index_start = cb->args[0];
2992 index = 0;
2993
Vlad Buslovace4a262019-02-25 17:45:44 +02002994 mutex_lock(&block->lock);
2995 list_for_each_entry(chain, &block->chain_list, list) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002996 if ((tca[TCA_CHAIN] &&
2997 nla_get_u32(tca[TCA_CHAIN]) != chain->index))
2998 continue;
2999 if (index < index_start) {
3000 index++;
3001 continue;
3002 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003003 if (tcf_chain_held_by_acts_only(chain))
3004 continue;
Vlad Buslova5654822019-02-11 10:55:37 +02003005 err = tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
3006 chain->index, net, skb, block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003007 NETLINK_CB(cb->skb).portid,
3008 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3009 RTM_NEWCHAIN);
Vlad Buslovace4a262019-02-25 17:45:44 +02003010 if (err <= 0)
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003011 break;
3012 index++;
3013 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003014 mutex_unlock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003015
Vlad Buslov787ce6d2018-09-24 19:22:58 +03003016 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02003017 tcf_block_refcnt_put(block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003018 cb->args[0] = index;
3019
3020out:
3021 /* If we did no progress, the error (EMSGSIZE) is real */
3022 if (skb->len == 0 && err)
3023 return err;
3024 return skb->len;
3025}
3026
WANG Cong18d02642014-09-25 10:26:37 -07003027void tcf_exts_destroy(struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028{
3029#ifdef CONFIG_NET_CLS_ACT
Vlad Buslov90b73b72018-07-05 17:24:33 +03003030 tcf_action_destroy(exts->actions, TCA_ACT_UNBIND);
WANG Cong22dc13c2016-08-13 22:35:00 -07003031 kfree(exts->actions);
3032 exts->nr_actions = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033#endif
3034}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003035EXPORT_SYMBOL(tcf_exts_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036
Benjamin LaHaisec1b52732013-01-14 05:15:39 +00003037int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
Alexander Aring50a56192018-01-18 11:20:52 -05003038 struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003039 bool rtnl_held, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041#ifdef CONFIG_NET_CLS_ACT
3042 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 struct tc_action *act;
Roman Mashakd04e6992018-03-08 16:59:17 -05003044 size_t attr_size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
WANG Cong5da57f42013-12-15 20:15:07 -08003046 if (exts->police && tb[exts->police]) {
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003047 act = tcf_action_init_1(net, tp, tb[exts->police],
3048 rate_tlv, "police", ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003049 TCA_ACT_BIND, rtnl_held,
3050 extack);
Patrick McHardyab27cfb2008-01-23 20:33:13 -08003051 if (IS_ERR(act))
3052 return PTR_ERR(act);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053
WANG Cong33be6272013-12-15 20:15:05 -08003054 act->type = exts->type = TCA_OLD_COMPAT;
WANG Cong22dc13c2016-08-13 22:35:00 -07003055 exts->actions[0] = act;
3056 exts->nr_actions = 1;
WANG Cong5da57f42013-12-15 20:15:07 -08003057 } else if (exts->action && tb[exts->action]) {
Vlad Buslov90b73b72018-07-05 17:24:33 +03003058 int err;
WANG Cong22dc13c2016-08-13 22:35:00 -07003059
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003060 err = tcf_action_init(net, tp, tb[exts->action],
3061 rate_tlv, NULL, ovr, TCA_ACT_BIND,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003062 exts->actions, &attr_size,
3063 rtnl_held, extack);
Vlad Buslov90b73b72018-07-05 17:24:33 +03003064 if (err < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003065 return err;
Vlad Buslov90b73b72018-07-05 17:24:33 +03003066 exts->nr_actions = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 }
3068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069#else
WANG Cong5da57f42013-12-15 20:15:07 -08003070 if ((exts->action && tb[exts->action]) ||
Alexander Aring50a56192018-01-18 11:20:52 -05003071 (exts->police && tb[exts->police])) {
3072 NL_SET_ERR_MSG(extack, "Classifier actions are not supported per compile options (CONFIG_NET_CLS_ACT)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 return -EOPNOTSUPP;
Alexander Aring50a56192018-01-18 11:20:52 -05003074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075#endif
3076
3077 return 0;
3078}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003079EXPORT_SYMBOL(tcf_exts_validate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003081void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082{
3083#ifdef CONFIG_NET_CLS_ACT
WANG Cong22dc13c2016-08-13 22:35:00 -07003084 struct tcf_exts old = *dst;
3085
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003086 *dst = *src;
WANG Cong22dc13c2016-08-13 22:35:00 -07003087 tcf_exts_destroy(&old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088#endif
3089}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003090EXPORT_SYMBOL(tcf_exts_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
WANG Cong22dc13c2016-08-13 22:35:00 -07003092#ifdef CONFIG_NET_CLS_ACT
3093static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
3094{
3095 if (exts->nr_actions == 0)
3096 return NULL;
3097 else
3098 return exts->actions[0];
3099}
3100#endif
WANG Cong33be6272013-12-15 20:15:05 -08003101
WANG Cong5da57f42013-12-15 20:15:07 -08003102int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103{
3104#ifdef CONFIG_NET_CLS_ACT
Cong Wang9cc63db2014-07-16 14:25:30 -07003105 struct nlattr *nest;
3106
Jiri Pirko978dfd82017-08-04 14:29:03 +02003107 if (exts->action && tcf_exts_has_actions(exts)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 /*
3109 * again for backward compatible mode - we want
3110 * to work with both old and new modes of entering
3111 * tc data even if iproute2 was newer - jhs
3112 */
WANG Cong33be6272013-12-15 20:15:05 -08003113 if (exts->type != TCA_OLD_COMPAT) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003114 nest = nla_nest_start_noflag(skb, exts->action);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003115 if (nest == NULL)
3116 goto nla_put_failure;
WANG Cong22dc13c2016-08-13 22:35:00 -07003117
Vlad Buslov90b73b72018-07-05 17:24:33 +03003118 if (tcf_action_dump(skb, exts->actions, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003119 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003120 nla_nest_end(skb, nest);
WANG Cong5da57f42013-12-15 20:15:07 -08003121 } else if (exts->police) {
WANG Cong33be6272013-12-15 20:15:05 -08003122 struct tc_action *act = tcf_exts_first_act(exts);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003123 nest = nla_nest_start_noflag(skb, exts->police);
Jamal Hadi Salim63acd682013-12-23 08:02:12 -05003124 if (nest == NULL || !act)
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003125 goto nla_put_failure;
WANG Cong33be6272013-12-15 20:15:05 -08003126 if (tcf_action_dump_old(skb, act, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003127 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003128 nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 }
3130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 return 0;
Cong Wang9cc63db2014-07-16 14:25:30 -07003132
3133nla_put_failure:
3134 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 return -1;
Cong Wang9cc63db2014-07-16 14:25:30 -07003136#else
3137 return 0;
3138#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003140EXPORT_SYMBOL(tcf_exts_dump);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003142
WANG Cong5da57f42013-12-15 20:15:07 -08003143int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144{
3145#ifdef CONFIG_NET_CLS_ACT
WANG Cong33be6272013-12-15 20:15:05 -08003146 struct tc_action *a = tcf_exts_first_act(exts);
Ignacy Gawędzkib057df22015-02-03 19:05:18 +01003147 if (a != NULL && tcf_action_copy_stats(skb, a, 1) < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003148 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149#endif
3150 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003152EXPORT_SYMBOL(tcf_exts_dump_stats);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
Cong Wangaeb3fec2018-12-11 11:15:46 -08003154int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
3155 void *type_data, bool err_stop)
Jiri Pirko717503b2017-10-11 09:41:09 +02003156{
Cong Wangaeb3fec2018-12-11 11:15:46 -08003157 struct tcf_block_cb *block_cb;
3158 int ok_count = 0;
3159 int err;
3160
3161 /* Make sure all netdevs sharing this block are offload-capable. */
3162 if (block->nooffloaddevcnt && err_stop)
3163 return -EOPNOTSUPP;
3164
3165 list_for_each_entry(block_cb, &block->cb_list, list) {
3166 err = block_cb->cb(type, type_data, block_cb->cb_priv);
3167 if (err) {
3168 if (err_stop)
3169 return err;
3170 } else {
3171 ok_count++;
3172 }
3173 }
3174 return ok_count;
Jiri Pirko717503b2017-10-11 09:41:09 +02003175}
3176EXPORT_SYMBOL(tc_setup_cb_call);
Jiri Pirkob3f55bd2017-10-11 09:41:08 +02003177
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003178int tc_setup_flow_action(struct flow_action *flow_action,
3179 const struct tcf_exts *exts)
3180{
3181 const struct tc_action *act;
3182 int i, j, k;
3183
3184 if (!exts)
3185 return 0;
3186
3187 j = 0;
3188 tcf_exts_for_each_action(i, act, exts) {
3189 struct flow_action_entry *entry;
3190
3191 entry = &flow_action->entries[j];
3192 if (is_tcf_gact_ok(act)) {
3193 entry->id = FLOW_ACTION_ACCEPT;
3194 } else if (is_tcf_gact_shot(act)) {
3195 entry->id = FLOW_ACTION_DROP;
3196 } else if (is_tcf_gact_trap(act)) {
3197 entry->id = FLOW_ACTION_TRAP;
3198 } else if (is_tcf_gact_goto_chain(act)) {
3199 entry->id = FLOW_ACTION_GOTO;
3200 entry->chain_index = tcf_gact_goto_chain_index(act);
3201 } else if (is_tcf_mirred_egress_redirect(act)) {
3202 entry->id = FLOW_ACTION_REDIRECT;
3203 entry->dev = tcf_mirred_dev(act);
3204 } else if (is_tcf_mirred_egress_mirror(act)) {
3205 entry->id = FLOW_ACTION_MIRRED;
3206 entry->dev = tcf_mirred_dev(act);
3207 } else if (is_tcf_vlan(act)) {
3208 switch (tcf_vlan_action(act)) {
3209 case TCA_VLAN_ACT_PUSH:
3210 entry->id = FLOW_ACTION_VLAN_PUSH;
3211 entry->vlan.vid = tcf_vlan_push_vid(act);
3212 entry->vlan.proto = tcf_vlan_push_proto(act);
3213 entry->vlan.prio = tcf_vlan_push_prio(act);
3214 break;
3215 case TCA_VLAN_ACT_POP:
3216 entry->id = FLOW_ACTION_VLAN_POP;
3217 break;
3218 case TCA_VLAN_ACT_MODIFY:
3219 entry->id = FLOW_ACTION_VLAN_MANGLE;
3220 entry->vlan.vid = tcf_vlan_push_vid(act);
3221 entry->vlan.proto = tcf_vlan_push_proto(act);
3222 entry->vlan.prio = tcf_vlan_push_prio(act);
3223 break;
3224 default:
3225 goto err_out;
3226 }
3227 } else if (is_tcf_tunnel_set(act)) {
3228 entry->id = FLOW_ACTION_TUNNEL_ENCAP;
3229 entry->tunnel = tcf_tunnel_info(act);
3230 } else if (is_tcf_tunnel_release(act)) {
3231 entry->id = FLOW_ACTION_TUNNEL_DECAP;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003232 } else if (is_tcf_pedit(act)) {
3233 for (k = 0; k < tcf_pedit_nkeys(act); k++) {
3234 switch (tcf_pedit_cmd(act, k)) {
3235 case TCA_PEDIT_KEY_EX_CMD_SET:
3236 entry->id = FLOW_ACTION_MANGLE;
3237 break;
3238 case TCA_PEDIT_KEY_EX_CMD_ADD:
3239 entry->id = FLOW_ACTION_ADD;
3240 break;
3241 default:
3242 goto err_out;
3243 }
3244 entry->mangle.htype = tcf_pedit_htype(act, k);
3245 entry->mangle.mask = tcf_pedit_mask(act, k);
3246 entry->mangle.val = tcf_pedit_val(act, k);
3247 entry->mangle.offset = tcf_pedit_offset(act, k);
3248 entry = &flow_action->entries[++j];
3249 }
3250 } else if (is_tcf_csum(act)) {
3251 entry->id = FLOW_ACTION_CSUM;
3252 entry->csum_flags = tcf_csum_update_flags(act);
3253 } else if (is_tcf_skbedit_mark(act)) {
3254 entry->id = FLOW_ACTION_MARK;
3255 entry->mark = tcf_skbedit_mark(act);
3256 } else {
3257 goto err_out;
3258 }
3259
3260 if (!is_tcf_pedit(act))
3261 j++;
3262 }
3263 return 0;
3264err_out:
3265 return -EOPNOTSUPP;
3266}
3267EXPORT_SYMBOL(tc_setup_flow_action);
3268
Pablo Neira Ayusoe3ab7862019-02-02 12:50:45 +01003269unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
3270{
3271 unsigned int num_acts = 0;
3272 struct tc_action *act;
3273 int i;
3274
3275 tcf_exts_for_each_action(i, act, exts) {
3276 if (is_tcf_pedit(act))
3277 num_acts += tcf_pedit_nkeys(act);
3278 else
3279 num_acts++;
3280 }
3281 return num_acts;
3282}
3283EXPORT_SYMBOL(tcf_exts_num_actions);
3284
Jiri Pirko48617382018-01-17 11:46:46 +01003285static __net_init int tcf_net_init(struct net *net)
3286{
3287 struct tcf_net *tn = net_generic(net, tcf_net_id);
3288
Vlad Buslovab281622018-09-24 19:22:56 +03003289 spin_lock_init(&tn->idr_lock);
Jiri Pirko48617382018-01-17 11:46:46 +01003290 idr_init(&tn->idr);
3291 return 0;
3292}
3293
3294static void __net_exit tcf_net_exit(struct net *net)
3295{
3296 struct tcf_net *tn = net_generic(net, tcf_net_id);
3297
3298 idr_destroy(&tn->idr);
3299}
3300
3301static struct pernet_operations tcf_net_ops = {
3302 .init = tcf_net_init,
3303 .exit = tcf_net_exit,
3304 .id = &tcf_net_id,
3305 .size = sizeof(struct tcf_net),
3306};
3307
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308static int __init tc_filter_init(void)
3309{
Jiri Pirko48617382018-01-17 11:46:46 +01003310 int err;
3311
Cong Wang7aa00452017-10-26 18:24:28 -07003312 tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0);
3313 if (!tc_filter_wq)
3314 return -ENOMEM;
3315
Jiri Pirko48617382018-01-17 11:46:46 +01003316 err = register_pernet_subsys(&tcf_net_ops);
3317 if (err)
3318 goto err_register_pernet_subsys;
3319
John Hurley7f76fa32018-11-09 21:21:26 -08003320 err = rhashtable_init(&indr_setup_block_ht,
3321 &tc_indr_setup_block_ht_params);
3322 if (err)
3323 goto err_rhash_setup_block_ht;
3324
Vlad Buslov470502d2019-02-11 10:55:48 +02003325 rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_new_tfilter, NULL,
3326 RTNL_FLAG_DOIT_UNLOCKED);
3327 rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_del_tfilter, NULL,
3328 RTNL_FLAG_DOIT_UNLOCKED);
Vlad Buslovc431f892018-05-31 09:52:53 +03003329 rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_get_tfilter,
Vlad Buslov470502d2019-02-11 10:55:48 +02003330 tc_dump_tfilter, RTNL_FLAG_DOIT_UNLOCKED);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003331 rtnl_register(PF_UNSPEC, RTM_NEWCHAIN, tc_ctl_chain, NULL, 0);
3332 rtnl_register(PF_UNSPEC, RTM_DELCHAIN, tc_ctl_chain, NULL, 0);
3333 rtnl_register(PF_UNSPEC, RTM_GETCHAIN, tc_ctl_chain,
3334 tc_dump_chain, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 return 0;
Jiri Pirko48617382018-01-17 11:46:46 +01003337
John Hurley7f76fa32018-11-09 21:21:26 -08003338err_rhash_setup_block_ht:
3339 unregister_pernet_subsys(&tcf_net_ops);
Jiri Pirko48617382018-01-17 11:46:46 +01003340err_register_pernet_subsys:
3341 destroy_workqueue(tc_filter_wq);
3342 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343}
3344
3345subsys_initcall(tc_filter_init);