blob: cb2c10e0fee5dbe755af80b373aa2940df5e203f [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,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03001854 bool terse_dump, 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;
Vlad Buslovf8ab1802020-05-15 14:40:11 +03001881 } else if (terse_dump) {
1882 if (tp->ops->terse_dump) {
1883 if (tp->ops->terse_dump(net, tp, fh, skb, tcm,
1884 rtnl_held) < 0)
1885 goto nla_put_failure;
1886 } else {
1887 goto cls_op_not_supp;
1888 }
WANG Cong71203712017-08-07 15:26:50 -07001889 } else {
Vlad Buslov12db03b2019-02-11 10:55:45 +02001890 if (tp->ops->dump &&
1891 tp->ops->dump(net, tp, fh, skb, tcm, rtnl_held) < 0)
WANG Cong71203712017-08-07 15:26:50 -07001892 goto nla_put_failure;
1893 }
1894 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
1895 return skb->len;
1896
1897out_nlmsg_trim:
1898nla_put_failure:
Vlad Buslovf8ab1802020-05-15 14:40:11 +03001899cls_op_not_supp:
WANG Cong71203712017-08-07 15:26:50 -07001900 nlmsg_trim(skb, b);
1901 return -1;
1902}
1903
1904static int tfilter_notify(struct net *net, struct sk_buff *oskb,
1905 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001906 struct tcf_block *block, struct Qdisc *q,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001907 u32 parent, void *fh, int event, bool unicast,
1908 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001909{
1910 struct sk_buff *skb;
1911 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001912 int err = 0;
WANG Cong71203712017-08-07 15:26:50 -07001913
1914 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1915 if (!skb)
1916 return -ENOBUFS;
1917
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001918 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001919 n->nlmsg_seq, n->nlmsg_flags, event,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03001920 false, rtnl_held) <= 0) {
WANG Cong71203712017-08-07 15:26:50 -07001921 kfree_skb(skb);
1922 return -EINVAL;
1923 }
1924
1925 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001926 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1927 else
1928 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1929 n->nlmsg_flags & NLM_F_ECHO);
WANG Cong71203712017-08-07 15:26:50 -07001930
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001931 if (err > 0)
1932 err = 0;
1933 return err;
WANG Cong71203712017-08-07 15:26:50 -07001934}
1935
1936static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
1937 struct nlmsghdr *n, struct tcf_proto *tp,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001938 struct tcf_block *block, struct Qdisc *q,
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001939 u32 parent, void *fh, bool unicast, bool *last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001940 bool rtnl_held, struct netlink_ext_ack *extack)
WANG Cong71203712017-08-07 15:26:50 -07001941{
1942 struct sk_buff *skb;
1943 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
1944 int err;
1945
1946 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1947 if (!skb)
1948 return -ENOBUFS;
1949
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001950 if (tcf_fill_node(net, skb, tp, block, q, parent, fh, portid,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001951 n->nlmsg_seq, n->nlmsg_flags, RTM_DELTFILTER,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03001952 false, rtnl_held) <= 0) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001953 NL_SET_ERR_MSG(extack, "Failed to build del event notification");
WANG Cong71203712017-08-07 15:26:50 -07001954 kfree_skb(skb);
1955 return -EINVAL;
1956 }
1957
Vlad Buslov12db03b2019-02-11 10:55:45 +02001958 err = tp->ops->delete(tp, fh, last, rtnl_held, extack);
WANG Cong71203712017-08-07 15:26:50 -07001959 if (err) {
1960 kfree_skb(skb);
1961 return err;
1962 }
1963
1964 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001965 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
1966 else
1967 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
1968 n->nlmsg_flags & NLM_F_ECHO);
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001969 if (err < 0)
1970 NL_SET_ERR_MSG(extack, "Failed to send filter delete notification");
Zhike Wang5b5f99b2019-03-11 03:15:54 -07001971
1972 if (err > 0)
1973 err = 0;
Alexander Aringc35a4ac2018-01-18 11:20:50 -05001974 return err;
WANG Cong71203712017-08-07 15:26:50 -07001975}
1976
1977static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001978 struct tcf_block *block, struct Qdisc *q,
1979 u32 parent, struct nlmsghdr *n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001980 struct tcf_chain *chain, int event,
1981 bool rtnl_held)
WANG Cong71203712017-08-07 15:26:50 -07001982{
1983 struct tcf_proto *tp;
1984
Vlad Buslov12db03b2019-02-11 10:55:45 +02001985 for (tp = tcf_get_next_proto(chain, NULL, rtnl_held);
1986 tp; tp = tcf_get_next_proto(chain, tp, rtnl_held))
Jiri Pirko7960d1d2018-01-17 11:46:51 +01001987 tfilter_notify(net, oskb, n, tp, block,
Vlad Buslov12db03b2019-02-11 10:55:45 +02001988 q, parent, NULL, event, false, rtnl_held);
WANG Cong71203712017-08-07 15:26:50 -07001989}
1990
Vlad Buslov7d5509f2019-02-11 10:55:44 +02001991static void tfilter_put(struct tcf_proto *tp, void *fh)
1992{
1993 if (tp->ops->put && fh)
1994 tp->ops->put(tp, fh);
1995}
1996
Vlad Buslovc431f892018-05-31 09:52:53 +03001997static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
David Ahernc21ef3e2017-04-16 09:48:24 -07001998 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002000 struct net *net = sock_net(skb->sk);
Patrick McHardyadd93b62008-01-22 22:11:33 -08002001 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07002002 char name[IFNAMSIZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 struct tcmsg *t;
2004 u32 protocol;
2005 u32 prio;
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002006 bool prio_allocate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002008 u32 chain_index;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002009 struct Qdisc *q = NULL;
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002010 struct tcf_chain_info chain_info;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002011 struct tcf_chain *chain = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02002012 struct tcf_block *block;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 struct tcf_proto *tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 unsigned long cl;
WANG Cong8113c092017-08-04 21:31:43 -07002015 void *fh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 int err;
Daniel Borkmann628185c2016-12-21 18:04:11 +01002017 int tp_created;
Vlad Buslov470502d2019-02-11 10:55:48 +02002018 bool rtnl_held = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Vlad Buslovc431f892018-05-31 09:52:53 +03002020 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
Eric W. Biedermandfc47ef2012-11-16 03:03:00 +00002021 return -EPERM;
Hong zhi guode179c82013-03-25 17:36:33 +00002022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023replay:
Daniel Borkmann628185c2016-12-21 18:04:11 +01002024 tp_created = 0;
2025
Johannes Berg8cb08172019-04-26 14:07:28 +02002026 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2027 rtm_tca_policy, extack);
Hong zhi guode179c82013-03-25 17:36:33 +00002028 if (err < 0)
2029 return err;
2030
David S. Miller942b8162012-06-26 21:48:50 -07002031 t = nlmsg_data(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 protocol = TC_H_MIN(t->tcm_info);
2033 prio = TC_H_MAJ(t->tcm_info);
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002034 prio_allocate = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 parent = t->tcm_parent;
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002036 tp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 cl = 0;
Vlad Buslov470502d2019-02-11 10:55:48 +02002038 block = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
2040 if (prio == 0) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002041 /* If no priority is provided by the user,
2042 * we allocate one.
2043 */
2044 if (n->nlmsg_flags & NLM_F_CREATE) {
2045 prio = TC_H_MAKE(0x80000000U, 0U);
2046 prio_allocate = true;
2047 } else {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002048 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 return -ENOENT;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 }
2052
2053 /* Find head of filter chain. */
2054
Vlad Buslov470502d2019-02-11 10:55:48 +02002055 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2056 if (err)
2057 return err;
2058
Cong Wang6f96c3c2019-10-07 13:26:28 -07002059 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2060 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2061 err = -EINVAL;
2062 goto errout;
2063 }
2064
Vlad Buslov470502d2019-02-11 10:55:48 +02002065 /* Take rtnl mutex if rtnl_held was set to true on previous iteration,
2066 * block is shared (no qdisc found), qdisc is not unlocked, classifier
2067 * type is not specified, classifier is not unlocked.
2068 */
2069 if (rtnl_held ||
2070 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002071 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002072 rtnl_held = true;
2073 rtnl_lock();
2074 }
2075
2076 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2077 if (err)
2078 goto errout;
2079
2080 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2081 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002082 if (IS_ERR(block)) {
2083 err = PTR_ERR(block);
2084 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002085 }
Cong Wanga7df4872020-04-30 20:53:49 -07002086 block->classid = parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002087
2088 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2089 if (chain_index > TC_ACT_EXT_VAL_MASK) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002090 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Jiri Pirko5bc17012017-05-17 11:08:01 +02002091 err = -EINVAL;
2092 goto errout;
2093 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002094 chain = tcf_chain_get(block, chain_index, true);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002095 if (!chain) {
Jiri Pirkod5ed72a2018-08-27 20:58:43 +02002096 NL_SET_ERR_MSG(extack, "Cannot create specified filter chain");
Vlad Buslovc431f892018-05-31 09:52:53 +03002097 err = -ENOMEM;
Daniel Borkmannea7f8272016-06-10 23:10:22 +02002098 goto errout;
2099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Vlad Busloved76f5e2019-02-11 10:55:38 +02002101 mutex_lock(&chain->filter_chain_lock);
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002102 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2103 prio, prio_allocate);
2104 if (IS_ERR(tp)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002105 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Jiri Pirko2190d1d2017-05-17 11:07:59 +02002106 err = PTR_ERR(tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002107 goto errout_locked;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 }
2109
2110 if (tp == NULL) {
Vlad Buslov8b646782019-02-11 10:55:41 +02002111 struct tcf_proto *tp_new = NULL;
2112
Vlad Buslov726d06122019-02-11 10:55:42 +02002113 if (chain->flushing) {
2114 err = -EAGAIN;
2115 goto errout_locked;
2116 }
2117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 /* Proto-tcf does not exist, create new one */
2119
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002120 if (tca[TCA_KIND] == NULL || !protocol) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002121 NL_SET_ERR_MSG(extack, "Filter kind and protocol must be specified");
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002122 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002123 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Vlad Buslovc431f892018-05-31 09:52:53 +03002126 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002127 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 +01002128 err = -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002129 goto errout_locked;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Jiri Pirko9d36d9e2017-05-17 11:07:57 +02002132 if (prio_allocate)
Vlad Busloved76f5e2019-02-11 10:55:38 +02002133 prio = tcf_auto_prio(tcf_chain_tp_prev(chain,
2134 &chain_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Vlad Busloved76f5e2019-02-11 10:55:38 +02002136 mutex_unlock(&chain->filter_chain_lock);
Eric Dumazet36d79af2020-01-21 11:02:20 -08002137 tp_new = tcf_proto_create(name, protocol, prio, chain,
2138 rtnl_held, extack);
Vlad Buslov8b646782019-02-11 10:55:41 +02002139 if (IS_ERR(tp_new)) {
2140 err = PTR_ERR(tp_new);
Vlad Buslov726d06122019-02-11 10:55:42 +02002141 goto errout_tp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002143
Minoru Usui12186be2009-06-02 02:17:34 -07002144 tp_created = 1;
Vlad Buslov12db03b2019-02-11 10:55:45 +02002145 tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio,
2146 rtnl_held);
Vlad Buslov726d06122019-02-11 10:55:42 +02002147 if (IS_ERR(tp)) {
2148 err = PTR_ERR(tp);
2149 goto errout_tp;
2150 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002151 } else {
2152 mutex_unlock(&chain->filter_chain_lock);
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Vlad Buslov8b646782019-02-11 10:55:41 +02002155 if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2156 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2157 err = -EINVAL;
2158 goto errout;
2159 }
2160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 fh = tp->ops->get(tp, t->tcm_handle);
2162
WANG Cong8113c092017-08-04 21:31:43 -07002163 if (!fh) {
Vlad Buslovc431f892018-05-31 09:52:53 +03002164 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
Alexander Aringc35a4ac2018-01-18 11:20:50 -05002165 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 +01002166 err = -ENOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 goto errout;
Jiri Pirko6bb16e72017-02-09 14:38:58 +01002168 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002169 } else if (n->nlmsg_flags & NLM_F_EXCL) {
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002170 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002171 NL_SET_ERR_MSG(extack, "Filter already exists");
2172 err = -EEXIST;
2173 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 }
2175
Jiri Pirko9f407f12018-07-23 09:23:07 +02002176 if (chain->tmplt_ops && chain->tmplt_ops != tp->ops) {
2177 NL_SET_ERR_MSG(extack, "Chain template is set to a different filter kind");
2178 err = -EINVAL;
2179 goto errout;
2180 }
2181
Cong Wang2f7ef2f2014-04-25 13:54:06 -07002182 err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
Alexander Aring7306db32018-01-18 11:20:51 -05002183 n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002184 rtnl_held, extack);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002185 if (err == 0) {
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002186 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002187 RTM_NEWTFILTER, false, rtnl_held);
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002188 tfilter_put(tp, fh);
Vlad Buslov503d81d2019-07-21 17:44:12 +03002189 /* q pointer is NULL for shared blocks */
2190 if (q)
2191 q->flags &= ~TCQ_F_CAN_BYPASS;
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
2194errout:
Vlad Buslov8b646782019-02-11 10:55:41 +02002195 if (err && tp_created)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002196 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL);
Vlad Buslov726d06122019-02-11 10:55:42 +02002197errout_tp:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002198 if (chain) {
2199 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002200 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002201 if (!tp_created)
2202 tcf_chain_put(chain);
2203 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002204 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002205
2206 if (rtnl_held)
2207 rtnl_unlock();
2208
2209 if (err == -EAGAIN) {
2210 /* Take rtnl lock in case EAGAIN is caused by concurrent flush
2211 * of target chain.
2212 */
2213 rtnl_held = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 /* Replay the request. */
2215 goto replay;
Vlad Buslov470502d2019-02-11 10:55:48 +02002216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002218
2219errout_locked:
2220 mutex_unlock(&chain->filter_chain_lock);
2221 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222}
2223
Vlad Buslovc431f892018-05-31 09:52:53 +03002224static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2225 struct netlink_ext_ack *extack)
2226{
2227 struct net *net = sock_net(skb->sk);
2228 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07002229 char name[IFNAMSIZ];
Vlad Buslovc431f892018-05-31 09:52:53 +03002230 struct tcmsg *t;
2231 u32 protocol;
2232 u32 prio;
2233 u32 parent;
2234 u32 chain_index;
2235 struct Qdisc *q = NULL;
2236 struct tcf_chain_info chain_info;
2237 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002238 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002239 struct tcf_proto *tp = NULL;
2240 unsigned long cl = 0;
2241 void *fh = NULL;
2242 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002243 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002244
2245 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2246 return -EPERM;
2247
Johannes Berg8cb08172019-04-26 14:07:28 +02002248 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2249 rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002250 if (err < 0)
2251 return err;
2252
2253 t = nlmsg_data(n);
2254 protocol = TC_H_MIN(t->tcm_info);
2255 prio = TC_H_MAJ(t->tcm_info);
2256 parent = t->tcm_parent;
2257
2258 if (prio == 0 && (protocol || t->tcm_handle || tca[TCA_KIND])) {
2259 NL_SET_ERR_MSG(extack, "Cannot flush filters with protocol, handle or kind set");
2260 return -ENOENT;
2261 }
2262
2263 /* Find head of filter chain. */
2264
Vlad Buslov470502d2019-02-11 10:55:48 +02002265 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2266 if (err)
2267 return err;
2268
Cong Wang6f96c3c2019-10-07 13:26:28 -07002269 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2270 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2271 err = -EINVAL;
2272 goto errout;
2273 }
Vlad Buslov470502d2019-02-11 10:55:48 +02002274 /* Take rtnl mutex if flushing whole chain, block is shared (no qdisc
2275 * found), qdisc is not unlocked, classifier type is not specified,
2276 * classifier is not unlocked.
2277 */
2278 if (!prio ||
2279 (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002280 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002281 rtnl_held = true;
2282 rtnl_lock();
2283 }
2284
2285 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2286 if (err)
2287 goto errout;
2288
2289 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2290 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002291 if (IS_ERR(block)) {
2292 err = PTR_ERR(block);
2293 goto errout;
2294 }
2295
2296 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2297 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2298 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2299 err = -EINVAL;
2300 goto errout;
2301 }
2302 chain = tcf_chain_get(block, chain_index, false);
2303 if (!chain) {
Jiri Pirko5ca8a252018-08-03 11:08:47 +02002304 /* User requested flush on non-existent chain. Nothing to do,
2305 * so just return success.
2306 */
2307 if (prio == 0) {
2308 err = 0;
2309 goto errout;
2310 }
Vlad Buslovc431f892018-05-31 09:52:53 +03002311 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Jiri Pirkob7b42472018-08-27 20:58:44 +02002312 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002313 goto errout;
2314 }
2315
2316 if (prio == 0) {
2317 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002318 chain, RTM_DELTFILTER, rtnl_held);
2319 tcf_chain_flush(chain, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002320 err = 0;
2321 goto errout;
2322 }
2323
Vlad Busloved76f5e2019-02-11 10:55:38 +02002324 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002325 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2326 prio, false);
2327 if (!tp || IS_ERR(tp)) {
2328 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002329 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002330 goto errout_locked;
Vlad Buslovc431f892018-05-31 09:52:53 +03002331 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2332 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2333 err = -EINVAL;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002334 goto errout_locked;
2335 } else if (t->tcm_handle == 0) {
John Hurley59eb87c2019-11-02 14:17:47 +00002336 tcf_proto_signal_destroying(chain, tp);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002337 tcf_chain_tp_remove(chain, &chain_info, tp);
2338 mutex_unlock(&chain->filter_chain_lock);
2339
Vlad Buslov12db03b2019-02-11 10:55:45 +02002340 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002341 tfilter_notify(net, skb, n, tp, block, q, parent, fh,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002342 RTM_DELTFILTER, false, rtnl_held);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002343 err = 0;
Vlad Buslovc431f892018-05-31 09:52:53 +03002344 goto errout;
2345 }
Vlad Busloved76f5e2019-02-11 10:55:38 +02002346 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002347
2348 fh = tp->ops->get(tp, t->tcm_handle);
2349
2350 if (!fh) {
Vlad Busloved76f5e2019-02-11 10:55:38 +02002351 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2352 err = -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002353 } else {
2354 bool last;
2355
2356 err = tfilter_del_notify(net, skb, n, tp, block,
2357 q, parent, fh, false, &last,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002358 rtnl_held, extack);
2359
Vlad Buslovc431f892018-05-31 09:52:53 +03002360 if (err)
2361 goto errout;
Vlad Buslov8b646782019-02-11 10:55:41 +02002362 if (last)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002363 tcf_chain_tp_delete_empty(chain, tp, rtnl_held, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002364 }
2365
2366errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002367 if (chain) {
2368 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002369 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002370 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002371 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002372 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002373
2374 if (rtnl_held)
2375 rtnl_unlock();
2376
Vlad Buslovc431f892018-05-31 09:52:53 +03002377 return err;
Vlad Busloved76f5e2019-02-11 10:55:38 +02002378
2379errout_locked:
2380 mutex_unlock(&chain->filter_chain_lock);
2381 goto errout;
Vlad Buslovc431f892018-05-31 09:52:53 +03002382}
2383
2384static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
2385 struct netlink_ext_ack *extack)
2386{
2387 struct net *net = sock_net(skb->sk);
2388 struct nlattr *tca[TCA_MAX + 1];
Cong Wang6f96c3c2019-10-07 13:26:28 -07002389 char name[IFNAMSIZ];
Vlad Buslovc431f892018-05-31 09:52:53 +03002390 struct tcmsg *t;
2391 u32 protocol;
2392 u32 prio;
2393 u32 parent;
2394 u32 chain_index;
2395 struct Qdisc *q = NULL;
2396 struct tcf_chain_info chain_info;
2397 struct tcf_chain *chain = NULL;
Vlad Buslov470502d2019-02-11 10:55:48 +02002398 struct tcf_block *block = NULL;
Vlad Buslovc431f892018-05-31 09:52:53 +03002399 struct tcf_proto *tp = NULL;
2400 unsigned long cl = 0;
2401 void *fh = NULL;
2402 int err;
Vlad Buslov470502d2019-02-11 10:55:48 +02002403 bool rtnl_held = false;
Vlad Buslovc431f892018-05-31 09:52:53 +03002404
Johannes Berg8cb08172019-04-26 14:07:28 +02002405 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2406 rtm_tca_policy, extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002407 if (err < 0)
2408 return err;
2409
2410 t = nlmsg_data(n);
2411 protocol = TC_H_MIN(t->tcm_info);
2412 prio = TC_H_MAJ(t->tcm_info);
2413 parent = t->tcm_parent;
2414
2415 if (prio == 0) {
2416 NL_SET_ERR_MSG(extack, "Invalid filter command with priority of zero");
2417 return -ENOENT;
2418 }
2419
2420 /* Find head of filter chain. */
2421
Vlad Buslov470502d2019-02-11 10:55:48 +02002422 err = __tcf_qdisc_find(net, &q, &parent, t->tcm_ifindex, false, extack);
2423 if (err)
2424 return err;
2425
Cong Wang6f96c3c2019-10-07 13:26:28 -07002426 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2427 NL_SET_ERR_MSG(extack, "Specified TC filter name too long");
2428 err = -EINVAL;
2429 goto errout;
2430 }
Vlad Buslov470502d2019-02-11 10:55:48 +02002431 /* Take rtnl mutex if block is shared (no qdisc found), qdisc is not
2432 * unlocked, classifier type is not specified, classifier is not
2433 * unlocked.
2434 */
2435 if ((q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) ||
Cong Wang6f96c3c2019-10-07 13:26:28 -07002436 !tcf_proto_is_unlocked(name)) {
Vlad Buslov470502d2019-02-11 10:55:48 +02002437 rtnl_held = true;
2438 rtnl_lock();
2439 }
2440
2441 err = __tcf_qdisc_cl_find(q, parent, &cl, t->tcm_ifindex, extack);
2442 if (err)
2443 goto errout;
2444
2445 block = __tcf_block_find(net, q, cl, t->tcm_ifindex, t->tcm_block_index,
2446 extack);
Vlad Buslovc431f892018-05-31 09:52:53 +03002447 if (IS_ERR(block)) {
2448 err = PTR_ERR(block);
2449 goto errout;
2450 }
2451
2452 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2453 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2454 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
2455 err = -EINVAL;
2456 goto errout;
2457 }
2458 chain = tcf_chain_get(block, chain_index, false);
2459 if (!chain) {
2460 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
2461 err = -EINVAL;
2462 goto errout;
2463 }
2464
Vlad Busloved76f5e2019-02-11 10:55:38 +02002465 mutex_lock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002466 tp = tcf_chain_tp_find(chain, &chain_info, protocol,
2467 prio, false);
Vlad Busloved76f5e2019-02-11 10:55:38 +02002468 mutex_unlock(&chain->filter_chain_lock);
Vlad Buslovc431f892018-05-31 09:52:53 +03002469 if (!tp || IS_ERR(tp)) {
2470 NL_SET_ERR_MSG(extack, "Filter with specified priority/protocol not found");
Vlad Buslov0e399032018-06-04 18:32:23 +03002471 err = tp ? PTR_ERR(tp) : -ENOENT;
Vlad Buslovc431f892018-05-31 09:52:53 +03002472 goto errout;
2473 } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind)) {
2474 NL_SET_ERR_MSG(extack, "Specified filter kind does not match existing one");
2475 err = -EINVAL;
2476 goto errout;
2477 }
2478
2479 fh = tp->ops->get(tp, t->tcm_handle);
2480
2481 if (!fh) {
2482 NL_SET_ERR_MSG(extack, "Specified filter handle not found");
2483 err = -ENOENT;
2484 } else {
2485 err = tfilter_notify(net, skb, n, tp, block, q, parent,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002486 fh, RTM_NEWTFILTER, true, rtnl_held);
Vlad Buslovc431f892018-05-31 09:52:53 +03002487 if (err < 0)
2488 NL_SET_ERR_MSG(extack, "Failed to send filter notify message");
2489 }
2490
Vlad Buslov7d5509f2019-02-11 10:55:44 +02002491 tfilter_put(tp, fh);
Vlad Buslovc431f892018-05-31 09:52:53 +03002492errout:
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002493 if (chain) {
2494 if (tp && !IS_ERR(tp))
Vlad Buslov12db03b2019-02-11 10:55:45 +02002495 tcf_proto_put(tp, rtnl_held, NULL);
Vlad Buslovc431f892018-05-31 09:52:53 +03002496 tcf_chain_put(chain);
Vlad Buslov4dbfa762019-02-11 10:55:39 +02002497 }
Vlad Buslov12db03b2019-02-11 10:55:45 +02002498 tcf_block_release(q, block, rtnl_held);
Vlad Buslov470502d2019-02-11 10:55:48 +02002499
2500 if (rtnl_held)
2501 rtnl_unlock();
2502
Vlad Buslovc431f892018-05-31 09:52:53 +03002503 return err;
2504}
2505
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002506struct tcf_dump_args {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 struct tcf_walker w;
2508 struct sk_buff *skb;
2509 struct netlink_callback *cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002510 struct tcf_block *block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002511 struct Qdisc *q;
2512 u32 parent;
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002513 bool terse_dump;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514};
2515
WANG Cong8113c092017-08-04 21:31:43 -07002516static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517{
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08002518 struct tcf_dump_args *a = (void *)arg;
WANG Cong832d1d52014-01-09 16:14:01 -08002519 struct net *net = sock_net(a->skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002521 return tcf_fill_node(net, a->skb, tp, a->block, a->q, a->parent,
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002522 n, NETLINK_CB(a->cb->skb).portid,
Jamal Hadi Salim5a7a5552016-09-18 08:45:33 -04002523 a->cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002524 RTM_NEWTFILTER, a->terse_dump, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525}
2526
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002527static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
2528 struct sk_buff *skb, struct netlink_callback *cb,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002529 long index_start, long *p_index, bool terse)
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002530{
2531 struct net *net = sock_net(skb->sk);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002532 struct tcf_block *block = chain->block;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002533 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002534 struct tcf_proto *tp, *tp_prev;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002535 struct tcf_dump_args arg;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002536
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002537 for (tp = __tcf_get_next_proto(chain, NULL);
2538 tp;
2539 tp_prev = tp,
2540 tp = __tcf_get_next_proto(chain, tp),
Vlad Buslov12db03b2019-02-11 10:55:45 +02002541 tcf_proto_put(tp_prev, true, NULL),
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002542 (*p_index)++) {
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002543 if (*p_index < index_start)
2544 continue;
2545 if (TC_H_MAJ(tcm->tcm_info) &&
2546 TC_H_MAJ(tcm->tcm_info) != tp->prio)
2547 continue;
2548 if (TC_H_MIN(tcm->tcm_info) &&
2549 TC_H_MIN(tcm->tcm_info) != tp->protocol)
2550 continue;
2551 if (*p_index > index_start)
2552 memset(&cb->args[1], 0,
2553 sizeof(cb->args) - sizeof(cb->args[0]));
2554 if (cb->args[1] == 0) {
YueHaibing53189182018-07-17 20:58:14 +08002555 if (tcf_fill_node(net, skb, tp, block, q, parent, NULL,
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002556 NETLINK_CB(cb->skb).portid,
2557 cb->nlh->nlmsg_seq, NLM_F_MULTI,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002558 RTM_NEWTFILTER, false, true) <= 0)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002559 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002560 cb->args[1] = 1;
2561 }
2562 if (!tp->ops->walk)
2563 continue;
2564 arg.w.fn = tcf_node_dump;
2565 arg.skb = skb;
2566 arg.cb = cb;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002567 arg.block = block;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002568 arg.q = q;
2569 arg.parent = parent;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002570 arg.w.stop = 0;
2571 arg.w.skip = cb->args[1] - 1;
2572 arg.w.count = 0;
Vlad Buslov01683a12018-07-09 13:29:11 +03002573 arg.w.cookie = cb->args[2];
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002574 arg.terse_dump = terse;
Vlad Buslov12db03b2019-02-11 10:55:45 +02002575 tp->ops->walk(tp, &arg.w, true);
Vlad Buslov01683a12018-07-09 13:29:11 +03002576 cb->args[2] = arg.w.cookie;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002577 cb->args[1] = arg.w.count + 1;
2578 if (arg.w.stop)
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002579 goto errout;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002580 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002581 return true;
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002582
2583errout:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002584 tcf_proto_put(tp, true, NULL);
Vlad Buslovfe2923a2019-02-11 10:55:40 +02002585 return false;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002586}
2587
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002588static const struct nla_policy tcf_tfilter_dump_policy[TCA_MAX + 1] = {
2589 [TCA_DUMP_FLAGS] = NLA_POLICY_BITFIELD32(TCA_DUMP_FLAGS_TERSE),
2590};
2591
Eric Dumazetbd27a872009-11-05 20:57:26 -08002592/* called with RTNL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
2594{
Vlad Buslovbbf73832019-02-11 10:55:36 +02002595 struct tcf_chain *chain, *chain_prev;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002596 struct net *net = sock_net(skb->sk);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002597 struct nlattr *tca[TCA_MAX + 1];
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002598 struct Qdisc *q = NULL;
Jiri Pirko6529eab2017-05-17 11:07:55 +02002599 struct tcf_block *block;
David S. Miller942b8162012-06-26 21:48:50 -07002600 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002601 bool terse_dump = false;
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002602 long index_start;
2603 long index;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002604 u32 parent;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002605 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Hong zhi guo573ce262013-03-27 06:47:04 +00002607 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 return skb->len;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002609
Johannes Berg8cb08172019-04-26 14:07:28 +02002610 err = nlmsg_parse_deprecated(cb->nlh, sizeof(*tcm), tca, TCA_MAX,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002611 tcf_tfilter_dump_policy, cb->extack);
Jiri Pirko5bc17012017-05-17 11:08:01 +02002612 if (err)
2613 return err;
2614
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002615 if (tca[TCA_DUMP_FLAGS]) {
2616 struct nla_bitfield32 flags =
2617 nla_get_bitfield32(tca[TCA_DUMP_FLAGS]);
2618
2619 terse_dump = flags.value & TCA_DUMP_FLAGS_TERSE;
2620 }
2621
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002622 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002623 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002624 if (!block)
WANG Cong143976c2017-08-24 16:51:29 -07002625 goto out;
Jiri Pirkod680b352018-01-18 16:14:49 +01002626 /* If we work with block index, q is NULL and parent value
2627 * will never be used in the following code. The check
2628 * in tcf_fill_node prevents it. However, compiler does not
2629 * see that far, so set parent to zero to silence the warning
2630 * about parent being uninitialized.
2631 */
2632 parent = 0;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002633 } else {
2634 const struct Qdisc_class_ops *cops;
2635 struct net_device *dev;
2636 unsigned long cl = 0;
2637
2638 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
2639 if (!dev)
2640 return skb->len;
2641
2642 parent = tcm->tcm_parent;
Cong Wanga7df4872020-04-30 20:53:49 -07002643 if (!parent)
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002644 q = dev->qdisc;
Cong Wanga7df4872020-04-30 20:53:49 -07002645 else
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002646 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002647 if (!q)
2648 goto out;
2649 cops = q->ops->cl_ops;
2650 if (!cops)
2651 goto out;
2652 if (!cops->tcf_block)
2653 goto out;
2654 if (TC_H_MIN(tcm->tcm_parent)) {
2655 cl = cops->find(q, tcm->tcm_parent);
2656 if (cl == 0)
2657 goto out;
2658 }
2659 block = cops->tcf_block(q, cl, NULL);
2660 if (!block)
2661 goto out;
Cong Wanga7df4872020-04-30 20:53:49 -07002662 parent = block->classid;
Jiri Pirko7960d1d2018-01-17 11:46:51 +01002663 if (tcf_block_shared(block))
2664 q = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002667 index_start = cb->args[0];
2668 index = 0;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002669
Vlad Buslovbbf73832019-02-11 10:55:36 +02002670 for (chain = __tcf_get_next_chain(block, NULL);
2671 chain;
2672 chain_prev = chain,
2673 chain = __tcf_get_next_chain(block, chain),
2674 tcf_chain_put(chain_prev)) {
Jiri Pirko5bc17012017-05-17 11:08:01 +02002675 if (tca[TCA_CHAIN] &&
2676 nla_get_u32(tca[TCA_CHAIN]) != chain->index)
2677 continue;
Jiri Pirkoa10fa202017-10-13 14:01:05 +02002678 if (!tcf_chain_dump(chain, q, parent, skb, cb,
Vlad Buslovf8ab1802020-05-15 14:40:11 +03002679 index_start, &index, terse_dump)) {
Vlad Buslovbbf73832019-02-11 10:55:36 +02002680 tcf_chain_put(chain);
Roman Kapl5ae437a2018-02-19 21:32:51 +01002681 err = -EMSGSIZE;
Jiri Pirko5bc17012017-05-17 11:08:01 +02002682 break;
Roman Kapl5ae437a2018-02-19 21:32:51 +01002683 }
Jiri Pirko5bc17012017-05-17 11:08:01 +02002684 }
2685
Vlad Buslov787ce6d2018-09-24 19:22:58 +03002686 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02002687 tcf_block_refcnt_put(block, true);
Jiri Pirkoacb31fa2017-05-17 11:08:00 +02002688 cb->args[0] = index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690out:
Roman Kapl5ae437a2018-02-19 21:32:51 +01002691 /* If we did no progress, the error (EMSGSIZE) is real */
2692 if (skb->len == 0 && err)
2693 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 return skb->len;
2695}
2696
Vlad Buslova5654822019-02-11 10:55:37 +02002697static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
2698 void *tmplt_priv, u32 chain_index,
2699 struct net *net, struct sk_buff *skb,
2700 struct tcf_block *block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002701 u32 portid, u32 seq, u16 flags, int event)
2702{
2703 unsigned char *b = skb_tail_pointer(skb);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002704 const struct tcf_proto_ops *ops;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002705 struct nlmsghdr *nlh;
2706 struct tcmsg *tcm;
Jiri Pirko9f407f12018-07-23 09:23:07 +02002707 void *priv;
2708
Vlad Buslova5654822019-02-11 10:55:37 +02002709 ops = tmplt_ops;
2710 priv = tmplt_priv;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002711
2712 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
2713 if (!nlh)
2714 goto out_nlmsg_trim;
2715 tcm = nlmsg_data(nlh);
2716 tcm->tcm_family = AF_UNSPEC;
2717 tcm->tcm__pad1 = 0;
2718 tcm->tcm__pad2 = 0;
2719 tcm->tcm_handle = 0;
2720 if (block->q) {
2721 tcm->tcm_ifindex = qdisc_dev(block->q)->ifindex;
2722 tcm->tcm_parent = block->q->handle;
2723 } else {
2724 tcm->tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
2725 tcm->tcm_block_index = block->index;
2726 }
2727
Vlad Buslova5654822019-02-11 10:55:37 +02002728 if (nla_put_u32(skb, TCA_CHAIN, chain_index))
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002729 goto nla_put_failure;
2730
Jiri Pirko9f407f12018-07-23 09:23:07 +02002731 if (ops) {
2732 if (nla_put_string(skb, TCA_KIND, ops->kind))
2733 goto nla_put_failure;
2734 if (ops->tmplt_dump(skb, net, priv) < 0)
2735 goto nla_put_failure;
2736 }
2737
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002738 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
2739 return skb->len;
2740
2741out_nlmsg_trim:
2742nla_put_failure:
2743 nlmsg_trim(skb, b);
2744 return -EMSGSIZE;
2745}
2746
2747static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
2748 u32 seq, u16 flags, int event, bool unicast)
2749{
2750 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2751 struct tcf_block *block = chain->block;
2752 struct net *net = block->net;
2753 struct sk_buff *skb;
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002754 int err = 0;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002755
2756 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2757 if (!skb)
2758 return -ENOBUFS;
2759
Vlad Buslova5654822019-02-11 10:55:37 +02002760 if (tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
2761 chain->index, net, skb, block, portid,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002762 seq, flags, event) <= 0) {
2763 kfree_skb(skb);
2764 return -EINVAL;
2765 }
2766
2767 if (unicast)
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002768 err = netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2769 else
2770 err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
2771 flags & NLM_F_ECHO);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002772
Zhike Wang5b5f99b2019-03-11 03:15:54 -07002773 if (err > 0)
2774 err = 0;
2775 return err;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002776}
2777
Vlad Buslova5654822019-02-11 10:55:37 +02002778static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
2779 void *tmplt_priv, u32 chain_index,
2780 struct tcf_block *block, struct sk_buff *oskb,
2781 u32 seq, u16 flags, bool unicast)
2782{
2783 u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
2784 struct net *net = block->net;
2785 struct sk_buff *skb;
2786
2787 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2788 if (!skb)
2789 return -ENOBUFS;
2790
2791 if (tc_chain_fill_node(tmplt_ops, tmplt_priv, chain_index, net, skb,
2792 block, portid, seq, flags, RTM_DELCHAIN) <= 0) {
2793 kfree_skb(skb);
2794 return -EINVAL;
2795 }
2796
2797 if (unicast)
2798 return netlink_unicast(net->rtnl, skb, portid, MSG_DONTWAIT);
2799
2800 return rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
2801}
2802
Jiri Pirko9f407f12018-07-23 09:23:07 +02002803static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
2804 struct nlattr **tca,
2805 struct netlink_ext_ack *extack)
2806{
2807 const struct tcf_proto_ops *ops;
Eric Dumazet2dd56162019-12-07 11:34:45 -08002808 char name[IFNAMSIZ];
Jiri Pirko9f407f12018-07-23 09:23:07 +02002809 void *tmplt_priv;
2810
2811 /* If kind is not set, user did not specify template. */
2812 if (!tca[TCA_KIND])
2813 return 0;
2814
Eric Dumazet2dd56162019-12-07 11:34:45 -08002815 if (tcf_proto_check_kind(tca[TCA_KIND], name)) {
2816 NL_SET_ERR_MSG(extack, "Specified TC chain template name too long");
2817 return -EINVAL;
2818 }
2819
2820 ops = tcf_proto_lookup_ops(name, true, extack);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002821 if (IS_ERR(ops))
2822 return PTR_ERR(ops);
2823 if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
2824 NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier");
2825 return -EOPNOTSUPP;
2826 }
2827
2828 tmplt_priv = ops->tmplt_create(net, chain, tca, extack);
2829 if (IS_ERR(tmplt_priv)) {
2830 module_put(ops->owner);
2831 return PTR_ERR(tmplt_priv);
2832 }
2833 chain->tmplt_ops = ops;
2834 chain->tmplt_priv = tmplt_priv;
2835 return 0;
2836}
2837
Vlad Buslova5654822019-02-11 10:55:37 +02002838static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
2839 void *tmplt_priv)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002840{
Jiri Pirko9f407f12018-07-23 09:23:07 +02002841 /* If template ops are set, no work to do for us. */
Vlad Buslova5654822019-02-11 10:55:37 +02002842 if (!tmplt_ops)
Jiri Pirko9f407f12018-07-23 09:23:07 +02002843 return;
2844
Vlad Buslova5654822019-02-11 10:55:37 +02002845 tmplt_ops->tmplt_destroy(tmplt_priv);
2846 module_put(tmplt_ops->owner);
Jiri Pirko9f407f12018-07-23 09:23:07 +02002847}
2848
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002849/* Add/delete/get a chain */
2850
2851static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
2852 struct netlink_ext_ack *extack)
2853{
2854 struct net *net = sock_net(skb->sk);
2855 struct nlattr *tca[TCA_MAX + 1];
2856 struct tcmsg *t;
2857 u32 parent;
2858 u32 chain_index;
2859 struct Qdisc *q = NULL;
2860 struct tcf_chain *chain = NULL;
2861 struct tcf_block *block;
2862 unsigned long cl;
2863 int err;
2864
2865 if (n->nlmsg_type != RTM_GETCHAIN &&
2866 !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))
2867 return -EPERM;
2868
2869replay:
Johannes Berg8cb08172019-04-26 14:07:28 +02002870 err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
2871 rtm_tca_policy, extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002872 if (err < 0)
2873 return err;
2874
2875 t = nlmsg_data(n);
2876 parent = t->tcm_parent;
2877 cl = 0;
2878
2879 block = tcf_block_find(net, &q, &parent, &cl,
2880 t->tcm_ifindex, t->tcm_block_index, extack);
2881 if (IS_ERR(block))
2882 return PTR_ERR(block);
2883
2884 chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
2885 if (chain_index > TC_ACT_EXT_VAL_MASK) {
2886 NL_SET_ERR_MSG(extack, "Specified chain index exceeds upper limit");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002887 err = -EINVAL;
2888 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002889 }
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002890
2891 mutex_lock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002892 chain = tcf_chain_lookup(block, chain_index);
2893 if (n->nlmsg_type == RTM_NEWCHAIN) {
2894 if (chain) {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002895 if (tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002896 /* The chain exists only because there is
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002897 * some action referencing it.
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002898 */
2899 tcf_chain_hold(chain);
2900 } else {
2901 NL_SET_ERR_MSG(extack, "Filter chain already exists");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002902 err = -EEXIST;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002903 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002904 }
2905 } else {
2906 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
2907 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 +03002908 err = -ENOENT;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002909 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002910 }
2911 chain = tcf_chain_create(block, chain_index);
2912 if (!chain) {
2913 NL_SET_ERR_MSG(extack, "Failed to create filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002914 err = -ENOMEM;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002915 goto errout_block_locked;
Jiri Pirko1f3ed382018-07-27 09:45:05 +02002916 }
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002917 }
2918 } else {
Jiri Pirko3d32f4c2018-08-01 12:36:55 +02002919 if (!chain || tcf_chain_held_by_acts_only(chain)) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002920 NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
Vlad Buslove368fdb2018-09-24 19:22:53 +03002921 err = -EINVAL;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002922 goto errout_block_locked;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002923 }
2924 tcf_chain_hold(chain);
2925 }
2926
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002927 if (n->nlmsg_type == RTM_NEWCHAIN) {
2928 /* Modifying chain requires holding parent block lock. In case
2929 * the chain was successfully added, take a reference to the
2930 * chain. This ensures that an empty chain does not disappear at
2931 * the end of this function.
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002932 */
2933 tcf_chain_hold(chain);
2934 chain->explicitly_created = true;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002935 }
2936 mutex_unlock(&block->lock);
2937
2938 switch (n->nlmsg_type) {
2939 case RTM_NEWCHAIN:
2940 err = tc_chain_tmplt_add(chain, net, tca, extack);
2941 if (err) {
2942 tcf_chain_put_explicitly_created(chain);
2943 goto errout;
2944 }
2945
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002946 tc_chain_notify(chain, NULL, 0, NLM_F_CREATE | NLM_F_EXCL,
2947 RTM_NEWCHAIN, false);
2948 break;
2949 case RTM_DELCHAIN:
Cong Wangf5b9bac2018-09-11 14:22:23 -07002950 tfilter_notify_chain(net, skb, block, q, parent, n,
Vlad Buslov12db03b2019-02-11 10:55:45 +02002951 chain, RTM_DELTFILTER, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002952 /* Flush the chain first as the user requested chain removal. */
Vlad Buslov12db03b2019-02-11 10:55:45 +02002953 tcf_chain_flush(chain, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002954 /* In case the chain was successfully deleted, put a reference
2955 * to the chain previously taken during addition.
2956 */
2957 tcf_chain_put_explicitly_created(chain);
2958 break;
2959 case RTM_GETCHAIN:
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002960 err = tc_chain_notify(chain, skb, n->nlmsg_seq,
2961 n->nlmsg_seq, n->nlmsg_type, true);
2962 if (err < 0)
2963 NL_SET_ERR_MSG(extack, "Failed to send chain notify message");
2964 break;
2965 default:
2966 err = -EOPNOTSUPP;
2967 NL_SET_ERR_MSG(extack, "Unsupported message type");
2968 goto errout;
2969 }
2970
2971errout:
2972 tcf_chain_put(chain);
Vlad Buslove368fdb2018-09-24 19:22:53 +03002973errout_block:
Vlad Buslov12db03b2019-02-11 10:55:45 +02002974 tcf_block_release(q, block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002975 if (err == -EAGAIN)
2976 /* Replay the request. */
2977 goto replay;
2978 return err;
Vlad Buslov2cbfab02019-02-11 10:55:34 +02002979
2980errout_block_locked:
2981 mutex_unlock(&block->lock);
2982 goto errout_block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002983}
2984
2985/* called with RTNL */
2986static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
2987{
2988 struct net *net = sock_net(skb->sk);
2989 struct nlattr *tca[TCA_MAX + 1];
2990 struct Qdisc *q = NULL;
2991 struct tcf_block *block;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002992 struct tcmsg *tcm = nlmsg_data(cb->nlh);
Vlad Buslovace4a262019-02-25 17:45:44 +02002993 struct tcf_chain *chain;
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02002994 long index_start;
2995 long index;
2996 u32 parent;
2997 int err;
2998
2999 if (nlmsg_len(cb->nlh) < sizeof(*tcm))
3000 return skb->len;
3001
Johannes Berg8cb08172019-04-26 14:07:28 +02003002 err = nlmsg_parse_deprecated(cb->nlh, sizeof(*tcm), tca, TCA_MAX,
3003 rtm_tca_policy, cb->extack);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003004 if (err)
3005 return err;
3006
3007 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK) {
Vlad Buslov787ce6d2018-09-24 19:22:58 +03003008 block = tcf_block_refcnt_get(net, tcm->tcm_block_index);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003009 if (!block)
3010 goto out;
3011 /* If we work with block index, q is NULL and parent value
3012 * will never be used in the following code. The check
3013 * in tcf_fill_node prevents it. However, compiler does not
3014 * see that far, so set parent to zero to silence the warning
3015 * about parent being uninitialized.
3016 */
3017 parent = 0;
3018 } else {
3019 const struct Qdisc_class_ops *cops;
3020 struct net_device *dev;
3021 unsigned long cl = 0;
3022
3023 dev = __dev_get_by_index(net, tcm->tcm_ifindex);
3024 if (!dev)
3025 return skb->len;
3026
3027 parent = tcm->tcm_parent;
3028 if (!parent) {
3029 q = dev->qdisc;
3030 parent = q->handle;
3031 } else {
3032 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
3033 }
3034 if (!q)
3035 goto out;
3036 cops = q->ops->cl_ops;
3037 if (!cops)
3038 goto out;
3039 if (!cops->tcf_block)
3040 goto out;
3041 if (TC_H_MIN(tcm->tcm_parent)) {
3042 cl = cops->find(q, tcm->tcm_parent);
3043 if (cl == 0)
3044 goto out;
3045 }
3046 block = cops->tcf_block(q, cl, NULL);
3047 if (!block)
3048 goto out;
3049 if (tcf_block_shared(block))
3050 q = NULL;
3051 }
3052
3053 index_start = cb->args[0];
3054 index = 0;
3055
Vlad Buslovace4a262019-02-25 17:45:44 +02003056 mutex_lock(&block->lock);
3057 list_for_each_entry(chain, &block->chain_list, list) {
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003058 if ((tca[TCA_CHAIN] &&
3059 nla_get_u32(tca[TCA_CHAIN]) != chain->index))
3060 continue;
3061 if (index < index_start) {
3062 index++;
3063 continue;
3064 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003065 if (tcf_chain_held_by_acts_only(chain))
3066 continue;
Vlad Buslova5654822019-02-11 10:55:37 +02003067 err = tc_chain_fill_node(chain->tmplt_ops, chain->tmplt_priv,
3068 chain->index, net, skb, block,
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003069 NETLINK_CB(cb->skb).portid,
3070 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3071 RTM_NEWCHAIN);
Vlad Buslovace4a262019-02-25 17:45:44 +02003072 if (err <= 0)
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003073 break;
3074 index++;
3075 }
Vlad Buslovace4a262019-02-25 17:45:44 +02003076 mutex_unlock(&block->lock);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003077
Vlad Buslov787ce6d2018-09-24 19:22:58 +03003078 if (tcm->tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK)
Vlad Buslov12db03b2019-02-11 10:55:45 +02003079 tcf_block_refcnt_put(block, true);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003080 cb->args[0] = index;
3081
3082out:
3083 /* If we did no progress, the error (EMSGSIZE) is real */
3084 if (skb->len == 0 && err)
3085 return err;
3086 return skb->len;
3087}
3088
WANG Cong18d02642014-09-25 10:26:37 -07003089void tcf_exts_destroy(struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090{
3091#ifdef CONFIG_NET_CLS_ACT
Eric Dumazet3d66b892019-09-18 12:57:04 -07003092 if (exts->actions) {
3093 tcf_action_destroy(exts->actions, TCA_ACT_UNBIND);
3094 kfree(exts->actions);
3095 }
WANG Cong22dc13c2016-08-13 22:35:00 -07003096 exts->nr_actions = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097#endif
3098}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003099EXPORT_SYMBOL(tcf_exts_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Benjamin LaHaisec1b52732013-01-14 05:15:39 +00003101int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
Alexander Aring50a56192018-01-18 11:20:52 -05003102 struct nlattr *rate_tlv, struct tcf_exts *exts, bool ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003103 bool rtnl_held, struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105#ifdef CONFIG_NET_CLS_ACT
3106 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 struct tc_action *act;
Roman Mashakd04e6992018-03-08 16:59:17 -05003108 size_t attr_size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
WANG Cong5da57f42013-12-15 20:15:07 -08003110 if (exts->police && tb[exts->police]) {
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003111 act = tcf_action_init_1(net, tp, tb[exts->police],
3112 rate_tlv, "police", ovr,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003113 TCA_ACT_BIND, rtnl_held,
3114 extack);
Patrick McHardyab27cfb2008-01-23 20:33:13 -08003115 if (IS_ERR(act))
3116 return PTR_ERR(act);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
WANG Cong33be6272013-12-15 20:15:05 -08003118 act->type = exts->type = TCA_OLD_COMPAT;
WANG Cong22dc13c2016-08-13 22:35:00 -07003119 exts->actions[0] = act;
3120 exts->nr_actions = 1;
WANG Cong5da57f42013-12-15 20:15:07 -08003121 } else if (exts->action && tb[exts->action]) {
Vlad Buslov90b73b72018-07-05 17:24:33 +03003122 int err;
WANG Cong22dc13c2016-08-13 22:35:00 -07003123
Jiri Pirko9fb9f252017-05-17 11:08:02 +02003124 err = tcf_action_init(net, tp, tb[exts->action],
3125 rate_tlv, NULL, ovr, TCA_ACT_BIND,
Vlad Buslovec6743a2019-02-11 10:55:43 +02003126 exts->actions, &attr_size,
3127 rtnl_held, extack);
Vlad Buslov90b73b72018-07-05 17:24:33 +03003128 if (err < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003129 return err;
Vlad Buslov90b73b72018-07-05 17:24:33 +03003130 exts->nr_actions = err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 }
3132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133#else
WANG Cong5da57f42013-12-15 20:15:07 -08003134 if ((exts->action && tb[exts->action]) ||
Alexander Aring50a56192018-01-18 11:20:52 -05003135 (exts->police && tb[exts->police])) {
3136 NL_SET_ERR_MSG(extack, "Classifier actions are not supported per compile options (CONFIG_NET_CLS_ACT)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 return -EOPNOTSUPP;
Alexander Aring50a56192018-01-18 11:20:52 -05003138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139#endif
3140
3141 return 0;
3142}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003143EXPORT_SYMBOL(tcf_exts_validate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003145void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146{
3147#ifdef CONFIG_NET_CLS_ACT
WANG Cong22dc13c2016-08-13 22:35:00 -07003148 struct tcf_exts old = *dst;
3149
Jiri Pirko9b0d4442017-08-04 14:29:15 +02003150 *dst = *src;
WANG Cong22dc13c2016-08-13 22:35:00 -07003151 tcf_exts_destroy(&old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152#endif
3153}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003154EXPORT_SYMBOL(tcf_exts_change);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
WANG Cong22dc13c2016-08-13 22:35:00 -07003156#ifdef CONFIG_NET_CLS_ACT
3157static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
3158{
3159 if (exts->nr_actions == 0)
3160 return NULL;
3161 else
3162 return exts->actions[0];
3163}
3164#endif
WANG Cong33be6272013-12-15 20:15:05 -08003165
WANG Cong5da57f42013-12-15 20:15:07 -08003166int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167{
3168#ifdef CONFIG_NET_CLS_ACT
Cong Wang9cc63db2014-07-16 14:25:30 -07003169 struct nlattr *nest;
3170
Jiri Pirko978dfd82017-08-04 14:29:03 +02003171 if (exts->action && tcf_exts_has_actions(exts)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 /*
3173 * again for backward compatible mode - we want
3174 * to work with both old and new modes of entering
3175 * tc data even if iproute2 was newer - jhs
3176 */
WANG Cong33be6272013-12-15 20:15:05 -08003177 if (exts->type != TCA_OLD_COMPAT) {
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003178 nest = nla_nest_start_noflag(skb, exts->action);
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003179 if (nest == NULL)
3180 goto nla_put_failure;
WANG Cong22dc13c2016-08-13 22:35:00 -07003181
Vlad Buslov90b73b72018-07-05 17:24:33 +03003182 if (tcf_action_dump(skb, exts->actions, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003183 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003184 nla_nest_end(skb, nest);
WANG Cong5da57f42013-12-15 20:15:07 -08003185 } else if (exts->police) {
WANG Cong33be6272013-12-15 20:15:05 -08003186 struct tc_action *act = tcf_exts_first_act(exts);
Michal Kubecekae0be8d2019-04-26 11:13:06 +02003187 nest = nla_nest_start_noflag(skb, exts->police);
Jamal Hadi Salim63acd682013-12-23 08:02:12 -05003188 if (nest == NULL || !act)
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003189 goto nla_put_failure;
WANG Cong33be6272013-12-15 20:15:05 -08003190 if (tcf_action_dump_old(skb, act, 0, 0) < 0)
Patrick McHardyadd93b62008-01-22 22:11:33 -08003191 goto nla_put_failure;
Patrick McHardy4b3550ef2008-01-23 20:34:11 -08003192 nla_nest_end(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 }
3194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 return 0;
Cong Wang9cc63db2014-07-16 14:25:30 -07003196
3197nla_put_failure:
3198 nla_nest_cancel(skb, nest);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 return -1;
Cong Wang9cc63db2014-07-16 14:25:30 -07003200#else
3201 return 0;
3202#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003204EXPORT_SYMBOL(tcf_exts_dump);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003206
WANG Cong5da57f42013-12-15 20:15:07 -08003207int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
3209#ifdef CONFIG_NET_CLS_ACT
WANG Cong33be6272013-12-15 20:15:05 -08003210 struct tc_action *a = tcf_exts_first_act(exts);
Ignacy Gawędzkib057df22015-02-03 19:05:18 +01003211 if (a != NULL && tcf_action_copy_stats(skb, a, 1) < 0)
WANG Cong33be6272013-12-15 20:15:05 -08003212 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213#endif
3214 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215}
Stephen Hemmingeraa767bf2008-01-21 02:26:41 -08003216EXPORT_SYMBOL(tcf_exts_dump_stats);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Vlad Buslov40119212019-08-26 16:44:59 +03003218static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
3219{
3220 if (*flags & TCA_CLS_FLAGS_IN_HW)
3221 return;
3222 *flags |= TCA_CLS_FLAGS_IN_HW;
3223 atomic_inc(&block->offloadcnt);
3224}
3225
3226static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)
3227{
3228 if (!(*flags & TCA_CLS_FLAGS_IN_HW))
3229 return;
3230 *flags &= ~TCA_CLS_FLAGS_IN_HW;
3231 atomic_dec(&block->offloadcnt);
3232}
3233
3234static void tc_cls_offload_cnt_update(struct tcf_block *block,
3235 struct tcf_proto *tp, u32 *cnt,
3236 u32 *flags, u32 diff, bool add)
3237{
3238 lockdep_assert_held(&block->cb_lock);
3239
3240 spin_lock(&tp->lock);
3241 if (add) {
3242 if (!*cnt)
3243 tcf_block_offload_inc(block, flags);
3244 *cnt += diff;
3245 } else {
3246 *cnt -= diff;
3247 if (!*cnt)
3248 tcf_block_offload_dec(block, flags);
3249 }
3250 spin_unlock(&tp->lock);
3251}
3252
3253static void
3254tc_cls_offload_cnt_reset(struct tcf_block *block, struct tcf_proto *tp,
3255 u32 *cnt, u32 *flags)
3256{
3257 lockdep_assert_held(&block->cb_lock);
3258
3259 spin_lock(&tp->lock);
3260 tcf_block_offload_dec(block, flags);
3261 *cnt = 0;
3262 spin_unlock(&tp->lock);
3263}
3264
3265static int
3266__tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
3267 void *type_data, bool err_stop)
Jiri Pirko717503b2017-10-11 09:41:09 +02003268{
Pablo Neira Ayuso955bcb62019-07-09 22:55:46 +02003269 struct flow_block_cb *block_cb;
Cong Wangaeb3fec2018-12-11 11:15:46 -08003270 int ok_count = 0;
3271 int err;
3272
Vlad Buslov40119212019-08-26 16:44:59 +03003273 list_for_each_entry(block_cb, &block->flow_block.cb_list, list) {
3274 err = block_cb->cb(type, type_data, block_cb->cb_priv);
3275 if (err) {
3276 if (err_stop)
3277 return err;
3278 } else {
3279 ok_count++;
3280 }
3281 }
3282 return ok_count;
3283}
3284
3285int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
3286 void *type_data, bool err_stop, bool rtnl_held)
3287{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003288 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003289 int ok_count;
3290
Vlad Buslov11bd6342019-08-26 16:45:02 +03003291retry:
3292 if (take_rtnl)
3293 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003294 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003295 /* Need to obtain rtnl lock if block is bound to devs that require it.
3296 * In block bind code cb_lock is obtained while holding rtnl, so we must
3297 * obtain the locks in same order here.
3298 */
3299 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3300 up_read(&block->cb_lock);
3301 take_rtnl = true;
3302 goto retry;
3303 }
3304
Vlad Buslov40119212019-08-26 16:44:59 +03003305 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003306
Vlad Buslov40119212019-08-26 16:44:59 +03003307 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003308 if (take_rtnl)
3309 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003310 return ok_count;
3311}
3312EXPORT_SYMBOL(tc_setup_cb_call);
3313
3314/* Non-destructive filter add. If filter that wasn't already in hardware is
3315 * successfully offloaded, increment block offloads counter. On failure,
3316 * previously offloaded filter is considered to be intact and offloads counter
3317 * is not decremented.
3318 */
3319
3320int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
3321 enum tc_setup_type type, void *type_data, bool err_stop,
3322 u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
3323{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003324 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003325 int ok_count;
3326
Vlad Buslov11bd6342019-08-26 16:45:02 +03003327retry:
3328 if (take_rtnl)
3329 rtnl_lock();
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003330 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003331 /* Need to obtain rtnl lock if block is bound to devs that require it.
3332 * In block bind code cb_lock is obtained while holding rtnl, so we must
3333 * obtain the locks in same order here.
3334 */
3335 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3336 up_read(&block->cb_lock);
3337 take_rtnl = true;
3338 goto retry;
3339 }
3340
Cong Wangaeb3fec2018-12-11 11:15:46 -08003341 /* Make sure all netdevs sharing this block are offload-capable. */
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003342 if (block->nooffloaddevcnt && err_stop) {
3343 ok_count = -EOPNOTSUPP;
3344 goto err_unlock;
3345 }
Cong Wangaeb3fec2018-12-11 11:15:46 -08003346
Vlad Buslov40119212019-08-26 16:44:59 +03003347 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003348 if (ok_count < 0)
3349 goto err_unlock;
3350
3351 if (tp->ops->hw_add)
3352 tp->ops->hw_add(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003353 if (ok_count > 0)
3354 tc_cls_offload_cnt_update(block, tp, in_hw_count, flags,
3355 ok_count, true);
Vlad Buslov4f8116c2019-08-26 16:44:57 +03003356err_unlock:
3357 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003358 if (take_rtnl)
3359 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003360 return ok_count < 0 ? ok_count : 0;
Jiri Pirko717503b2017-10-11 09:41:09 +02003361}
Vlad Buslov40119212019-08-26 16:44:59 +03003362EXPORT_SYMBOL(tc_setup_cb_add);
3363
3364/* Destructive filter replace. If filter that wasn't already in hardware is
3365 * successfully offloaded, increment block offload counter. On failure,
3366 * previously offloaded filter is considered to be destroyed and offload counter
3367 * is decremented.
3368 */
3369
3370int tc_setup_cb_replace(struct tcf_block *block, struct tcf_proto *tp,
3371 enum tc_setup_type type, void *type_data, bool err_stop,
3372 u32 *old_flags, unsigned int *old_in_hw_count,
3373 u32 *new_flags, unsigned int *new_in_hw_count,
3374 bool rtnl_held)
3375{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003376 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003377 int ok_count;
3378
Vlad Buslov11bd6342019-08-26 16:45:02 +03003379retry:
3380 if (take_rtnl)
3381 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003382 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003383 /* Need to obtain rtnl lock if block is bound to devs that require it.
3384 * In block bind code cb_lock is obtained while holding rtnl, so we must
3385 * obtain the locks in same order here.
3386 */
3387 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3388 up_read(&block->cb_lock);
3389 take_rtnl = true;
3390 goto retry;
3391 }
3392
Vlad Buslov40119212019-08-26 16:44:59 +03003393 /* Make sure all netdevs sharing this block are offload-capable. */
3394 if (block->nooffloaddevcnt && err_stop) {
3395 ok_count = -EOPNOTSUPP;
3396 goto err_unlock;
3397 }
3398
3399 tc_cls_offload_cnt_reset(block, tp, old_in_hw_count, old_flags);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003400 if (tp->ops->hw_del)
3401 tp->ops->hw_del(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003402
3403 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003404 if (ok_count < 0)
3405 goto err_unlock;
3406
3407 if (tp->ops->hw_add)
3408 tp->ops->hw_add(tp, type_data);
Vlad Buslov40119212019-08-26 16:44:59 +03003409 if (ok_count > 0)
Vlad Buslova449a3e2019-08-26 16:45:00 +03003410 tc_cls_offload_cnt_update(block, tp, new_in_hw_count,
3411 new_flags, ok_count, true);
Vlad Buslov40119212019-08-26 16:44:59 +03003412err_unlock:
3413 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003414 if (take_rtnl)
3415 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003416 return ok_count < 0 ? ok_count : 0;
3417}
3418EXPORT_SYMBOL(tc_setup_cb_replace);
3419
3420/* Destroy filter and decrement block offload counter, if filter was previously
3421 * offloaded.
3422 */
3423
3424int tc_setup_cb_destroy(struct tcf_block *block, struct tcf_proto *tp,
3425 enum tc_setup_type type, void *type_data, bool err_stop,
3426 u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
3427{
Vlad Buslov11bd6342019-08-26 16:45:02 +03003428 bool take_rtnl = READ_ONCE(block->lockeddevcnt) && !rtnl_held;
Vlad Buslov40119212019-08-26 16:44:59 +03003429 int ok_count;
3430
Vlad Buslov11bd6342019-08-26 16:45:02 +03003431retry:
3432 if (take_rtnl)
3433 rtnl_lock();
Vlad Buslov40119212019-08-26 16:44:59 +03003434 down_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003435 /* Need to obtain rtnl lock if block is bound to devs that require it.
3436 * In block bind code cb_lock is obtained while holding rtnl, so we must
3437 * obtain the locks in same order here.
3438 */
3439 if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
3440 up_read(&block->cb_lock);
3441 take_rtnl = true;
3442 goto retry;
3443 }
3444
Vlad Buslov40119212019-08-26 16:44:59 +03003445 ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
3446
3447 tc_cls_offload_cnt_reset(block, tp, in_hw_count, flags);
Vlad Buslova449a3e2019-08-26 16:45:00 +03003448 if (tp->ops->hw_del)
3449 tp->ops->hw_del(tp, type_data);
3450
Vlad Buslov40119212019-08-26 16:44:59 +03003451 up_read(&block->cb_lock);
Vlad Buslov11bd6342019-08-26 16:45:02 +03003452 if (take_rtnl)
3453 rtnl_unlock();
Vlad Buslov40119212019-08-26 16:44:59 +03003454 return ok_count < 0 ? ok_count : 0;
3455}
3456EXPORT_SYMBOL(tc_setup_cb_destroy);
3457
3458int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
3459 bool add, flow_setup_cb_t *cb,
3460 enum tc_setup_type type, void *type_data,
3461 void *cb_priv, u32 *flags, unsigned int *in_hw_count)
3462{
3463 int err = cb(type, type_data, cb_priv);
3464
3465 if (err) {
3466 if (add && tc_skip_sw(*flags))
3467 return err;
3468 } else {
3469 tc_cls_offload_cnt_update(block, tp, in_hw_count, flags, 1,
3470 add);
3471 }
3472
3473 return 0;
3474}
3475EXPORT_SYMBOL(tc_setup_cb_reoffload);
Jiri Pirkob3f55bd2017-10-11 09:41:08 +02003476
Jiri Pirko20084952020-02-25 11:45:18 +01003477static int tcf_act_get_cookie(struct flow_action_entry *entry,
3478 const struct tc_action *act)
3479{
3480 struct tc_cookie *cookie;
3481 int err = 0;
3482
3483 rcu_read_lock();
3484 cookie = rcu_dereference(act->act_cookie);
3485 if (cookie) {
3486 entry->cookie = flow_action_cookie_create(cookie->data,
3487 cookie->len,
3488 GFP_ATOMIC);
3489 if (!entry->cookie)
3490 err = -ENOMEM;
3491 }
3492 rcu_read_unlock();
3493 return err;
3494}
3495
3496static void tcf_act_put_cookie(struct flow_action_entry *entry)
3497{
3498 flow_action_cookie_destroy(entry->cookie);
3499}
3500
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003501void tc_cleanup_flow_action(struct flow_action *flow_action)
3502{
3503 struct flow_action_entry *entry;
3504 int i;
3505
Jiri Pirko20084952020-02-25 11:45:18 +01003506 flow_action_for_each(i, entry, flow_action) {
3507 tcf_act_put_cookie(entry);
Vlad Buslov11589582019-09-13 18:28:39 +03003508 if (entry->destructor)
3509 entry->destructor(entry->destructor_priv);
Jiri Pirko20084952020-02-25 11:45:18 +01003510 }
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003511}
3512EXPORT_SYMBOL(tc_cleanup_flow_action);
3513
Vlad Buslov11589582019-09-13 18:28:39 +03003514static void tcf_mirred_get_dev(struct flow_action_entry *entry,
3515 const struct tc_action *act)
3516{
Vlad Buslov470d5062019-09-13 18:28:41 +03003517#ifdef CONFIG_NET_CLS_ACT
3518 entry->dev = act->ops->get_dev(act, &entry->destructor);
Vlad Buslov11589582019-09-13 18:28:39 +03003519 if (!entry->dev)
3520 return;
Vlad Buslov11589582019-09-13 18:28:39 +03003521 entry->destructor_priv = entry->dev;
Vlad Buslov470d5062019-09-13 18:28:41 +03003522#endif
Vlad Buslov11589582019-09-13 18:28:39 +03003523}
3524
3525static void tcf_tunnel_encap_put_tunnel(void *priv)
3526{
3527 struct ip_tunnel_info *tunnel = priv;
3528
3529 kfree(tunnel);
3530}
3531
3532static int tcf_tunnel_encap_get_tunnel(struct flow_action_entry *entry,
3533 const struct tc_action *act)
3534{
3535 entry->tunnel = tcf_tunnel_info_copy(act);
3536 if (!entry->tunnel)
3537 return -ENOMEM;
3538 entry->destructor = tcf_tunnel_encap_put_tunnel;
3539 entry->destructor_priv = entry->tunnel;
3540 return 0;
3541}
3542
Vlad Buslov4a5da472019-09-13 18:28:40 +03003543static void tcf_sample_get_group(struct flow_action_entry *entry,
3544 const struct tc_action *act)
3545{
3546#ifdef CONFIG_NET_CLS_ACT
3547 entry->sample.psample_group =
3548 act->ops->get_psample_group(act, &entry->destructor);
3549 entry->destructor_priv = entry->sample.psample_group;
3550#endif
3551}
3552
Po Liud29bdd62020-05-01 08:53:16 +08003553static void tcf_gate_entry_destructor(void *priv)
3554{
3555 struct action_gate_entry *oe = priv;
3556
3557 kfree(oe);
3558}
3559
3560static int tcf_gate_get_entries(struct flow_action_entry *entry,
3561 const struct tc_action *act)
3562{
3563 entry->gate.entries = tcf_gate_get_list(act);
3564
3565 if (!entry->gate.entries)
3566 return -EINVAL;
3567
3568 entry->destructor = tcf_gate_entry_destructor;
3569 entry->destructor_priv = entry->gate.entries;
3570
3571 return 0;
3572}
3573
Pablo Neira Ayuso16f80362020-05-06 20:34:50 +02003574static enum flow_action_hw_stats tc_act_hw_stats(u8 hw_stats)
3575{
3576 if (WARN_ON_ONCE(hw_stats > TCA_ACT_HW_STATS_ANY))
3577 return FLOW_ACTION_HW_STATS_DONT_CARE;
3578 else if (!hw_stats)
3579 return FLOW_ACTION_HW_STATS_DISABLED;
3580
3581 return hw_stats;
3582}
3583
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003584int tc_setup_flow_action(struct flow_action *flow_action,
Vlad Buslovb15e7a62020-02-17 12:12:12 +02003585 const struct tcf_exts *exts)
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003586{
Vlad Buslov7a472812020-02-17 12:12:09 +02003587 struct tc_action *act;
Vlad Buslov9838b202019-08-26 16:45:03 +03003588 int i, j, k, err = 0;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003589
Jakub Kicinski0dfb2d82020-03-19 16:26:23 -07003590 BUILD_BUG_ON(TCA_ACT_HW_STATS_ANY != FLOW_ACTION_HW_STATS_ANY);
3591 BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE);
3592 BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED);
Jiri Pirko44f86582020-03-07 12:40:20 +01003593
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003594 if (!exts)
3595 return 0;
3596
3597 j = 0;
3598 tcf_exts_for_each_action(i, act, exts) {
3599 struct flow_action_entry *entry;
3600
3601 entry = &flow_action->entries[j];
Vlad Buslov7a472812020-02-17 12:12:09 +02003602 spin_lock_bh(&act->tcfa_lock);
Jiri Pirko20084952020-02-25 11:45:18 +01003603 err = tcf_act_get_cookie(entry, act);
3604 if (err)
3605 goto err_out_locked;
Jiri Pirko44f86582020-03-07 12:40:20 +01003606
Pablo Neira Ayuso16f80362020-05-06 20:34:50 +02003607 entry->hw_stats = tc_act_hw_stats(act->hw_stats);
Jiri Pirko44f86582020-03-07 12:40:20 +01003608
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003609 if (is_tcf_gact_ok(act)) {
3610 entry->id = FLOW_ACTION_ACCEPT;
3611 } else if (is_tcf_gact_shot(act)) {
3612 entry->id = FLOW_ACTION_DROP;
3613 } else if (is_tcf_gact_trap(act)) {
3614 entry->id = FLOW_ACTION_TRAP;
3615 } else if (is_tcf_gact_goto_chain(act)) {
3616 entry->id = FLOW_ACTION_GOTO;
3617 entry->chain_index = tcf_gact_goto_chain_index(act);
3618 } else if (is_tcf_mirred_egress_redirect(act)) {
3619 entry->id = FLOW_ACTION_REDIRECT;
Vlad Buslov11589582019-09-13 18:28:39 +03003620 tcf_mirred_get_dev(entry, act);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003621 } else if (is_tcf_mirred_egress_mirror(act)) {
3622 entry->id = FLOW_ACTION_MIRRED;
Vlad Buslov11589582019-09-13 18:28:39 +03003623 tcf_mirred_get_dev(entry, act);
John Hurley48e584a2019-08-04 16:09:06 +01003624 } else if (is_tcf_mirred_ingress_redirect(act)) {
3625 entry->id = FLOW_ACTION_REDIRECT_INGRESS;
Vlad Buslov11589582019-09-13 18:28:39 +03003626 tcf_mirred_get_dev(entry, act);
John Hurley48e584a2019-08-04 16:09:06 +01003627 } else if (is_tcf_mirred_ingress_mirror(act)) {
3628 entry->id = FLOW_ACTION_MIRRED_INGRESS;
Vlad Buslov11589582019-09-13 18:28:39 +03003629 tcf_mirred_get_dev(entry, act);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003630 } else if (is_tcf_vlan(act)) {
3631 switch (tcf_vlan_action(act)) {
3632 case TCA_VLAN_ACT_PUSH:
3633 entry->id = FLOW_ACTION_VLAN_PUSH;
3634 entry->vlan.vid = tcf_vlan_push_vid(act);
3635 entry->vlan.proto = tcf_vlan_push_proto(act);
3636 entry->vlan.prio = tcf_vlan_push_prio(act);
3637 break;
3638 case TCA_VLAN_ACT_POP:
3639 entry->id = FLOW_ACTION_VLAN_POP;
3640 break;
3641 case TCA_VLAN_ACT_MODIFY:
3642 entry->id = FLOW_ACTION_VLAN_MANGLE;
3643 entry->vlan.vid = tcf_vlan_push_vid(act);
3644 entry->vlan.proto = tcf_vlan_push_proto(act);
3645 entry->vlan.prio = tcf_vlan_push_prio(act);
3646 break;
3647 default:
Vlad Buslov9838b202019-08-26 16:45:03 +03003648 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003649 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003650 }
3651 } else if (is_tcf_tunnel_set(act)) {
3652 entry->id = FLOW_ACTION_TUNNEL_ENCAP;
Vlad Buslov11589582019-09-13 18:28:39 +03003653 err = tcf_tunnel_encap_get_tunnel(entry, act);
3654 if (err)
Vlad Buslov7a472812020-02-17 12:12:09 +02003655 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003656 } else if (is_tcf_tunnel_release(act)) {
3657 entry->id = FLOW_ACTION_TUNNEL_DECAP;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003658 } else if (is_tcf_pedit(act)) {
3659 for (k = 0; k < tcf_pedit_nkeys(act); k++) {
3660 switch (tcf_pedit_cmd(act, k)) {
3661 case TCA_PEDIT_KEY_EX_CMD_SET:
3662 entry->id = FLOW_ACTION_MANGLE;
3663 break;
3664 case TCA_PEDIT_KEY_EX_CMD_ADD:
3665 entry->id = FLOW_ACTION_ADD;
3666 break;
3667 default:
Vlad Buslov9838b202019-08-26 16:45:03 +03003668 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003669 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003670 }
3671 entry->mangle.htype = tcf_pedit_htype(act, k);
3672 entry->mangle.mask = tcf_pedit_mask(act, k);
3673 entry->mangle.val = tcf_pedit_val(act, k);
3674 entry->mangle.offset = tcf_pedit_offset(act, k);
Pablo Neira Ayuso16f80362020-05-06 20:34:50 +02003675 entry->hw_stats = tc_act_hw_stats(act->hw_stats);
Petr Machata2c4b58d2020-03-18 19:42:29 +02003676 entry = &flow_action->entries[++j];
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003677 }
3678 } else if (is_tcf_csum(act)) {
3679 entry->id = FLOW_ACTION_CSUM;
3680 entry->csum_flags = tcf_csum_update_flags(act);
3681 } else if (is_tcf_skbedit_mark(act)) {
3682 entry->id = FLOW_ACTION_MARK;
3683 entry->mark = tcf_skbedit_mark(act);
Pieter Jansen van Vuurena7a7be62019-05-04 04:46:16 -07003684 } else if (is_tcf_sample(act)) {
3685 entry->id = FLOW_ACTION_SAMPLE;
Pieter Jansen van Vuurena7a7be62019-05-04 04:46:16 -07003686 entry->sample.trunc_size = tcf_sample_trunc_size(act);
3687 entry->sample.truncate = tcf_sample_truncate(act);
3688 entry->sample.rate = tcf_sample_rate(act);
Vlad Buslov4a5da472019-09-13 18:28:40 +03003689 tcf_sample_get_group(entry, act);
Pieter Jansen van Vuuren8c8cfc62019-05-04 04:46:22 -07003690 } else if (is_tcf_police(act)) {
3691 entry->id = FLOW_ACTION_POLICE;
3692 entry->police.burst = tcf_police_tcfp_burst(act);
3693 entry->police.rate_bytes_ps =
3694 tcf_police_rate_bytes_ps(act);
Paul Blakeyb57dc7c2019-07-09 10:30:48 +03003695 } else if (is_tcf_ct(act)) {
3696 entry->id = FLOW_ACTION_CT;
3697 entry->ct.action = tcf_ct_action(act);
3698 entry->ct.zone = tcf_ct_zone(act);
Paul Blakeyedd58612020-03-12 12:23:09 +02003699 entry->ct.flow_table = tcf_ct_ft(act);
John Hurley6749d5902019-07-23 15:33:59 +01003700 } else if (is_tcf_mpls(act)) {
3701 switch (tcf_mpls_action(act)) {
3702 case TCA_MPLS_ACT_PUSH:
3703 entry->id = FLOW_ACTION_MPLS_PUSH;
3704 entry->mpls_push.proto = tcf_mpls_proto(act);
3705 entry->mpls_push.label = tcf_mpls_label(act);
3706 entry->mpls_push.tc = tcf_mpls_tc(act);
3707 entry->mpls_push.bos = tcf_mpls_bos(act);
3708 entry->mpls_push.ttl = tcf_mpls_ttl(act);
3709 break;
3710 case TCA_MPLS_ACT_POP:
3711 entry->id = FLOW_ACTION_MPLS_POP;
3712 entry->mpls_pop.proto = tcf_mpls_proto(act);
3713 break;
3714 case TCA_MPLS_ACT_MODIFY:
3715 entry->id = FLOW_ACTION_MPLS_MANGLE;
3716 entry->mpls_mangle.label = tcf_mpls_label(act);
3717 entry->mpls_mangle.tc = tcf_mpls_tc(act);
3718 entry->mpls_mangle.bos = tcf_mpls_bos(act);
3719 entry->mpls_mangle.ttl = tcf_mpls_ttl(act);
3720 break;
3721 default:
Vlad Buslov7a472812020-02-17 12:12:09 +02003722 goto err_out_locked;
John Hurley6749d5902019-07-23 15:33:59 +01003723 }
John Hurleyfb1b7752019-08-04 16:09:04 +01003724 } else if (is_tcf_skbedit_ptype(act)) {
3725 entry->id = FLOW_ACTION_PTYPE;
3726 entry->ptype = tcf_skbedit_ptype(act);
Petr Machata2ce12412020-03-19 15:47:21 +02003727 } else if (is_tcf_skbedit_priority(act)) {
3728 entry->id = FLOW_ACTION_PRIORITY;
3729 entry->priority = tcf_skbedit_priority(act);
Po Liud29bdd62020-05-01 08:53:16 +08003730 } else if (is_tcf_gate(act)) {
3731 entry->id = FLOW_ACTION_GATE;
3732 entry->gate.index = tcf_gate_index(act);
3733 entry->gate.prio = tcf_gate_prio(act);
3734 entry->gate.basetime = tcf_gate_basetime(act);
3735 entry->gate.cycletime = tcf_gate_cycletime(act);
3736 entry->gate.cycletimeext = tcf_gate_cycletimeext(act);
3737 entry->gate.num_entries = tcf_gate_num_entries(act);
3738 err = tcf_gate_get_entries(entry, act);
3739 if (err)
3740 goto err_out;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003741 } else {
Vlad Buslov9838b202019-08-26 16:45:03 +03003742 err = -EOPNOTSUPP;
Vlad Buslov7a472812020-02-17 12:12:09 +02003743 goto err_out_locked;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003744 }
Vlad Buslov7a472812020-02-17 12:12:09 +02003745 spin_unlock_bh(&act->tcfa_lock);
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003746
3747 if (!is_tcf_pedit(act))
3748 j++;
3749 }
Vlad Buslov9838b202019-08-26 16:45:03 +03003750
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003751err_out:
Vlad Buslov5a6ff4b2019-08-26 16:45:04 +03003752 if (err)
3753 tc_cleanup_flow_action(flow_action);
3754
Vlad Buslov9838b202019-08-26 16:45:03 +03003755 return err;
Vlad Buslov7a472812020-02-17 12:12:09 +02003756err_out_locked:
3757 spin_unlock_bh(&act->tcfa_lock);
3758 goto err_out;
Pablo Neira Ayuso3a7b6862019-02-02 12:50:46 +01003759}
3760EXPORT_SYMBOL(tc_setup_flow_action);
3761
Pablo Neira Ayusoe3ab7862019-02-02 12:50:45 +01003762unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
3763{
3764 unsigned int num_acts = 0;
3765 struct tc_action *act;
3766 int i;
3767
3768 tcf_exts_for_each_action(i, act, exts) {
3769 if (is_tcf_pedit(act))
3770 num_acts += tcf_pedit_nkeys(act);
3771 else
3772 num_acts++;
3773 }
3774 return num_acts;
3775}
3776EXPORT_SYMBOL(tcf_exts_num_actions);
3777
Jiri Pirko48617382018-01-17 11:46:46 +01003778static __net_init int tcf_net_init(struct net *net)
3779{
3780 struct tcf_net *tn = net_generic(net, tcf_net_id);
3781
Vlad Buslovab281622018-09-24 19:22:56 +03003782 spin_lock_init(&tn->idr_lock);
Jiri Pirko48617382018-01-17 11:46:46 +01003783 idr_init(&tn->idr);
3784 return 0;
3785}
3786
3787static void __net_exit tcf_net_exit(struct net *net)
3788{
3789 struct tcf_net *tn = net_generic(net, tcf_net_id);
3790
3791 idr_destroy(&tn->idr);
3792}
3793
3794static struct pernet_operations tcf_net_ops = {
3795 .init = tcf_net_init,
3796 .exit = tcf_net_exit,
3797 .id = &tcf_net_id,
3798 .size = sizeof(struct tcf_net),
3799};
3800
John Hurley25a443f2019-12-05 17:03:35 +00003801static struct flow_indr_block_entry block_entry = {
3802 .cb = tc_indr_block_get_and_cmd,
3803 .list = LIST_HEAD_INIT(block_entry.list),
wenxu1150ab02019-08-07 09:13:53 +08003804};
3805
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806static int __init tc_filter_init(void)
3807{
Jiri Pirko48617382018-01-17 11:46:46 +01003808 int err;
3809
Cong Wang7aa00452017-10-26 18:24:28 -07003810 tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0);
3811 if (!tc_filter_wq)
3812 return -ENOMEM;
3813
Jiri Pirko48617382018-01-17 11:46:46 +01003814 err = register_pernet_subsys(&tcf_net_ops);
3815 if (err)
3816 goto err_register_pernet_subsys;
3817
John Hurley25a443f2019-12-05 17:03:35 +00003818 flow_indr_add_block_cb(&block_entry);
wenxu1150ab02019-08-07 09:13:53 +08003819
Vlad Buslov470502d2019-02-11 10:55:48 +02003820 rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_new_tfilter, NULL,
3821 RTNL_FLAG_DOIT_UNLOCKED);
3822 rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_del_tfilter, NULL,
3823 RTNL_FLAG_DOIT_UNLOCKED);
Vlad Buslovc431f892018-05-31 09:52:53 +03003824 rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_get_tfilter,
Vlad Buslov470502d2019-02-11 10:55:48 +02003825 tc_dump_tfilter, RTNL_FLAG_DOIT_UNLOCKED);
Jiri Pirko32a4f5e2018-07-23 09:23:06 +02003826 rtnl_register(PF_UNSPEC, RTM_NEWCHAIN, tc_ctl_chain, NULL, 0);
3827 rtnl_register(PF_UNSPEC, RTM_DELCHAIN, tc_ctl_chain, NULL, 0);
3828 rtnl_register(PF_UNSPEC, RTM_GETCHAIN, tc_ctl_chain,
3829 tc_dump_chain, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 return 0;
Jiri Pirko48617382018-01-17 11:46:46 +01003832
3833err_register_pernet_subsys:
3834 destroy_workqueue(tc_filter_wq);
3835 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836}
3837
3838subsys_initcall(tc_filter_init);