162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef __NET_PKT_CLS_H
362306a36Sopenharmony_ci#define __NET_PKT_CLS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/pkt_cls.h>
662306a36Sopenharmony_ci#include <linux/workqueue.h>
762306a36Sopenharmony_ci#include <net/sch_generic.h>
862306a36Sopenharmony_ci#include <net/act_api.h>
962306a36Sopenharmony_ci#include <net/net_namespace.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* TC action not accessible from user space */
1262306a36Sopenharmony_ci#define TC_ACT_CONSUMED		(TC_ACT_VALUE_MAX + 1)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* Basic packet classifier frontend definitions. */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct tcf_walker {
1762306a36Sopenharmony_ci	int	stop;
1862306a36Sopenharmony_ci	int	skip;
1962306a36Sopenharmony_ci	int	count;
2062306a36Sopenharmony_ci	bool	nonempty;
2162306a36Sopenharmony_ci	unsigned long cookie;
2262306a36Sopenharmony_ci	int	(*fn)(struct tcf_proto *, void *node, struct tcf_walker *);
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciint register_tcf_proto_ops(struct tcf_proto_ops *ops);
2662306a36Sopenharmony_civoid unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct tcf_block_ext_info {
2962306a36Sopenharmony_ci	enum flow_block_binder_type binder_type;
3062306a36Sopenharmony_ci	tcf_chain_head_change_t *chain_head_change;
3162306a36Sopenharmony_ci	void *chain_head_change_priv;
3262306a36Sopenharmony_ci	u32 block_index;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct tcf_qevent {
3662306a36Sopenharmony_ci	struct tcf_block	*block;
3762306a36Sopenharmony_ci	struct tcf_block_ext_info info;
3862306a36Sopenharmony_ci	struct tcf_proto __rcu *filter_chain;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistruct tcf_block_cb;
4262306a36Sopenharmony_cibool tcf_queue_work(struct rcu_work *rwork, work_func_t func);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS
4562306a36Sopenharmony_cistruct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block,
4662306a36Sopenharmony_ci				       u32 chain_index);
4762306a36Sopenharmony_civoid tcf_chain_put_by_act(struct tcf_chain *chain);
4862306a36Sopenharmony_cistruct tcf_chain *tcf_get_next_chain(struct tcf_block *block,
4962306a36Sopenharmony_ci				     struct tcf_chain *chain);
5062306a36Sopenharmony_cistruct tcf_proto *tcf_get_next_proto(struct tcf_chain *chain,
5162306a36Sopenharmony_ci				     struct tcf_proto *tp);
5262306a36Sopenharmony_civoid tcf_block_netif_keep_dst(struct tcf_block *block);
5362306a36Sopenharmony_ciint tcf_block_get(struct tcf_block **p_block,
5462306a36Sopenharmony_ci		  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
5562306a36Sopenharmony_ci		  struct netlink_ext_ack *extack);
5662306a36Sopenharmony_ciint tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
5762306a36Sopenharmony_ci		      struct tcf_block_ext_info *ei,
5862306a36Sopenharmony_ci		      struct netlink_ext_ack *extack);
5962306a36Sopenharmony_civoid tcf_block_put(struct tcf_block *block);
6062306a36Sopenharmony_civoid tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
6162306a36Sopenharmony_ci		       struct tcf_block_ext_info *ei);
6262306a36Sopenharmony_ciint tcf_exts_init_ex(struct tcf_exts *exts, struct net *net, int action,
6362306a36Sopenharmony_ci		     int police, struct tcf_proto *tp, u32 handle, bool used_action_miss);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic inline bool tcf_block_shared(struct tcf_block *block)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	return block->index;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline bool tcf_block_non_null_shared(struct tcf_block *block)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	return block && block->index;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline struct Qdisc *tcf_block_q(struct tcf_block *block)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	WARN_ON(tcf_block_shared(block));
7862306a36Sopenharmony_ci	return block->q;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciint tcf_classify(struct sk_buff *skb,
8262306a36Sopenharmony_ci		 const struct tcf_block *block,
8362306a36Sopenharmony_ci		 const struct tcf_proto *tp, struct tcf_result *res,
8462306a36Sopenharmony_ci		 bool compat_mode);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic inline bool tc_cls_stats_dump(struct tcf_proto *tp,
8762306a36Sopenharmony_ci				     struct tcf_walker *arg,
8862306a36Sopenharmony_ci				     void *filter)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	if (arg->count >= arg->skip && arg->fn(tp, filter, arg) < 0) {
9162306a36Sopenharmony_ci		arg->stop = 1;
9262306a36Sopenharmony_ci		return false;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	arg->count++;
9662306a36Sopenharmony_ci	return true;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#else
10062306a36Sopenharmony_cistatic inline bool tcf_block_shared(struct tcf_block *block)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	return false;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline bool tcf_block_non_null_shared(struct tcf_block *block)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	return false;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline
11162306a36Sopenharmony_ciint tcf_block_get(struct tcf_block **p_block,
11262306a36Sopenharmony_ci		  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
11362306a36Sopenharmony_ci		  struct netlink_ext_ack *extack)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	return 0;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline
11962306a36Sopenharmony_ciint tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
12062306a36Sopenharmony_ci		      struct tcf_block_ext_info *ei,
12162306a36Sopenharmony_ci		      struct netlink_ext_ack *extack)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return 0;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline void tcf_block_put(struct tcf_block *block)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline
13162306a36Sopenharmony_civoid tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
13262306a36Sopenharmony_ci		       struct tcf_block_ext_info *ei)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline struct Qdisc *tcf_block_q(struct tcf_block *block)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	return NULL;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline int tcf_classify(struct sk_buff *skb,
14262306a36Sopenharmony_ci			       const struct tcf_block *block,
14362306a36Sopenharmony_ci			       const struct tcf_proto *tp,
14462306a36Sopenharmony_ci			       struct tcf_result *res, bool compat_mode)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	return TC_ACT_UNSPEC;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic inline unsigned long
15262306a36Sopenharmony_ci__cls_set_class(unsigned long *clp, unsigned long cl)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	return xchg(clp, cl);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic inline void
15862306a36Sopenharmony_ci__tcf_bind_filter(struct Qdisc *q, struct tcf_result *r, unsigned long base)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	unsigned long cl;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	cl = q->ops->cl_ops->bind_tcf(q, base, r->classid);
16362306a36Sopenharmony_ci	cl = __cls_set_class(&r->class, cl);
16462306a36Sopenharmony_ci	if (cl)
16562306a36Sopenharmony_ci		q->ops->cl_ops->unbind_tcf(q, cl);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic inline void
16962306a36Sopenharmony_citcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct Qdisc *q = tp->chain->block->q;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Check q as it is not set for shared blocks. In that case,
17462306a36Sopenharmony_ci	 * setting class is not supported.
17562306a36Sopenharmony_ci	 */
17662306a36Sopenharmony_ci	if (!q)
17762306a36Sopenharmony_ci		return;
17862306a36Sopenharmony_ci	sch_tree_lock(q);
17962306a36Sopenharmony_ci	__tcf_bind_filter(q, r, base);
18062306a36Sopenharmony_ci	sch_tree_unlock(q);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline void
18462306a36Sopenharmony_ci__tcf_unbind_filter(struct Qdisc *q, struct tcf_result *r)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned long cl;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if ((cl = __cls_set_class(&r->class, 0)) != 0)
18962306a36Sopenharmony_ci		q->ops->cl_ops->unbind_tcf(q, cl);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic inline void
19362306a36Sopenharmony_citcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct Qdisc *q = tp->chain->block->q;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (!q)
19862306a36Sopenharmony_ci		return;
19962306a36Sopenharmony_ci	__tcf_unbind_filter(q, r);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline void tc_cls_bind_class(u32 classid, unsigned long cl,
20362306a36Sopenharmony_ci				     void *q, struct tcf_result *res,
20462306a36Sopenharmony_ci				     unsigned long base)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	if (res->classid == classid) {
20762306a36Sopenharmony_ci		if (cl)
20862306a36Sopenharmony_ci			__tcf_bind_filter(q, res, base);
20962306a36Sopenharmony_ci		else
21062306a36Sopenharmony_ci			__tcf_unbind_filter(q, res);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistruct tcf_exts {
21562306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
21662306a36Sopenharmony_ci	__u32	type; /* for backward compat(TCA_OLD_COMPAT) */
21762306a36Sopenharmony_ci	int nr_actions;
21862306a36Sopenharmony_ci	struct tc_action **actions;
21962306a36Sopenharmony_ci	struct net	*net;
22062306a36Sopenharmony_ci	netns_tracker	ns_tracker;
22162306a36Sopenharmony_ci	struct tcf_exts_miss_cookie_node *miss_cookie_node;
22262306a36Sopenharmony_ci#endif
22362306a36Sopenharmony_ci	/* Map to export classifier specific extension TLV types to the
22462306a36Sopenharmony_ci	 * generic extensions API. Unsupported extensions must be set to 0.
22562306a36Sopenharmony_ci	 */
22662306a36Sopenharmony_ci	int action;
22762306a36Sopenharmony_ci	int police;
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline int tcf_exts_init(struct tcf_exts *exts, struct net *net,
23162306a36Sopenharmony_ci				int action, int police)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS
23462306a36Sopenharmony_ci	return tcf_exts_init_ex(exts, net, action, police, NULL, 0, false);
23562306a36Sopenharmony_ci#else
23662306a36Sopenharmony_ci	return -EOPNOTSUPP;
23762306a36Sopenharmony_ci#endif
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/* Return false if the netns is being destroyed in cleanup_net(). Callers
24162306a36Sopenharmony_ci * need to do cleanup synchronously in this case, otherwise may race with
24262306a36Sopenharmony_ci * tc_action_net_exit(). Return true for other cases.
24362306a36Sopenharmony_ci */
24462306a36Sopenharmony_cistatic inline bool tcf_exts_get_net(struct tcf_exts *exts)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
24762306a36Sopenharmony_ci	exts->net = maybe_get_net(exts->net);
24862306a36Sopenharmony_ci	if (exts->net)
24962306a36Sopenharmony_ci		netns_tracker_alloc(exts->net, &exts->ns_tracker, GFP_KERNEL);
25062306a36Sopenharmony_ci	return exts->net != NULL;
25162306a36Sopenharmony_ci#else
25262306a36Sopenharmony_ci	return true;
25362306a36Sopenharmony_ci#endif
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline void tcf_exts_put_net(struct tcf_exts *exts)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
25962306a36Sopenharmony_ci	if (exts->net)
26062306a36Sopenharmony_ci		put_net_track(exts->net, &exts->ns_tracker);
26162306a36Sopenharmony_ci#endif
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
26562306a36Sopenharmony_ci#define tcf_exts_for_each_action(i, a, exts) \
26662306a36Sopenharmony_ci	for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = (exts)->actions[i]); i++)
26762306a36Sopenharmony_ci#else
26862306a36Sopenharmony_ci#define tcf_exts_for_each_action(i, a, exts) \
26962306a36Sopenharmony_ci	for (; 0; (void)(i), (void)(a), (void)(exts))
27062306a36Sopenharmony_ci#endif
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci#define tcf_act_for_each_action(i, a, actions) \
27362306a36Sopenharmony_ci	for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = actions[i]); i++)
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic inline bool tc_act_in_hw(struct tc_action *act)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	return !!act->in_hw_count;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic inline void
28162306a36Sopenharmony_citcf_exts_hw_stats_update(const struct tcf_exts *exts,
28262306a36Sopenharmony_ci			 struct flow_stats *stats,
28362306a36Sopenharmony_ci			 bool use_act_stats)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
28662306a36Sopenharmony_ci	int i;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < exts->nr_actions; i++) {
28962306a36Sopenharmony_ci		struct tc_action *a = exts->actions[i];
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		if (use_act_stats || tc_act_in_hw(a)) {
29262306a36Sopenharmony_ci			if (!tcf_action_update_hw_stats(a))
29362306a36Sopenharmony_ci				continue;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		preempt_disable();
29762306a36Sopenharmony_ci		tcf_action_stats_update(a, stats->bytes, stats->pkts, stats->drops,
29862306a36Sopenharmony_ci					stats->lastused, true);
29962306a36Sopenharmony_ci		preempt_enable();
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		a->used_hw_stats = stats->used_hw_stats;
30262306a36Sopenharmony_ci		a->used_hw_stats_valid = stats->used_hw_stats_valid;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci#endif
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/**
30862306a36Sopenharmony_ci * tcf_exts_has_actions - check if at least one action is present
30962306a36Sopenharmony_ci * @exts: tc filter extensions handle
31062306a36Sopenharmony_ci *
31162306a36Sopenharmony_ci * Returns true if at least one action is present.
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cistatic inline bool tcf_exts_has_actions(struct tcf_exts *exts)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
31662306a36Sopenharmony_ci	return exts->nr_actions;
31762306a36Sopenharmony_ci#else
31862306a36Sopenharmony_ci	return false;
31962306a36Sopenharmony_ci#endif
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/**
32362306a36Sopenharmony_ci * tcf_exts_exec - execute tc filter extensions
32462306a36Sopenharmony_ci * @skb: socket buffer
32562306a36Sopenharmony_ci * @exts: tc filter extensions handle
32662306a36Sopenharmony_ci * @res: desired result
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * Executes all configured extensions. Returns TC_ACT_OK on a normal execution,
32962306a36Sopenharmony_ci * a negative number if the filter must be considered unmatched or
33062306a36Sopenharmony_ci * a positive action code (TC_ACT_*) which must be returned to the
33162306a36Sopenharmony_ci * underlying layer.
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic inline int
33462306a36Sopenharmony_citcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
33562306a36Sopenharmony_ci	      struct tcf_result *res)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
33862306a36Sopenharmony_ci	return tcf_action_exec(skb, exts->actions, exts->nr_actions, res);
33962306a36Sopenharmony_ci#endif
34062306a36Sopenharmony_ci	return TC_ACT_OK;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic inline int
34462306a36Sopenharmony_citcf_exts_exec_ex(struct sk_buff *skb, struct tcf_exts *exts, int act_index,
34562306a36Sopenharmony_ci		 struct tcf_result *res)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
34862306a36Sopenharmony_ci	return tcf_action_exec(skb, exts->actions + act_index,
34962306a36Sopenharmony_ci			       exts->nr_actions - act_index, res);
35062306a36Sopenharmony_ci#else
35162306a36Sopenharmony_ci	return TC_ACT_OK;
35262306a36Sopenharmony_ci#endif
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ciint tcf_exts_validate(struct net *net, struct tcf_proto *tp,
35662306a36Sopenharmony_ci		      struct nlattr **tb, struct nlattr *rate_tlv,
35762306a36Sopenharmony_ci		      struct tcf_exts *exts, u32 flags,
35862306a36Sopenharmony_ci		      struct netlink_ext_ack *extack);
35962306a36Sopenharmony_ciint tcf_exts_validate_ex(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
36062306a36Sopenharmony_ci			 struct nlattr *rate_tlv, struct tcf_exts *exts,
36162306a36Sopenharmony_ci			 u32 flags, u32 fl_flags, struct netlink_ext_ack *extack);
36262306a36Sopenharmony_civoid tcf_exts_destroy(struct tcf_exts *exts);
36362306a36Sopenharmony_civoid tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src);
36462306a36Sopenharmony_ciint tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts);
36562306a36Sopenharmony_ciint tcf_exts_terse_dump(struct sk_buff *skb, struct tcf_exts *exts);
36662306a36Sopenharmony_ciint tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/**
36962306a36Sopenharmony_ci * struct tcf_pkt_info - packet information
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * @ptr: start of the pkt data
37262306a36Sopenharmony_ci * @nexthdr: offset of the next header
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_cistruct tcf_pkt_info {
37562306a36Sopenharmony_ci	unsigned char *		ptr;
37662306a36Sopenharmony_ci	int			nexthdr;
37762306a36Sopenharmony_ci};
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci#ifdef CONFIG_NET_EMATCH
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistruct tcf_ematch_ops;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci/**
38462306a36Sopenharmony_ci * struct tcf_ematch - extended match (ematch)
38562306a36Sopenharmony_ci *
38662306a36Sopenharmony_ci * @matchid: identifier to allow userspace to reidentify a match
38762306a36Sopenharmony_ci * @flags: flags specifying attributes and the relation to other matches
38862306a36Sopenharmony_ci * @ops: the operations lookup table of the corresponding ematch module
38962306a36Sopenharmony_ci * @datalen: length of the ematch specific configuration data
39062306a36Sopenharmony_ci * @data: ematch specific data
39162306a36Sopenharmony_ci * @net: the network namespace
39262306a36Sopenharmony_ci */
39362306a36Sopenharmony_cistruct tcf_ematch {
39462306a36Sopenharmony_ci	struct tcf_ematch_ops * ops;
39562306a36Sopenharmony_ci	unsigned long		data;
39662306a36Sopenharmony_ci	unsigned int		datalen;
39762306a36Sopenharmony_ci	u16			matchid;
39862306a36Sopenharmony_ci	u16			flags;
39962306a36Sopenharmony_ci	struct net		*net;
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic inline int tcf_em_is_container(struct tcf_ematch *em)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	return !em->ops;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic inline int tcf_em_is_simple(struct tcf_ematch *em)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	return em->flags & TCF_EM_SIMPLE;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic inline int tcf_em_is_inverted(struct tcf_ematch *em)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	return em->flags & TCF_EM_INVERT;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic inline int tcf_em_last_match(struct tcf_ematch *em)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	return (em->flags & TCF_EM_REL_MASK) == TCF_EM_REL_END;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic inline int tcf_em_early_end(struct tcf_ematch *em, int result)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	if (tcf_em_last_match(em))
42562306a36Sopenharmony_ci		return 1;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (result == 0 && em->flags & TCF_EM_REL_AND)
42862306a36Sopenharmony_ci		return 1;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (result != 0 && em->flags & TCF_EM_REL_OR)
43162306a36Sopenharmony_ci		return 1;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/**
43762306a36Sopenharmony_ci * struct tcf_ematch_tree - ematch tree handle
43862306a36Sopenharmony_ci *
43962306a36Sopenharmony_ci * @hdr: ematch tree header supplied by userspace
44062306a36Sopenharmony_ci * @matches: array of ematches
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_cistruct tcf_ematch_tree {
44362306a36Sopenharmony_ci	struct tcf_ematch_tree_hdr hdr;
44462306a36Sopenharmony_ci	struct tcf_ematch *	matches;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/**
44962306a36Sopenharmony_ci * struct tcf_ematch_ops - ematch module operations
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci * @kind: identifier (kind) of this ematch module
45262306a36Sopenharmony_ci * @datalen: length of expected configuration data (optional)
45362306a36Sopenharmony_ci * @change: called during validation (optional)
45462306a36Sopenharmony_ci * @match: called during ematch tree evaluation, must return 1/0
45562306a36Sopenharmony_ci * @destroy: called during destroyage (optional)
45662306a36Sopenharmony_ci * @dump: called during dumping process (optional)
45762306a36Sopenharmony_ci * @owner: owner, must be set to THIS_MODULE
45862306a36Sopenharmony_ci * @link: link to previous/next ematch module (internal use)
45962306a36Sopenharmony_ci */
46062306a36Sopenharmony_cistruct tcf_ematch_ops {
46162306a36Sopenharmony_ci	int			kind;
46262306a36Sopenharmony_ci	int			datalen;
46362306a36Sopenharmony_ci	int			(*change)(struct net *net, void *,
46462306a36Sopenharmony_ci					  int, struct tcf_ematch *);
46562306a36Sopenharmony_ci	int			(*match)(struct sk_buff *, struct tcf_ematch *,
46662306a36Sopenharmony_ci					 struct tcf_pkt_info *);
46762306a36Sopenharmony_ci	void			(*destroy)(struct tcf_ematch *);
46862306a36Sopenharmony_ci	int			(*dump)(struct sk_buff *, struct tcf_ematch *);
46962306a36Sopenharmony_ci	struct module		*owner;
47062306a36Sopenharmony_ci	struct list_head	link;
47162306a36Sopenharmony_ci};
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ciint tcf_em_register(struct tcf_ematch_ops *);
47462306a36Sopenharmony_civoid tcf_em_unregister(struct tcf_ematch_ops *);
47562306a36Sopenharmony_ciint tcf_em_tree_validate(struct tcf_proto *, struct nlattr *,
47662306a36Sopenharmony_ci			 struct tcf_ematch_tree *);
47762306a36Sopenharmony_civoid tcf_em_tree_destroy(struct tcf_ematch_tree *);
47862306a36Sopenharmony_ciint tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int);
47962306a36Sopenharmony_ciint __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *,
48062306a36Sopenharmony_ci			struct tcf_pkt_info *);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/**
48362306a36Sopenharmony_ci * tcf_em_tree_match - evaulate an ematch tree
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci * @skb: socket buffer of the packet in question
48662306a36Sopenharmony_ci * @tree: ematch tree to be used for evaluation
48762306a36Sopenharmony_ci * @info: packet information examined by classifier
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * This function matches @skb against the ematch tree in @tree by going
49062306a36Sopenharmony_ci * through all ematches respecting their logic relations returning
49162306a36Sopenharmony_ci * as soon as the result is obvious.
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * Returns 1 if the ematch tree as-one matches, no ematches are configured
49462306a36Sopenharmony_ci * or ematch is not enabled in the kernel, otherwise 0 is returned.
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_cistatic inline int tcf_em_tree_match(struct sk_buff *skb,
49762306a36Sopenharmony_ci				    struct tcf_ematch_tree *tree,
49862306a36Sopenharmony_ci				    struct tcf_pkt_info *info)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	if (tree->hdr.nmatches)
50162306a36Sopenharmony_ci		return __tcf_em_tree_match(skb, tree, info);
50262306a36Sopenharmony_ci	else
50362306a36Sopenharmony_ci		return 1;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci#define MODULE_ALIAS_TCF_EMATCH(kind)	MODULE_ALIAS("ematch-kind-" __stringify(kind))
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci#else /* CONFIG_NET_EMATCH */
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistruct tcf_ematch_tree {
51162306a36Sopenharmony_ci};
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci#define tcf_em_tree_validate(tp, tb, t) ((void)(t), 0)
51462306a36Sopenharmony_ci#define tcf_em_tree_destroy(t) do { (void)(t); } while(0)
51562306a36Sopenharmony_ci#define tcf_em_tree_dump(skb, t, tlv) (0)
51662306a36Sopenharmony_ci#define tcf_em_tree_match(skb, t, info) ((void)(info), 1)
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci#endif /* CONFIG_NET_EMATCH */
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic inline unsigned char * tcf_get_base_ptr(struct sk_buff *skb, int layer)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	switch (layer) {
52362306a36Sopenharmony_ci		case TCF_LAYER_LINK:
52462306a36Sopenharmony_ci			return skb_mac_header(skb);
52562306a36Sopenharmony_ci		case TCF_LAYER_NETWORK:
52662306a36Sopenharmony_ci			return skb_network_header(skb);
52762306a36Sopenharmony_ci		case TCF_LAYER_TRANSPORT:
52862306a36Sopenharmony_ci			return skb_transport_header(skb);
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	return NULL;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic inline int tcf_valid_offset(const struct sk_buff *skb,
53562306a36Sopenharmony_ci				   const unsigned char *ptr, const int len)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	return likely((ptr + len) <= skb_tail_pointer(skb) &&
53862306a36Sopenharmony_ci		      ptr >= skb->head &&
53962306a36Sopenharmony_ci		      (ptr <= (ptr + len)));
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic inline int
54362306a36Sopenharmony_citcf_change_indev(struct net *net, struct nlattr *indev_tlv,
54462306a36Sopenharmony_ci		 struct netlink_ext_ack *extack)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	char indev[IFNAMSIZ];
54762306a36Sopenharmony_ci	struct net_device *dev;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (nla_strscpy(indev, indev_tlv, IFNAMSIZ) < 0) {
55062306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, indev_tlv,
55162306a36Sopenharmony_ci				    "Interface name too long");
55262306a36Sopenharmony_ci		return -EINVAL;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci	dev = __dev_get_by_name(net, indev);
55562306a36Sopenharmony_ci	if (!dev) {
55662306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, indev_tlv,
55762306a36Sopenharmony_ci				    "Network device not found");
55862306a36Sopenharmony_ci		return -ENODEV;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	return dev->ifindex;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cistatic inline bool
56462306a36Sopenharmony_citcf_match_indev(struct sk_buff *skb, int ifindex)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	if (!ifindex)
56762306a36Sopenharmony_ci		return true;
56862306a36Sopenharmony_ci	if  (!skb->skb_iif)
56962306a36Sopenharmony_ci		return false;
57062306a36Sopenharmony_ci	return ifindex == skb->skb_iif;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ciint tc_setup_offload_action(struct flow_action *flow_action,
57462306a36Sopenharmony_ci			    const struct tcf_exts *exts,
57562306a36Sopenharmony_ci			    struct netlink_ext_ack *extack);
57662306a36Sopenharmony_civoid tc_cleanup_offload_action(struct flow_action *flow_action);
57762306a36Sopenharmony_ciint tc_setup_action(struct flow_action *flow_action,
57862306a36Sopenharmony_ci		    struct tc_action *actions[],
57962306a36Sopenharmony_ci		    u32 miss_cookie_base,
58062306a36Sopenharmony_ci		    struct netlink_ext_ack *extack);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ciint tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
58362306a36Sopenharmony_ci		     void *type_data, bool err_stop, bool rtnl_held);
58462306a36Sopenharmony_ciint tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
58562306a36Sopenharmony_ci		    enum tc_setup_type type, void *type_data, bool err_stop,
58662306a36Sopenharmony_ci		    u32 *flags, unsigned int *in_hw_count, bool rtnl_held);
58762306a36Sopenharmony_ciint tc_setup_cb_replace(struct tcf_block *block, struct tcf_proto *tp,
58862306a36Sopenharmony_ci			enum tc_setup_type type, void *type_data, bool err_stop,
58962306a36Sopenharmony_ci			u32 *old_flags, unsigned int *old_in_hw_count,
59062306a36Sopenharmony_ci			u32 *new_flags, unsigned int *new_in_hw_count,
59162306a36Sopenharmony_ci			bool rtnl_held);
59262306a36Sopenharmony_ciint tc_setup_cb_destroy(struct tcf_block *block, struct tcf_proto *tp,
59362306a36Sopenharmony_ci			enum tc_setup_type type, void *type_data, bool err_stop,
59462306a36Sopenharmony_ci			u32 *flags, unsigned int *in_hw_count, bool rtnl_held);
59562306a36Sopenharmony_ciint tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
59662306a36Sopenharmony_ci			  bool add, flow_setup_cb_t *cb,
59762306a36Sopenharmony_ci			  enum tc_setup_type type, void *type_data,
59862306a36Sopenharmony_ci			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
59962306a36Sopenharmony_ciunsigned int tcf_exts_num_actions(struct tcf_exts *exts);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
60262306a36Sopenharmony_ciint tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
60362306a36Sopenharmony_ci		    enum flow_block_binder_type binder_type,
60462306a36Sopenharmony_ci		    struct nlattr *block_index_attr,
60562306a36Sopenharmony_ci		    struct netlink_ext_ack *extack);
60662306a36Sopenharmony_civoid tcf_qevent_destroy(struct tcf_qevent *qe, struct Qdisc *sch);
60762306a36Sopenharmony_ciint tcf_qevent_validate_change(struct tcf_qevent *qe, struct nlattr *block_index_attr,
60862306a36Sopenharmony_ci			       struct netlink_ext_ack *extack);
60962306a36Sopenharmony_cistruct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struct sk_buff *skb,
61062306a36Sopenharmony_ci				  struct sk_buff **to_free, int *ret);
61162306a36Sopenharmony_ciint tcf_qevent_dump(struct sk_buff *skb, int attr_name, struct tcf_qevent *qe);
61262306a36Sopenharmony_ci#else
61362306a36Sopenharmony_cistatic inline int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
61462306a36Sopenharmony_ci				  enum flow_block_binder_type binder_type,
61562306a36Sopenharmony_ci				  struct nlattr *block_index_attr,
61662306a36Sopenharmony_ci				  struct netlink_ext_ack *extack)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	return 0;
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic inline void tcf_qevent_destroy(struct tcf_qevent *qe, struct Qdisc *sch)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic inline int tcf_qevent_validate_change(struct tcf_qevent *qe, struct nlattr *block_index_attr,
62662306a36Sopenharmony_ci					     struct netlink_ext_ack *extack)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic inline struct sk_buff *
63262306a36Sopenharmony_citcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struct sk_buff *skb,
63362306a36Sopenharmony_ci		  struct sk_buff **to_free, int *ret)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	return skb;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic inline int tcf_qevent_dump(struct sk_buff *skb, int attr_name, struct tcf_qevent *qe)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci#endif
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistruct tc_cls_u32_knode {
64562306a36Sopenharmony_ci	struct tcf_exts *exts;
64662306a36Sopenharmony_ci	struct tcf_result *res;
64762306a36Sopenharmony_ci	struct tc_u32_sel *sel;
64862306a36Sopenharmony_ci	u32 handle;
64962306a36Sopenharmony_ci	u32 val;
65062306a36Sopenharmony_ci	u32 mask;
65162306a36Sopenharmony_ci	u32 link_handle;
65262306a36Sopenharmony_ci	u8 fshift;
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistruct tc_cls_u32_hnode {
65662306a36Sopenharmony_ci	u32 handle;
65762306a36Sopenharmony_ci	u32 prio;
65862306a36Sopenharmony_ci	unsigned int divisor;
65962306a36Sopenharmony_ci};
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cienum tc_clsu32_command {
66262306a36Sopenharmony_ci	TC_CLSU32_NEW_KNODE,
66362306a36Sopenharmony_ci	TC_CLSU32_REPLACE_KNODE,
66462306a36Sopenharmony_ci	TC_CLSU32_DELETE_KNODE,
66562306a36Sopenharmony_ci	TC_CLSU32_NEW_HNODE,
66662306a36Sopenharmony_ci	TC_CLSU32_REPLACE_HNODE,
66762306a36Sopenharmony_ci	TC_CLSU32_DELETE_HNODE,
66862306a36Sopenharmony_ci};
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistruct tc_cls_u32_offload {
67162306a36Sopenharmony_ci	struct flow_cls_common_offload common;
67262306a36Sopenharmony_ci	/* knode values */
67362306a36Sopenharmony_ci	enum tc_clsu32_command command;
67462306a36Sopenharmony_ci	union {
67562306a36Sopenharmony_ci		struct tc_cls_u32_knode knode;
67662306a36Sopenharmony_ci		struct tc_cls_u32_hnode hnode;
67762306a36Sopenharmony_ci	};
67862306a36Sopenharmony_ci};
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic inline bool tc_can_offload(const struct net_device *dev)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return dev->features & NETIF_F_HW_TC;
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic inline bool tc_can_offload_extack(const struct net_device *dev,
68662306a36Sopenharmony_ci					 struct netlink_ext_ack *extack)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	bool can = tc_can_offload(dev);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (!can)
69162306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack, "TC offload is disabled on net device");
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return can;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic inline bool
69762306a36Sopenharmony_citc_cls_can_offload_and_chain0(const struct net_device *dev,
69862306a36Sopenharmony_ci			      struct flow_cls_common_offload *common)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	if (!tc_can_offload_extack(dev, common->extack))
70162306a36Sopenharmony_ci		return false;
70262306a36Sopenharmony_ci	if (common->chain_index) {
70362306a36Sopenharmony_ci		NL_SET_ERR_MSG(common->extack,
70462306a36Sopenharmony_ci			       "Driver supports only offload of chain 0");
70562306a36Sopenharmony_ci		return false;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci	return true;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic inline bool tc_skip_hw(u32 flags)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_SKIP_HW) ? true : false;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic inline bool tc_skip_sw(u32 flags)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_SKIP_SW) ? true : false;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/* SKIP_HW and SKIP_SW are mutually exclusive flags. */
72162306a36Sopenharmony_cistatic inline bool tc_flags_valid(u32 flags)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	if (flags & ~(TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW |
72462306a36Sopenharmony_ci		      TCA_CLS_FLAGS_VERBOSE))
72562306a36Sopenharmony_ci		return false;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	flags &= TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW;
72862306a36Sopenharmony_ci	if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)))
72962306a36Sopenharmony_ci		return false;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return true;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic inline bool tc_in_hw(u32 flags)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_IN_HW) ? true : false;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic inline void
74062306a36Sopenharmony_citc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
74162306a36Sopenharmony_ci			   const struct tcf_proto *tp, u32 flags,
74262306a36Sopenharmony_ci			   struct netlink_ext_ack *extack)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	cls_common->chain_index = tp->chain->index;
74562306a36Sopenharmony_ci	cls_common->protocol = tp->protocol;
74662306a36Sopenharmony_ci	cls_common->prio = tp->prio >> 16;
74762306a36Sopenharmony_ci	if (tc_skip_sw(flags) || flags & TCA_CLS_FLAGS_VERBOSE)
74862306a36Sopenharmony_ci		cls_common->extack = extack;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
75262306a36Sopenharmony_cistatic inline struct tc_skb_ext *tc_skb_ext_alloc(struct sk_buff *skb)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	struct tc_skb_ext *tc_skb_ext = skb_ext_add(skb, TC_SKB_EXT);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (tc_skb_ext)
75762306a36Sopenharmony_ci		memset(tc_skb_ext, 0, sizeof(*tc_skb_ext));
75862306a36Sopenharmony_ci	return tc_skb_ext;
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci#endif
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cienum tc_matchall_command {
76362306a36Sopenharmony_ci	TC_CLSMATCHALL_REPLACE,
76462306a36Sopenharmony_ci	TC_CLSMATCHALL_DESTROY,
76562306a36Sopenharmony_ci	TC_CLSMATCHALL_STATS,
76662306a36Sopenharmony_ci};
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistruct tc_cls_matchall_offload {
76962306a36Sopenharmony_ci	struct flow_cls_common_offload common;
77062306a36Sopenharmony_ci	enum tc_matchall_command command;
77162306a36Sopenharmony_ci	struct flow_rule *rule;
77262306a36Sopenharmony_ci	struct flow_stats stats;
77362306a36Sopenharmony_ci	bool use_act_stats;
77462306a36Sopenharmony_ci	unsigned long cookie;
77562306a36Sopenharmony_ci};
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cienum tc_clsbpf_command {
77862306a36Sopenharmony_ci	TC_CLSBPF_OFFLOAD,
77962306a36Sopenharmony_ci	TC_CLSBPF_STATS,
78062306a36Sopenharmony_ci};
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistruct tc_cls_bpf_offload {
78362306a36Sopenharmony_ci	struct flow_cls_common_offload common;
78462306a36Sopenharmony_ci	enum tc_clsbpf_command command;
78562306a36Sopenharmony_ci	struct tcf_exts *exts;
78662306a36Sopenharmony_ci	struct bpf_prog *prog;
78762306a36Sopenharmony_ci	struct bpf_prog *oldprog;
78862306a36Sopenharmony_ci	const char *name;
78962306a36Sopenharmony_ci	bool exts_integrated;
79062306a36Sopenharmony_ci};
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci/* This structure holds cookie structure that is passed from user
79362306a36Sopenharmony_ci * to the kernel for actions and classifiers
79462306a36Sopenharmony_ci */
79562306a36Sopenharmony_cistruct tc_cookie {
79662306a36Sopenharmony_ci	u8  *data;
79762306a36Sopenharmony_ci	u32 len;
79862306a36Sopenharmony_ci	struct rcu_head rcu;
79962306a36Sopenharmony_ci};
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistruct tc_qopt_offload_stats {
80262306a36Sopenharmony_ci	struct gnet_stats_basic_sync *bstats;
80362306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
80462306a36Sopenharmony_ci};
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cienum tc_mq_command {
80762306a36Sopenharmony_ci	TC_MQ_CREATE,
80862306a36Sopenharmony_ci	TC_MQ_DESTROY,
80962306a36Sopenharmony_ci	TC_MQ_STATS,
81062306a36Sopenharmony_ci	TC_MQ_GRAFT,
81162306a36Sopenharmony_ci};
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistruct tc_mq_opt_offload_graft_params {
81462306a36Sopenharmony_ci	unsigned long queue;
81562306a36Sopenharmony_ci	u32 child_handle;
81662306a36Sopenharmony_ci};
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistruct tc_mq_qopt_offload {
81962306a36Sopenharmony_ci	enum tc_mq_command command;
82062306a36Sopenharmony_ci	u32 handle;
82162306a36Sopenharmony_ci	union {
82262306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
82362306a36Sopenharmony_ci		struct tc_mq_opt_offload_graft_params graft_params;
82462306a36Sopenharmony_ci	};
82562306a36Sopenharmony_ci};
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cienum tc_htb_command {
82862306a36Sopenharmony_ci	/* Root */
82962306a36Sopenharmony_ci	TC_HTB_CREATE, /* Initialize HTB offload. */
83062306a36Sopenharmony_ci	TC_HTB_DESTROY, /* Destroy HTB offload. */
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/* Classes */
83362306a36Sopenharmony_ci	/* Allocate qid and create leaf. */
83462306a36Sopenharmony_ci	TC_HTB_LEAF_ALLOC_QUEUE,
83562306a36Sopenharmony_ci	/* Convert leaf to inner, preserve and return qid, create new leaf. */
83662306a36Sopenharmony_ci	TC_HTB_LEAF_TO_INNER,
83762306a36Sopenharmony_ci	/* Delete leaf, while siblings remain. */
83862306a36Sopenharmony_ci	TC_HTB_LEAF_DEL,
83962306a36Sopenharmony_ci	/* Delete leaf, convert parent to leaf, preserving qid. */
84062306a36Sopenharmony_ci	TC_HTB_LEAF_DEL_LAST,
84162306a36Sopenharmony_ci	/* TC_HTB_LEAF_DEL_LAST, but delete driver data on hardware errors. */
84262306a36Sopenharmony_ci	TC_HTB_LEAF_DEL_LAST_FORCE,
84362306a36Sopenharmony_ci	/* Modify parameters of a node. */
84462306a36Sopenharmony_ci	TC_HTB_NODE_MODIFY,
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/* Class qdisc */
84762306a36Sopenharmony_ci	TC_HTB_LEAF_QUERY_QUEUE, /* Query qid by classid. */
84862306a36Sopenharmony_ci};
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistruct tc_htb_qopt_offload {
85162306a36Sopenharmony_ci	struct netlink_ext_ack *extack;
85262306a36Sopenharmony_ci	enum tc_htb_command command;
85362306a36Sopenharmony_ci	u32 parent_classid;
85462306a36Sopenharmony_ci	u16 classid;
85562306a36Sopenharmony_ci	u16 qid;
85662306a36Sopenharmony_ci	u32 quantum;
85762306a36Sopenharmony_ci	u64 rate;
85862306a36Sopenharmony_ci	u64 ceil;
85962306a36Sopenharmony_ci	u8 prio;
86062306a36Sopenharmony_ci};
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci#define TC_HTB_CLASSID_ROOT U32_MAX
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cienum tc_red_command {
86562306a36Sopenharmony_ci	TC_RED_REPLACE,
86662306a36Sopenharmony_ci	TC_RED_DESTROY,
86762306a36Sopenharmony_ci	TC_RED_STATS,
86862306a36Sopenharmony_ci	TC_RED_XSTATS,
86962306a36Sopenharmony_ci	TC_RED_GRAFT,
87062306a36Sopenharmony_ci};
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistruct tc_red_qopt_offload_params {
87362306a36Sopenharmony_ci	u32 min;
87462306a36Sopenharmony_ci	u32 max;
87562306a36Sopenharmony_ci	u32 probability;
87662306a36Sopenharmony_ci	u32 limit;
87762306a36Sopenharmony_ci	bool is_ecn;
87862306a36Sopenharmony_ci	bool is_harddrop;
87962306a36Sopenharmony_ci	bool is_nodrop;
88062306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
88162306a36Sopenharmony_ci};
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistruct tc_red_qopt_offload {
88462306a36Sopenharmony_ci	enum tc_red_command command;
88562306a36Sopenharmony_ci	u32 handle;
88662306a36Sopenharmony_ci	u32 parent;
88762306a36Sopenharmony_ci	union {
88862306a36Sopenharmony_ci		struct tc_red_qopt_offload_params set;
88962306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
89062306a36Sopenharmony_ci		struct red_stats *xstats;
89162306a36Sopenharmony_ci		u32 child_handle;
89262306a36Sopenharmony_ci	};
89362306a36Sopenharmony_ci};
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cienum tc_gred_command {
89662306a36Sopenharmony_ci	TC_GRED_REPLACE,
89762306a36Sopenharmony_ci	TC_GRED_DESTROY,
89862306a36Sopenharmony_ci	TC_GRED_STATS,
89962306a36Sopenharmony_ci};
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistruct tc_gred_vq_qopt_offload_params {
90262306a36Sopenharmony_ci	bool present;
90362306a36Sopenharmony_ci	u32 limit;
90462306a36Sopenharmony_ci	u32 prio;
90562306a36Sopenharmony_ci	u32 min;
90662306a36Sopenharmony_ci	u32 max;
90762306a36Sopenharmony_ci	bool is_ecn;
90862306a36Sopenharmony_ci	bool is_harddrop;
90962306a36Sopenharmony_ci	u32 probability;
91062306a36Sopenharmony_ci	/* Only need backlog, see struct tc_prio_qopt_offload_params */
91162306a36Sopenharmony_ci	u32 *backlog;
91262306a36Sopenharmony_ci};
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistruct tc_gred_qopt_offload_params {
91562306a36Sopenharmony_ci	bool grio_on;
91662306a36Sopenharmony_ci	bool wred_on;
91762306a36Sopenharmony_ci	unsigned int dp_cnt;
91862306a36Sopenharmony_ci	unsigned int dp_def;
91962306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
92062306a36Sopenharmony_ci	struct tc_gred_vq_qopt_offload_params tab[MAX_DPs];
92162306a36Sopenharmony_ci};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistruct tc_gred_qopt_offload_stats {
92462306a36Sopenharmony_ci	struct gnet_stats_basic_sync bstats[MAX_DPs];
92562306a36Sopenharmony_ci	struct gnet_stats_queue qstats[MAX_DPs];
92662306a36Sopenharmony_ci	struct red_stats *xstats[MAX_DPs];
92762306a36Sopenharmony_ci};
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_cistruct tc_gred_qopt_offload {
93062306a36Sopenharmony_ci	enum tc_gred_command command;
93162306a36Sopenharmony_ci	u32 handle;
93262306a36Sopenharmony_ci	u32 parent;
93362306a36Sopenharmony_ci	union {
93462306a36Sopenharmony_ci		struct tc_gred_qopt_offload_params set;
93562306a36Sopenharmony_ci		struct tc_gred_qopt_offload_stats stats;
93662306a36Sopenharmony_ci	};
93762306a36Sopenharmony_ci};
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cienum tc_prio_command {
94062306a36Sopenharmony_ci	TC_PRIO_REPLACE,
94162306a36Sopenharmony_ci	TC_PRIO_DESTROY,
94262306a36Sopenharmony_ci	TC_PRIO_STATS,
94362306a36Sopenharmony_ci	TC_PRIO_GRAFT,
94462306a36Sopenharmony_ci};
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistruct tc_prio_qopt_offload_params {
94762306a36Sopenharmony_ci	int bands;
94862306a36Sopenharmony_ci	u8 priomap[TC_PRIO_MAX + 1];
94962306a36Sopenharmony_ci	/* At the point of un-offloading the Qdisc, the reported backlog and
95062306a36Sopenharmony_ci	 * qlen need to be reduced by the portion that is in HW.
95162306a36Sopenharmony_ci	 */
95262306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
95362306a36Sopenharmony_ci};
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_cistruct tc_prio_qopt_offload_graft_params {
95662306a36Sopenharmony_ci	u8 band;
95762306a36Sopenharmony_ci	u32 child_handle;
95862306a36Sopenharmony_ci};
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cistruct tc_prio_qopt_offload {
96162306a36Sopenharmony_ci	enum tc_prio_command command;
96262306a36Sopenharmony_ci	u32 handle;
96362306a36Sopenharmony_ci	u32 parent;
96462306a36Sopenharmony_ci	union {
96562306a36Sopenharmony_ci		struct tc_prio_qopt_offload_params replace_params;
96662306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
96762306a36Sopenharmony_ci		struct tc_prio_qopt_offload_graft_params graft_params;
96862306a36Sopenharmony_ci	};
96962306a36Sopenharmony_ci};
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cienum tc_root_command {
97262306a36Sopenharmony_ci	TC_ROOT_GRAFT,
97362306a36Sopenharmony_ci};
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistruct tc_root_qopt_offload {
97662306a36Sopenharmony_ci	enum tc_root_command command;
97762306a36Sopenharmony_ci	u32 handle;
97862306a36Sopenharmony_ci	bool ingress;
97962306a36Sopenharmony_ci};
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cienum tc_ets_command {
98262306a36Sopenharmony_ci	TC_ETS_REPLACE,
98362306a36Sopenharmony_ci	TC_ETS_DESTROY,
98462306a36Sopenharmony_ci	TC_ETS_STATS,
98562306a36Sopenharmony_ci	TC_ETS_GRAFT,
98662306a36Sopenharmony_ci};
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistruct tc_ets_qopt_offload_replace_params {
98962306a36Sopenharmony_ci	unsigned int bands;
99062306a36Sopenharmony_ci	u8 priomap[TC_PRIO_MAX + 1];
99162306a36Sopenharmony_ci	unsigned int quanta[TCQ_ETS_MAX_BANDS];	/* 0 for strict bands. */
99262306a36Sopenharmony_ci	unsigned int weights[TCQ_ETS_MAX_BANDS];
99362306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
99462306a36Sopenharmony_ci};
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cistruct tc_ets_qopt_offload_graft_params {
99762306a36Sopenharmony_ci	u8 band;
99862306a36Sopenharmony_ci	u32 child_handle;
99962306a36Sopenharmony_ci};
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistruct tc_ets_qopt_offload {
100262306a36Sopenharmony_ci	enum tc_ets_command command;
100362306a36Sopenharmony_ci	u32 handle;
100462306a36Sopenharmony_ci	u32 parent;
100562306a36Sopenharmony_ci	union {
100662306a36Sopenharmony_ci		struct tc_ets_qopt_offload_replace_params replace_params;
100762306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
100862306a36Sopenharmony_ci		struct tc_ets_qopt_offload_graft_params graft_params;
100962306a36Sopenharmony_ci	};
101062306a36Sopenharmony_ci};
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cienum tc_tbf_command {
101362306a36Sopenharmony_ci	TC_TBF_REPLACE,
101462306a36Sopenharmony_ci	TC_TBF_DESTROY,
101562306a36Sopenharmony_ci	TC_TBF_STATS,
101662306a36Sopenharmony_ci	TC_TBF_GRAFT,
101762306a36Sopenharmony_ci};
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistruct tc_tbf_qopt_offload_replace_params {
102062306a36Sopenharmony_ci	struct psched_ratecfg rate;
102162306a36Sopenharmony_ci	u32 max_size;
102262306a36Sopenharmony_ci	struct gnet_stats_queue *qstats;
102362306a36Sopenharmony_ci};
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistruct tc_tbf_qopt_offload {
102662306a36Sopenharmony_ci	enum tc_tbf_command command;
102762306a36Sopenharmony_ci	u32 handle;
102862306a36Sopenharmony_ci	u32 parent;
102962306a36Sopenharmony_ci	union {
103062306a36Sopenharmony_ci		struct tc_tbf_qopt_offload_replace_params replace_params;
103162306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
103262306a36Sopenharmony_ci		u32 child_handle;
103362306a36Sopenharmony_ci	};
103462306a36Sopenharmony_ci};
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cienum tc_fifo_command {
103762306a36Sopenharmony_ci	TC_FIFO_REPLACE,
103862306a36Sopenharmony_ci	TC_FIFO_DESTROY,
103962306a36Sopenharmony_ci	TC_FIFO_STATS,
104062306a36Sopenharmony_ci};
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistruct tc_fifo_qopt_offload {
104362306a36Sopenharmony_ci	enum tc_fifo_command command;
104462306a36Sopenharmony_ci	u32 handle;
104562306a36Sopenharmony_ci	u32 parent;
104662306a36Sopenharmony_ci	union {
104762306a36Sopenharmony_ci		struct tc_qopt_offload_stats stats;
104862306a36Sopenharmony_ci	};
104962306a36Sopenharmony_ci};
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
105262306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(tc_skb_ext_tc);
105362306a36Sopenharmony_civoid tc_skb_ext_tc_enable(void);
105462306a36Sopenharmony_civoid tc_skb_ext_tc_disable(void);
105562306a36Sopenharmony_ci#define tc_skb_ext_tc_enabled() static_branch_unlikely(&tc_skb_ext_tc)
105662306a36Sopenharmony_ci#else /* CONFIG_NET_CLS_ACT */
105762306a36Sopenharmony_cistatic inline void tc_skb_ext_tc_enable(void) { }
105862306a36Sopenharmony_cistatic inline void tc_skb_ext_tc_disable(void) { }
105962306a36Sopenharmony_ci#define tc_skb_ext_tc_enabled() false
106062306a36Sopenharmony_ci#endif
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci#endif
1063