blob: 7e85c91d07526e0eca42f67fa629a70b6d8da6b9 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * net/sched/cls_api.c Packet classifier API.
4 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6 *
7 * Changes:
8 *
9 * Eduardo J. Blanco <ejbs@netlabs.com.uy> :990222: kmod support
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/errno.h>
Jiri Pirko33a48922017-02-09 14:38:57 +010017#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/init.h>
20#include <linux/kmod.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Jiri Pirko48617382018-01-17 11:46:46 +010022#include <linux/idr.h>
John Hurley7f76fa32018-11-09 21:21:26 -080023#include <linux/rhashtable.h>
John Hurley59eb87c2019-11-02 14:17:47 +000024#include <linux/jhash.h>
Paul Blakey43719292020-02-16 12:01:23 +020025#include <linux/rculist.h>
Denis V. Lunevb8542722007-12-01 00:21:31 +110026#include <net/net_namespace.h>
27#include <net/sock.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070028#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/pkt_sched.h>
30#include <net/pkt_cls.h>
Pablo Neira Ayusoe3ab7862019-02-02 12:50:45 +010031#include <net/tc_act/tc_pedit.h>
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +010032#include <net/tc_act/tc_mirred.h>
33#include <net/tc_act/tc_vlan.h>
34#include <net/tc_act/tc_tunnel_key.h>
35#include <net/tc_act/tc_csum.h>
36#include <net/tc_act/tc_gact.h>
Pieter Jansen van Vuuren8c8cfc62019-05-04 04:46:22 -070037#include <net/tc_act/tc_police.h>
Pieter Jansen van Vuurena7a7be62019-05-04 04:46:16 -070038#include <net/tc_act/tc_sample.h>
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +010039#include <net/tc_act/tc_skbedit.h>
Paul Blakeyb57dc7c2019-07-09 10:30:48 +030040#include <net/tc_act/tc_ct.h>
John Hurley6749d5902019-07-23 15:33:59 +010041#include <net/tc_act/tc_mpls.h>
Po Liud29bdd62020-05-01 08:53:16 +080042#include <net/tc_act/tc_gate.h>
wenxu4e481902019-08-07 09:13:52 +080043#include <net/flow_offload.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Davide Carattie3314732018-10-10 22:00:58 +020045extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047/* The list of all installed classifier types */
WANG Cong36272872013-12-15 20:15:11 -080048static LIST_HEAD(tcf_proto_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50/* Protects list of registered TC modules. It is pure SMP lock. */
51static DEFINE_RWLOCK(cls_mod_lock);
52
John Hurley59eb87c2019-11-02 14:17:47 +000053static u32 destroy_obj_hashfn(const struct tcf_proto *tp)
54{
55 return jhash_3words(tp->chain->index, tp->prio,
56 (__force __u32)tp->protocol, 0);
57}
58
59static void tcf_proto_signal_destroying(struct tcf_chain *chain,
60 struct tcf_proto *tp)
61{
62 struct tcf_block *block = chain->block;
63
64 mutex_lock(&block->proto_destroy_lock);
65 hash_add_rcu(block->proto_destroy_ht, &tp->destroy_ht_node,
66 destroy_obj_hashfn(tp));
67 mutex_unlock(&block->proto_destroy_lock);
68}
69
70static bool tcf_proto_cmp(const struct tcf_proto *tp1,
71 const struct tcf_proto *tp2)
72{
73 return tp1->chain->index == tp2->chain->index &&
74 tp1->prio == tp2->prio &&
75 tp1->protocol == tp2->protocol;
76}
77
78static bool tcf_proto_exists_destroying(struct tcf_chain *chain,
79 struct tcf_proto *tp)
80{
81 u32 hash = destroy_obj_hashfn(tp);
82 struct tcf_proto *iter;
83 bool found = false;
84
85 rcu_read_lock();
86 hash_for_each_possible_rcu(chain->block->proto_destroy_ht, iter,
87 destroy_ht_node, hash) {
88 if (tcf_proto_cmp(tp, iter)) {
89 found = true;
90 break;
91 }
92 }
93 rcu_read_unlock();
94
95 return found;
96}
97
98static void
99tcf_proto_signal_destroyed(struct tcf_chain *chain, struct tcf_proto *tp)
100{
101 struct tcf_block *block = chain->block;
102
103 mutex_lock(&block->proto_destroy_lock);
104 if (hash_hashed(&tp->destroy_ht_node))
105 hash_del_rcu(&tp->destroy_ht_node);
106 mutex_unlock(&block->proto_destroy_lock);
107}
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/* Find classifier type by string name */
110
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200111static const struct tcf_proto_ops *__tcf_proto_lookup_ops(const char *kind)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Eric Dumazetdcd76082013-12-20 10:04:18 -0800113 const struct tcf_proto_ops *t, *res = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115 if (kind) {
116 read_lock(&cls_mod_lock);
WANG Cong36272872013-12-15 20:15:11 -0800117 list_for_each_entry(t, &tcf_proto_base, head) {
Jiri Pirko33a48922017-02-09 14:38:57 +0100118 if (strcmp(kind, t->kind) == 0) {
Eric Dumazetdcd76082013-12-20 10:04:18 -0800119 if (try_module_get(t->owner))
120 res = t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 break;
122 }
123 }
124 read_unlock(&cls_mod_lock);
125 }
Eric Dumazetdcd76082013-12-20 10:04:18 -0800126 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200129static const struct tcf_proto_ops *
Vlad Buslov12db03b2019-02-11 10:55:45 +0200130tcf_proto_lookup_ops(const char *kind, bool rtnl_held,
131 struct netlink_ext_ack *extack)
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200132{
133 const struct tcf_proto_ops *ops;
134
135 ops = __tcf_proto_lookup_ops(kind);
136 if (ops)
137 return ops;
138#ifdef CONFIG_MODULES
Vlad Buslov12db03b2019-02-11 10:55:45 +0200139 if (rtnl_held)
140 rtnl_unlock();
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200141 request_module("cls_%s", kind);
Vlad Buslov12db03b2019-02-11 10:55:45 +0200142 if (rtnl_held)
143 rtnl_lock();
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200144 ops = __tcf_proto_lookup_ops(kind);
145 /* We dropped the RTNL semaphore in order to perform
146 * the module load. So, even if we succeeded in loading
147 * the module we have to replay the request. We indicate
148 * this using -EAGAIN.
149 */
150 if (ops) {
151 module_put(ops->owner);
152 return ERR_PTR(-EAGAIN);
153 }
154#endif
155 NL_SET_ERR_MSG(extack, "TC classifier not found");
156 return ERR_PTR(-ENOENT);
157}
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159/* Register(unregister) new classifier type */
160
161int register_tcf_proto_ops(struct tcf_proto_ops *ops)
162{
WANG Cong36272872013-12-15 20:15:11 -0800163 struct tcf_proto_ops *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 int rc = -EEXIST;
165
166 write_lock(&cls_mod_lock);
WANG Cong36272872013-12-15 20:15:11 -0800167 list_for_each_entry(t, &tcf_proto_base, head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (!strcmp(ops->kind, t->kind))
169 goto out;
170
WANG Cong36272872013-12-15 20:15:11 -0800171 list_add_tail(&ops->head, &tcf_proto_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 rc = 0;
173out:
174 write_unlock(&cls_mod_lock);
175 return rc;
176}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800177EXPORT_SYMBOL(register_tcf_proto_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Cong Wang7aa00452017-10-26 18:24:28 -0700179static struct workqueue_struct *tc_filter_wq;
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
182{
WANG Cong36272872013-12-15 20:15:11 -0800183 struct tcf_proto_ops *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 int rc = -ENOENT;
185
Daniel Borkmannc78e1742015-05-20 17:13:33 +0200186 /* Wait for outstanding call_rcu()s, if any, from a
187 * tcf_proto_ops's destroy() handler.
188 */
189 rcu_barrier();
Cong Wang7aa00452017-10-26 18:24:28 -0700190 flush_workqueue(tc_filter_wq);
Daniel Borkmannc78e1742015-05-20 17:13:33 +0200191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 write_lock(&cls_mod_lock);
Eric Dumazetdcd76082013-12-20 10:04:18 -0800193 list_for_each_entry(t, &tcf_proto_base, head) {
194 if (t == ops) {
195 list_del(&t->head);
196 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 break;
Eric Dumazetdcd76082013-12-20 10:04:18 -0800198 }
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 write_unlock(&cls_mod_lock);
201 return rc;
202}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800203EXPORT_SYMBOL(unregister_tcf_proto_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Cong Wangaaa908f2018-05-23 15:26:53 -0700205bool tcf_queue_work(struct rcu_work *rwork, work_func_t func)
Cong Wang7aa00452017-10-26 18:24:28 -0700206{
Cong Wangaaa908f2018-05-23 15:26:53 -0700207 INIT_RCU_WORK(rwork, func);
208 return queue_rcu_work(tc_filter_wq, rwork);
Cong Wang7aa00452017-10-26 18:24:28 -0700209}
210EXPORT_SYMBOL(tcf_queue_work);
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212/* Select new prio value from the range, managed by kernel. */
213
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800214static inline u32 tcf_auto_prio(struct tcf_proto *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -0800216 u32 first = TC_H_MAKE(0xC0000000U, 0U);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218 if (tp)
Eric Dumazetcc7ec452011-01-19 19:26:56 +0000219 first = tp->prio - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Jiri Pirko79619732017-05-17 11:07:58 +0200221 return TC_H_MAJ(first);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Cong Wang6f96c3c2019-10-07 13:26:28 -0700224static bool tcf_proto_check_kind(struct nlattr *kind, char *name)
225{
226 if (kind)
227 return nla_strlcpy(name, kind, IFNAMSIZ) >= IFNAMSIZ;
228 memset(name, 0, IFNAMSIZ);
229 return false;
230}
231
Vlad Buslov470502d2019-02-11 10:55:48 +0200232static bool tcf_proto_is_unlocked(const char *kind)
233{
234 const struct tcf_proto_ops *ops;
235 bool ret;
236
Cong Wang6f96c3c2019-10-07 13:26:28 -0700237 if (strlen(kind) == 0)
238 return false;
239
Vlad Buslov470502d2019-02-11 10:55:48 +0200240 ops = tcf_proto_lookup_ops(kind, false, NULL);
241 /* On error return false to take rtnl lock. Proto lookup/create
242 * functions will perform lookup again and properly handle errors.
243 */
244 if (IS_ERR(ops))
245 return false;
246
247 ret = !!(ops->flags & TCF_PROTO_OPS_DOIT_UNLOCKED);
248 module_put(ops->owner);
249 return ret;
250}
251
Jiri Pirko33a48922017-02-09 14:38:57 +0100252static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
Alexander Aringc35a4ac2018-01-18 11:20:50 -0500253 u32 prio, struct tcf_chain *chain,
Vlad Buslov12db03b2019-02-11 10:55:45 +0200254 bool rtnl_held,
Alexander Aringc35a4ac2018-01-18 11:20:50 -0500255 struct netlink_ext_ack *extack)
Jiri Pirko33a48922017-02-09 14:38:57 +0100256{
257 struct tcf_proto *tp;
258 int err;
259
260 tp = kzalloc(sizeof(*tp), GFP_KERNEL);
261 if (!tp)
262 return ERR_PTR(-ENOBUFS);
263
Vlad Buslov12db03b2019-02-11 10:55:45 +0200264 tp->ops = tcf_proto_lookup_ops(kind, rtnl_held, extack);
Jiri Pirkof34e8bf2018-07-23 09:23:04 +0200265 if (IS_ERR(tp->ops)) {
266 err = PTR_ERR(tp->ops);
Jiri Pirkod68d75f2018-05-11 17:45:32 +0200267 goto errout;
Jiri Pirko33a48922017-02-09 14:38:57 +0100268 }
269 tp->classify = tp->ops->classify;
270 tp->protocol = protocol;
271 tp->prio = prio;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200272 tp->chain = chain;
Vlad Buslov8b646782019-02-11 10:55:41 +0200273 spin_lock_init(&tp->lock);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200274 refcount_set(&tp->refcnt, 1);
Jiri Pirko33a48922017-02-09 14:38:57 +0100275
276 err = tp->ops->init(tp);
277 if (err) {
278 module_put(tp->ops->owner);
279 goto errout;
280 }
281 return tp;
282
283errout:
284 kfree(tp);
285 return ERR_PTR(err);
286}
287
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200288static void tcf_proto_get(struct tcf_proto *tp)
289{
290 refcount_inc(&tp->refcnt);
291}
292
293static void tcf_chain_put(struct tcf_chain *chain);
294
Vlad Buslov12db03b2019-02-11 10:55:45 +0200295static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
John Hurley59eb87c2019-11-02 14:17:47 +0000296 bool sig_destroy, struct netlink_ext_ack *extack)
Jiri Pirkocf1facd2017-02-09 14:38:56 +0100297{
Vlad Buslov12db03b2019-02-11 10:55:45 +0200298 tp->ops->destroy(tp, rtnl_held, extack);
John Hurley59eb87c2019-11-02 14:17:47 +0000299 if (sig_destroy)
300 tcf_proto_signal_destroyed(tp->chain, tp);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200301 tcf_chain_put(tp->chain);
WANG Cong763dbf62017-04-19 14:21:21 -0700302 module_put(tp->ops->owner);
303 kfree_rcu(tp, rcu);
Jiri Pirkocf1facd2017-02-09 14:38:56 +0100304}
305
Vlad Buslov12db03b2019-02-11 10:55:45 +0200306static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held,
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200307 struct netlink_ext_ack *extack)
308{
309 if (refcount_dec_and_test(&tp->refcnt))
John Hurley59eb87c2019-11-02 14:17:47 +0000310 tcf_proto_destroy(tp, rtnl_held, true, extack);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200311}
312
Davide Carattia5b72a02019-12-28 16:36:58 +0100313static bool tcf_proto_check_delete(struct tcf_proto *tp)
Vlad Buslov8b646782019-02-11 10:55:41 +0200314{
Davide Carattia5b72a02019-12-28 16:36:58 +0100315 if (tp->ops->delete_empty)
316 return tp->ops->delete_empty(tp);
Vlad Buslov8b646782019-02-11 10:55:41 +0200317
Davide Carattia5b72a02019-12-28 16:36:58 +0100318 tp->deleting = true;
Vlad Buslov8b646782019-02-11 10:55:41 +0200319 return tp->deleting;
320}
321
322static void tcf_proto_mark_delete(struct tcf_proto *tp)
323{
324 spin_lock(&tp->lock);
325 tp->deleting = true;
326 spin_unlock(&tp->lock);
327}
328
329static bool tcf_proto_is_deleting(struct tcf_proto *tp)
330{
331 bool deleting;
332
333 spin_lock(&tp->lock);
334 deleting = tp->deleting;
335 spin_unlock(&tp->lock);
336
337 return deleting;
338}
339
Vlad Buslovc266f642019-02-11 10:55:32 +0200340#define ASSERT_BLOCK_LOCKED(block) \
341 lockdep_assert_held(&(block)->lock)
342
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100343struct tcf_filter_chain_list_item {
344 struct list_head list;
345 tcf_chain_head_change_t *chain_head_change;
346 void *chain_head_change_priv;
347};
348
Jiri Pirko5bc17012017-05-17 11:08:01 +0200349static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
350 u32 chain_index)
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200351{
Jiri Pirko5bc17012017-05-17 11:08:01 +0200352 struct tcf_chain *chain;
353
Vlad Buslovc266f642019-02-11 10:55:32 +0200354 ASSERT_BLOCK_LOCKED(block);
355
Jiri Pirko5bc17012017-05-17 11:08:01 +0200356 chain = kzalloc(sizeof(*chain), GFP_KERNEL);
357 if (!chain)
358 return NULL;
Paul Blakey43719292020-02-16 12:01:23 +0200359 list_add_tail_rcu(&chain->list, &block->chain_list);
Vlad Busloved76f5e2019-02-11 10:55:38 +0200360 mutex_init(&chain->filter_chain_lock);
Jiri Pirko5bc17012017-05-17 11:08:01 +0200361 chain->block = block;
362 chain->index = chain_index;
Cong Wange2ef7542017-09-11 16:33:31 -0700363 chain->refcnt = 1;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200364 if (!chain->index)
365 block->chain0.chain = chain;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200366 return chain;
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200367}
368
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100369static void tcf_chain_head_change_item(struct tcf_filter_chain_list_item *item,
370 struct tcf_proto *tp_head)
371{
372 if (item->chain_head_change)
373 item->chain_head_change(tp_head, item->chain_head_change_priv);
374}
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200375
376static void tcf_chain0_head_change(struct tcf_chain *chain,
377 struct tcf_proto *tp_head)
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100378{
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100379 struct tcf_filter_chain_list_item *item;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200380 struct tcf_block *block = chain->block;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100381
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200382 if (chain->index)
383 return;
Vlad Buslov165f0132019-02-11 10:55:35 +0200384
385 mutex_lock(&block->lock);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200386 list_for_each_entry(item, &block->chain0.filter_chain_list, list)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100387 tcf_chain_head_change_item(item, tp_head);
Vlad Buslov165f0132019-02-11 10:55:35 +0200388 mutex_unlock(&block->lock);
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +0100389}
390
Vlad Buslovc266f642019-02-11 10:55:32 +0200391/* Returns true if block can be safely freed. */
392
393static bool tcf_chain_detach(struct tcf_chain *chain)
Jiri Pirkof93e1cd2017-05-20 15:01:32 +0200394{
Cong Wangefbf7892017-12-04 10:48:18 -0800395 struct tcf_block *block = chain->block;
396
Vlad Buslovc266f642019-02-11 10:55:32 +0200397 ASSERT_BLOCK_LOCKED(block);
398
Paul Blakey43719292020-02-16 12:01:23 +0200399 list_del_rcu(&chain->list);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200400 if (!chain->index)
401 block->chain0.chain = NULL;
Vlad Buslovc266f642019-02-11 10:55:32 +0200402
403 if (list_empty(&block->chain_list) &&
404 refcount_read(&block->refcnt) == 0)
405 return true;
406
407 return false;
408}
409
410static void tcf_block_destroy(struct tcf_block *block)
411{
412 mutex_destroy(&block->lock);
John Hurley59eb87c2019-11-02 14:17:47 +0000413 mutex_destroy(&block->proto_destroy_lock);
Vlad Buslovc266f642019-02-11 10:55:32 +0200414 kfree_rcu(block, rcu);
415}
416
417static void tcf_chain_destroy(struct tcf_chain *chain, bool free_block)
418{
419 struct tcf_block *block = chain->block;
420
Vlad Busloved76f5e2019-02-11 10:55:38 +0200421 mutex_destroy(&chain->filter_chain_lock);
Davide Carattiee3bbfe2019-03-20 15:00:16 +0100422 kfree_rcu(chain, rcu);
Vlad Buslovc266f642019-02-11 10:55:32 +0200423 if (free_block)
424 tcf_block_destroy(block);
Cong Wange2ef7542017-09-11 16:33:31 -0700425}
Jiri Pirko744a4cf2017-08-22 22:46:49 +0200426
Cong Wange2ef7542017-09-11 16:33:31 -0700427static void tcf_chain_hold(struct tcf_chain *chain)
428{
Vlad Buslovc266f642019-02-11 10:55:32 +0200429 ASSERT_BLOCK_LOCKED(chain->block);
430
Cong Wange2ef7542017-09-11 16:33:31 -0700431 ++chain->refcnt;
Jiri Pirko2190d1d2017-05-17 11:07:59 +0200432}
433
Jiri Pirko3d32f4c2018-08-01 12:36:55 +0200434static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain)
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200435{
Vlad Buslovc266f642019-02-11 10:55:32 +0200436 ASSERT_BLOCK_LOCKED(chain->block);
437
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200438 /* In case all the references are action references, this
Jiri Pirko3d32f4c2018-08-01 12:36:55 +0200439 * chain should not be shown to the user.
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200440 */
441 return chain->refcnt == chain->action_refcnt;
442}
443
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200444static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
445 u32 chain_index)
Jiri Pirko5bc17012017-05-17 11:08:01 +0200446{
447 struct tcf_chain *chain;
448
Vlad Buslovc266f642019-02-11 10:55:32 +0200449 ASSERT_BLOCK_LOCKED(block);
450
Jiri Pirko5bc17012017-05-17 11:08:01 +0200451 list_for_each_entry(chain, &block->chain_list, list) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200452 if (chain->index == chain_index)
Cong Wange2ef7542017-09-11 16:33:31 -0700453 return chain;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200454 }
455 return NULL;
456}
457
Paul Blakeyaf699622020-02-16 12:01:24 +0200458#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
459static struct tcf_chain *tcf_chain_lookup_rcu(const struct tcf_block *block,
460 u32 chain_index)
461{
462 struct tcf_chain *chain;
463
464 list_for_each_entry_rcu(chain, &block->chain_list, list) {
465 if (chain->index == chain_index)
466 return chain;
467 }
468 return NULL;
469}
470#endif
471
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200472static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
473 u32 seq, u16 flags, int event, bool unicast);
474
Jiri Pirko53681402018-08-01 12:36:56 +0200475static struct tcf_chain *__tcf_chain_get(struct tcf_block *block,
476 u32 chain_index, bool create,
477 bool by_act)
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200478{
Vlad Buslovc266f642019-02-11 10:55:32 +0200479 struct tcf_chain *chain = NULL;
480 bool is_first_reference;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200481
Vlad Buslovc266f642019-02-11 10:55:32 +0200482 mutex_lock(&block->lock);
483 chain = tcf_chain_lookup(block, chain_index);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200484 if (chain) {
485 tcf_chain_hold(chain);
Jiri Pirko53681402018-08-01 12:36:56 +0200486 } else {
487 if (!create)
Vlad Buslovc266f642019-02-11 10:55:32 +0200488 goto errout;
Jiri Pirko53681402018-08-01 12:36:56 +0200489 chain = tcf_chain_create(block, chain_index);
490 if (!chain)
Vlad Buslovc266f642019-02-11 10:55:32 +0200491 goto errout;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200492 }
Jiri Pirko80532382017-09-06 13:14:19 +0200493
Jiri Pirko53681402018-08-01 12:36:56 +0200494 if (by_act)
495 ++chain->action_refcnt;
Vlad Buslovc266f642019-02-11 10:55:32 +0200496 is_first_reference = chain->refcnt - chain->action_refcnt == 1;
497 mutex_unlock(&block->lock);
Jiri Pirko53681402018-08-01 12:36:56 +0200498
499 /* Send notification only in case we got the first
500 * non-action reference. Until then, the chain acts only as
501 * a placeholder for actions pointing to it and user ought
502 * not know about them.
503 */
Vlad Buslovc266f642019-02-11 10:55:32 +0200504 if (is_first_reference && !by_act)
Jiri Pirko53681402018-08-01 12:36:56 +0200505 tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
506 RTM_NEWCHAIN, false);
507
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200508 return chain;
Vlad Buslovc266f642019-02-11 10:55:32 +0200509
510errout:
511 mutex_unlock(&block->lock);
512 return chain;
Jiri Pirko5bc17012017-05-17 11:08:01 +0200513}
Jiri Pirko53681402018-08-01 12:36:56 +0200514
Jiri Pirko290b1c82018-08-01 12:36:57 +0200515static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
516 bool create)
Jiri Pirko53681402018-08-01 12:36:56 +0200517{
518 return __tcf_chain_get(block, chain_index, create, false);
519}
Jiri Pirko5bc17012017-05-17 11:08:01 +0200520
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200521struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
522{
Jiri Pirko53681402018-08-01 12:36:56 +0200523 return __tcf_chain_get(block, chain_index, true, true);
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200524}
525EXPORT_SYMBOL(tcf_chain_get_by_act);
526
Vlad Buslova5654822019-02-11 10:55:37 +0200527static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
528 void *tmplt_priv);
529static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
530 void *tmplt_priv, u32 chain_index,
531 struct tcf_block *block, struct sk_buff *oskb,
532 u32 seq, u16 flags, bool unicast);
Jiri Pirko9f407f12018-07-23 09:23:07 +0200533
Vlad Buslov91052fa2019-02-11 10:55:33 +0200534static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
535 bool explicitly_created)
Jiri Pirko5bc17012017-05-17 11:08:01 +0200536{
Vlad Buslovc266f642019-02-11 10:55:32 +0200537 struct tcf_block *block = chain->block;
Vlad Buslova5654822019-02-11 10:55:37 +0200538 const struct tcf_proto_ops *tmplt_ops;
Vlad Buslovb62989f2019-03-06 17:50:43 +0200539 bool free_block = false;
Vlad Buslovc266f642019-02-11 10:55:32 +0200540 unsigned int refcnt;
Vlad Buslova5654822019-02-11 10:55:37 +0200541 void *tmplt_priv;
Vlad Buslovc266f642019-02-11 10:55:32 +0200542
543 mutex_lock(&block->lock);
Vlad Buslov91052fa2019-02-11 10:55:33 +0200544 if (explicitly_created) {
545 if (!chain->explicitly_created) {
546 mutex_unlock(&block->lock);
547 return;
548 }
549 chain->explicitly_created = false;
550 }
551
Jiri Pirko53681402018-08-01 12:36:56 +0200552 if (by_act)
553 chain->action_refcnt--;
Vlad Buslovc266f642019-02-11 10:55:32 +0200554
555 /* tc_chain_notify_delete can't be called while holding block lock.
556 * However, when block is unlocked chain can be changed concurrently, so
557 * save these to temporary variables.
558 */
559 refcnt = --chain->refcnt;
Vlad Buslova5654822019-02-11 10:55:37 +0200560 tmplt_ops = chain->tmplt_ops;
561 tmplt_priv = chain->tmplt_priv;
Jiri Pirko53681402018-08-01 12:36:56 +0200562
563 /* The last dropped non-action reference will trigger notification. */
Vlad Buslovb62989f2019-03-06 17:50:43 +0200564 if (refcnt - chain->action_refcnt == 0 && !by_act) {
565 tc_chain_notify_delete(tmplt_ops, tmplt_priv, chain->index,
Vlad Buslova5654822019-02-11 10:55:37 +0200566 block, NULL, 0, 0, false);
Vlad Buslov726d06122019-02-11 10:55:42 +0200567 /* Last reference to chain, no need to lock. */
568 chain->flushing = false;
569 }
Jiri Pirko53681402018-08-01 12:36:56 +0200570
Vlad Buslovb62989f2019-03-06 17:50:43 +0200571 if (refcnt == 0)
572 free_block = tcf_chain_detach(chain);
573 mutex_unlock(&block->lock);
574
Vlad Buslovc266f642019-02-11 10:55:32 +0200575 if (refcnt == 0) {
Vlad Buslova5654822019-02-11 10:55:37 +0200576 tc_chain_tmplt_del(tmplt_ops, tmplt_priv);
Vlad Buslovc266f642019-02-11 10:55:32 +0200577 tcf_chain_destroy(chain, free_block);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200578 }
Jiri Pirko5bc17012017-05-17 11:08:01 +0200579}
Jiri Pirko53681402018-08-01 12:36:56 +0200580
Jiri Pirko290b1c82018-08-01 12:36:57 +0200581static void tcf_chain_put(struct tcf_chain *chain)
Jiri Pirko53681402018-08-01 12:36:56 +0200582{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200583 __tcf_chain_put(chain, false, false);
Jiri Pirko53681402018-08-01 12:36:56 +0200584}
Jiri Pirko5bc17012017-05-17 11:08:01 +0200585
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200586void tcf_chain_put_by_act(struct tcf_chain *chain)
587{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200588 __tcf_chain_put(chain, true, false);
Jiri Pirko1f3ed382018-07-27 09:45:05 +0200589}
590EXPORT_SYMBOL(tcf_chain_put_by_act);
591
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200592static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
593{
Vlad Buslov91052fa2019-02-11 10:55:33 +0200594 __tcf_chain_put(chain, false, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +0200595}
596
Vlad Buslov12db03b2019-02-11 10:55:45 +0200597static void tcf_chain_flush(struct tcf_chain *chain, bool rtnl_held)
Jiri Pirko290b1c82018-08-01 12:36:57 +0200598{
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200599 struct tcf_proto *tp, *tp_next;
Jiri Pirko290b1c82018-08-01 12:36:57 +0200600
Vlad Busloved76f5e2019-02-11 10:55:38 +0200601 mutex_lock(&chain->filter_chain_lock);
602 tp = tcf_chain_dereference(chain->filter_chain, chain);
John Hurley59eb87c2019-11-02 14:17:47 +0000603 while (tp) {
604 tp_next = rcu_dereference_protected(tp->next, 1);
605 tcf_proto_signal_destroying(chain, tp);
606 tp = tp_next;
607 }
608 tp = tcf_chain_dereference(chain->filter_chain, chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200609 RCU_INIT_POINTER(chain->filter_chain, NULL);
Jiri Pirko290b1c82018-08-01 12:36:57 +0200610 tcf_chain0_head_change(chain, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +0200611 chain->flushing = true;
Vlad Busloved76f5e2019-02-11 10:55:38 +0200612 mutex_unlock(&chain->filter_chain_lock);
613
Jiri Pirko290b1c82018-08-01 12:36:57 +0200614 while (tp) {
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200615 tp_next = rcu_dereference_protected(tp->next, 1);
Vlad Buslov12db03b2019-02-11 10:55:45 +0200616 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslov4dbfa762019-02-11 10:55:39 +0200617 tp = tp_next;
Jiri Pirko290b1c82018-08-01 12:36:57 +0200618 }
619}
620
wenxu4e481902019-08-07 09:13:52 +0800621static int tcf_block_setup(struct tcf_block *block,
622 struct flow_block_offload *bo);
623
John Hurley25a443f2019-12-05 17:03:35 +0000624static void tc_indr_block_cmd(struct net_device *dev, struct tcf_block *block,
625 flow_indr_block_bind_cb_t *cb, void *cb_priv,
626 enum flow_block_command command, bool ingress)
wenxu4e481902019-08-07 09:13:52 +0800627{
628 struct flow_block_offload bo = {
629 .command = command,
John Hurley25a443f2019-12-05 17:03:35 +0000630 .binder_type = ingress ?
631 FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS :
632 FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
wenxu4e481902019-08-07 09:13:52 +0800633 .net = dev_net(dev),
634 .block_shared = tcf_block_non_null_shared(block),
635 };
636 INIT_LIST_HEAD(&bo.cb_list);
637
638 if (!block)
639 return;
640
641 bo.block = &block->flow_block;
642
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300643 down_write(&block->cb_lock);
wenxu4e481902019-08-07 09:13:52 +0800644 cb(dev, cb_priv, TC_SETUP_BLOCK, &bo);
645
646 tcf_block_setup(block, &bo);
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300647 up_write(&block->cb_lock);
wenxu4e481902019-08-07 09:13:52 +0800648}
649
John Hurley25a443f2019-12-05 17:03:35 +0000650static struct tcf_block *tc_dev_block(struct net_device *dev, bool ingress)
John Hurley7f76fa32018-11-09 21:21:26 -0800651{
652 const struct Qdisc_class_ops *cops;
John Hurley25a443f2019-12-05 17:03:35 +0000653 const struct Qdisc_ops *ops;
John Hurley7f76fa32018-11-09 21:21:26 -0800654 struct Qdisc *qdisc;
655
656 if (!dev_ingress_queue(dev))
657 return NULL;
658
659 qdisc = dev_ingress_queue(dev)->qdisc_sleeping;
660 if (!qdisc)
661 return NULL;
662
John Hurley25a443f2019-12-05 17:03:35 +0000663 ops = qdisc->ops;
664 if (!ops)
665 return NULL;
666
667 if (!ingress && !strcmp("ingress", ops->id))
668 return NULL;
669
670 cops = ops->cl_ops;
John Hurley7f76fa32018-11-09 21:21:26 -0800671 if (!cops)
672 return NULL;
673
674 if (!cops->tcf_block)
675 return NULL;
676
John Hurley25a443f2019-12-05 17:03:35 +0000677 return cops->tcf_block(qdisc,
678 ingress ? TC_H_MIN_INGRESS : TC_H_MIN_EGRESS,
679 NULL);
John Hurley7f76fa32018-11-09 21:21:26 -0800680}
681
John Hurley25a443f2019-12-05 17:03:35 +0000682static void tc_indr_block_get_and_cmd(struct net_device *dev,
683 flow_indr_block_bind_cb_t *cb,
684 void *cb_priv,
685 enum flow_block_command command)
John Hurley7f76fa32018-11-09 21:21:26 -0800686{
John Hurley25a443f2019-12-05 17:03:35 +0000687 struct tcf_block *block;
wenxu4e481902019-08-07 09:13:52 +0800688
John Hurley25a443f2019-12-05 17:03:35 +0000689 block = tc_dev_block(dev, true);
690 tc_indr_block_cmd(dev, block, cb, cb_priv, command, true);
691
692 block = tc_dev_block(dev, false);
693 tc_indr_block_cmd(dev, block, cb, cb_priv, command, false);
John Hurley7f76fa32018-11-09 21:21:26 -0800694}
695
wenxu4e481902019-08-07 09:13:52 +0800696static void tc_indr_block_call(struct tcf_block *block,
697 struct net_device *dev,
John Hurley7f76fa32018-11-09 21:21:26 -0800698 struct tcf_block_ext_info *ei,
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200699 enum flow_block_command command,
John Hurley7f76fa32018-11-09 21:21:26 -0800700 struct netlink_ext_ack *extack)
701{
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +0200702 struct flow_block_offload bo = {
John Hurley7f76fa32018-11-09 21:21:26 -0800703 .command = command,
704 .binder_type = ei->binder_type,
Pablo Neira Ayusoda3eeb92019-07-09 22:55:43 +0200705 .net = dev_net(dev),
Pablo Neira Ayuso14bfb132019-07-19 18:20:16 +0200706 .block = &block->flow_block,
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +0200707 .block_shared = tcf_block_shared(block),
John Hurley7f76fa32018-11-09 21:21:26 -0800708 .extack = extack,
709 };
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200710 INIT_LIST_HEAD(&bo.cb_list);
John Hurley7f76fa32018-11-09 21:21:26 -0800711
wenxu133a2fe52020-03-24 07:34:25 +0800712 flow_indr_block_call(dev, &bo, command, TC_SETUP_BLOCK);
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200713 tcf_block_setup(block, &bo);
John Hurley7f76fa32018-11-09 21:21:26 -0800714}
715
Jiri Pirkocaa72602018-01-17 11:46:50 +0100716static bool tcf_block_offload_in_use(struct tcf_block *block)
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200717{
Vlad Buslov97394be2019-08-26 16:44:58 +0300718 return atomic_read(&block->offloadcnt);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100719}
720
721static int tcf_block_offload_cmd(struct tcf_block *block,
722 struct net_device *dev,
723 struct tcf_block_ext_info *ei,
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200724 enum flow_block_command command,
John Hurley60513bd2018-06-25 14:30:04 -0700725 struct netlink_ext_ack *extack)
Jiri Pirkocaa72602018-01-17 11:46:50 +0100726{
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +0200727 struct flow_block_offload bo = {};
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200728 int err;
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200729
Pablo Neira Ayusoda3eeb92019-07-09 22:55:43 +0200730 bo.net = dev_net(dev);
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200731 bo.command = command;
732 bo.binder_type = ei->binder_type;
Pablo Neira Ayuso14bfb132019-07-19 18:20:16 +0200733 bo.block = &block->flow_block;
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +0200734 bo.block_shared = tcf_block_shared(block);
John Hurley60513bd2018-06-25 14:30:04 -0700735 bo.extack = extack;
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200736 INIT_LIST_HEAD(&bo.cb_list);
737
738 err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
Jesper Dangaard Brouerb70ba692020-04-23 16:57:45 +0200739 if (err < 0) {
740 if (err != -EOPNOTSUPP)
741 NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200742 return err;
Jesper Dangaard Brouerb70ba692020-04-23 16:57:45 +0200743 }
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +0200744
745 return tcf_block_setup(block, &bo);
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200746}
747
Jiri Pirkocaa72602018-01-17 11:46:50 +0100748static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
John Hurley60513bd2018-06-25 14:30:04 -0700749 struct tcf_block_ext_info *ei,
750 struct netlink_ext_ack *extack)
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200751{
Jiri Pirkocaa72602018-01-17 11:46:50 +0100752 struct net_device *dev = q->dev_queue->dev;
753 int err;
754
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300755 down_write(&block->cb_lock);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100756 if (!dev->netdev_ops->ndo_setup_tc)
757 goto no_offload_dev_inc;
758
759 /* If tc offload feature is disabled and the block we try to bind
760 * to already has some offloaded filters, forbid to bind.
761 */
John Hurley60513bd2018-06-25 14:30:04 -0700762 if (!tc_can_offload(dev) && tcf_block_offload_in_use(block)) {
763 NL_SET_ERR_MSG(extack, "Bind to offloaded block failed as dev has offload disabled");
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300764 err = -EOPNOTSUPP;
765 goto err_unlock;
John Hurley60513bd2018-06-25 14:30:04 -0700766 }
Jiri Pirkocaa72602018-01-17 11:46:50 +0100767
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200768 err = tcf_block_offload_cmd(block, dev, ei, FLOW_BLOCK_BIND, extack);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100769 if (err == -EOPNOTSUPP)
770 goto no_offload_dev_inc;
John Hurley7f76fa32018-11-09 21:21:26 -0800771 if (err)
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300772 goto err_unlock;
John Hurley7f76fa32018-11-09 21:21:26 -0800773
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200774 tc_indr_block_call(block, dev, ei, FLOW_BLOCK_BIND, extack);
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300775 up_write(&block->cb_lock);
John Hurley7f76fa32018-11-09 21:21:26 -0800776 return 0;
Jiri Pirkocaa72602018-01-17 11:46:50 +0100777
778no_offload_dev_inc:
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300779 if (tcf_block_offload_in_use(block)) {
780 err = -EOPNOTSUPP;
781 goto err_unlock;
782 }
783 err = 0;
Jiri Pirkocaa72602018-01-17 11:46:50 +0100784 block->nooffloaddevcnt++;
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200785 tc_indr_block_call(block, dev, ei, FLOW_BLOCK_BIND, extack);
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300786err_unlock:
787 up_write(&block->cb_lock);
788 return err;
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200789}
790
791static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
792 struct tcf_block_ext_info *ei)
793{
Jiri Pirkocaa72602018-01-17 11:46:50 +0100794 struct net_device *dev = q->dev_queue->dev;
795 int err;
796
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300797 down_write(&block->cb_lock);
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200798 tc_indr_block_call(block, dev, ei, FLOW_BLOCK_UNBIND, NULL);
John Hurley7f76fa32018-11-09 21:21:26 -0800799
Jiri Pirkocaa72602018-01-17 11:46:50 +0100800 if (!dev->netdev_ops->ndo_setup_tc)
801 goto no_offload_dev_dec;
Pablo Neira Ayuso9c0e1892019-07-09 22:55:40 +0200802 err = tcf_block_offload_cmd(block, dev, ei, FLOW_BLOCK_UNBIND, NULL);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100803 if (err == -EOPNOTSUPP)
804 goto no_offload_dev_dec;
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300805 up_write(&block->cb_lock);
Jiri Pirkocaa72602018-01-17 11:46:50 +0100806 return;
807
808no_offload_dev_dec:
809 WARN_ON(block->nooffloaddevcnt-- == 0);
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300810 up_write(&block->cb_lock);
Jiri Pirko8c4083b2017-10-19 15:50:29 +0200811}
812
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100813static int
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200814tcf_chain0_head_change_cb_add(struct tcf_block *block,
815 struct tcf_block_ext_info *ei,
816 struct netlink_ext_ack *extack)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100817{
818 struct tcf_filter_chain_list_item *item;
Vlad Buslov165f0132019-02-11 10:55:35 +0200819 struct tcf_chain *chain0;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100820
821 item = kmalloc(sizeof(*item), GFP_KERNEL);
822 if (!item) {
823 NL_SET_ERR_MSG(extack, "Memory allocation for head change callback item failed");
824 return -ENOMEM;
825 }
826 item->chain_head_change = ei->chain_head_change;
827 item->chain_head_change_priv = ei->chain_head_change_priv;
Vlad Buslov165f0132019-02-11 10:55:35 +0200828
829 mutex_lock(&block->lock);
830 chain0 = block->chain0.chain;
Vlad Busloved76f5e2019-02-11 10:55:38 +0200831 if (chain0)
832 tcf_chain_hold(chain0);
833 else
834 list_add(&item->list, &block->chain0.filter_chain_list);
Vlad Buslov165f0132019-02-11 10:55:35 +0200835 mutex_unlock(&block->lock);
836
Vlad Busloved76f5e2019-02-11 10:55:38 +0200837 if (chain0) {
838 struct tcf_proto *tp_head;
839
840 mutex_lock(&chain0->filter_chain_lock);
841
842 tp_head = tcf_chain_dereference(chain0->filter_chain, chain0);
843 if (tp_head)
844 tcf_chain_head_change_item(item, tp_head);
845
846 mutex_lock(&block->lock);
847 list_add(&item->list, &block->chain0.filter_chain_list);
848 mutex_unlock(&block->lock);
849
850 mutex_unlock(&chain0->filter_chain_lock);
851 tcf_chain_put(chain0);
852 }
853
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100854 return 0;
855}
856
857static void
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200858tcf_chain0_head_change_cb_del(struct tcf_block *block,
859 struct tcf_block_ext_info *ei)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100860{
861 struct tcf_filter_chain_list_item *item;
862
Vlad Buslov165f0132019-02-11 10:55:35 +0200863 mutex_lock(&block->lock);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200864 list_for_each_entry(item, &block->chain0.filter_chain_list, list) {
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100865 if ((!ei->chain_head_change && !ei->chain_head_change_priv) ||
866 (item->chain_head_change == ei->chain_head_change &&
867 item->chain_head_change_priv == ei->chain_head_change_priv)) {
Vlad Buslov165f0132019-02-11 10:55:35 +0200868 if (block->chain0.chain)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200869 tcf_chain_head_change_item(item, NULL);
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100870 list_del(&item->list);
Vlad Buslov165f0132019-02-11 10:55:35 +0200871 mutex_unlock(&block->lock);
872
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100873 kfree(item);
874 return;
875 }
876 }
Vlad Buslov165f0132019-02-11 10:55:35 +0200877 mutex_unlock(&block->lock);
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100878 WARN_ON(1);
879}
880
Jiri Pirko48617382018-01-17 11:46:46 +0100881struct tcf_net {
Vlad Buslovab281622018-09-24 19:22:56 +0300882 spinlock_t idr_lock; /* Protects idr */
Jiri Pirko48617382018-01-17 11:46:46 +0100883 struct idr idr;
884};
885
886static unsigned int tcf_net_id;
887
888static int tcf_block_insert(struct tcf_block *block, struct net *net,
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100889 struct netlink_ext_ack *extack)
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100890{
Jiri Pirko48617382018-01-17 11:46:46 +0100891 struct tcf_net *tn = net_generic(net, tcf_net_id);
Vlad Buslovab281622018-09-24 19:22:56 +0300892 int err;
Jiri Pirko48617382018-01-17 11:46:46 +0100893
Vlad Buslovab281622018-09-24 19:22:56 +0300894 idr_preload(GFP_KERNEL);
895 spin_lock(&tn->idr_lock);
896 err = idr_alloc_u32(&tn->idr, block, &block->index, block->index,
897 GFP_NOWAIT);
898 spin_unlock(&tn->idr_lock);
899 idr_preload_end();
900
901 return err;
Jiri Pirkoa9b19442018-01-17 11:46:45 +0100902}
903
Jiri Pirko48617382018-01-17 11:46:46 +0100904static void tcf_block_remove(struct tcf_block *block, struct net *net)
Jiri Pirko6529eab2017-05-17 11:07:55 +0200905{
Jiri Pirko48617382018-01-17 11:46:46 +0100906 struct tcf_net *tn = net_generic(net, tcf_net_id);
907
Vlad Buslovab281622018-09-24 19:22:56 +0300908 spin_lock(&tn->idr_lock);
Matthew Wilcox9c160942017-11-28 09:48:43 -0500909 idr_remove(&tn->idr, block->index);
Vlad Buslovab281622018-09-24 19:22:56 +0300910 spin_unlock(&tn->idr_lock);
Jiri Pirko48617382018-01-17 11:46:46 +0100911}
912
913static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100914 u32 block_index,
Jiri Pirko48617382018-01-17 11:46:46 +0100915 struct netlink_ext_ack *extack)
916{
917 struct tcf_block *block;
Jiri Pirko6529eab2017-05-17 11:07:55 +0200918
Jiri Pirko48617382018-01-17 11:46:46 +0100919 block = kzalloc(sizeof(*block), GFP_KERNEL);
Alexander Aring8d1a77f2017-12-20 12:35:19 -0500920 if (!block) {
921 NL_SET_ERR_MSG(extack, "Memory allocation for block failed");
Jiri Pirko48617382018-01-17 11:46:46 +0100922 return ERR_PTR(-ENOMEM);
Alexander Aring8d1a77f2017-12-20 12:35:19 -0500923 }
Vlad Buslovc266f642019-02-11 10:55:32 +0200924 mutex_init(&block->lock);
John Hurley59eb87c2019-11-02 14:17:47 +0000925 mutex_init(&block->proto_destroy_lock);
Vlad Buslov4f8116c2019-08-26 16:44:57 +0300926 init_rwsem(&block->cb_lock);
Pablo Neira Ayuso14bfb132019-07-19 18:20:16 +0200927 flow_block_init(&block->flow_block);
Jiri Pirko5bc17012017-05-17 11:08:01 +0200928 INIT_LIST_HEAD(&block->chain_list);
Jiri Pirkof36fe1c2018-01-17 11:46:48 +0100929 INIT_LIST_HEAD(&block->owner_list);
Jiri Pirkof71e0ca42018-07-23 09:23:05 +0200930 INIT_LIST_HEAD(&block->chain0.filter_chain_list);
Jiri Pirkoacb67442017-10-19 15:50:31 +0200931
Vlad Buslovcfebd7e2018-09-24 19:22:54 +0300932 refcount_set(&block->refcnt, 1);
Jiri Pirko48617382018-01-17 11:46:46 +0100933 block->net = net;
Jiri Pirkobb047dd2018-02-13 12:00:16 +0100934 block->index = block_index;
935
936 /* Don't store q pointer for blocks which are shared */
937 if (!tcf_block_shared(block))
938 block->q = q;
Jiri Pirko48617382018-01-17 11:46:46 +0100939 return block;
Jiri Pirko48617382018-01-17 11:46:46 +0100940}
941
942static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index)
943{
944 struct tcf_net *tn = net_generic(net, tcf_net_id);
945
Matthew Wilcox322d8842017-11-28 10:01:24 -0500946 return idr_find(&tn->idr, block_index);
Jiri Pirko48617382018-01-17 11:46:46 +0100947}
948
Vlad Buslov0607e432018-09-24 19:22:57 +0300949static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index)
950{
951 struct tcf_block *block;
952
953 rcu_read_lock();
954 block = tcf_block_lookup(net, block_index);
955 if (block && !refcount_inc_not_zero(&block->refcnt))
956 block = NULL;
957 rcu_read_unlock();
958
959 return block;
960}
961
Vlad Buslovbbf73832019-02-11 10:55:36 +0200962static struct tcf_chain *
963__tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
964{
965 mutex_lock(&block->lock);
966 if (chain)
967 chain = list_is_last(&chain->list, &block->chain_list) ?
968 NULL : list_next_entry(chain, list);
969 else
970 chain = list_first_entry_or_null(&block->chain_list,
971 struct tcf_chain, list);
972
973 /* skip all action-only chains */
974 while (chain && tcf_chain_held_by_acts_only(chain))
975 chain = list_is_last(&chain->list, &block->chain_list) ?
976 NULL : list_next_entry(chain, list);
977
978 if (chain)
979 tcf_chain_hold(chain);
980 mutex_unlock(&block->lock);
981
982 return chain;
983}
984
985/* Function to be used by all clients that want to iterate over all chains on
986 * block. It properly obtains block->lock and takes reference to chain before
987 * returning it. Users of this function must be tolerant to concurrent chain
988 * insertion/deletion or ensure that no concurrent chain modification is
989 * possible. Note that all netlink dump callbacks cannot guarantee to provide
990 * consistent dump because rtnl lock is released each time skb is filled with
991 * data and sent to user-space.
992 */
993
994struct tcf_chain *
995tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
996{
997 struct tcf_chain *chain_next = __tcf_get_next_chain(block, chain);
998
999 if (chain)
1000 tcf_chain_put(chain);
1001
1002 return chain_next;
1003}
1004EXPORT_SYMBOL(tcf_get_next_chain);
1005
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001006static struct tcf_proto *
1007__tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
1008{
Vlad Buslov8b646782019-02-11 10:55:41 +02001009 u32 prio = 0;
1010
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001011 ASSERT_RTNL();
1012 mutex_lock(&chain->filter_chain_lock);
1013
Vlad Buslov8b646782019-02-11 10:55:41 +02001014 if (!tp) {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001015 tp = tcf_chain_dereference(chain->filter_chain, chain);
Vlad Buslov8b646782019-02-11 10:55:41 +02001016 } else if (tcf_proto_is_deleting(tp)) {
1017 /* 'deleting' flag is set and chain->filter_chain_lock was
1018 * unlocked, which means next pointer could be invalid. Restart
1019 * search.
1020 */
1021 prio = tp->prio + 1;
1022 tp = tcf_chain_dereference(chain->filter_chain, chain);
1023
1024 for (; tp; tp = tcf_chain_dereference(tp->next, chain))
1025 if (!tp->deleting && tp->prio >= prio)
1026 break;
1027 } else {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001028 tp = tcf_chain_dereference(tp->next, chain);
Vlad Buslov8b646782019-02-11 10:55:41 +02001029 }
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001030
1031 if (tp)
1032 tcf_proto_get(tp);
1033
1034 mutex_unlock(&chain->filter_chain_lock);
1035
1036 return tp;
1037}
1038
1039/* Function to be used by all clients that want to iterate over all tp's on
1040 * chain. Users of this function must be tolerant to concurrent tp
1041 * insertion/deletion or ensure that no concurrent chain modification is
1042 * possible. Note that all netlink dump callbacks cannot guarantee to provide
1043 * consistent dump because rtnl lock is released each time skb is filled with
1044 * data and sent to user-space.
1045 */
1046
1047struct tcf_proto *
Vlad Buslov12db03b2019-02-11 10:55:45 +02001048tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp,
1049 bool rtnl_held)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001050{
1051 struct tcf_proto *tp_next = __tcf_get_next_proto(chain, tp);
1052
1053 if (tp)
Vlad Buslov12db03b2019-02-11 10:55:45 +02001054 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001055
1056 return tp_next;
1057}
1058EXPORT_SYMBOL(tcf_get_next_proto);
1059
Vlad Buslov12db03b2019-02-11 10:55:45 +02001060static void tcf_block_flush_all_chains(struct tcf_block *block, bool rtnl_held)
Vlad Buslovf0023432018-09-24 19:22:55 +03001061{
1062 struct tcf_chain *chain;
1063
Vlad Buslovbbf73832019-02-11 10:55:36 +02001064 /* Last reference to block. At this point chains cannot be added or
1065 * removed concurrently.
Vlad Buslovf0023432018-09-24 19:22:55 +03001066 */
Vlad Buslovbbf73832019-02-11 10:55:36 +02001067 for (chain = tcf_get_next_chain(block, NULL);
1068 chain;
1069 chain = tcf_get_next_chain(block, chain)) {
Vlad Buslovf0023432018-09-24 19:22:55 +03001070 tcf_chain_put_explicitly_created(chain);
Vlad Buslov12db03b2019-02-11 10:55:45 +02001071 tcf_chain_flush(chain, rtnl_held);
Vlad Buslovf0023432018-09-24 19:22:55 +03001072 }
1073}
1074
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001075/* Lookup Qdisc and increments its reference counter.
1076 * Set parent, if necessary.
1077 */
1078
1079static int __tcf_qdisc_find(struct net *net, struct Qdisc **q,
1080 u32 *parent, int ifindex, bool rtnl_held,
1081 struct netlink_ext_ack *extack)
1082{
1083 const struct Qdisc_class_ops *cops;
1084 struct net_device *dev;
1085 int err = 0;
1086
1087 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK)
1088 return 0;
1089
1090 rcu_read_lock();
1091
1092 /* Find link */
1093 dev = dev_get_by_index_rcu(net, ifindex);
1094 if (!dev) {
1095 rcu_read_unlock();
1096 return -ENODEV;
1097 }
1098
1099 /* Find qdisc */
1100 if (!*parent) {
1101 *q = dev->qdisc;
1102 *parent = (*q)->handle;
1103 } else {
1104 *q = qdisc_lookup_rcu(dev, TC_H_MAJ(*parent));
1105 if (!*q) {
1106 NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists");
1107 err = -EINVAL;
1108 goto errout_rcu;
1109 }
1110 }
1111
1112 *q = qdisc_refcount_inc_nz(*q);
1113 if (!*q) {
1114 NL_SET_ERR_MSG(extack, "Parent Qdisc doesn't exists");
1115 err = -EINVAL;
1116 goto errout_rcu;
1117 }
1118
1119 /* Is it classful? */
1120 cops = (*q)->ops->cl_ops;
1121 if (!cops) {
1122 NL_SET_ERR_MSG(extack, "Qdisc not classful");
1123 err = -EINVAL;
1124 goto errout_qdisc;
1125 }
1126
1127 if (!cops->tcf_block) {
1128 NL_SET_ERR_MSG(extack, "Class doesn't support blocks");
1129 err = -EOPNOTSUPP;
1130 goto errout_qdisc;
1131 }
1132
1133errout_rcu:
1134 /* At this point we know that qdisc is not noop_qdisc,
1135 * which means that qdisc holds a reference to net_device
1136 * and we hold a reference to qdisc, so it is safe to release
1137 * rcu read lock.
1138 */
1139 rcu_read_unlock();
1140 return err;
1141
1142errout_qdisc:
1143 rcu_read_unlock();
1144
1145 if (rtnl_held)
1146 qdisc_put(*q);
1147 else
1148 qdisc_put_unlocked(*q);
1149 *q = NULL;
1150
1151 return err;
1152}
1153
1154static int __tcf_qdisc_cl_find(struct Qdisc *q, u32 parent, unsigned long *cl,
1155 int ifindex, struct netlink_ext_ack *extack)
1156{
1157 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK)
1158 return 0;
1159
1160 /* Do we search for filter, attached to class? */
1161 if (TC_H_MIN(parent)) {
1162 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1163
1164 *cl = cops->find(q, parent);
1165 if (*cl == 0) {
1166 NL_SET_ERR_MSG(extack, "Specified class doesn't exist");
1167 return -ENOENT;
1168 }
1169 }
1170
1171 return 0;
1172}
1173
1174static struct tcf_block *__tcf_block_find(struct net *net, struct Qdisc *q,
1175 unsigned long cl, int ifindex,
1176 u32 block_index,
1177 struct netlink_ext_ack *extack)
1178{
1179 struct tcf_block *block;
1180
1181 if (ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
1182 block = tcf_block_refcnt_get(net, block_index);
1183 if (!block) {
1184 NL_SET_ERR_MSG(extack, "Block of given index was not found");
1185 return ERR_PTR(-EINVAL);
1186 }
1187 } else {
1188 const struct Qdisc_class_ops *cops = q->ops->cl_ops;
1189
1190 block = cops->tcf_block(q, cl, extack);
1191 if (!block)
1192 return ERR_PTR(-EINVAL);
1193
1194 if (tcf_block_shared(block)) {
1195 NL_SET_ERR_MSG(extack, "This filter block is shared. Please use the block index to manipulate the filters");
1196 return ERR_PTR(-EOPNOTSUPP);
1197 }
1198
1199 /* Always take reference to block in order to support execution
1200 * of rules update path of cls API without rtnl lock. Caller
1201 * must release block when it is finished using it. 'if' block
1202 * of this conditional obtain reference to block by calling
1203 * tcf_block_refcnt_get().
1204 */
1205 refcount_inc(&block->refcnt);
1206 }
1207
1208 return block;
1209}
1210
Vlad Buslov0607e432018-09-24 19:22:57 +03001211static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001212 struct tcf_block_ext_info *ei, bool rtnl_held)
Vlad Buslov0607e432018-09-24 19:22:57 +03001213{
Vlad Buslovc266f642019-02-11 10:55:32 +02001214 if (refcount_dec_and_mutex_lock(&block->refcnt, &block->lock)) {
Vlad Buslov0607e432018-09-24 19:22:57 +03001215 /* Flushing/putting all chains will cause the block to be
1216 * deallocated when last chain is freed. However, if chain_list
1217 * is empty, block has to be manually deallocated. After block
1218 * reference counter reached 0, it is no longer possible to
1219 * increment it or add new chains to block.
1220 */
1221 bool free_block = list_empty(&block->chain_list);
1222
Vlad Buslovc266f642019-02-11 10:55:32 +02001223 mutex_unlock(&block->lock);
Vlad Buslov0607e432018-09-24 19:22:57 +03001224 if (tcf_block_shared(block))
1225 tcf_block_remove(block, block->net);
Vlad Buslov0607e432018-09-24 19:22:57 +03001226
1227 if (q)
1228 tcf_block_offload_unbind(block, q, ei);
1229
1230 if (free_block)
Vlad Buslovc266f642019-02-11 10:55:32 +02001231 tcf_block_destroy(block);
Vlad Buslov0607e432018-09-24 19:22:57 +03001232 else
Vlad Buslov12db03b2019-02-11 10:55:45 +02001233 tcf_block_flush_all_chains(block, rtnl_held);
Vlad Buslov0607e432018-09-24 19:22:57 +03001234 } else if (q) {
1235 tcf_block_offload_unbind(block, q, ei);
1236 }
1237}
1238
Vlad Buslov12db03b2019-02-11 10:55:45 +02001239static void tcf_block_refcnt_put(struct tcf_block *block, bool rtnl_held)
Vlad Buslov0607e432018-09-24 19:22:57 +03001240{
Vlad Buslov12db03b2019-02-11 10:55:45 +02001241 __tcf_block_put(block, NULL, NULL, rtnl_held);
Vlad Buslov0607e432018-09-24 19:22:57 +03001242}
1243
Vlad Buslovc431f892018-05-31 09:52:53 +03001244/* Find tcf block.
1245 * Set q, parent, cl when appropriate.
1246 */
1247
1248static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q,
1249 u32 *parent, unsigned long *cl,
1250 int ifindex, u32 block_index,
1251 struct netlink_ext_ack *extack)
1252{
1253 struct tcf_block *block;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001254 int err = 0;
Vlad Buslovc431f892018-05-31 09:52:53 +03001255
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001256 ASSERT_RTNL();
Vlad Buslovc431f892018-05-31 09:52:53 +03001257
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001258 err = __tcf_qdisc_find(net, q, parent, ifindex, true, extack);
1259 if (err)
1260 goto errout;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001261
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001262 err = __tcf_qdisc_cl_find(*q, *parent, cl, ifindex, extack);
1263 if (err)
1264 goto errout_qdisc;
Vlad Buslovc431f892018-05-31 09:52:53 +03001265
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001266 block = __tcf_block_find(net, *q, *cl, ifindex, block_index, extack);
Dan Carpenteraf736bf2019-02-18 12:26:32 +03001267 if (IS_ERR(block)) {
1268 err = PTR_ERR(block);
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001269 goto errout_qdisc;
Dan Carpenteraf736bf2019-02-18 12:26:32 +03001270 }
Vlad Buslovc431f892018-05-31 09:52:53 +03001271
1272 return block;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001273
Vlad Buslove368fdb2018-09-24 19:22:53 +03001274errout_qdisc:
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001275 if (*q)
Vlad Buslove368fdb2018-09-24 19:22:53 +03001276 qdisc_put(*q);
Vlad Buslov18d3eef2019-02-11 10:55:47 +02001277errout:
1278 *q = NULL;
Vlad Buslove368fdb2018-09-24 19:22:53 +03001279 return ERR_PTR(err);
1280}
1281
Vlad Buslov12db03b2019-02-11 10:55:45 +02001282static void tcf_block_release(struct Qdisc *q, struct tcf_block *block,
1283 bool rtnl_held)
Vlad Buslove368fdb2018-09-24 19:22:53 +03001284{
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001285 if (!IS_ERR_OR_NULL(block))
Vlad Buslov12db03b2019-02-11 10:55:45 +02001286 tcf_block_refcnt_put(block, rtnl_held);
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001287
Vlad Buslov470502d2019-02-11 10:55:48 +02001288 if (q) {
1289 if (rtnl_held)
1290 qdisc_put(q);
1291 else
1292 qdisc_put_unlocked(q);
1293 }
Vlad Buslovc431f892018-05-31 09:52:53 +03001294}
1295
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001296struct tcf_block_owner_item {
1297 struct list_head list;
1298 struct Qdisc *q;
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001299 enum flow_block_binder_type binder_type;
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001300};
1301
1302static void
1303tcf_block_owner_netif_keep_dst(struct tcf_block *block,
1304 struct Qdisc *q,
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001305 enum flow_block_binder_type binder_type)
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001306{
1307 if (block->keep_dst &&
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001308 binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
1309 binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001310 netif_keep_dst(qdisc_dev(q));
1311}
1312
1313void tcf_block_netif_keep_dst(struct tcf_block *block)
1314{
1315 struct tcf_block_owner_item *item;
1316
1317 block->keep_dst = true;
1318 list_for_each_entry(item, &block->owner_list, list)
1319 tcf_block_owner_netif_keep_dst(block, item->q,
1320 item->binder_type);
1321}
1322EXPORT_SYMBOL(tcf_block_netif_keep_dst);
1323
1324static int tcf_block_owner_add(struct tcf_block *block,
1325 struct Qdisc *q,
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001326 enum flow_block_binder_type binder_type)
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001327{
1328 struct tcf_block_owner_item *item;
1329
1330 item = kmalloc(sizeof(*item), GFP_KERNEL);
1331 if (!item)
1332 return -ENOMEM;
1333 item->q = q;
1334 item->binder_type = binder_type;
1335 list_add(&item->list, &block->owner_list);
1336 return 0;
1337}
1338
1339static void tcf_block_owner_del(struct tcf_block *block,
1340 struct Qdisc *q,
Pablo Neira Ayuso32f8c402019-07-09 22:55:41 +02001341 enum flow_block_binder_type binder_type)
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001342{
1343 struct tcf_block_owner_item *item;
1344
1345 list_for_each_entry(item, &block->owner_list, list) {
1346 if (item->q == q && item->binder_type == binder_type) {
1347 list_del(&item->list);
1348 kfree(item);
1349 return;
1350 }
1351 }
1352 WARN_ON(1);
1353}
1354
Jiri Pirko48617382018-01-17 11:46:46 +01001355int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
1356 struct tcf_block_ext_info *ei,
1357 struct netlink_ext_ack *extack)
1358{
1359 struct net *net = qdisc_net(q);
1360 struct tcf_block *block = NULL;
Jiri Pirko48617382018-01-17 11:46:46 +01001361 int err;
1362
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001363 if (ei->block_index)
Jiri Pirko48617382018-01-17 11:46:46 +01001364 /* block_index not 0 means the shared block is requested */
Vlad Buslov787ce6d2018-09-24 19:22:58 +03001365 block = tcf_block_refcnt_get(net, ei->block_index);
Jiri Pirko48617382018-01-17 11:46:46 +01001366
1367 if (!block) {
Jiri Pirkobb047dd2018-02-13 12:00:16 +01001368 block = tcf_block_create(net, q, ei->block_index, extack);
Jiri Pirko48617382018-01-17 11:46:46 +01001369 if (IS_ERR(block))
1370 return PTR_ERR(block);
Jiri Pirkobb047dd2018-02-13 12:00:16 +01001371 if (tcf_block_shared(block)) {
1372 err = tcf_block_insert(block, net, extack);
Jiri Pirko48617382018-01-17 11:46:46 +01001373 if (err)
1374 goto err_block_insert;
1375 }
1376 }
1377
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001378 err = tcf_block_owner_add(block, q, ei->binder_type);
1379 if (err)
1380 goto err_block_owner_add;
1381
1382 tcf_block_owner_netif_keep_dst(block, q, ei->binder_type);
1383
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001384 err = tcf_chain0_head_change_cb_add(block, ei, extack);
Jiri Pirkoa9b19442018-01-17 11:46:45 +01001385 if (err)
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001386 goto err_chain0_head_change_cb_add;
Jiri Pirkocaa72602018-01-17 11:46:50 +01001387
John Hurley60513bd2018-06-25 14:30:04 -07001388 err = tcf_block_offload_bind(block, q, ei, extack);
Jiri Pirkocaa72602018-01-17 11:46:50 +01001389 if (err)
1390 goto err_block_offload_bind;
1391
Jiri Pirko6529eab2017-05-17 11:07:55 +02001392 *p_block = block;
1393 return 0;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001394
Jiri Pirkocaa72602018-01-17 11:46:50 +01001395err_block_offload_bind:
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001396 tcf_chain0_head_change_cb_del(block, ei);
1397err_chain0_head_change_cb_add:
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001398 tcf_block_owner_del(block, q, ei->binder_type);
1399err_block_owner_add:
Jiri Pirko48617382018-01-17 11:46:46 +01001400err_block_insert:
Vlad Buslov12db03b2019-02-11 10:55:45 +02001401 tcf_block_refcnt_put(block, true);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001402 return err;
Jiri Pirko6529eab2017-05-17 11:07:55 +02001403}
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001404EXPORT_SYMBOL(tcf_block_get_ext);
1405
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001406static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
1407{
1408 struct tcf_proto __rcu **p_filter_chain = priv;
1409
1410 rcu_assign_pointer(*p_filter_chain, tp_head);
1411}
1412
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001413int tcf_block_get(struct tcf_block **p_block,
Alexander Aring8d1a77f2017-12-20 12:35:19 -05001414 struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
1415 struct netlink_ext_ack *extack)
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001416{
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001417 struct tcf_block_ext_info ei = {
1418 .chain_head_change = tcf_chain_head_change_dflt,
1419 .chain_head_change_priv = p_filter_chain,
1420 };
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001421
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001422 WARN_ON(!p_filter_chain);
Alexander Aring8d1a77f2017-12-20 12:35:19 -05001423 return tcf_block_get_ext(p_block, q, &ei, extack);
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001424}
Jiri Pirko6529eab2017-05-17 11:07:55 +02001425EXPORT_SYMBOL(tcf_block_get);
1426
Cong Wang7aa00452017-10-26 18:24:28 -07001427/* XXX: Standalone actions are not allowed to jump to any chain, and bound
Roman Kapla60b3f52017-11-24 12:27:58 +01001428 * actions should be all removed after flushing.
Cong Wang7aa00452017-10-26 18:24:28 -07001429 */
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001430void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
David S. Millere1ea2f92017-10-30 14:10:01 +09001431 struct tcf_block_ext_info *ei)
Cong Wang7aa00452017-10-26 18:24:28 -07001432{
David S. Millerc30abd52017-12-16 22:11:55 -05001433 if (!block)
1434 return;
Jiri Pirkof71e0ca42018-07-23 09:23:05 +02001435 tcf_chain0_head_change_cb_del(block, ei);
Jiri Pirkof36fe1c2018-01-17 11:46:48 +01001436 tcf_block_owner_del(block, q, ei->binder_type);
Roman Kapla60b3f52017-11-24 12:27:58 +01001437
Vlad Buslov12db03b2019-02-11 10:55:45 +02001438 __tcf_block_put(block, q, ei, true);
Jiri Pirko6529eab2017-05-17 11:07:55 +02001439}
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001440EXPORT_SYMBOL(tcf_block_put_ext);
1441
1442void tcf_block_put(struct tcf_block *block)
1443{
1444 struct tcf_block_ext_info ei = {0, };
1445
Jiri Pirko4853f122017-12-21 13:13:59 +01001446 if (!block)
1447 return;
Jiri Pirkoc7eb7d72017-11-03 11:46:24 +01001448 tcf_block_put_ext(block, block->q, &ei);
Jiri Pirko8c4083b2017-10-19 15:50:29 +02001449}
David S. Millere1ea2f92017-10-30 14:10:01 +09001450
Jiri Pirko6529eab2017-05-17 11:07:55 +02001451EXPORT_SYMBOL(tcf_block_put);
Jiri Pirkocf1facd2017-02-09 14:38:56 +01001452
John Hurley32636742018-06-25 14:30:10 -07001453static int
Pablo Neira Ayusoa7323312019-07-19 18:20:15 +02001454tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb,
John Hurley32636742018-06-25 14:30:10 -07001455 void *cb_priv, bool add, bool offload_in_use,
1456 struct netlink_ext_ack *extack)
1457{
Vlad Buslovbbf73832019-02-11 10:55:36 +02001458 struct tcf_chain *chain, *chain_prev;
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001459 struct tcf_proto *tp, *tp_prev;
John Hurley32636742018-06-25 14:30:10 -07001460 int err;
1461
Vlad Buslov4f8116c2019-08-26 16:44:57 +03001462 lockdep_assert_held(&block->cb_lock);
1463
Vlad Buslovbbf73832019-02-11 10:55:36 +02001464 for (chain = __tcf_get_next_chain(block, NULL);
1465 chain;
1466 chain_prev = chain,
1467 chain = __tcf_get_next_chain(block, chain),
1468 tcf_chain_put(chain_prev)) {
Vlad Buslovfe2923a2019-02-11 10:55:40 +02001469 for (tp = __tcf_get_next_proto(chain, NULL); tp;
1470 tp_prev = tp,
1471 tp = __tcf_get_next_proto(chain, tp),
Vlad Buslov12db03b2019-02-11 10:55:45 +02001472 tcf_proto_put(tp_prev, true, NULL)) {
John Hurley32636742018-06-25 14:30:10 -07001473 if (tp->ops->reoffload) {
1474 err = tp->ops->reoffload(tp, add, cb, cb_priv,
1475 extack);
1476 if (err && add)
1477 goto err_playback_remove;
1478 } else if (add && offload_in_use) {
1479 err = -EOPNOTSUPP;
1480 NL_SET_ERR_MSG(extack, "Filter HW offload failed - classifier without re-offloading support");
1481 goto err_playback_remove;
1482 }
1483 }
1484 }
1485
1486 return 0;
1487
1488err_playback_remove:
Vlad Buslov12db03b2019-02-11 10:55:45 +02001489 tcf_proto_put(tp, true, NULL);
Vlad Buslovbbf73832019-02-11 10:55:36 +02001490 tcf_chain_put(chain);
John Hurley32636742018-06-25 14:30:10 -07001491 tcf_block_playback_offloads(block, cb, cb_priv, false, offload_in_use,
1492 extack);
1493 return err;
1494}
1495
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001496static int tcf_block_bind(struct tcf_block *block,
1497 struct flow_block_offload *bo)
1498{
1499 struct flow_block_cb *block_cb, *next;
1500 int err, i = 0;
1501
Vlad Buslov4f8116c2019-08-26 16:44:57 +03001502 lockdep_assert_held(&block->cb_lock);
1503
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001504 list_for_each_entry(block_cb, &bo->cb_list, list) {
1505 err = tcf_block_playback_offloads(block, block_cb->cb,
1506 block_cb->cb_priv, true,
1507 tcf_block_offload_in_use(block),
1508 bo->extack);
1509 if (err)
1510 goto err_unroll;
Vlad Buslovc9f14472019-08-26 16:45:01 +03001511 if (!bo->unlocked_driver_cb)
1512 block->lockeddevcnt++;
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001513
1514 i++;
1515 }
Pablo Neira Ayuso14bfb132019-07-19 18:20:16 +02001516 list_splice(&bo->cb_list, &block->flow_block.cb_list);
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001517
1518 return 0;
1519
1520err_unroll:
1521 list_for_each_entry_safe(block_cb, next, &bo->cb_list, list) {
1522 if (i-- > 0) {
1523 list_del(&block_cb->list);
1524 tcf_block_playback_offloads(block, block_cb->cb,
1525 block_cb->cb_priv, false,
1526 tcf_block_offload_in_use(block),
1527 NULL);
Vlad Buslovc9f14472019-08-26 16:45:01 +03001528 if (!bo->unlocked_driver_cb)
1529 block->lockeddevcnt--;
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001530 }
1531 flow_block_cb_free(block_cb);
1532 }
1533
1534 return err;
1535}
1536
1537static void tcf_block_unbind(struct tcf_block *block,
1538 struct flow_block_offload *bo)
1539{
1540 struct flow_block_cb *block_cb, *next;
1541
Vlad Buslov4f8116c2019-08-26 16:44:57 +03001542 lockdep_assert_held(&block->cb_lock);
1543
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001544 list_for_each_entry_safe(block_cb, next, &bo->cb_list, list) {
1545 tcf_block_playback_offloads(block, block_cb->cb,
1546 block_cb->cb_priv, false,
1547 tcf_block_offload_in_use(block),
1548 NULL);
1549 list_del(&block_cb->list);
1550 flow_block_cb_free(block_cb);
Vlad Buslovc9f14472019-08-26 16:45:01 +03001551 if (!bo->unlocked_driver_cb)
1552 block->lockeddevcnt--;
Pablo Neira Ayuso59094b12019-07-09 22:55:45 +02001553 }
1554}
1555
1556static int tcf_block_setup(struct tcf_block *block,
1557 struct flow_block_offload *bo)
1558{
1559 int err;
1560
1561 switch (bo->command) {
1562 case FLOW_BLOCK_BIND:
1563 err = tcf_block_bind(block, bo);
1564 break;
1565 case FLOW_BLOCK_UNBIND:
1566 err = 0;
1567 tcf_block_unbind(block, bo);
1568 break;
1569 default:
1570 WARN_ON_ONCE(1);
1571 err = -EOPNOTSUPP;
1572 }
1573
1574 return err;
1575}
1576
Jiri Pirko87d83092017-05-17 11:07:54 +02001577/* Main classifier routine: scans classifier chain attached
1578 * to this qdisc, (optionally) tests for protocol and asks
1579 * specific classifiers.
1580 */
Paul Blakey9410c942020-02-16 12:01:21 +02001581static inline int __tcf_classify(struct sk_buff *skb,
1582 const struct tcf_proto *tp,
Paul Blakeyaf699622020-02-16 12:01:24 +02001583 const struct tcf_proto *orig_tp,
Paul Blakey9410c942020-02-16 12:01:21 +02001584 struct tcf_result *res,
1585 bool compat_mode,
1586 u32 *last_executed_chain)
Jiri Pirko87d83092017-05-17 11:07:54 +02001587{
Jiri Pirko87d83092017-05-17 11:07:54 +02001588#ifdef CONFIG_NET_CLS_ACT
1589 const int max_reclassify_loop = 4;
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001590 const struct tcf_proto *first_tp;
Jiri Pirko87d83092017-05-17 11:07:54 +02001591 int limit = 0;
1592
1593reclassify:
1594#endif
1595 for (; tp; tp = rcu_dereference_bh(tp->next)) {
Cong Wangcd0c4e72019-01-11 18:55:42 -08001596 __be16 protocol = tc_skb_protocol(skb);
Jiri Pirko87d83092017-05-17 11:07:54 +02001597 int err;
1598
1599 if (tp->protocol != protocol &&
1600 tp->protocol != htons(ETH_P_ALL))
1601 continue;
1602
1603 err = tp->classify(skb, tp, res);
1604#ifdef CONFIG_NET_CLS_ACT
Jiri Pirkodb505142017-05-17 11:08:03 +02001605 if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001606 first_tp = orig_tp;
Paul Blakey9410c942020-02-16 12:01:21 +02001607 *last_executed_chain = first_tp->chain->index;
Jiri Pirko87d83092017-05-17 11:07:54 +02001608 goto reset;
Jiri Pirkodb505142017-05-17 11:08:03 +02001609 } else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001610 first_tp = res->goto_tp;
Paul Blakey9410c942020-02-16 12:01:21 +02001611 *last_executed_chain = err & TC_ACT_EXT_VAL_MASK;
Jiri Pirkodb505142017-05-17 11:08:03 +02001612 goto reset;
1613 }
Jiri Pirko87d83092017-05-17 11:07:54 +02001614#endif
1615 if (err >= 0)
1616 return err;
1617 }
1618
1619 return TC_ACT_UNSPEC; /* signal: continue lookup */
1620#ifdef CONFIG_NET_CLS_ACT
1621reset:
1622 if (unlikely(limit++ >= max_reclassify_loop)) {
Jiri Pirko9d3aaff2018-01-17 11:46:47 +01001623 net_notice_ratelimited("%u: reclassify loop, rule prio %u, protocol %02x\n",
1624 tp->chain->block->index,
1625 tp->prio & 0xffff,
Jiri Pirko87d83092017-05-17 11:07:54 +02001626 ntohs(tp->protocol));
1627 return TC_ACT_SHOT;
1628 }
1629
Jiri Pirkoee538dc2017-05-23 09:11:59 +02001630 tp = first_tp;
Jiri Pirko87d83092017-05-17 11:07:54 +02001631 goto reclassify;
1632#endif
1633}
Paul Blakey9410c942020-02-16 12:01:21 +02001634
1635int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1636 struct tcf_result *res, bool compat_mode)
1637{
1638 u32 last_executed_chain = 0;
1639
Paul Blakeyaf699622020-02-16 12:01:24 +02001640 return __tcf_classify(skb, tp, tp, res, compat_mode,
Paul Blakey9410c942020-02-16 12:01:21 +02001641 &last_executed_chain);
1642}
Jiri Pirko87d83092017-05-17 11:07:54 +02001643EXPORT_SYMBOL(tcf_classify);
1644
Paul Blakey7d17c542020-02-16 12:01:22 +02001645int tcf_classify_ingress(struct sk_buff *skb,
1646 const struct tcf_block *ingress_block,
1647 const struct tcf_proto *tp,
Paul Blakey9410c942020-02-16 12:01:21 +02001648 struct tcf_result *res, bool compat_mode)
1649{
1650#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
1651 u32 last_executed_chain = 0;
1652
Paul Blakeyaf699622020-02-16 12:01:24 +02001653 return __tcf_classify(skb, tp, tp, res, compat_mode,
Paul Blakey9410c942020-02-16 12:01:21 +02001654 &last_executed_chain);
1655#else
1656 u32 last_executed_chain = tp ? tp->chain->index : 0;
Paul Blakeyaf699622020-02-16 12:01:24 +02001657 const struct tcf_proto *orig_tp = tp;
Paul Blakey9410c942020-02-16 12:01:21 +02001658 struct tc_skb_ext *ext;
1659 int ret;
1660
Paul Blakeyaf699622020-02-16 12:01:24 +02001661 ext = skb_ext_find(skb, TC_SKB_EXT);
1662
1663 if (ext && ext->chain) {
1664 struct tcf_chain *fchain;
1665
1666 fchain = tcf_chain_lookup_rcu(ingress_block, ext->chain);
1667 if (!fchain)
1668 return TC_ACT_SHOT;
1669
1670 /* Consume, so cloned/redirect skbs won't inherit ext */
1671 skb_ext_del(skb, TC_SKB_EXT);
1672
1673 tp = rcu_dereference_bh(fchain->filter_chain);
Paul Blakeya080da62020-04-06 18:36:56 +03001674 last_executed_chain = fchain->index;
Paul Blakeyaf699622020-02-16 12:01:24 +02001675 }
1676
1677 ret = __tcf_classify(skb, tp, orig_tp, res, compat_mode,
1678 &last_executed_chain);
Paul Blakey9410c942020-02-16 12:01:21 +02001679
1680 /* If we missed on some chain */
1681 if (ret == TC_ACT_UNSPEC && last_executed_chain) {
1682 ext = skb_ext_add(skb, TC_SKB_EXT);
1683 if (WARN_ON_ONCE(!ext))
1684 return TC_ACT_SHOT;
1685 ext->chain = last_executed_chain;
1686 }
1687
1688 return ret;
1689#endif
1690}
1691EXPORT_SYMBOL(tcf_classify_ingress);
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
John Hurley59eb87c2019-11-02 14:17:47 +00001753 if (tcf_proto_exists_destroying(chain, tp_new)) {
1754 mutex_unlock(&chain->filter_chain_lock);
1755 tcf_proto_destroy(tp_new, rtnl_held, false, NULL);
1756 return ERR_PTR(-EAGAIN);
1757 }
1758
Vlad Buslov8b646782019-02-11 10:55:41 +02001759 tp = tcf_chain_tp_find(chain, &chain_info,
1760 protocol, prio, false);
1761 if (!tp)
Vlad Buslov726d06122019-02-11 10:55:42 +02001762 err = tcf_chain_tp_insert(chain, &chain_info, tp_new);
Vlad Buslov8b646782019-02-11 10:55:41 +02001763 mutex_unlock(&chain->filter_chain_lock);
1764
1765 if (tp) {
John Hurley59eb87c2019-11-02 14:17:47 +00001766 tcf_proto_destroy(tp_new, rtnl_held, false, NULL);
Vlad Buslov8b646782019-02-11 10:55:41 +02001767 tp_new = tp;
Vlad Buslov726d06122019-02-11 10:55:42 +02001768 } else if (err) {
John Hurley59eb87c2019-11-02 14:17:47 +00001769 tcf_proto_destroy(tp_new, rtnl_held, false, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +02001770 tp_new = ERR_PTR(err);
Vlad Buslov8b646782019-02-11 10:55:41 +02001771 }
1772
1773 return tp_new;
1774}
1775
1776static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001777 struct tcf_proto *tp, bool rtnl_held,
Vlad Buslov8b646782019-02-11 10:55:41 +02001778 struct netlink_ext_ack *extack)
1779{
1780 struct tcf_chain_info chain_info;
1781 struct tcf_proto *tp_iter;
1782 struct tcf_proto **pprev;
1783 struct tcf_proto *next;
1784
1785 mutex_lock(&chain->filter_chain_lock);
1786
1787 /* Atomically find and remove tp from chain. */
1788 for (pprev = &chain->filter_chain;
1789 (tp_iter = tcf_chain_dereference(*pprev, chain));
1790 pprev = &tp_iter->next) {
1791 if (tp_iter == tp) {
1792 chain_info.pprev = pprev;
1793 chain_info.next = tp_iter->next;
1794 WARN_ON(tp_iter->deleting);
1795 break;
1796 }
1797 }
1798 /* Verify that tp still exists and no new filters were inserted
1799 * concurrently.
1800 * Mark tp for deletion if it is empty.
1801 */
Davide Carattia5b72a02019-12-28 16:36:58 +01001802 if (!tp_iter || !tcf_proto_check_delete(tp)) {
Vlad Buslov8b646782019-02-11 10:55:41 +02001803 mutex_unlock(&chain->filter_chain_lock);
1804 return;
1805 }
1806
John Hurley59eb87c2019-11-02 14:17:47 +00001807 tcf_proto_signal_destroying(chain, tp);
Vlad Buslov8b646782019-02-11 10:55:41 +02001808 next = tcf_chain_dereference(chain_info.next, chain);
1809 if (tp == chain->filter_chain)
1810 tcf_chain0_head_change(chain, next);
1811 RCU_INIT_POINTER(*chain_info.pprev, next);
1812 mutex_unlock(&chain->filter_chain_lock);
1813
Vlad Buslov12db03b2019-02-11 10:55:45 +02001814 tcf_proto_put(tp, rtnl_held, extack);
Vlad Buslov8b646782019-02-11 10:55:41 +02001815}
1816
1817static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
1818 struct tcf_chain_info *chain_info,
1819 u32 protocol, u32 prio,
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001820 bool prio_allocate)
1821{
1822 struct tcf_proto **pprev;
1823 struct tcf_proto *tp;
1824
1825 /* Check the chain for existence of proto-tcf with this priority */
1826 for (pprev = &chain->filter_chain;
Vlad Busloved76f5e2019-02-11 10:55:38 +02001827 (tp = tcf_chain_dereference(*pprev, chain));
1828 pprev = &tp->next) {
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001829 if (tp->prio >= prio) {
1830 if (tp->prio == prio) {
1831 if (prio_allocate ||
1832 (tp->protocol != protocol && protocol))
1833 return ERR_PTR(-EINVAL);
1834 } else {
1835 tp = NULL;
1836 }
1837 break;
1838 }
1839 }
1840 chain_info->pprev = pprev;
Vlad Buslov4dbfa762019-02-11 10:55:39 +02001841 if (tp) {
1842 chain_info->next = tp->next;
1843 tcf_proto_get(tp);
1844 } else {
1845 chain_info->next = NULL;
1846 }
Jiri Pirko2190d1d2017-05-17 11:07:59 +02001847 return tp;
1848}
1849
WANG Cong71203712017-08-07 15:26:50 -07001850static int tcf_fill_node(struct net *net, struct sk_buff *skb,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001851 struct tcf_proto *tp, struct tcf_block *block,
1852 struct Qdisc *q, u32 parent, void *fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001853 u32 portid, u32 seq, u16 flags, int event,
1854 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001855{
1856 struct tcmsg *tcm;
1857 struct nlmsghdr *nlh;
1858 unsigned char *b = skb_tail_pointer(skb);
1859
1860 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
1861 if (!nlh)
1862 goto out_nlmsg_trim;
1863 tcm = nlmsg_data(nlh);
1864 tcm->tcm_family = AF_UNSPEC;
1865 tcm->tcm__pad1 = 0;
1866 tcm->tcm__pad2 = 0;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001867 if (q) {
1868 tcm->tcm_ifindex = qdisc_dev(q)->ifindex;
1869 tcm->tcm_parent = parent;
1870 } else {
1871 tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
1872 tcm->tcm_block_index = block->index;
1873 }
WANG Cong71203712017-08-07 15:26:50 -07001874 tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
1875 if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
1876 goto nla_put_failure;
1877 if (nla_put_u32(skb, TCA_CHAIN, tp->chain->index))
1878 goto nla_put_failure;
1879 if (!fh) {
1880 tcm->tcm_handle = 0;
1881 } else {
Vlad Buslov12db03b2019-02-11 10:55:45 +02001882 if (tp->ops->dump &&
1883 tp->ops->dump(net, tp, fh, skb, tcm, rtnl_held) < 0)
WANG Cong71203712017-08-07 15:26:50 -07001884 goto nla_put_failure;
1885 }
1886 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1887 return skb->len;
1888
1889out_nlmsg_trim:
1890nla_put_failure:
1891 nlmsg_trim(skb, b);
1892 return -1;
1893}
1894
1895static int tfilter_notify(struct net *net, struct sk_buff *oskb,
1896 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001897 struct tcf_block *block, struct Qdisc *q,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001898 u32 parent, void *fh, int event, bool unicast,
1899 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001900{
1901 struct sk_buff *skb;
1902 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001903 int err = 0;
WANG Cong71203712017-08-07 15:26:50 -07001904
1905 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1906 if (!skb)
1907 return -ENOBUFS;
1908
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001909 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001910 n->nlmsg_seq, n->nlmsg_flags, event,
1911 rtnl_held) <= 0) {
WANG Cong71203712017-08-07 15:26:50 -07001912 kfree_skb(skb);
1913 return -EINVAL;
1914 }
1915
1916 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001917 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1918 else
1919 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1920 n->nlmsg_flags & NLM_F_ECHO);
WANG Cong71203712017-08-07 15:26:50 -07001921
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001922 if (err > 0)
1923 err = 0;
1924 return err;
WANG Cong71203712017-08-07 15:26:50 -07001925}
1926
1927static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
1928 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001929 struct tcf_block *block, struct Qdisc *q,
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001930 u32 parent, void *fh, bool unicast, bool *last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001931 bool rtnl_held, struct netlink_ext_ack *extack)
WANG Cong71203712017-08-07 15:26:50 -07001932{
1933 struct sk_buff *skb;
1934 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
1935 int err;
1936
1937 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1938 if (!skb)
1939 return -ENOBUFS;
1940
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001941 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001942 n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER,
1943 rtnl_held) <= 0) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001944 NL_SET_ERR_MSG(extack, "Failed to build del event notification");
WANG Cong71203712017-08-07 15:26:50 -07001945 kfree_skb(skb);
1946 return -EINVAL;
1947 }
1948
Vlad Buslov12db03b2019-02-11 10:55:45 +02001949 err = tp->ops->delete(tp, fh, last, rtnl_held, extack);
WANG Cong71203712017-08-07 15:26:50 -07001950 if (err) {
1951 kfree_skb(skb);
1952 return err;
1953 }
1954
1955 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001956 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1957 else
1958 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1959 n->nlmsg_flags & NLM_F_ECHO);
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001960 if (err < 0)
1961 NL_SET_ERR_MSG(extack, "Failed to send filter delete notification");
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001962
1963 if (err > 0)
1964 err = 0;
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001965 return err;
WANG Cong71203712017-08-07 15:26:50 -07001966}
1967
1968static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001969 struct tcf_block *block, struct Qdisc *q,
1970 u32 parent, struct nlmsghdr *n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001971 struct tcf_chain *chain, int event,
1972 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001973{
1974 struct tcf_proto *tp;
1975
Vlad Buslov12db03b2019-02-11 10:55:45 +02001976 for (tp = tcf_get_next_proto(chain, NULL, rtnl_held);
1977 tp; tp = tcf_get_next_proto(chain, tp, rtnl_held))
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001978 tfilter_notify(net, oskb, n, tp, block,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001979 q, parent, NULL, event, false, rtnl_held);
WANG Cong71203712017-08-07 15:26:50 -07001980}
1981
Vlad Buslov7d5509f2019-02-11 10:55:44 +02001982static void tfilter_put(struct tcf_proto *tp, void *fh)
1983{
1984 if (tp->ops->put && fh)
1985 tp->ops->put(tp, fh);
1986}
1987
Vlad Buslovc431f892018-05-31 09:52:53 +03001988static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
David Ahernc21ef3e2017-04-16 09:48:24 -07001989 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001991 struct net *net = sock_net(skb->sk);
Patrick McHardyadd93b62008-01-22 22:11:33 -08001992 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07001993 char name[IFNAMSIZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 struct tcmsg *t;
1995 u32 protocol;
1996 u32 prio;
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02001997 bool prio_allocate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02001999 u32 chain_index;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002000 struct Qdisc *q = NULL;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002001 struct tcf_chain_info chain_info;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002002 struct tcf_chain *chain = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02002003 struct tcf_block *block;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 struct tcf_proto *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 unsigned long cl;
WANG Cong8113c092017-08-04 21:31:43 -07002006 void *fh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 int err;
Daniel Borkmann628185c2016-12-21 18:04:11 +01002008 int tp_created;
Vlad Buslov470502d2019-02-11 10:55:48 +02002009 bool rtnl_held = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Vlad Buslovc431f892018-05-31 09:52:53 +03002011 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
Eric W. Biedermandfc47ef2012-11-16 03:03:00 +00002012 return -EPERM;
Hong zhi guode179c82013-03-25 17:36:33 +00002013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014replay:
Daniel Borkmann628185c2016-12-21 18:04:11 +01002015 tp_created = 0;
2016
Johannes Berg8cb08172019-04-26 14:07:28 +02002017 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2018 rtm_tca_policy, extack);
Hong zhi guode179c82013-03-25 17:36:33 +00002019 if (err < 0)
2020 return err;
2021
David S. Miller942b8162012-06-26 21:48:50 -07002022 t = nlmsg_data(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 protocol = TC_H_MIN(t->tcm_info);
2024 prio = TC_H_MAJ(t->tcm_info);
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002025 prio_allocate = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 parent = t->tcm_parent;
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002027 tp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 cl = 0;
Vlad Buslov470502d2019-02-11 10:55:48 +02002029 block = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 if (prio == 0) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002032 /* If no priority is provided by the user,
2033 * we allocate one.
2034 */
2035 if (n->nlmsg_flags & NLM_F_CREATE) {
2036 prio = TC_H_MAKE(0x80000000U, 0U);
2037 prio_allocate = true;
2038 } else {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002039 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 return -ENOENT;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043
2044 /* Find head of filter chain. */
2045
Vlad Buslov470502d2019-02-11 10:55:48 +02002046 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2047 if (err)
2048 return err;
2049
Cong Wang6f96c3c2019-10-07 13:26:28 -07002050 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2051 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2052 err = -EINVAL;
2053 goto errout;
2054 }
2055
Vlad Buslov470502d2019-02-11 10:55:48 +02002056 /* Take rtnl mutex if rtnl_held was set to true on previous iteration,
2057 * block is shared (no qdisc found), qdisc is not unlocked, classifier
2058 * type is not specified, classifier is not unlocked.
2059 */
2060 if (rtnl_held ||
2061 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002062 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002063 rtnl_held = true;
2064 rtnl_lock();
2065 }
2066
2067 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2068 if (err)
2069 goto errout;
2070
2071 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2072 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002073 if (IS_ERR(block)) {
2074 err = PTR_ERR(block);
2075 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002076 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002077
2078 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2079 if (chain_index > TC_ACT_EXT_VAL_MASK) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002080 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Jiri Pirko5bc17012017-05-17 11:08:01 +02002081 err = -EINVAL;
2082 goto errout;
2083 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002084 chain = tcf_chain_get(block, chain_index, true);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002085 if (!chain) {
Jiri Pirkod5ed72a2018-08-27 20:58:43 +02002086 NL_SET_ERR_MSG(extack, "Cannot create specified filter chain");
Vlad Buslovc431f892018-05-31 09:52:53 +03002087 err = -ENOMEM;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002088 goto errout;
2089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Vlad Busloved76f5e2019-02-11 10:55:38 +02002091 mutex_lock(&chain->filter_chain_lock);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002092 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2093 prio, prio_allocate);
2094 if (IS_ERR(tp)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002095 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002096 err = PTR_ERR(tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002097 goto errout_locked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 }
2099
2100 if (tp == NULL) {
Vlad Buslov8b646782019-02-11 10:55:41 +02002101 struct tcf_proto *tp_new = NULL;
2102
Vlad Buslov726d06122019-02-11 10:55:42 +02002103 if (chain->flushing) {
2104 err = -EAGAIN;
2105 goto errout_locked;
2106 }
2107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 /* Proto-tcf does not exist, create new one */
2109
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002110 if (tca[TCA_KIND] == NULL || !protocol) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002111 NL_SET_ERR_MSG(extack, "Filter kind and protocol must be specified");
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002112 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002113 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Vlad Buslovc431f892018-05-31 09:52:53 +03002116 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002117 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 +01002118 err = -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002119 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002122 if (prio_allocate)
Vlad Busloved76f5e2019-02-11 10:55:38 +02002123 prio = tcf_auto_prio(tcf_chain_tp_prev(chain,
2124 &chain_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Vlad Busloved76f5e2019-02-11 10:55:38 +02002126 mutex_unlock(&chain->filter_chain_lock);
Eric Dumazet36d79af2020-01-21 11:02:20 -08002127 tp_new = tcf_proto_create(name, protocol, prio, chain,
2128 rtnl_held, extack);
Vlad Buslov8b646782019-02-11 10:55:41 +02002129 if (IS_ERR(tp_new)) {
2130 err = PTR_ERR(tp_new);
Vlad Buslov726d06122019-02-11 10:55:42 +02002131 goto errout_tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002133
Minoru Usui12186be2009-06-02 02:17:34 -07002134 tp_created = 1;
Vlad Buslov12db03b2019-02-11 10:55:45 +02002135 tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio,
2136 rtnl_held);
Vlad Buslov726d06122019-02-11 10:55:42 +02002137 if (IS_ERR(tp)) {
2138 err = PTR_ERR(tp);
2139 goto errout_tp;
2140 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002141 } else {
2142 mutex_unlock(&chain->filter_chain_lock);
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Vlad Buslov8b646782019-02-11 10:55:41 +02002145 if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2146 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2147 err = -EINVAL;
2148 goto errout;
2149 }
2150
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 fh = tp->ops->get(tp, t->tcm_handle);
2152
WANG Cong8113c092017-08-04 21:31:43 -07002153 if (!fh) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002154 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002155 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 +01002156 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002158 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002159 } else if (n->nlmsg_flags & NLM_F_EXCL) {
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002160 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002161 NL_SET_ERR_MSG(extack, "Filter already exists");
2162 err = -EEXIST;
2163 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 }
2165
Jiri Pirko9f407f12018-07-23 09:23:07 +02002166 if (chain->tmplt_ops && chain->tmplt_ops != tp->ops) {
2167 NL_SET_ERR_MSG(extack, "Chain template is set to a different filter kind");
2168 err = -EINVAL;
2169 goto errout;
2170 }
2171
Cong Wang2f7ef2f2014-04-25 13:54:06 -07002172 err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
Alexander Aring7306db32018-01-18 11:20:51 -05002173 n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002174 rtnl_held, extack);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002175 if (err == 0) {
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002176 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002177 RTM_NEWTFILTER, false, rtnl_held);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002178 tfilter_put(tp, fh);
Vlad Buslov503d81d2019-07-21 17:44:12 +03002179 /* q pointer is NULL for shared blocks */
2180 if (q)
2181 q->flags &= ~TCQ_F_CAN_BYPASS;
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
2184errout:
Vlad Buslov8b646782019-02-11 10:55:41 +02002185 if (err && tp_created)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002186 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +02002187errout_tp:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002188 if (chain) {
2189 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002190 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002191 if (!tp_created)
2192 tcf_chain_put(chain);
2193 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002194 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002195
2196 if (rtnl_held)
2197 rtnl_unlock();
2198
2199 if (err == -EAGAIN) {
2200 /* Take rtnl lock in case EAGAIN is caused by concurrent flush
2201 * of target chain.
2202 */
2203 rtnl_held = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 /* Replay the request. */
2205 goto replay;
Vlad Buslov470502d2019-02-11 10:55:48 +02002206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002208
2209errout_locked:
2210 mutex_unlock(&chain->filter_chain_lock);
2211 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212}
2213
Vlad Buslovc431f892018-05-31 09:52:53 +03002214static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2215 struct netlink_ext_ack *extack)
2216{
2217 struct net *net = sock_net(skb->sk);
2218 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07002219 char name[IFNAMSIZ];
Vlad Buslovc431f892018-05-31 09:52:53 +03002220 struct tcmsg *t;
2221 u32 protocol;
2222 u32 prio;
2223 u32 parent;
2224 u32 chain_index;
2225 struct Qdisc *q = NULL;
2226 struct tcf_chain_info chain_info;
2227 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002228 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002229 struct tcf_proto *tp = NULL;
2230 unsigned long cl = 0;
2231 void *fh = NULL;
2232 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002233 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002234
2235 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2236 return -EPERM;
2237
Johannes Berg8cb08172019-04-26 14:07:28 +02002238 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2239 rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002240 if (err < 0)
2241 return err;
2242
2243 t = nlmsg_data(n);
2244 protocol = TC_H_MIN(t->tcm_info);
2245 prio = TC_H_MAJ(t->tcm_info);
2246 parent = t->tcm_parent;
2247
2248 if (prio == 0 && (protocol || t->tcm_handle || tca[TCA_KIND])) {
2249 NL_SET_ERR_MSG(extack, "Cannot flush filters with protocol, handle or kind set");
2250 return -ENOENT;
2251 }
2252
2253 /* Find head of filter chain. */
2254
Vlad Buslov470502d2019-02-11 10:55:48 +02002255 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2256 if (err)
2257 return err;
2258
Cong Wang6f96c3c2019-10-07 13:26:28 -07002259 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2260 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2261 err = -EINVAL;
2262 goto errout;
2263 }
Vlad Buslov470502d2019-02-11 10:55:48 +02002264 /* Take rtnl mutex if flushing whole chain, block is shared (no qdisc
2265 * found), qdisc is not unlocked, classifier type is not specified,
2266 * classifier is not unlocked.
2267 */
2268 if (!prio ||
2269 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002270 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002271 rtnl_held = true;
2272 rtnl_lock();
2273 }
2274
2275 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2276 if (err)
2277 goto errout;
2278
2279 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2280 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002281 if (IS_ERR(block)) {
2282 err = PTR_ERR(block);
2283 goto errout;
2284 }
2285
2286 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2287 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2288 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2289 err = -EINVAL;
2290 goto errout;
2291 }
2292 chain = tcf_chain_get(block, chain_index, false);
2293 if (!chain) {
Jiri Pirko5ca8a252018-08-03 11:08:47 +02002294 /* User requested flush on non-existent chain. Nothing to do,
2295 * so just return success.
2296 */
2297 if (prio == 0) {
2298 err = 0;
2299 goto errout;
2300 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002301 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Jiri Pirkob7b42472018-08-27 20:58:44 +02002302 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002303 goto errout;
2304 }
2305
2306 if (prio == 0) {
2307 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002308 chain, RTM_DELTFILTER, rtnl_held);
2309 tcf_chain_flush(chain, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002310 err = 0;
2311 goto errout;
2312 }
2313
Vlad Busloved76f5e2019-02-11 10:55:38 +02002314 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002315 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2316 prio, false);
2317 if (!tp || IS_ERR(tp)) {
2318 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002319 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002320 goto errout_locked;
Vlad Buslovc431f892018-05-31 09:52:53 +03002321 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2322 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2323 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002324 goto errout_locked;
2325 } else if (t->tcm_handle == 0) {
John Hurley59eb87c2019-11-02 14:17:47 +00002326 tcf_proto_signal_destroying(chain, tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002327 tcf_chain_tp_remove(chain, &chain_info, tp);
2328 mutex_unlock(&chain->filter_chain_lock);
2329
Vlad Buslov12db03b2019-02-11 10:55:45 +02002330 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002331 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002332 RTM_DELTFILTER, false, rtnl_held);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002333 err = 0;
Vlad Buslovc431f892018-05-31 09:52:53 +03002334 goto errout;
2335 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002336 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002337
2338 fh = tp->ops->get(tp, t->tcm_handle);
2339
2340 if (!fh) {
Vlad Busloved76f5e2019-02-11 10:55:38 +02002341 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2342 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002343 } else {
2344 bool last;
2345
2346 err = tfilter_del_notify(net, skb, n, tp, block,
2347 q, parent, fh, false, &last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002348 rtnl_held, extack);
2349
Vlad Buslovc431f892018-05-31 09:52:53 +03002350 if (err)
2351 goto errout;
Vlad Buslov8b646782019-02-11 10:55:41 +02002352 if (last)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002353 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002354 }
2355
2356errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002357 if (chain) {
2358 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002359 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002360 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002361 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002362 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002363
2364 if (rtnl_held)
2365 rtnl_unlock();
2366
Vlad Buslovc431f892018-05-31 09:52:53 +03002367 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002368
2369errout_locked:
2370 mutex_unlock(&chain->filter_chain_lock);
2371 goto errout;
Vlad Buslovc431f892018-05-31 09:52:53 +03002372}
2373
2374static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2375 struct netlink_ext_ack *extack)
2376{
2377 struct net *net = sock_net(skb->sk);
2378 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07002379 char name[IFNAMSIZ];
Vlad Buslovc431f892018-05-31 09:52:53 +03002380 struct tcmsg *t;
2381 u32 protocol;
2382 u32 prio;
2383 u32 parent;
2384 u32 chain_index;
2385 struct Qdisc *q = NULL;
2386 struct tcf_chain_info chain_info;
2387 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002388 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002389 struct tcf_proto *tp = NULL;
2390 unsigned long cl = 0;
2391 void *fh = NULL;
2392 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002393 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002394
Johannes Berg8cb08172019-04-26 14:07:28 +02002395 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2396 rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002397 if (err < 0)
2398 return err;
2399
2400 t = nlmsg_data(n);
2401 protocol = TC_H_MIN(t->tcm_info);
2402 prio = TC_H_MAJ(t->tcm_info);
2403 parent = t->tcm_parent;
2404
2405 if (prio == 0) {
2406 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
2407 return -ENOENT;
2408 }
2409
2410 /* Find head of filter chain. */
2411
Vlad Buslov470502d2019-02-11 10:55:48 +02002412 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2413 if (err)
2414 return err;
2415
Cong Wang6f96c3c2019-10-07 13:26:28 -07002416 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2417 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2418 err = -EINVAL;
2419 goto errout;
2420 }
Vlad Buslov470502d2019-02-11 10:55:48 +02002421 /* Take rtnl mutex if block is shared (no qdisc found), qdisc is not
2422 * unlocked, classifier type is not specified, classifier is not
2423 * unlocked.
2424 */
2425 if ((q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002426 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002427 rtnl_held = true;
2428 rtnl_lock();
2429 }
2430
2431 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2432 if (err)
2433 goto errout;
2434
2435 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2436 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002437 if (IS_ERR(block)) {
2438 err = PTR_ERR(block);
2439 goto errout;
2440 }
2441
2442 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2443 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2444 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2445 err = -EINVAL;
2446 goto errout;
2447 }
2448 chain = tcf_chain_get(block, chain_index, false);
2449 if (!chain) {
2450 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
2451 err = -EINVAL;
2452 goto errout;
2453 }
2454
Vlad Busloved76f5e2019-02-11 10:55:38 +02002455 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002456 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2457 prio, false);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002458 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002459 if (!tp || IS_ERR(tp)) {
2460 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002461 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002462 goto errout;
2463 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2464 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2465 err = -EINVAL;
2466 goto errout;
2467 }
2468
2469 fh = tp->ops->get(tp, t->tcm_handle);
2470
2471 if (!fh) {
2472 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2473 err = -ENOENT;
2474 } else {
2475 err = tfilter_notify(net, skb, n, tp, block, q, parent,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002476 fh, RTM_NEWTFILTER, true, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002477 if (err < 0)
2478 NL_SET_ERR_MSG(extack, "Failed to send filter notify message");
2479 }
2480
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002481 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002482errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002483 if (chain) {
2484 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002485 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002486 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002487 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002488 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002489
2490 if (rtnl_held)
2491 rtnl_unlock();
2492
Vlad Buslovc431f892018-05-31 09:52:53 +03002493 return err;
2494}
2495
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002496struct tcf_dump_args {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 struct tcf_walker w;
2498 struct sk_buff *skb;
2499 struct netlink_callback *cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002500 struct tcf_block *block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002501 struct Qdisc *q;
2502 u32 parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503};
2504
WANG Cong8113c092017-08-04 21:31:43 -07002505static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002507 struct tcf_dump_args *a = (void *)arg;
WANG Cong832d1d52014-01-09 16:14:01 -08002508 struct net *net = sock_net(a->skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002510 return tcf_fill_node(net, a->skb, tp, a->block, a->q, a->parent,
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002511 n, NETLINK_CB(a->cb->skb).portid,
Jamal Hadi Salim5a7a5552016-09-18 08:45:33 -04002512 a->cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002513 RTM_NEWTFILTER, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514}
2515
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002516static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
2517 struct sk_buff *skb, struct netlink_callback *cb,
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002518 long index_start, long *p_index)
2519{
2520 struct net *net = sock_net(skb->sk);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002521 struct tcf_block *block = chain->block;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002522 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002523 struct tcf_proto *tp, *tp_prev;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002524 struct tcf_dump_args arg;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002525
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002526 for (tp = __tcf_get_next_proto(chain, NULL);
2527 tp;
2528 tp_prev = tp,
2529 tp = __tcf_get_next_proto(chain, tp),
Vlad Buslov12db03b2019-02-11 10:55:45 +02002530 tcf_proto_put(tp_prev, true, NULL),
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002531 (*p_index)++) {
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002532 if (*p_index < index_start)
2533 continue;
2534 if (TC_H_MAJ(tcm->tcm_info) &&
2535 TC_H_MAJ(tcm->tcm_info) != tp->prio)
2536 continue;
2537 if (TC_H_MIN(tcm->tcm_info) &&
2538 TC_H_MIN(tcm->tcm_info) != tp->protocol)
2539 continue;
2540 if (*p_index > index_start)
2541 memset(&cb->args[1], 0,
2542 sizeof(cb->args) - sizeof(cb->args[0]));
2543 if (cb->args[1] == 0) {
YueHaibing53189182018-07-17 20:58:14 +08002544 if (tcf_fill_node(net, skb, tp, block, q, parent, NULL,
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002545 NETLINK_CB(cb->skb).portid,
2546 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002547 RTM_NEWTFILTER, true) <= 0)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002548 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002549 cb->args[1] = 1;
2550 }
2551 if (!tp->ops->walk)
2552 continue;
2553 arg.w.fn = tcf_node_dump;
2554 arg.skb = skb;
2555 arg.cb = cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002556 arg.block = block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002557 arg.q = q;
2558 arg.parent = parent;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002559 arg.w.stop = 0;
2560 arg.w.skip = cb->args[1] - 1;
2561 arg.w.count = 0;
Vlad Buslov01683a12018-07-09 13:29:11 +03002562 arg.w.cookie = cb->args[2];
Vlad Buslov12db03b2019-02-11 10:55:45 +02002563 tp->ops->walk(tp, &arg.w, true);
Vlad Buslov01683a12018-07-09 13:29:11 +03002564 cb->args[2] = arg.w.cookie;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002565 cb->args[1] = arg.w.count + 1;
2566 if (arg.w.stop)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002567 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002568 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002569 return true;
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002570
2571errout:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002572 tcf_proto_put(tp, true, NULL);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002573 return false;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002574}
2575
Eric Dumazetbd27a872009-11-05 20:57:26 -08002576/* called with RTNL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
2578{
Vlad Buslovbbf73832019-02-11 10:55:36 +02002579 struct tcf_chain *chain, *chain_prev;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002580 struct net *net = sock_net(skb->sk);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002581 struct nlattr *tca[TCA_MAX + 1];
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002582 struct Qdisc *q = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02002583 struct tcf_block *block;
David S. Miller942b8162012-06-26 21:48:50 -07002584 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002585 long index_start;
2586 long index;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002587 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002588 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
Hong zhi guo573ce262013-03-27 06:47:04 +00002590 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 return skb->len;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002592
Johannes Berg8cb08172019-04-26 14:07:28 +02002593 err = nlmsg_parse_deprecated(cb->nlh, sizeof(*tcm), tca, TCA_MAX,
2594 NULL, cb->extack);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002595 if (err)
2596 return err;
2597
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002598 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002599 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002600 if (!block)
WANG Cong143976c2017-08-24 16:51:29 -07002601 goto out;
Jiri Pirkod680b352018-01-18 16:14:49 +01002602 /* If we work with block index, q is NULL and parent value
2603 * will never be used in the following code. The check
2604 * in tcf_fill_node prevents it. However, compiler does not
2605 * see that far, so set parent to zero to silence the warning
2606 * about parent being uninitialized.
2607 */
2608 parent = 0;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002609 } else {
2610 const struct Qdisc_class_ops *cops;
2611 struct net_device *dev;
2612 unsigned long cl = 0;
2613
2614 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
2615 if (!dev)
2616 return skb->len;
2617
2618 parent = tcm->tcm_parent;
2619 if (!parent) {
2620 q = dev->qdisc;
2621 parent = q->handle;
2622 } else {
2623 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
2624 }
2625 if (!q)
2626 goto out;
2627 cops = q->ops->cl_ops;
2628 if (!cops)
2629 goto out;
2630 if (!cops->tcf_block)
2631 goto out;
2632 if (TC_H_MIN(tcm->tcm_parent)) {
2633 cl = cops->find(q, tcm->tcm_parent);
2634 if (cl == 0)
2635 goto out;
2636 }
2637 block = cops->tcf_block(q, cl, NULL);
2638 if (!block)
2639 goto out;
2640 if (tcf_block_shared(block))
2641 q = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002644 index_start = cb->args[0];
2645 index = 0;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002646
Vlad Buslovbbf73832019-02-11 10:55:36 +02002647 for (chain = __tcf_get_next_chain(block, NULL);
2648 chain;
2649 chain_prev = chain,
2650 chain = __tcf_get_next_chain(block, chain),
2651 tcf_chain_put(chain_prev)) {
Jiri Pirko5bc17012017-05-17 11:08:01 +02002652 if (tca[TCA_CHAIN] &&
2653 nla_get_u32(tca[TCA_CHAIN]) != chain->index)
2654 continue;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002655 if (!tcf_chain_dump(chain, q, parent, skb, cb,
Roman Kapl5ae437a2018-02-19 21:32:51 +01002656 index_start, &index)) {
Vlad Buslovbbf73832019-02-11 10:55:36 +02002657 tcf_chain_put(chain);
Roman Kapl5ae437a2018-02-19 21:32:51 +01002658 err = -EMSGSIZE;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002659 break;
Roman Kapl5ae437a2018-02-19 21:32:51 +01002660 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002661 }
2662
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002663 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002664 tcf_block_refcnt_put(block, true);
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002665 cb->args[0] = index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667out:
Roman Kapl5ae437a2018-02-19 21:32:51 +01002668 /* If we did no progress, the error (EMSGSIZE) is real */
2669 if (skb->len == 0 && err)
2670 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return skb->len;
2672}
2673
Vlad Buslova5654822019-02-11 10:55:37 +02002674static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
2675 void *tmplt_priv, u32 chain_index,
2676 struct net *net, struct sk_buff *skb,
2677 struct tcf_block *block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002678 u32 portid, u32 seq, u16 flags, int event)
2679{
2680 unsigned char *b = skb_tail_pointer(skb);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002681 const struct tcf_proto_ops *ops;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002682 struct nlmsghdr *nlh;
2683 struct tcmsg *tcm;
Jiri Pirko9f407f12018-07-23 09:23:07 +02002684 void *priv;
2685
Vlad Buslova5654822019-02-11 10:55:37 +02002686 ops = tmplt_ops;
2687 priv = tmplt_priv;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002688
2689 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
2690 if (!nlh)
2691 goto out_nlmsg_trim;
2692 tcm = nlmsg_data(nlh);
2693 tcm->tcm_family = AF_UNSPEC;
2694 tcm->tcm__pad1 = 0;
2695 tcm->tcm__pad2 = 0;
2696 tcm->tcm_handle = 0;
2697 if (block->q) {
2698 tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
2699 tcm->tcm_parent = block->q->handle;
2700 } else {
2701 tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
2702 tcm->tcm_block_index = block->index;
2703 }
2704
Vlad Buslova5654822019-02-11 10:55:37 +02002705 if (nla_put_u32(skb, TCA_CHAIN, chain_index))
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002706 goto nla_put_failure;
2707
Jiri Pirko9f407f12018-07-23 09:23:07 +02002708 if (ops) {
2709 if (nla_put_string(skb, TCA_KIND, ops->kind))
2710 goto nla_put_failure;
2711 if (ops->tmplt_dump(skb, net, priv) < 0)
2712 goto nla_put_failure;
2713 }
2714
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002715 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
2716 return skb->len;
2717
2718out_nlmsg_trim:
2719nla_put_failure:
2720 nlmsg_trim(skb, b);
2721 return -EMSGSIZE;
2722}
2723
2724static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
2725 u32 seq, u16 flags, int event, bool unicast)
2726{
2727 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2728 struct tcf_block *block = chain->block;
2729 struct net *net = block->net;
2730 struct sk_buff *skb;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002731 int err = 0;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002732
2733 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2734 if (!skb)
2735 return -ENOBUFS;
2736
Vlad Buslova5654822019-02-11 10:55:37 +02002737 if (tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
2738 chain->index, net, skb, block, portid,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002739 seq, flags, event) <= 0) {
2740 kfree_skb(skb);
2741 return -EINVAL;
2742 }
2743
2744 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002745 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2746 else
2747 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
2748 flags & NLM_F_ECHO);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002749
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002750 if (err > 0)
2751 err = 0;
2752 return err;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002753}
2754
Vlad Buslova5654822019-02-11 10:55:37 +02002755static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
2756 void *tmplt_priv, u32 chain_index,
2757 struct tcf_block *block, struct sk_buff *oskb,
2758 u32 seq, u16 flags, bool unicast)
2759{
2760 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2761 struct net *net = block->net;
2762 struct sk_buff *skb;
2763
2764 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2765 if (!skb)
2766 return -ENOBUFS;
2767
2768 if (tc_chain_fill_node(tmplt_ops, tmplt_priv, chain_index, net, skb,
2769 block, portid, seq, flags, RTM_DELCHAIN) <= 0) {
2770 kfree_skb(skb);
2771 return -EINVAL;
2772 }
2773
2774 if (unicast)
2775 return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2776
2777 return rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
2778}
2779
Jiri Pirko9f407f12018-07-23 09:23:07 +02002780static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
2781 struct nlattr **tca,
2782 struct netlink_ext_ack *extack)
2783{
2784 const struct tcf_proto_ops *ops;
Eric Dumazet2dd56162019-12-07 11:34:45 -08002785 char name[IFNAMSIZ];
Jiri Pirko9f407f12018-07-23 09:23:07 +02002786 void *tmplt_priv;
2787
2788 /* If kind is not set, user did not specify template. */
2789 if (!tca[TCA_KIND])
2790 return 0;
2791
Eric Dumazet2dd56162019-12-07 11:34:45 -08002792 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2793 NL_SET_ERR_MSG(extack, "Specified TC chain template name too long");
2794 return -EINVAL;
2795 }
2796
2797 ops = tcf_proto_lookup_ops(name, true, extack);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002798 if (IS_ERR(ops))
2799 return PTR_ERR(ops);
2800 if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
2801 NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier");
2802 return -EOPNOTSUPP;
2803 }
2804
2805 tmplt_priv = ops->tmplt_create(net, chain, tca, extack);
2806 if (IS_ERR(tmplt_priv)) {
2807 module_put(ops->owner);
2808 return PTR_ERR(tmplt_priv);
2809 }
2810 chain->tmplt_ops = ops;
2811 chain->tmplt_priv = tmplt_priv;
2812 return 0;
2813}
2814
Vlad Buslova5654822019-02-11 10:55:37 +02002815static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
2816 void *tmplt_priv)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002817{
Jiri Pirko9f407f12018-07-23 09:23:07 +02002818 /* If template ops are set, no work to do for us. */
Vlad Buslova5654822019-02-11 10:55:37 +02002819 if (!tmplt_ops)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002820 return;
2821
Vlad Buslova5654822019-02-11 10:55:37 +02002822 tmplt_ops->tmplt_destroy(tmplt_priv);
2823 module_put(tmplt_ops->owner);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002824}
2825
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002826/* Add/delete/get a chain */
2827
2828static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
2829 struct netlink_ext_ack *extack)
2830{
2831 struct net *net = sock_net(skb->sk);
2832 struct nlattr *tca[TCA_MAX + 1];
2833 struct tcmsg *t;
2834 u32 parent;
2835 u32 chain_index;
2836 struct Qdisc *q = NULL;
2837 struct tcf_chain *chain = NULL;
2838 struct tcf_block *block;
2839 unsigned long cl;
2840 int err;
2841
2842 if (n->nlmsg_type != RTM_GETCHAIN &&
2843 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2844 return -EPERM;
2845
2846replay:
Johannes Berg8cb08172019-04-26 14:07:28 +02002847 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2848 rtm_tca_policy, extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002849 if (err < 0)
2850 return err;
2851
2852 t = nlmsg_data(n);
2853 parent = t->tcm_parent;
2854 cl = 0;
2855
2856 block = tcf_block_find(net, &q, &parent, &cl,
2857 t->tcm_ifindex, t->tcm_block_index, extack);
2858 if (IS_ERR(block))
2859 return PTR_ERR(block);
2860
2861 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2862 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2863 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002864 err = -EINVAL;
2865 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002866 }
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002867
2868 mutex_lock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002869 chain = tcf_chain_lookup(block, chain_index);
2870 if (n->nlmsg_type == RTM_NEWCHAIN) {
2871 if (chain) {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002872 if (tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002873 /* The chain exists only because there is
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002874 * some action referencing it.
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002875 */
2876 tcf_chain_hold(chain);
2877 } else {
2878 NL_SET_ERR_MSG(extack, "Filter chain already exists");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002879 err = -EEXIST;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002880 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002881 }
2882 } else {
2883 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
2884 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 +03002885 err = -ENOENT;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002886 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002887 }
2888 chain = tcf_chain_create(block, chain_index);
2889 if (!chain) {
2890 NL_SET_ERR_MSG(extack, "Failed to create filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002891 err = -ENOMEM;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002892 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002893 }
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002894 }
2895 } else {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002896 if (!chain || tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002897 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002898 err = -EINVAL;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002899 goto errout_block_locked;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002900 }
2901 tcf_chain_hold(chain);
2902 }
2903
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002904 if (n->nlmsg_type == RTM_NEWCHAIN) {
2905 /* Modifying chain requires holding parent block lock. In case
2906 * the chain was successfully added, take a reference to the
2907 * chain. This ensures that an empty chain does not disappear at
2908 * the end of this function.
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002909 */
2910 tcf_chain_hold(chain);
2911 chain->explicitly_created = true;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002912 }
2913 mutex_unlock(&block->lock);
2914
2915 switch (n->nlmsg_type) {
2916 case RTM_NEWCHAIN:
2917 err = tc_chain_tmplt_add(chain, net, tca, extack);
2918 if (err) {
2919 tcf_chain_put_explicitly_created(chain);
2920 goto errout;
2921 }
2922
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002923 tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
2924 RTM_NEWCHAIN, false);
2925 break;
2926 case RTM_DELCHAIN:
Cong Wangf5b9bac2018-09-11 14:22:23 -07002927 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002928 chain, RTM_DELTFILTER, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002929 /* Flush the chain first as the user requested chain removal. */
Vlad Buslov12db03b2019-02-11 10:55:45 +02002930 tcf_chain_flush(chain, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002931 /* In case the chain was successfully deleted, put a reference
2932 * to the chain previously taken during addition.
2933 */
2934 tcf_chain_put_explicitly_created(chain);
2935 break;
2936 case RTM_GETCHAIN:
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002937 err = tc_chain_notify(chain, skb, n->nlmsg_seq,
2938 n->nlmsg_seq, n->nlmsg_type, true);
2939 if (err < 0)
2940 NL_SET_ERR_MSG(extack, "Failed to send chain notify message");
2941 break;
2942 default:
2943 err = -EOPNOTSUPP;
2944 NL_SET_ERR_MSG(extack, "Unsupported message type");
2945 goto errout;
2946 }
2947
2948errout:
2949 tcf_chain_put(chain);
Vlad Buslove368fdb2018-09-24 19:22:53 +03002950errout_block:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002951 tcf_block_release(q, block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002952 if (err == -EAGAIN)
2953 /* Replay the request. */
2954 goto replay;
2955 return err;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002956
2957errout_block_locked:
2958 mutex_unlock(&block->lock);
2959 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002960}
2961
2962/* called with RTNL */
2963static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
2964{
2965 struct net *net = sock_net(skb->sk);
2966 struct nlattr *tca[TCA_MAX + 1];
2967 struct Qdisc *q = NULL;
2968 struct tcf_block *block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002969 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovace4a262019-02-25 17:45:44 +02002970 struct tcf_chain *chain;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002971 long index_start;
2972 long index;
2973 u32 parent;
2974 int err;
2975
2976 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
2977 return skb->len;
2978
Johannes Berg8cb08172019-04-26 14:07:28 +02002979 err = nlmsg_parse_deprecated(cb->nlh, sizeof(*tcm), tca, TCA_MAX,
2980 rtm_tca_policy, cb->extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002981 if (err)
2982 return err;
2983
2984 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002985 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002986 if (!block)
2987 goto out;
2988 /* If we work with block index, q is NULL and parent value
2989 * will never be used in the following code. The check
2990 * in tcf_fill_node prevents it. However, compiler does not
2991 * see that far, so set parent to zero to silence the warning
2992 * about parent being uninitialized.
2993 */
2994 parent = 0;
2995 } else {
2996 const struct Qdisc_class_ops *cops;
2997 struct net_device *dev;
2998 unsigned long cl = 0;
2999
3000 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
3001 if (!dev)
3002 return skb->len;
3003
3004 parent = tcm->tcm_parent;
3005 if (!parent) {
3006 q = dev->qdisc;
3007 parent = q->handle;
3008 } else {
3009 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
3010 }
3011 if (!q)
3012 goto out;
3013 cops = q->ops->cl_ops;
3014 if (!cops)
3015 goto out;
3016 if (!cops->tcf_block)
3017 goto out;
3018 if (TC_H_MIN(tcm->tcm_parent)) {
3019 cl = cops->find(q, tcm->tcm_parent);
3020 if (cl == 0)
3021 goto out;
3022 }
3023 block = cops->tcf_block(q, cl, NULL);
3024 if (!block)
3025 goto out;
3026 if (tcf_block_shared(block))
3027 q = NULL;
3028 }
3029
3030 index_start = cb->args[0];
3031 index = 0;
3032
Vlad Buslovace4a262019-02-25 17:45:44 +02003033 mutex_lock(&block->lock);
3034 list_for_each_entry(chain, &block->chain_list, list) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003035 if ((tca[TCA_CHAIN] &&
3036 nla_get_u32(tca[TCA_CHAIN]) != chain->index))
3037 continue;
3038 if (index < index_start) {
3039 index++;
3040 continue;
3041 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003042 if (tcf_chain_held_by_acts_only(chain))
3043 continue;
Vlad Buslova5654822019-02-11 10:55:37 +02003044 err = tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
3045 chain->index, net, skb, block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003046 NETLINK_CB(cb->skb).portid,
3047 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3048 RTM_NEWCHAIN);
Vlad Buslovace4a262019-02-25 17:45:44 +02003049 if (err <= 0)
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003050 break;
3051 index++;
3052 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003053 mutex_unlock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003054
Vlad Buslov787ce6d2018-09-24 19:22:58 +03003055 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02003056 tcf_block_refcnt_put(block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003057 cb->args[0] = index;
3058
3059out:
3060 /* If we did no progress, the error (EMSGSIZE) is real */
3061 if (skb->len == 0 && err)
3062 return err;
3063 return skb->len;
3064}
3065
WANG Cong18d02642014-09-25 10:26:37 -07003066void tcf_exts_destroy(struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067{
3068#ifdef CONFIG_NET_CLS_ACT
Eric Dumazet3d66b892019-09-18 12:57:04 -07003069 if (exts->actions) {
3070 tcf_action_destroy(exts->actions, TCA_ACT_UNBIND);
3071 kfree(exts->actions);
3072 }
WANG Cong22dc13c2016-08-13 22:35:00 -07003073 exts->nr_actions = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074#endif
3075}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003076EXPORT_SYMBOL(tcf_exts_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Benjamin LaHaisec1b52732013-01-14 05:15:39 +00003078int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
Alexander Aring50a56192018-01-18 11:20:52 -05003079 struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003080 bool rtnl_held, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082#ifdef CONFIG_NET_CLS_ACT
3083 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 struct tc_action *act;
Roman Mashakd04e6992018-03-08 16:59:17 -05003085 size_t attr_size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
WANG Cong5da57f42013-12-15 20:15:07 -08003087 if (exts->police && tb[exts->police]) {
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003088 act = tcf_action_init_1(net, tp, tb[exts->police],
3089 rate_tlv, "police", ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003090 TCA_ACT_BIND, rtnl_held,
3091 extack);
Patrick McHardyab27cfb2008-01-23 20:33:13 -08003092 if (IS_ERR(act))
3093 return PTR_ERR(act);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
WANG Cong33be6272013-12-15 20:15:05 -08003095 act->type = exts->type = TCA_OLD_COMPAT;
WANG Cong22dc13c2016-08-13 22:35:00 -07003096 exts->actions[0] = act;
3097 exts->nr_actions = 1;
WANG Cong5da57f42013-12-15 20:15:07 -08003098 } else if (exts->action && tb[exts->action]) {
Vlad Buslov90b73b72018-07-05 17:24:33 +03003099 int err;
WANG Cong22dc13c2016-08-13 22:35:00 -07003100
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003101 err = tcf_action_init(net, tp, tb[exts->action],
3102 rate_tlv, NULL, ovr, TCA_ACT_BIND,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003103 exts->actions, &attr_size,
3104 rtnl_held, extack);
Vlad Buslov90b73b72018-07-05 17:24:33 +03003105 if (err < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003106 return err;
Vlad Buslov90b73b72018-07-05 17:24:33 +03003107 exts->nr_actions = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
3109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110#else
WANG Cong5da57f42013-12-15 20:15:07 -08003111 if ((exts->action && tb[exts->action]) ||
Alexander Aring50a56192018-01-18 11:20:52 -05003112 (exts->police && tb[exts->police])) {
3113 NL_SET_ERR_MSG(extack, "Classifier actions are not supported per compile options (CONFIG_NET_CLS_ACT)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 return -EOPNOTSUPP;
Alexander Aring50a56192018-01-18 11:20:52 -05003115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116#endif
3117
3118 return 0;
3119}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003120EXPORT_SYMBOL(tcf_exts_validate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003122void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123{
3124#ifdef CONFIG_NET_CLS_ACT
WANG Cong22dc13c2016-08-13 22:35:00 -07003125 struct tcf_exts old = *dst;
3126
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003127 *dst = *src;
WANG Cong22dc13c2016-08-13 22:35:00 -07003128 tcf_exts_destroy(&old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129#endif
3130}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003131EXPORT_SYMBOL(tcf_exts_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132
WANG Cong22dc13c2016-08-13 22:35:00 -07003133#ifdef CONFIG_NET_CLS_ACT
3134static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
3135{
3136 if (exts->nr_actions == 0)
3137 return NULL;
3138 else
3139 return exts->actions[0];
3140}
3141#endif
WANG Cong33be6272013-12-15 20:15:05 -08003142
WANG Cong5da57f42013-12-15 20:15:07 -08003143int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144{
3145#ifdef CONFIG_NET_CLS_ACT
Cong Wang9cc63db2014-07-16 14:25:30 -07003146 struct nlattr *nest;
3147
Jiri Pirko978dfd82017-08-04 14:29:03 +02003148 if (exts->action && tcf_exts_has_actions(exts)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 /*
3150 * again for backward compatible mode - we want
3151 * to work with both old and new modes of entering
3152 * tc data even if iproute2 was newer - jhs
3153 */
WANG Cong33be6272013-12-15 20:15:05 -08003154 if (exts->type != TCA_OLD_COMPAT) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003155 nest = nla_nest_start_noflag(skb, exts->action);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003156 if (nest == NULL)
3157 goto nla_put_failure;
WANG Cong22dc13c2016-08-13 22:35:00 -07003158
Vlad Buslov90b73b72018-07-05 17:24:33 +03003159 if (tcf_action_dump(skb, exts->actions, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003160 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003161 nla_nest_end(skb, nest);
WANG Cong5da57f42013-12-15 20:15:07 -08003162 } else if (exts->police) {
WANG Cong33be6272013-12-15 20:15:05 -08003163 struct tc_action *act = tcf_exts_first_act(exts);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003164 nest = nla_nest_start_noflag(skb, exts->police);
Jamal Hadi Salim63acd682013-12-23 08:02:12 -05003165 if (nest == NULL || !act)
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003166 goto nla_put_failure;
WANG Cong33be6272013-12-15 20:15:05 -08003167 if (tcf_action_dump_old(skb, act, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003168 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003169 nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 }
3171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 return 0;
Cong Wang9cc63db2014-07-16 14:25:30 -07003173
3174nla_put_failure:
3175 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 return -1;
Cong Wang9cc63db2014-07-16 14:25:30 -07003177#else
3178 return 0;
3179#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003181EXPORT_SYMBOL(tcf_exts_dump);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003183
WANG Cong5da57f42013-12-15 20:15:07 -08003184int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185{
3186#ifdef CONFIG_NET_CLS_ACT
WANG Cong33be6272013-12-15 20:15:05 -08003187 struct tc_action *a = tcf_exts_first_act(exts);
Ignacy Gawędzkib057df22015-02-03 19:05:18 +01003188 if (a != NULL && tcf_action_copy_stats(skb, a, 1) < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003189 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190#endif
3191 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003193EXPORT_SYMBOL(tcf_exts_dump_stats);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Vlad Buslov40119212019-08-26 16:44:59 +03003195static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
3196{
3197 if (*flags & TCA_CLS_FLAGS_IN_HW)
3198 return;
3199 *flags |= TCA_CLS_FLAGS_IN_HW;
3200 atomic_inc(&block->offloadcnt);
3201}
3202
3203static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)
3204{
3205 if (!(*flags & TCA_CLS_FLAGS_IN_HW))
3206 return;
3207 *flags &= ~TCA_CLS_FLAGS_IN_HW;
3208 atomic_dec(&block->offloadcnt);
3209}
3210
3211static void tc_cls_offload_cnt_update(struct tcf_block *block,
3212 struct tcf_proto *tp, u32 *cnt,
3213 u32 *flags, u32 diff, bool add)
3214{
3215 lockdep_assert_held(&block->cb_lock);
3216
3217 spin_lock(&tp->lock);
3218 if (add) {
3219 if (!*cnt)
3220 tcf_block_offload_inc(block, flags);
3221 *cnt += diff;
3222 } else {
3223 *cnt -= diff;
3224 if (!*cnt)
3225 tcf_block_offload_dec(block, flags);
3226 }
3227 spin_unlock(&tp->lock);
3228}
3229
3230static void
3231tc_cls_offload_cnt_reset(struct tcf_block *block, struct tcf_proto *tp,
3232 u32 *cnt, u32 *flags)
3233{
3234 lockdep_assert_held(&block->cb_lock);
3235
3236 spin_lock(&tp->lock);
3237 tcf_block_offload_dec(block, flags);
3238 *cnt = 0;
3239 spin_unlock(&tp->lock);
3240}
3241
3242static int
3243__tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
3244 void *type_data, bool err_stop)
Jiri Pirko717503b2017-10-11 09:41:09 +02003245{
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02003246 struct flow_block_cb *block_cb;
Cong Wangaeb3fec2018-12-11 11:15:46 -08003247 int ok_count = 0;
3248 int err;
3249
Vlad Buslov40119212019-08-26 16:44:59 +03003250 list_for_each_entry(block_cb, &block->flow_block.cb_list, list) {
3251 err = block_cb->cb(type, type_data, block_cb->cb_priv);
3252 if (err) {
3253 if (err_stop)
3254 return err;
3255 } else {
3256 ok_count++;
3257 }
3258 }
3259 return ok_count;
3260}
3261
3262int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
3263 void *type_data, bool err_stop, bool rtnl_held)
3264{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003265 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003266 int ok_count;
3267
Vlad Buslov11bd6342019-08-26 16:45:02 +03003268retry:
3269 if (take_rtnl)
3270 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003271 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003272 /* Need to obtain rtnl lock if block is bound to devs that require it.
3273 * In block bind code cb_lock is obtained while holding rtnl, so we must
3274 * obtain the locks in same order here.
3275 */
3276 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3277 up_read(&block->cb_lock);
3278 take_rtnl = true;
3279 goto retry;
3280 }
3281
Vlad Buslov40119212019-08-26 16:44:59 +03003282 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003283
Vlad Buslov40119212019-08-26 16:44:59 +03003284 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003285 if (take_rtnl)
3286 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003287 return ok_count;
3288}
3289EXPORT_SYMBOL(tc_setup_cb_call);
3290
3291/* Non-destructive filter add. If filter that wasn't already in hardware is
3292 * successfully offloaded, increment block offloads counter. On failure,
3293 * previously offloaded filter is considered to be intact and offloads counter
3294 * is not decremented.
3295 */
3296
3297int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
3298 enum tc_setup_type type, void *type_data, bool err_stop,
3299 u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
3300{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003301 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003302 int ok_count;
3303
Vlad Buslov11bd6342019-08-26 16:45:02 +03003304retry:
3305 if (take_rtnl)
3306 rtnl_lock();
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003307 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003308 /* Need to obtain rtnl lock if block is bound to devs that require it.
3309 * In block bind code cb_lock is obtained while holding rtnl, so we must
3310 * obtain the locks in same order here.
3311 */
3312 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3313 up_read(&block->cb_lock);
3314 take_rtnl = true;
3315 goto retry;
3316 }
3317
Cong Wangaeb3fec2018-12-11 11:15:46 -08003318 /* Make sure all netdevs sharing this block are offload-capable. */
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003319 if (block->nooffloaddevcnt && err_stop) {
3320 ok_count = -EOPNOTSUPP;
3321 goto err_unlock;
3322 }
Cong Wangaeb3fec2018-12-11 11:15:46 -08003323
Vlad Buslov40119212019-08-26 16:44:59 +03003324 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003325 if (ok_count < 0)
3326 goto err_unlock;
3327
3328 if (tp->ops->hw_add)
3329 tp->ops->hw_add(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003330 if (ok_count > 0)
3331 tc_cls_offload_cnt_update(block, tp, in_hw_count, flags,
3332 ok_count, true);
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003333err_unlock:
3334 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003335 if (take_rtnl)
3336 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003337 return ok_count < 0 ? ok_count : 0;
Jiri Pirko717503b2017-10-11 09:41:09 +02003338}
Vlad Buslov40119212019-08-26 16:44:59 +03003339EXPORT_SYMBOL(tc_setup_cb_add);
3340
3341/* Destructive filter replace. If filter that wasn't already in hardware is
3342 * successfully offloaded, increment block offload counter. On failure,
3343 * previously offloaded filter is considered to be destroyed and offload counter
3344 * is decremented.
3345 */
3346
3347int tc_setup_cb_replace(struct tcf_block *block, struct tcf_proto *tp,
3348 enum tc_setup_type type, void *type_data, bool err_stop,
3349 u32 *old_flags, unsigned int *old_in_hw_count,
3350 u32 *new_flags, unsigned int *new_in_hw_count,
3351 bool rtnl_held)
3352{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003353 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003354 int ok_count;
3355
Vlad Buslov11bd6342019-08-26 16:45:02 +03003356retry:
3357 if (take_rtnl)
3358 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003359 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003360 /* Need to obtain rtnl lock if block is bound to devs that require it.
3361 * In block bind code cb_lock is obtained while holding rtnl, so we must
3362 * obtain the locks in same order here.
3363 */
3364 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3365 up_read(&block->cb_lock);
3366 take_rtnl = true;
3367 goto retry;
3368 }
3369
Vlad Buslov40119212019-08-26 16:44:59 +03003370 /* Make sure all netdevs sharing this block are offload-capable. */
3371 if (block->nooffloaddevcnt && err_stop) {
3372 ok_count = -EOPNOTSUPP;
3373 goto err_unlock;
3374 }
3375
3376 tc_cls_offload_cnt_reset(block, tp, old_in_hw_count, old_flags);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003377 if (tp->ops->hw_del)
3378 tp->ops->hw_del(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003379
3380 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003381 if (ok_count < 0)
3382 goto err_unlock;
3383
3384 if (tp->ops->hw_add)
3385 tp->ops->hw_add(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003386 if (ok_count > 0)
Vlad Buslova449a3e2019-08-26 16:45:00 +03003387 tc_cls_offload_cnt_update(block, tp, new_in_hw_count,
3388 new_flags, ok_count, true);
Vlad Buslov40119212019-08-26 16:44:59 +03003389err_unlock:
3390 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003391 if (take_rtnl)
3392 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003393 return ok_count < 0 ? ok_count : 0;
3394}
3395EXPORT_SYMBOL(tc_setup_cb_replace);
3396
3397/* Destroy filter and decrement block offload counter, if filter was previously
3398 * offloaded.
3399 */
3400
3401int tc_setup_cb_destroy(struct tcf_block *block, struct tcf_proto *tp,
3402 enum tc_setup_type type, void *type_data, bool err_stop,
3403 u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
3404{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003405 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003406 int ok_count;
3407
Vlad Buslov11bd6342019-08-26 16:45:02 +03003408retry:
3409 if (take_rtnl)
3410 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003411 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003412 /* Need to obtain rtnl lock if block is bound to devs that require it.
3413 * In block bind code cb_lock is obtained while holding rtnl, so we must
3414 * obtain the locks in same order here.
3415 */
3416 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3417 up_read(&block->cb_lock);
3418 take_rtnl = true;
3419 goto retry;
3420 }
3421
Vlad Buslov40119212019-08-26 16:44:59 +03003422 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
3423
3424 tc_cls_offload_cnt_reset(block, tp, in_hw_count, flags);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003425 if (tp->ops->hw_del)
3426 tp->ops->hw_del(tp, type_data);
3427
Vlad Buslov40119212019-08-26 16:44:59 +03003428 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003429 if (take_rtnl)
3430 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003431 return ok_count < 0 ? ok_count : 0;
3432}
3433EXPORT_SYMBOL(tc_setup_cb_destroy);
3434
3435int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
3436 bool add, flow_setup_cb_t *cb,
3437 enum tc_setup_type type, void *type_data,
3438 void *cb_priv, u32 *flags, unsigned int *in_hw_count)
3439{
3440 int err = cb(type, type_data, cb_priv);
3441
3442 if (err) {
3443 if (add && tc_skip_sw(*flags))
3444 return err;
3445 } else {
3446 tc_cls_offload_cnt_update(block, tp, in_hw_count, flags, 1,
3447 add);
3448 }
3449
3450 return 0;
3451}
3452EXPORT_SYMBOL(tc_setup_cb_reoffload);
Jiri Pirkob3f55bd2017-10-11 09:41:08 +02003453
Jiri Pirko20084952020-02-25 11:45:18 +01003454static int tcf_act_get_cookie(struct flow_action_entry *entry,
3455 const struct tc_action *act)
3456{
3457 struct tc_cookie *cookie;
3458 int err = 0;
3459
3460 rcu_read_lock();
3461 cookie = rcu_dereference(act->act_cookie);
3462 if (cookie) {
3463 entry->cookie = flow_action_cookie_create(cookie->data,
3464 cookie->len,
3465 GFP_ATOMIC);
3466 if (!entry->cookie)
3467 err = -ENOMEM;
3468 }
3469 rcu_read_unlock();
3470 return err;
3471}
3472
3473static void tcf_act_put_cookie(struct flow_action_entry *entry)
3474{
3475 flow_action_cookie_destroy(entry->cookie);
3476}
3477
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003478void tc_cleanup_flow_action(struct flow_action *flow_action)
3479{
3480 struct flow_action_entry *entry;
3481 int i;
3482
Jiri Pirko20084952020-02-25 11:45:18 +01003483 flow_action_for_each(i, entry, flow_action) {
3484 tcf_act_put_cookie(entry);
Vlad Buslov11589582019-09-13 18:28:39 +03003485 if (entry->destructor)
3486 entry->destructor(entry->destructor_priv);
Jiri Pirko20084952020-02-25 11:45:18 +01003487 }
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003488}
3489EXPORT_SYMBOL(tc_cleanup_flow_action);
3490
Vlad Buslov11589582019-09-13 18:28:39 +03003491static void tcf_mirred_get_dev(struct flow_action_entry *entry,
3492 const struct tc_action *act)
3493{
Vlad Buslov470d5062019-09-13 18:28:41 +03003494#ifdef CONFIG_NET_CLS_ACT
3495 entry->dev = act->ops->get_dev(act, &entry->destructor);
Vlad Buslov11589582019-09-13 18:28:39 +03003496 if (!entry->dev)
3497 return;
Vlad Buslov11589582019-09-13 18:28:39 +03003498 entry->destructor_priv = entry->dev;
Vlad Buslov470d5062019-09-13 18:28:41 +03003499#endif
Vlad Buslov11589582019-09-13 18:28:39 +03003500}
3501
3502static void tcf_tunnel_encap_put_tunnel(void *priv)
3503{
3504 struct ip_tunnel_info *tunnel = priv;
3505
3506 kfree(tunnel);
3507}
3508
3509static int tcf_tunnel_encap_get_tunnel(struct flow_action_entry *entry,
3510 const struct tc_action *act)
3511{
3512 entry->tunnel = tcf_tunnel_info_copy(act);
3513 if (!entry->tunnel)
3514 return -ENOMEM;
3515 entry->destructor = tcf_tunnel_encap_put_tunnel;
3516 entry->destructor_priv = entry->tunnel;
3517 return 0;
3518}
3519
Vlad Buslov4a5da472019-09-13 18:28:40 +03003520static void tcf_sample_get_group(struct flow_action_entry *entry,
3521 const struct tc_action *act)
3522{
3523#ifdef CONFIG_NET_CLS_ACT
3524 entry->sample.psample_group =
3525 act->ops->get_psample_group(act, &entry->destructor);
3526 entry->destructor_priv = entry->sample.psample_group;
3527#endif
3528}
3529
Po Liud29bdd62020-05-01 08:53:16 +08003530static void tcf_gate_entry_destructor(void *priv)
3531{
3532 struct action_gate_entry *oe = priv;
3533
3534 kfree(oe);
3535}
3536
3537static int tcf_gate_get_entries(struct flow_action_entry *entry,
3538 const struct tc_action *act)
3539{
3540 entry->gate.entries = tcf_gate_get_list(act);
3541
3542 if (!entry->gate.entries)
3543 return -EINVAL;
3544
3545 entry->destructor = tcf_gate_entry_destructor;
3546 entry->destructor_priv = entry->gate.entries;
3547
3548 return 0;
3549}
3550
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003551int tc_setup_flow_action(struct flow_action *flow_action,
Vlad Buslovb15e7a62020-02-17 12:12:12 +02003552 const struct tcf_exts *exts)
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003553{
Vlad Buslov7a472812020-02-17 12:12:09 +02003554 struct tc_action *act;
Vlad Buslov9838b202019-08-26 16:45:03 +03003555 int i, j, k, err = 0;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003556
Jakub Kicinski0dfb2d82020-03-19 16:26:23 -07003557 BUILD_BUG_ON(TCA_ACT_HW_STATS_ANY != FLOW_ACTION_HW_STATS_ANY);
3558 BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
3559 BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED);
Jiri Pirko44f86582020-03-07 12:40:20 +01003560
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003561 if (!exts)
3562 return 0;
3563
3564 j = 0;
3565 tcf_exts_for_each_action(i, act, exts) {
3566 struct flow_action_entry *entry;
3567
3568 entry = &flow_action->entries[j];
Vlad Buslov7a472812020-02-17 12:12:09 +02003569 spin_lock_bh(&act->tcfa_lock);
Jiri Pirko20084952020-02-25 11:45:18 +01003570 err = tcf_act_get_cookie(entry, act);
3571 if (err)
3572 goto err_out_locked;
Jiri Pirko44f86582020-03-07 12:40:20 +01003573
Jakub Kicinski0dfb2d82020-03-19 16:26:23 -07003574 entry->hw_stats = act->hw_stats;
Jiri Pirko44f86582020-03-07 12:40:20 +01003575
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003576 if (is_tcf_gact_ok(act)) {
3577 entry->id = FLOW_ACTION_ACCEPT;
3578 } else if (is_tcf_gact_shot(act)) {
3579 entry->id = FLOW_ACTION_DROP;
3580 } else if (is_tcf_gact_trap(act)) {
3581 entry->id = FLOW_ACTION_TRAP;
3582 } else if (is_tcf_gact_goto_chain(act)) {
3583 entry->id = FLOW_ACTION_GOTO;
3584 entry->chain_index = tcf_gact_goto_chain_index(act);
3585 } else if (is_tcf_mirred_egress_redirect(act)) {
3586 entry->id = FLOW_ACTION_REDIRECT;
Vlad Buslov11589582019-09-13 18:28:39 +03003587 tcf_mirred_get_dev(entry, act);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003588 } else if (is_tcf_mirred_egress_mirror(act)) {
3589 entry->id = FLOW_ACTION_MIRRED;
Vlad Buslov11589582019-09-13 18:28:39 +03003590 tcf_mirred_get_dev(entry, act);
John Hurley48e584a2019-08-04 16:09:06 +01003591 } else if (is_tcf_mirred_ingress_redirect(act)) {
3592 entry->id = FLOW_ACTION_REDIRECT_INGRESS;
Vlad Buslov11589582019-09-13 18:28:39 +03003593 tcf_mirred_get_dev(entry, act);
John Hurley48e584a2019-08-04 16:09:06 +01003594 } else if (is_tcf_mirred_ingress_mirror(act)) {
3595 entry->id = FLOW_ACTION_MIRRED_INGRESS;
Vlad Buslov11589582019-09-13 18:28:39 +03003596 tcf_mirred_get_dev(entry, act);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003597 } else if (is_tcf_vlan(act)) {
3598 switch (tcf_vlan_action(act)) {
3599 case TCA_VLAN_ACT_PUSH:
3600 entry->id = FLOW_ACTION_VLAN_PUSH;
3601 entry->vlan.vid = tcf_vlan_push_vid(act);
3602 entry->vlan.proto = tcf_vlan_push_proto(act);
3603 entry->vlan.prio = tcf_vlan_push_prio(act);
3604 break;
3605 case TCA_VLAN_ACT_POP:
3606 entry->id = FLOW_ACTION_VLAN_POP;
3607 break;
3608 case TCA_VLAN_ACT_MODIFY:
3609 entry->id = FLOW_ACTION_VLAN_MANGLE;
3610 entry->vlan.vid = tcf_vlan_push_vid(act);
3611 entry->vlan.proto = tcf_vlan_push_proto(act);
3612 entry->vlan.prio = tcf_vlan_push_prio(act);
3613 break;
3614 default:
Vlad Buslov9838b202019-08-26 16:45:03 +03003615 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003616 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003617 }
3618 } else if (is_tcf_tunnel_set(act)) {
3619 entry->id = FLOW_ACTION_TUNNEL_ENCAP;
Vlad Buslov11589582019-09-13 18:28:39 +03003620 err = tcf_tunnel_encap_get_tunnel(entry, act);
3621 if (err)
Vlad Buslov7a472812020-02-17 12:12:09 +02003622 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003623 } else if (is_tcf_tunnel_release(act)) {
3624 entry->id = FLOW_ACTION_TUNNEL_DECAP;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003625 } else if (is_tcf_pedit(act)) {
3626 for (k = 0; k < tcf_pedit_nkeys(act); k++) {
3627 switch (tcf_pedit_cmd(act, k)) {
3628 case TCA_PEDIT_KEY_EX_CMD_SET:
3629 entry->id = FLOW_ACTION_MANGLE;
3630 break;
3631 case TCA_PEDIT_KEY_EX_CMD_ADD:
3632 entry->id = FLOW_ACTION_ADD;
3633 break;
3634 default:
Vlad Buslov9838b202019-08-26 16:45:03 +03003635 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003636 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003637 }
3638 entry->mangle.htype = tcf_pedit_htype(act, k);
3639 entry->mangle.mask = tcf_pedit_mask(act, k);
3640 entry->mangle.val = tcf_pedit_val(act, k);
3641 entry->mangle.offset = tcf_pedit_offset(act, k);
Jakub Kicinski0dfb2d82020-03-19 16:26:23 -07003642 entry->hw_stats = act->hw_stats;
Petr Machata2c4b58d2020-03-18 19:42:29 +02003643 entry = &flow_action->entries[++j];
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003644 }
3645 } else if (is_tcf_csum(act)) {
3646 entry->id = FLOW_ACTION_CSUM;
3647 entry->csum_flags = tcf_csum_update_flags(act);
3648 } else if (is_tcf_skbedit_mark(act)) {
3649 entry->id = FLOW_ACTION_MARK;
3650 entry->mark = tcf_skbedit_mark(act);
Pieter Jansen van Vuurena7a7be62019-05-04 04:46:16 -07003651 } else if (is_tcf_sample(act)) {
3652 entry->id = FLOW_ACTION_SAMPLE;
Pieter Jansen van Vuurena7a7be62019-05-04 04:46:16 -07003653 entry->sample.trunc_size = tcf_sample_trunc_size(act);
3654 entry->sample.truncate = tcf_sample_truncate(act);
3655 entry->sample.rate = tcf_sample_rate(act);
Vlad Buslov4a5da472019-09-13 18:28:40 +03003656 tcf_sample_get_group(entry, act);
Pieter Jansen van Vuuren8c8cfc62019-05-04 04:46:22 -07003657 } else if (is_tcf_police(act)) {
3658 entry->id = FLOW_ACTION_POLICE;
3659 entry->police.burst = tcf_police_tcfp_burst(act);
3660 entry->police.rate_bytes_ps =
3661 tcf_police_rate_bytes_ps(act);
Paul Blakeyb57dc7c2019-07-09 10:30:48 +03003662 } else if (is_tcf_ct(act)) {
3663 entry->id = FLOW_ACTION_CT;
3664 entry->ct.action = tcf_ct_action(act);
3665 entry->ct.zone = tcf_ct_zone(act);
Paul Blakeyedd58612020-03-12 12:23:09 +02003666 entry->ct.flow_table = tcf_ct_ft(act);
John Hurley6749d5902019-07-23 15:33:59 +01003667 } else if (is_tcf_mpls(act)) {
3668 switch (tcf_mpls_action(act)) {
3669 case TCA_MPLS_ACT_PUSH:
3670 entry->id = FLOW_ACTION_MPLS_PUSH;
3671 entry->mpls_push.proto = tcf_mpls_proto(act);
3672 entry->mpls_push.label = tcf_mpls_label(act);
3673 entry->mpls_push.tc = tcf_mpls_tc(act);
3674 entry->mpls_push.bos = tcf_mpls_bos(act);
3675 entry->mpls_push.ttl = tcf_mpls_ttl(act);
3676 break;
3677 case TCA_MPLS_ACT_POP:
3678 entry->id = FLOW_ACTION_MPLS_POP;
3679 entry->mpls_pop.proto = tcf_mpls_proto(act);
3680 break;
3681 case TCA_MPLS_ACT_MODIFY:
3682 entry->id = FLOW_ACTION_MPLS_MANGLE;
3683 entry->mpls_mangle.label = tcf_mpls_label(act);
3684 entry->mpls_mangle.tc = tcf_mpls_tc(act);
3685 entry->mpls_mangle.bos = tcf_mpls_bos(act);
3686 entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
3687 break;
3688 default:
Vlad Buslov7a472812020-02-17 12:12:09 +02003689 goto err_out_locked;
John Hurley6749d5902019-07-23 15:33:59 +01003690 }
John Hurleyfb1b7752019-08-04 16:09:04 +01003691 } else if (is_tcf_skbedit_ptype(act)) {
3692 entry->id = FLOW_ACTION_PTYPE;
3693 entry->ptype = tcf_skbedit_ptype(act);
Petr Machata2ce12412020-03-19 15:47:21 +02003694 } else if (is_tcf_skbedit_priority(act)) {
3695 entry->id = FLOW_ACTION_PRIORITY;
3696 entry->priority = tcf_skbedit_priority(act);
Po Liud29bdd62020-05-01 08:53:16 +08003697 } else if (is_tcf_gate(act)) {
3698 entry->id = FLOW_ACTION_GATE;
3699 entry->gate.index = tcf_gate_index(act);
3700 entry->gate.prio = tcf_gate_prio(act);
3701 entry->gate.basetime = tcf_gate_basetime(act);
3702 entry->gate.cycletime = tcf_gate_cycletime(act);
3703 entry->gate.cycletimeext = tcf_gate_cycletimeext(act);
3704 entry->gate.num_entries = tcf_gate_num_entries(act);
3705 err = tcf_gate_get_entries(entry, act);
3706 if (err)
3707 goto err_out;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003708 } else {
Vlad Buslov9838b202019-08-26 16:45:03 +03003709 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003710 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003711 }
Vlad Buslov7a472812020-02-17 12:12:09 +02003712 spin_unlock_bh(&act->tcfa_lock);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003713
3714 if (!is_tcf_pedit(act))
3715 j++;
3716 }
Vlad Buslov9838b202019-08-26 16:45:03 +03003717
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003718err_out:
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003719 if (err)
3720 tc_cleanup_flow_action(flow_action);
3721
Vlad Buslov9838b202019-08-26 16:45:03 +03003722 return err;
Vlad Buslov7a472812020-02-17 12:12:09 +02003723err_out_locked:
3724 spin_unlock_bh(&act->tcfa_lock);
3725 goto err_out;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003726}
3727EXPORT_SYMBOL(tc_setup_flow_action);
3728
Pablo Neira Ayusoe3ab7862019-02-02 12:50:45 +01003729unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
3730{
3731 unsigned int num_acts = 0;
3732 struct tc_action *act;
3733 int i;
3734
3735 tcf_exts_for_each_action(i, act, exts) {
3736 if (is_tcf_pedit(act))
3737 num_acts += tcf_pedit_nkeys(act);
3738 else
3739 num_acts++;
3740 }
3741 return num_acts;
3742}
3743EXPORT_SYMBOL(tcf_exts_num_actions);
3744
Jiri Pirko48617382018-01-17 11:46:46 +01003745static __net_init int tcf_net_init(struct net *net)
3746{
3747 struct tcf_net *tn = net_generic(net, tcf_net_id);
3748
Vlad Buslovab281622018-09-24 19:22:56 +03003749 spin_lock_init(&tn->idr_lock);
Jiri Pirko48617382018-01-17 11:46:46 +01003750 idr_init(&tn->idr);
3751 return 0;
3752}
3753
3754static void __net_exit tcf_net_exit(struct net *net)
3755{
3756 struct tcf_net *tn = net_generic(net, tcf_net_id);
3757
3758 idr_destroy(&tn->idr);
3759}
3760
3761static struct pernet_operations tcf_net_ops = {
3762 .init = tcf_net_init,
3763 .exit = tcf_net_exit,
3764 .id = &tcf_net_id,
3765 .size = sizeof(struct tcf_net),
3766};
3767
John Hurley25a443f2019-12-05 17:03:35 +00003768static struct flow_indr_block_entry block_entry = {
3769 .cb = tc_indr_block_get_and_cmd,
3770 .list = LIST_HEAD_INIT(block_entry.list),
wenxu1150ab02019-08-07 09:13:53 +08003771};
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773static int __init tc_filter_init(void)
3774{
Jiri Pirko48617382018-01-17 11:46:46 +01003775 int err;
3776
Cong Wang7aa00452017-10-26 18:24:28 -07003777 tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0);
3778 if (!tc_filter_wq)
3779 return -ENOMEM;
3780
Jiri Pirko48617382018-01-17 11:46:46 +01003781 err = register_pernet_subsys(&tcf_net_ops);
3782 if (err)
3783 goto err_register_pernet_subsys;
3784
John Hurley25a443f2019-12-05 17:03:35 +00003785 flow_indr_add_block_cb(&block_entry);
wenxu1150ab02019-08-07 09:13:53 +08003786
Vlad Buslov470502d2019-02-11 10:55:48 +02003787 rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_new_tfilter, NULL,
3788 RTNL_FLAG_DOIT_UNLOCKED);
3789 rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_del_tfilter, NULL,
3790 RTNL_FLAG_DOIT_UNLOCKED);
Vlad Buslovc431f892018-05-31 09:52:53 +03003791 rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_get_tfilter,
Vlad Buslov470502d2019-02-11 10:55:48 +02003792 tc_dump_tfilter, RTNL_FLAG_DOIT_UNLOCKED);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003793 rtnl_register(PF_UNSPEC, RTM_NEWCHAIN, tc_ctl_chain, NULL, 0);
3794 rtnl_register(PF_UNSPEC, RTM_DELCHAIN, tc_ctl_chain, NULL, 0);
3795 rtnl_register(PF_UNSPEC, RTM_GETCHAIN, tc_ctl_chain,
3796 tc_dump_chain, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 return 0;
Jiri Pirko48617382018-01-17 11:46:46 +01003799
3800err_register_pernet_subsys:
3801 destroy_workqueue(tc_filter_wq);
3802 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803}
3804
3805subsys_initcall(tc_filter_init);