18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef __NET_PKT_CLS_H
38c2ecf20Sopenharmony_ci#define __NET_PKT_CLS_H
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/pkt_cls.h>
68c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
78c2ecf20Sopenharmony_ci#include <net/sch_generic.h>
88c2ecf20Sopenharmony_ci#include <net/act_api.h>
98c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/* TC action not accessible from user space */
128c2ecf20Sopenharmony_ci#define TC_ACT_CONSUMED		(TC_ACT_VALUE_MAX + 1)
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* Basic packet classifier frontend definitions. */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistruct tcf_walker {
178c2ecf20Sopenharmony_ci	int	stop;
188c2ecf20Sopenharmony_ci	int	skip;
198c2ecf20Sopenharmony_ci	int	count;
208c2ecf20Sopenharmony_ci	bool	nonempty;
218c2ecf20Sopenharmony_ci	unsigned long cookie;
228c2ecf20Sopenharmony_ci	int	(*fn)(struct tcf_proto *, void *node, struct tcf_walker *);
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciint register_tcf_proto_ops(struct tcf_proto_ops *ops);
268c2ecf20Sopenharmony_ciint unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct tcf_block_ext_info {
298c2ecf20Sopenharmony_ci	enum flow_block_binder_type binder_type;
308c2ecf20Sopenharmony_ci	tcf_chain_head_change_t *chain_head_change;
318c2ecf20Sopenharmony_ci	void *chain_head_change_priv;
328c2ecf20Sopenharmony_ci	u32 block_index;
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct tcf_qevent {
368c2ecf20Sopenharmony_ci	struct tcf_block	*block;
378c2ecf20Sopenharmony_ci	struct tcf_block_ext_info info;
388c2ecf20Sopenharmony_ci	struct tcf_proto __rcu *filter_chain;
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct tcf_block_cb;
428c2ecf20Sopenharmony_cibool tcf_queue_work(struct rcu_work *rwork, work_func_t func);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS
458c2ecf20Sopenharmony_cistruct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block,
468c2ecf20Sopenharmony_ci				       u32 chain_index);
478c2ecf20Sopenharmony_civoid tcf_chain_put_by_act(struct tcf_chain *chain);
488c2ecf20Sopenharmony_cistruct tcf_chain *tcf_get_next_chain(struct tcf_block *block,
498c2ecf20Sopenharmony_ci				     struct tcf_chain *chain);
508c2ecf20Sopenharmony_cistruct tcf_proto *tcf_get_next_proto(struct tcf_chain *chain,
518c2ecf20Sopenharmony_ci				     struct tcf_proto *tp, bool rtnl_held);
528c2ecf20Sopenharmony_civoid tcf_block_netif_keep_dst(struct tcf_block *block);
538c2ecf20Sopenharmony_ciint tcf_block_get(struct tcf_block **p_block,
548c2ecf20Sopenharmony_ci		  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
558c2ecf20Sopenharmony_ci		  struct netlink_ext_ack *extack);
568c2ecf20Sopenharmony_ciint tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
578c2ecf20Sopenharmony_ci		      struct tcf_block_ext_info *ei,
588c2ecf20Sopenharmony_ci		      struct netlink_ext_ack *extack);
598c2ecf20Sopenharmony_civoid tcf_block_put(struct tcf_block *block);
608c2ecf20Sopenharmony_civoid tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
618c2ecf20Sopenharmony_ci		       struct tcf_block_ext_info *ei);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline bool tcf_block_shared(struct tcf_block *block)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	return block->index;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline bool tcf_block_non_null_shared(struct tcf_block *block)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	return block && block->index;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline struct Qdisc *tcf_block_q(struct tcf_block *block)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	WARN_ON(tcf_block_shared(block));
768c2ecf20Sopenharmony_ci	return block->q;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ciint tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
808c2ecf20Sopenharmony_ci		 struct tcf_result *res, bool compat_mode);
818c2ecf20Sopenharmony_ciint tcf_classify_ingress(struct sk_buff *skb,
828c2ecf20Sopenharmony_ci			 const struct tcf_block *ingress_block,
838c2ecf20Sopenharmony_ci			 const struct tcf_proto *tp, struct tcf_result *res,
848c2ecf20Sopenharmony_ci			 bool compat_mode);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#else
878c2ecf20Sopenharmony_cistatic inline bool tcf_block_shared(struct tcf_block *block)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	return false;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic inline bool tcf_block_non_null_shared(struct tcf_block *block)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	return false;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic inline
988c2ecf20Sopenharmony_ciint tcf_block_get(struct tcf_block **p_block,
998c2ecf20Sopenharmony_ci		  struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
1008c2ecf20Sopenharmony_ci		  struct netlink_ext_ack *extack)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline
1068c2ecf20Sopenharmony_ciint tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
1078c2ecf20Sopenharmony_ci		      struct tcf_block_ext_info *ei,
1088c2ecf20Sopenharmony_ci		      struct netlink_ext_ack *extack)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic inline void tcf_block_put(struct tcf_block *block)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic inline
1188c2ecf20Sopenharmony_civoid tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
1198c2ecf20Sopenharmony_ci		       struct tcf_block_ext_info *ei)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline struct Qdisc *tcf_block_q(struct tcf_block *block)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return NULL;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline
1298c2ecf20Sopenharmony_ciint tc_setup_cb_block_register(struct tcf_block *block, flow_setup_cb_t *cb,
1308c2ecf20Sopenharmony_ci			       void *cb_priv)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic inline
1368c2ecf20Sopenharmony_civoid tc_setup_cb_block_unregister(struct tcf_block *block, flow_setup_cb_t *cb,
1378c2ecf20Sopenharmony_ci				  void *cb_priv)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic inline int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
1428c2ecf20Sopenharmony_ci			       struct tcf_result *res, bool compat_mode)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	return TC_ACT_UNSPEC;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic inline int tcf_classify_ingress(struct sk_buff *skb,
1488c2ecf20Sopenharmony_ci				       const struct tcf_block *ingress_block,
1498c2ecf20Sopenharmony_ci				       const struct tcf_proto *tp,
1508c2ecf20Sopenharmony_ci				       struct tcf_result *res, bool compat_mode)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	return TC_ACT_UNSPEC;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#endif
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic inline unsigned long
1588c2ecf20Sopenharmony_ci__cls_set_class(unsigned long *clp, unsigned long cl)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	return xchg(clp, cl);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic inline void
1648c2ecf20Sopenharmony_ci__tcf_bind_filter(struct Qdisc *q, struct tcf_result *r, unsigned long base)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	unsigned long cl;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	cl = q->ops->cl_ops->bind_tcf(q, base, r->classid);
1698c2ecf20Sopenharmony_ci	cl = __cls_set_class(&r->class, cl);
1708c2ecf20Sopenharmony_ci	if (cl)
1718c2ecf20Sopenharmony_ci		q->ops->cl_ops->unbind_tcf(q, cl);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline void
1758c2ecf20Sopenharmony_citcf_bind_filter(struct tcf_proto *tp, struct tcf_result *r, unsigned long base)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct Qdisc *q = tp->chain->block->q;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Check q as it is not set for shared blocks. In that case,
1808c2ecf20Sopenharmony_ci	 * setting class is not supported.
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	if (!q)
1838c2ecf20Sopenharmony_ci		return;
1848c2ecf20Sopenharmony_ci	sch_tree_lock(q);
1858c2ecf20Sopenharmony_ci	__tcf_bind_filter(q, r, base);
1868c2ecf20Sopenharmony_ci	sch_tree_unlock(q);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline void
1908c2ecf20Sopenharmony_ci__tcf_unbind_filter(struct Qdisc *q, struct tcf_result *r)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	unsigned long cl;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if ((cl = __cls_set_class(&r->class, 0)) != 0)
1958c2ecf20Sopenharmony_ci		q->ops->cl_ops->unbind_tcf(q, cl);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic inline void
1998c2ecf20Sopenharmony_citcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct Qdisc *q = tp->chain->block->q;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (!q)
2048c2ecf20Sopenharmony_ci		return;
2058c2ecf20Sopenharmony_ci	__tcf_unbind_filter(q, r);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistruct tcf_exts {
2098c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2108c2ecf20Sopenharmony_ci	__u32	type; /* for backward compat(TCA_OLD_COMPAT) */
2118c2ecf20Sopenharmony_ci	int nr_actions;
2128c2ecf20Sopenharmony_ci	struct tc_action **actions;
2138c2ecf20Sopenharmony_ci	struct net *net;
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci	/* Map to export classifier specific extension TLV types to the
2168c2ecf20Sopenharmony_ci	 * generic extensions API. Unsupported extensions must be set to 0.
2178c2ecf20Sopenharmony_ci	 */
2188c2ecf20Sopenharmony_ci	int action;
2198c2ecf20Sopenharmony_ci	int police;
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic inline int tcf_exts_init(struct tcf_exts *exts, struct net *net,
2238c2ecf20Sopenharmony_ci				int action, int police)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2268c2ecf20Sopenharmony_ci	exts->type = 0;
2278c2ecf20Sopenharmony_ci	exts->nr_actions = 0;
2288c2ecf20Sopenharmony_ci	exts->net = net;
2298c2ecf20Sopenharmony_ci	exts->actions = kcalloc(TCA_ACT_MAX_PRIO, sizeof(struct tc_action *),
2308c2ecf20Sopenharmony_ci				GFP_KERNEL);
2318c2ecf20Sopenharmony_ci	if (!exts->actions)
2328c2ecf20Sopenharmony_ci		return -ENOMEM;
2338c2ecf20Sopenharmony_ci#endif
2348c2ecf20Sopenharmony_ci	exts->action = action;
2358c2ecf20Sopenharmony_ci	exts->police = police;
2368c2ecf20Sopenharmony_ci	return 0;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/* Return false if the netns is being destroyed in cleanup_net(). Callers
2408c2ecf20Sopenharmony_ci * need to do cleanup synchronously in this case, otherwise may race with
2418c2ecf20Sopenharmony_ci * tc_action_net_exit(). Return true for other cases.
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic inline bool tcf_exts_get_net(struct tcf_exts *exts)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2468c2ecf20Sopenharmony_ci	exts->net = maybe_get_net(exts->net);
2478c2ecf20Sopenharmony_ci	return exts->net != NULL;
2488c2ecf20Sopenharmony_ci#else
2498c2ecf20Sopenharmony_ci	return true;
2508c2ecf20Sopenharmony_ci#endif
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic inline void tcf_exts_put_net(struct tcf_exts *exts)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2568c2ecf20Sopenharmony_ci	if (exts->net)
2578c2ecf20Sopenharmony_ci		put_net(exts->net);
2588c2ecf20Sopenharmony_ci#endif
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2628c2ecf20Sopenharmony_ci#define tcf_exts_for_each_action(i, a, exts) \
2638c2ecf20Sopenharmony_ci	for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = (exts)->actions[i]); i++)
2648c2ecf20Sopenharmony_ci#else
2658c2ecf20Sopenharmony_ci#define tcf_exts_for_each_action(i, a, exts) \
2668c2ecf20Sopenharmony_ci	for (; 0; (void)(i), (void)(a), (void)(exts))
2678c2ecf20Sopenharmony_ci#endif
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic inline void
2708c2ecf20Sopenharmony_citcf_exts_stats_update(const struct tcf_exts *exts,
2718c2ecf20Sopenharmony_ci		      u64 bytes, u64 packets, u64 drops, u64 lastuse,
2728c2ecf20Sopenharmony_ci		      u8 used_hw_stats, bool used_hw_stats_valid)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
2758c2ecf20Sopenharmony_ci	int i;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	preempt_disable();
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	for (i = 0; i < exts->nr_actions; i++) {
2808c2ecf20Sopenharmony_ci		struct tc_action *a = exts->actions[i];
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		tcf_action_stats_update(a, bytes, packets, drops,
2838c2ecf20Sopenharmony_ci					lastuse, true);
2848c2ecf20Sopenharmony_ci		a->used_hw_stats = used_hw_stats;
2858c2ecf20Sopenharmony_ci		a->used_hw_stats_valid = used_hw_stats_valid;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	preempt_enable();
2898c2ecf20Sopenharmony_ci#endif
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/**
2938c2ecf20Sopenharmony_ci * tcf_exts_has_actions - check if at least one action is present
2948c2ecf20Sopenharmony_ci * @exts: tc filter extensions handle
2958c2ecf20Sopenharmony_ci *
2968c2ecf20Sopenharmony_ci * Returns true if at least one action is present.
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_cistatic inline bool tcf_exts_has_actions(struct tcf_exts *exts)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
3018c2ecf20Sopenharmony_ci	return exts->nr_actions;
3028c2ecf20Sopenharmony_ci#else
3038c2ecf20Sopenharmony_ci	return false;
3048c2ecf20Sopenharmony_ci#endif
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/**
3088c2ecf20Sopenharmony_ci * tcf_exts_exec - execute tc filter extensions
3098c2ecf20Sopenharmony_ci * @skb: socket buffer
3108c2ecf20Sopenharmony_ci * @exts: tc filter extensions handle
3118c2ecf20Sopenharmony_ci * @res: desired result
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * Executes all configured extensions. Returns TC_ACT_OK on a normal execution,
3148c2ecf20Sopenharmony_ci * a negative number if the filter must be considered unmatched or
3158c2ecf20Sopenharmony_ci * a positive action code (TC_ACT_*) which must be returned to the
3168c2ecf20Sopenharmony_ci * underlying layer.
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_cistatic inline int
3198c2ecf20Sopenharmony_citcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
3208c2ecf20Sopenharmony_ci	      struct tcf_result *res)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
3238c2ecf20Sopenharmony_ci	return tcf_action_exec(skb, exts->actions, exts->nr_actions, res);
3248c2ecf20Sopenharmony_ci#endif
3258c2ecf20Sopenharmony_ci	return TC_ACT_OK;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ciint tcf_exts_validate(struct net *net, struct tcf_proto *tp,
3298c2ecf20Sopenharmony_ci		      struct nlattr **tb, struct nlattr *rate_tlv,
3308c2ecf20Sopenharmony_ci		      struct tcf_exts *exts, bool ovr, bool rtnl_held,
3318c2ecf20Sopenharmony_ci		      struct netlink_ext_ack *extack);
3328c2ecf20Sopenharmony_civoid tcf_exts_destroy(struct tcf_exts *exts);
3338c2ecf20Sopenharmony_civoid tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src);
3348c2ecf20Sopenharmony_ciint tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts);
3358c2ecf20Sopenharmony_ciint tcf_exts_terse_dump(struct sk_buff *skb, struct tcf_exts *exts);
3368c2ecf20Sopenharmony_ciint tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/**
3398c2ecf20Sopenharmony_ci * struct tcf_pkt_info - packet information
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_cistruct tcf_pkt_info {
3428c2ecf20Sopenharmony_ci	unsigned char *		ptr;
3438c2ecf20Sopenharmony_ci	int			nexthdr;
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_EMATCH
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistruct tcf_ematch_ops;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/**
3518c2ecf20Sopenharmony_ci * struct tcf_ematch - extended match (ematch)
3528c2ecf20Sopenharmony_ci *
3538c2ecf20Sopenharmony_ci * @matchid: identifier to allow userspace to reidentify a match
3548c2ecf20Sopenharmony_ci * @flags: flags specifying attributes and the relation to other matches
3558c2ecf20Sopenharmony_ci * @ops: the operations lookup table of the corresponding ematch module
3568c2ecf20Sopenharmony_ci * @datalen: length of the ematch specific configuration data
3578c2ecf20Sopenharmony_ci * @data: ematch specific data
3588c2ecf20Sopenharmony_ci */
3598c2ecf20Sopenharmony_cistruct tcf_ematch {
3608c2ecf20Sopenharmony_ci	struct tcf_ematch_ops * ops;
3618c2ecf20Sopenharmony_ci	unsigned long		data;
3628c2ecf20Sopenharmony_ci	unsigned int		datalen;
3638c2ecf20Sopenharmony_ci	u16			matchid;
3648c2ecf20Sopenharmony_ci	u16			flags;
3658c2ecf20Sopenharmony_ci	struct net		*net;
3668c2ecf20Sopenharmony_ci};
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic inline int tcf_em_is_container(struct tcf_ematch *em)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	return !em->ops;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic inline int tcf_em_is_simple(struct tcf_ematch *em)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	return em->flags & TCF_EM_SIMPLE;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic inline int tcf_em_is_inverted(struct tcf_ematch *em)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	return em->flags & TCF_EM_INVERT;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic inline int tcf_em_last_match(struct tcf_ematch *em)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	return (em->flags & TCF_EM_REL_MASK) == TCF_EM_REL_END;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic inline int tcf_em_early_end(struct tcf_ematch *em, int result)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	if (tcf_em_last_match(em))
3918c2ecf20Sopenharmony_ci		return 1;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (result == 0 && em->flags & TCF_EM_REL_AND)
3948c2ecf20Sopenharmony_ci		return 1;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (result != 0 && em->flags & TCF_EM_REL_OR)
3978c2ecf20Sopenharmony_ci		return 1;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return 0;
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci/**
4038c2ecf20Sopenharmony_ci * struct tcf_ematch_tree - ematch tree handle
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * @hdr: ematch tree header supplied by userspace
4068c2ecf20Sopenharmony_ci * @matches: array of ematches
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistruct tcf_ematch_tree {
4098c2ecf20Sopenharmony_ci	struct tcf_ematch_tree_hdr hdr;
4108c2ecf20Sopenharmony_ci	struct tcf_ematch *	matches;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci};
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/**
4158c2ecf20Sopenharmony_ci * struct tcf_ematch_ops - ematch module operations
4168c2ecf20Sopenharmony_ci *
4178c2ecf20Sopenharmony_ci * @kind: identifier (kind) of this ematch module
4188c2ecf20Sopenharmony_ci * @datalen: length of expected configuration data (optional)
4198c2ecf20Sopenharmony_ci * @change: called during validation (optional)
4208c2ecf20Sopenharmony_ci * @match: called during ematch tree evaluation, must return 1/0
4218c2ecf20Sopenharmony_ci * @destroy: called during destroyage (optional)
4228c2ecf20Sopenharmony_ci * @dump: called during dumping process (optional)
4238c2ecf20Sopenharmony_ci * @owner: owner, must be set to THIS_MODULE
4248c2ecf20Sopenharmony_ci * @link: link to previous/next ematch module (internal use)
4258c2ecf20Sopenharmony_ci */
4268c2ecf20Sopenharmony_cistruct tcf_ematch_ops {
4278c2ecf20Sopenharmony_ci	int			kind;
4288c2ecf20Sopenharmony_ci	int			datalen;
4298c2ecf20Sopenharmony_ci	int			(*change)(struct net *net, void *,
4308c2ecf20Sopenharmony_ci					  int, struct tcf_ematch *);
4318c2ecf20Sopenharmony_ci	int			(*match)(struct sk_buff *, struct tcf_ematch *,
4328c2ecf20Sopenharmony_ci					 struct tcf_pkt_info *);
4338c2ecf20Sopenharmony_ci	void			(*destroy)(struct tcf_ematch *);
4348c2ecf20Sopenharmony_ci	int			(*dump)(struct sk_buff *, struct tcf_ematch *);
4358c2ecf20Sopenharmony_ci	struct module		*owner;
4368c2ecf20Sopenharmony_ci	struct list_head	link;
4378c2ecf20Sopenharmony_ci};
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ciint tcf_em_register(struct tcf_ematch_ops *);
4408c2ecf20Sopenharmony_civoid tcf_em_unregister(struct tcf_ematch_ops *);
4418c2ecf20Sopenharmony_ciint tcf_em_tree_validate(struct tcf_proto *, struct nlattr *,
4428c2ecf20Sopenharmony_ci			 struct tcf_ematch_tree *);
4438c2ecf20Sopenharmony_civoid tcf_em_tree_destroy(struct tcf_ematch_tree *);
4448c2ecf20Sopenharmony_ciint tcf_em_tree_dump(struct sk_buff *, struct tcf_ematch_tree *, int);
4458c2ecf20Sopenharmony_ciint __tcf_em_tree_match(struct sk_buff *, struct tcf_ematch_tree *,
4468c2ecf20Sopenharmony_ci			struct tcf_pkt_info *);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci/**
4498c2ecf20Sopenharmony_ci * tcf_em_tree_match - evaulate an ematch tree
4508c2ecf20Sopenharmony_ci *
4518c2ecf20Sopenharmony_ci * @skb: socket buffer of the packet in question
4528c2ecf20Sopenharmony_ci * @tree: ematch tree to be used for evaluation
4538c2ecf20Sopenharmony_ci * @info: packet information examined by classifier
4548c2ecf20Sopenharmony_ci *
4558c2ecf20Sopenharmony_ci * This function matches @skb against the ematch tree in @tree by going
4568c2ecf20Sopenharmony_ci * through all ematches respecting their logic relations returning
4578c2ecf20Sopenharmony_ci * as soon as the result is obvious.
4588c2ecf20Sopenharmony_ci *
4598c2ecf20Sopenharmony_ci * Returns 1 if the ematch tree as-one matches, no ematches are configured
4608c2ecf20Sopenharmony_ci * or ematch is not enabled in the kernel, otherwise 0 is returned.
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_cistatic inline int tcf_em_tree_match(struct sk_buff *skb,
4638c2ecf20Sopenharmony_ci				    struct tcf_ematch_tree *tree,
4648c2ecf20Sopenharmony_ci				    struct tcf_pkt_info *info)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	if (tree->hdr.nmatches)
4678c2ecf20Sopenharmony_ci		return __tcf_em_tree_match(skb, tree, info);
4688c2ecf20Sopenharmony_ci	else
4698c2ecf20Sopenharmony_ci		return 1;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci#define MODULE_ALIAS_TCF_EMATCH(kind)	MODULE_ALIAS("ematch-kind-" __stringify(kind))
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci#else /* CONFIG_NET_EMATCH */
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistruct tcf_ematch_tree {
4778c2ecf20Sopenharmony_ci};
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci#define tcf_em_tree_validate(tp, tb, t) ((void)(t), 0)
4808c2ecf20Sopenharmony_ci#define tcf_em_tree_destroy(t) do { (void)(t); } while(0)
4818c2ecf20Sopenharmony_ci#define tcf_em_tree_dump(skb, t, tlv) (0)
4828c2ecf20Sopenharmony_ci#define tcf_em_tree_match(skb, t, info) ((void)(info), 1)
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci#endif /* CONFIG_NET_EMATCH */
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic inline unsigned char * tcf_get_base_ptr(struct sk_buff *skb, int layer)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	switch (layer) {
4898c2ecf20Sopenharmony_ci		case TCF_LAYER_LINK:
4908c2ecf20Sopenharmony_ci			return skb_mac_header(skb);
4918c2ecf20Sopenharmony_ci		case TCF_LAYER_NETWORK:
4928c2ecf20Sopenharmony_ci			return skb_network_header(skb);
4938c2ecf20Sopenharmony_ci		case TCF_LAYER_TRANSPORT:
4948c2ecf20Sopenharmony_ci			return skb_transport_header(skb);
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return NULL;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic inline int tcf_valid_offset(const struct sk_buff *skb,
5018c2ecf20Sopenharmony_ci				   const unsigned char *ptr, const int len)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	return likely((ptr + len) <= skb_tail_pointer(skb) &&
5048c2ecf20Sopenharmony_ci		      ptr >= skb->head &&
5058c2ecf20Sopenharmony_ci		      (ptr <= (ptr + len)));
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic inline int
5098c2ecf20Sopenharmony_citcf_change_indev(struct net *net, struct nlattr *indev_tlv,
5108c2ecf20Sopenharmony_ci		 struct netlink_ext_ack *extack)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	char indev[IFNAMSIZ];
5138c2ecf20Sopenharmony_ci	struct net_device *dev;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (nla_strlcpy(indev, indev_tlv, IFNAMSIZ) >= IFNAMSIZ) {
5168c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, indev_tlv,
5178c2ecf20Sopenharmony_ci				    "Interface name too long");
5188c2ecf20Sopenharmony_ci		return -EINVAL;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci	dev = __dev_get_by_name(net, indev);
5218c2ecf20Sopenharmony_ci	if (!dev) {
5228c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, indev_tlv,
5238c2ecf20Sopenharmony_ci				    "Network device not found");
5248c2ecf20Sopenharmony_ci		return -ENODEV;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci	return dev->ifindex;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic inline bool
5308c2ecf20Sopenharmony_citcf_match_indev(struct sk_buff *skb, int ifindex)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	if (!ifindex)
5338c2ecf20Sopenharmony_ci		return true;
5348c2ecf20Sopenharmony_ci	if  (!skb->skb_iif)
5358c2ecf20Sopenharmony_ci		return false;
5368c2ecf20Sopenharmony_ci	return ifindex == skb->skb_iif;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ciint tc_setup_flow_action(struct flow_action *flow_action,
5408c2ecf20Sopenharmony_ci			 const struct tcf_exts *exts);
5418c2ecf20Sopenharmony_civoid tc_cleanup_flow_action(struct flow_action *flow_action);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ciint tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
5448c2ecf20Sopenharmony_ci		     void *type_data, bool err_stop, bool rtnl_held);
5458c2ecf20Sopenharmony_ciint tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
5468c2ecf20Sopenharmony_ci		    enum tc_setup_type type, void *type_data, bool err_stop,
5478c2ecf20Sopenharmony_ci		    u32 *flags, unsigned int *in_hw_count, bool rtnl_held);
5488c2ecf20Sopenharmony_ciint tc_setup_cb_replace(struct tcf_block *block, struct tcf_proto *tp,
5498c2ecf20Sopenharmony_ci			enum tc_setup_type type, void *type_data, bool err_stop,
5508c2ecf20Sopenharmony_ci			u32 *old_flags, unsigned int *old_in_hw_count,
5518c2ecf20Sopenharmony_ci			u32 *new_flags, unsigned int *new_in_hw_count,
5528c2ecf20Sopenharmony_ci			bool rtnl_held);
5538c2ecf20Sopenharmony_ciint tc_setup_cb_destroy(struct tcf_block *block, struct tcf_proto *tp,
5548c2ecf20Sopenharmony_ci			enum tc_setup_type type, void *type_data, bool err_stop,
5558c2ecf20Sopenharmony_ci			u32 *flags, unsigned int *in_hw_count, bool rtnl_held);
5568c2ecf20Sopenharmony_ciint tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
5578c2ecf20Sopenharmony_ci			  bool add, flow_setup_cb_t *cb,
5588c2ecf20Sopenharmony_ci			  enum tc_setup_type type, void *type_data,
5598c2ecf20Sopenharmony_ci			  void *cb_priv, u32 *flags, unsigned int *in_hw_count);
5608c2ecf20Sopenharmony_ciunsigned int tcf_exts_num_actions(struct tcf_exts *exts);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT
5638c2ecf20Sopenharmony_ciint tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
5648c2ecf20Sopenharmony_ci		    enum flow_block_binder_type binder_type,
5658c2ecf20Sopenharmony_ci		    struct nlattr *block_index_attr,
5668c2ecf20Sopenharmony_ci		    struct netlink_ext_ack *extack);
5678c2ecf20Sopenharmony_civoid tcf_qevent_destroy(struct tcf_qevent *qe, struct Qdisc *sch);
5688c2ecf20Sopenharmony_ciint tcf_qevent_validate_change(struct tcf_qevent *qe, struct nlattr *block_index_attr,
5698c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack);
5708c2ecf20Sopenharmony_cistruct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struct sk_buff *skb,
5718c2ecf20Sopenharmony_ci				  struct sk_buff **to_free, int *ret);
5728c2ecf20Sopenharmony_ciint tcf_qevent_dump(struct sk_buff *skb, int attr_name, struct tcf_qevent *qe);
5738c2ecf20Sopenharmony_ci#else
5748c2ecf20Sopenharmony_cistatic inline int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
5758c2ecf20Sopenharmony_ci				  enum flow_block_binder_type binder_type,
5768c2ecf20Sopenharmony_ci				  struct nlattr *block_index_attr,
5778c2ecf20Sopenharmony_ci				  struct netlink_ext_ack *extack)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	return 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic inline void tcf_qevent_destroy(struct tcf_qevent *qe, struct Qdisc *sch)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic inline int tcf_qevent_validate_change(struct tcf_qevent *qe, struct nlattr *block_index_attr,
5878c2ecf20Sopenharmony_ci					     struct netlink_ext_ack *extack)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	return 0;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic inline struct sk_buff *
5938c2ecf20Sopenharmony_citcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struct sk_buff *skb,
5948c2ecf20Sopenharmony_ci		  struct sk_buff **to_free, int *ret)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	return skb;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic inline int tcf_qevent_dump(struct sk_buff *skb, int attr_name, struct tcf_qevent *qe)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci#endif
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistruct tc_cls_u32_knode {
6068c2ecf20Sopenharmony_ci	struct tcf_exts *exts;
6078c2ecf20Sopenharmony_ci	struct tcf_result *res;
6088c2ecf20Sopenharmony_ci	struct tc_u32_sel *sel;
6098c2ecf20Sopenharmony_ci	u32 handle;
6108c2ecf20Sopenharmony_ci	u32 val;
6118c2ecf20Sopenharmony_ci	u32 mask;
6128c2ecf20Sopenharmony_ci	u32 link_handle;
6138c2ecf20Sopenharmony_ci	u8 fshift;
6148c2ecf20Sopenharmony_ci};
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistruct tc_cls_u32_hnode {
6178c2ecf20Sopenharmony_ci	u32 handle;
6188c2ecf20Sopenharmony_ci	u32 prio;
6198c2ecf20Sopenharmony_ci	unsigned int divisor;
6208c2ecf20Sopenharmony_ci};
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cienum tc_clsu32_command {
6238c2ecf20Sopenharmony_ci	TC_CLSU32_NEW_KNODE,
6248c2ecf20Sopenharmony_ci	TC_CLSU32_REPLACE_KNODE,
6258c2ecf20Sopenharmony_ci	TC_CLSU32_DELETE_KNODE,
6268c2ecf20Sopenharmony_ci	TC_CLSU32_NEW_HNODE,
6278c2ecf20Sopenharmony_ci	TC_CLSU32_REPLACE_HNODE,
6288c2ecf20Sopenharmony_ci	TC_CLSU32_DELETE_HNODE,
6298c2ecf20Sopenharmony_ci};
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistruct tc_cls_u32_offload {
6328c2ecf20Sopenharmony_ci	struct flow_cls_common_offload common;
6338c2ecf20Sopenharmony_ci	/* knode values */
6348c2ecf20Sopenharmony_ci	enum tc_clsu32_command command;
6358c2ecf20Sopenharmony_ci	union {
6368c2ecf20Sopenharmony_ci		struct tc_cls_u32_knode knode;
6378c2ecf20Sopenharmony_ci		struct tc_cls_u32_hnode hnode;
6388c2ecf20Sopenharmony_ci	};
6398c2ecf20Sopenharmony_ci};
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic inline bool tc_can_offload(const struct net_device *dev)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	return dev->features & NETIF_F_HW_TC;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic inline bool tc_can_offload_extack(const struct net_device *dev,
6478c2ecf20Sopenharmony_ci					 struct netlink_ext_ack *extack)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	bool can = tc_can_offload(dev);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	if (!can)
6528c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "TC offload is disabled on net device");
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	return can;
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic inline bool
6588c2ecf20Sopenharmony_citc_cls_can_offload_and_chain0(const struct net_device *dev,
6598c2ecf20Sopenharmony_ci			      struct flow_cls_common_offload *common)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	if (!tc_can_offload_extack(dev, common->extack))
6628c2ecf20Sopenharmony_ci		return false;
6638c2ecf20Sopenharmony_ci	if (common->chain_index) {
6648c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(common->extack,
6658c2ecf20Sopenharmony_ci			       "Driver supports only offload of chain 0");
6668c2ecf20Sopenharmony_ci		return false;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci	return true;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic inline bool tc_skip_hw(u32 flags)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_SKIP_HW) ? true : false;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic inline bool tc_skip_sw(u32 flags)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_SKIP_SW) ? true : false;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci/* SKIP_HW and SKIP_SW are mutually exclusive flags. */
6828c2ecf20Sopenharmony_cistatic inline bool tc_flags_valid(u32 flags)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	if (flags & ~(TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW |
6858c2ecf20Sopenharmony_ci		      TCA_CLS_FLAGS_VERBOSE))
6868c2ecf20Sopenharmony_ci		return false;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	flags &= TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW;
6898c2ecf20Sopenharmony_ci	if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)))
6908c2ecf20Sopenharmony_ci		return false;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	return true;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic inline bool tc_in_hw(u32 flags)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	return (flags & TCA_CLS_FLAGS_IN_HW) ? true : false;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic inline void
7018c2ecf20Sopenharmony_citc_cls_common_offload_init(struct flow_cls_common_offload *cls_common,
7028c2ecf20Sopenharmony_ci			   const struct tcf_proto *tp, u32 flags,
7038c2ecf20Sopenharmony_ci			   struct netlink_ext_ack *extack)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	cls_common->chain_index = tp->chain->index;
7068c2ecf20Sopenharmony_ci	cls_common->protocol = tp->protocol;
7078c2ecf20Sopenharmony_ci	cls_common->prio = tp->prio >> 16;
7088c2ecf20Sopenharmony_ci	if (tc_skip_sw(flags) || flags & TCA_CLS_FLAGS_VERBOSE)
7098c2ecf20Sopenharmony_ci		cls_common->extack = extack;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
7138c2ecf20Sopenharmony_cistatic inline struct tc_skb_ext *tc_skb_ext_alloc(struct sk_buff *skb)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	struct tc_skb_ext *tc_skb_ext = skb_ext_add(skb, TC_SKB_EXT);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (tc_skb_ext)
7188c2ecf20Sopenharmony_ci		memset(tc_skb_ext, 0, sizeof(*tc_skb_ext));
7198c2ecf20Sopenharmony_ci	return tc_skb_ext;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci#endif
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cienum tc_matchall_command {
7248c2ecf20Sopenharmony_ci	TC_CLSMATCHALL_REPLACE,
7258c2ecf20Sopenharmony_ci	TC_CLSMATCHALL_DESTROY,
7268c2ecf20Sopenharmony_ci	TC_CLSMATCHALL_STATS,
7278c2ecf20Sopenharmony_ci};
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistruct tc_cls_matchall_offload {
7308c2ecf20Sopenharmony_ci	struct flow_cls_common_offload common;
7318c2ecf20Sopenharmony_ci	enum tc_matchall_command command;
7328c2ecf20Sopenharmony_ci	struct flow_rule *rule;
7338c2ecf20Sopenharmony_ci	struct flow_stats stats;
7348c2ecf20Sopenharmony_ci	unsigned long cookie;
7358c2ecf20Sopenharmony_ci};
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cienum tc_clsbpf_command {
7388c2ecf20Sopenharmony_ci	TC_CLSBPF_OFFLOAD,
7398c2ecf20Sopenharmony_ci	TC_CLSBPF_STATS,
7408c2ecf20Sopenharmony_ci};
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistruct tc_cls_bpf_offload {
7438c2ecf20Sopenharmony_ci	struct flow_cls_common_offload common;
7448c2ecf20Sopenharmony_ci	enum tc_clsbpf_command command;
7458c2ecf20Sopenharmony_ci	struct tcf_exts *exts;
7468c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
7478c2ecf20Sopenharmony_ci	struct bpf_prog *oldprog;
7488c2ecf20Sopenharmony_ci	const char *name;
7498c2ecf20Sopenharmony_ci	bool exts_integrated;
7508c2ecf20Sopenharmony_ci};
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistruct tc_mqprio_qopt_offload {
7538c2ecf20Sopenharmony_ci	/* struct tc_mqprio_qopt must always be the first element */
7548c2ecf20Sopenharmony_ci	struct tc_mqprio_qopt qopt;
7558c2ecf20Sopenharmony_ci	u16 mode;
7568c2ecf20Sopenharmony_ci	u16 shaper;
7578c2ecf20Sopenharmony_ci	u32 flags;
7588c2ecf20Sopenharmony_ci	u64 min_rate[TC_QOPT_MAX_QUEUE];
7598c2ecf20Sopenharmony_ci	u64 max_rate[TC_QOPT_MAX_QUEUE];
7608c2ecf20Sopenharmony_ci};
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci/* This structure holds cookie structure that is passed from user
7638c2ecf20Sopenharmony_ci * to the kernel for actions and classifiers
7648c2ecf20Sopenharmony_ci */
7658c2ecf20Sopenharmony_cistruct tc_cookie {
7668c2ecf20Sopenharmony_ci	u8  *data;
7678c2ecf20Sopenharmony_ci	u32 len;
7688c2ecf20Sopenharmony_ci	struct rcu_head rcu;
7698c2ecf20Sopenharmony_ci};
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_cistruct tc_qopt_offload_stats {
7728c2ecf20Sopenharmony_ci	struct gnet_stats_basic_packed *bstats;
7738c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
7748c2ecf20Sopenharmony_ci};
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cienum tc_mq_command {
7778c2ecf20Sopenharmony_ci	TC_MQ_CREATE,
7788c2ecf20Sopenharmony_ci	TC_MQ_DESTROY,
7798c2ecf20Sopenharmony_ci	TC_MQ_STATS,
7808c2ecf20Sopenharmony_ci	TC_MQ_GRAFT,
7818c2ecf20Sopenharmony_ci};
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistruct tc_mq_opt_offload_graft_params {
7848c2ecf20Sopenharmony_ci	unsigned long queue;
7858c2ecf20Sopenharmony_ci	u32 child_handle;
7868c2ecf20Sopenharmony_ci};
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_cistruct tc_mq_qopt_offload {
7898c2ecf20Sopenharmony_ci	enum tc_mq_command command;
7908c2ecf20Sopenharmony_ci	u32 handle;
7918c2ecf20Sopenharmony_ci	union {
7928c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
7938c2ecf20Sopenharmony_ci		struct tc_mq_opt_offload_graft_params graft_params;
7948c2ecf20Sopenharmony_ci	};
7958c2ecf20Sopenharmony_ci};
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cienum tc_red_command {
7988c2ecf20Sopenharmony_ci	TC_RED_REPLACE,
7998c2ecf20Sopenharmony_ci	TC_RED_DESTROY,
8008c2ecf20Sopenharmony_ci	TC_RED_STATS,
8018c2ecf20Sopenharmony_ci	TC_RED_XSTATS,
8028c2ecf20Sopenharmony_ci	TC_RED_GRAFT,
8038c2ecf20Sopenharmony_ci};
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistruct tc_red_qopt_offload_params {
8068c2ecf20Sopenharmony_ci	u32 min;
8078c2ecf20Sopenharmony_ci	u32 max;
8088c2ecf20Sopenharmony_ci	u32 probability;
8098c2ecf20Sopenharmony_ci	u32 limit;
8108c2ecf20Sopenharmony_ci	bool is_ecn;
8118c2ecf20Sopenharmony_ci	bool is_harddrop;
8128c2ecf20Sopenharmony_ci	bool is_nodrop;
8138c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
8148c2ecf20Sopenharmony_ci};
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistruct tc_red_qopt_offload {
8178c2ecf20Sopenharmony_ci	enum tc_red_command command;
8188c2ecf20Sopenharmony_ci	u32 handle;
8198c2ecf20Sopenharmony_ci	u32 parent;
8208c2ecf20Sopenharmony_ci	union {
8218c2ecf20Sopenharmony_ci		struct tc_red_qopt_offload_params set;
8228c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
8238c2ecf20Sopenharmony_ci		struct red_stats *xstats;
8248c2ecf20Sopenharmony_ci		u32 child_handle;
8258c2ecf20Sopenharmony_ci	};
8268c2ecf20Sopenharmony_ci};
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cienum tc_gred_command {
8298c2ecf20Sopenharmony_ci	TC_GRED_REPLACE,
8308c2ecf20Sopenharmony_ci	TC_GRED_DESTROY,
8318c2ecf20Sopenharmony_ci	TC_GRED_STATS,
8328c2ecf20Sopenharmony_ci};
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistruct tc_gred_vq_qopt_offload_params {
8358c2ecf20Sopenharmony_ci	bool present;
8368c2ecf20Sopenharmony_ci	u32 limit;
8378c2ecf20Sopenharmony_ci	u32 prio;
8388c2ecf20Sopenharmony_ci	u32 min;
8398c2ecf20Sopenharmony_ci	u32 max;
8408c2ecf20Sopenharmony_ci	bool is_ecn;
8418c2ecf20Sopenharmony_ci	bool is_harddrop;
8428c2ecf20Sopenharmony_ci	u32 probability;
8438c2ecf20Sopenharmony_ci	/* Only need backlog, see struct tc_prio_qopt_offload_params */
8448c2ecf20Sopenharmony_ci	u32 *backlog;
8458c2ecf20Sopenharmony_ci};
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistruct tc_gred_qopt_offload_params {
8488c2ecf20Sopenharmony_ci	bool grio_on;
8498c2ecf20Sopenharmony_ci	bool wred_on;
8508c2ecf20Sopenharmony_ci	unsigned int dp_cnt;
8518c2ecf20Sopenharmony_ci	unsigned int dp_def;
8528c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
8538c2ecf20Sopenharmony_ci	struct tc_gred_vq_qopt_offload_params tab[MAX_DPs];
8548c2ecf20Sopenharmony_ci};
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistruct tc_gred_qopt_offload_stats {
8578c2ecf20Sopenharmony_ci	struct gnet_stats_basic_packed bstats[MAX_DPs];
8588c2ecf20Sopenharmony_ci	struct gnet_stats_queue qstats[MAX_DPs];
8598c2ecf20Sopenharmony_ci	struct red_stats *xstats[MAX_DPs];
8608c2ecf20Sopenharmony_ci};
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistruct tc_gred_qopt_offload {
8638c2ecf20Sopenharmony_ci	enum tc_gred_command command;
8648c2ecf20Sopenharmony_ci	u32 handle;
8658c2ecf20Sopenharmony_ci	u32 parent;
8668c2ecf20Sopenharmony_ci	union {
8678c2ecf20Sopenharmony_ci		struct tc_gred_qopt_offload_params set;
8688c2ecf20Sopenharmony_ci		struct tc_gred_qopt_offload_stats stats;
8698c2ecf20Sopenharmony_ci	};
8708c2ecf20Sopenharmony_ci};
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_cienum tc_prio_command {
8738c2ecf20Sopenharmony_ci	TC_PRIO_REPLACE,
8748c2ecf20Sopenharmony_ci	TC_PRIO_DESTROY,
8758c2ecf20Sopenharmony_ci	TC_PRIO_STATS,
8768c2ecf20Sopenharmony_ci	TC_PRIO_GRAFT,
8778c2ecf20Sopenharmony_ci};
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistruct tc_prio_qopt_offload_params {
8808c2ecf20Sopenharmony_ci	int bands;
8818c2ecf20Sopenharmony_ci	u8 priomap[TC_PRIO_MAX + 1];
8828c2ecf20Sopenharmony_ci	/* At the point of un-offloading the Qdisc, the reported backlog and
8838c2ecf20Sopenharmony_ci	 * qlen need to be reduced by the portion that is in HW.
8848c2ecf20Sopenharmony_ci	 */
8858c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
8868c2ecf20Sopenharmony_ci};
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistruct tc_prio_qopt_offload_graft_params {
8898c2ecf20Sopenharmony_ci	u8 band;
8908c2ecf20Sopenharmony_ci	u32 child_handle;
8918c2ecf20Sopenharmony_ci};
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistruct tc_prio_qopt_offload {
8948c2ecf20Sopenharmony_ci	enum tc_prio_command command;
8958c2ecf20Sopenharmony_ci	u32 handle;
8968c2ecf20Sopenharmony_ci	u32 parent;
8978c2ecf20Sopenharmony_ci	union {
8988c2ecf20Sopenharmony_ci		struct tc_prio_qopt_offload_params replace_params;
8998c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
9008c2ecf20Sopenharmony_ci		struct tc_prio_qopt_offload_graft_params graft_params;
9018c2ecf20Sopenharmony_ci	};
9028c2ecf20Sopenharmony_ci};
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cienum tc_root_command {
9058c2ecf20Sopenharmony_ci	TC_ROOT_GRAFT,
9068c2ecf20Sopenharmony_ci};
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistruct tc_root_qopt_offload {
9098c2ecf20Sopenharmony_ci	enum tc_root_command command;
9108c2ecf20Sopenharmony_ci	u32 handle;
9118c2ecf20Sopenharmony_ci	bool ingress;
9128c2ecf20Sopenharmony_ci};
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cienum tc_ets_command {
9158c2ecf20Sopenharmony_ci	TC_ETS_REPLACE,
9168c2ecf20Sopenharmony_ci	TC_ETS_DESTROY,
9178c2ecf20Sopenharmony_ci	TC_ETS_STATS,
9188c2ecf20Sopenharmony_ci	TC_ETS_GRAFT,
9198c2ecf20Sopenharmony_ci};
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistruct tc_ets_qopt_offload_replace_params {
9228c2ecf20Sopenharmony_ci	unsigned int bands;
9238c2ecf20Sopenharmony_ci	u8 priomap[TC_PRIO_MAX + 1];
9248c2ecf20Sopenharmony_ci	unsigned int quanta[TCQ_ETS_MAX_BANDS];	/* 0 for strict bands. */
9258c2ecf20Sopenharmony_ci	unsigned int weights[TCQ_ETS_MAX_BANDS];
9268c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
9278c2ecf20Sopenharmony_ci};
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistruct tc_ets_qopt_offload_graft_params {
9308c2ecf20Sopenharmony_ci	u8 band;
9318c2ecf20Sopenharmony_ci	u32 child_handle;
9328c2ecf20Sopenharmony_ci};
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_cistruct tc_ets_qopt_offload {
9358c2ecf20Sopenharmony_ci	enum tc_ets_command command;
9368c2ecf20Sopenharmony_ci	u32 handle;
9378c2ecf20Sopenharmony_ci	u32 parent;
9388c2ecf20Sopenharmony_ci	union {
9398c2ecf20Sopenharmony_ci		struct tc_ets_qopt_offload_replace_params replace_params;
9408c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
9418c2ecf20Sopenharmony_ci		struct tc_ets_qopt_offload_graft_params graft_params;
9428c2ecf20Sopenharmony_ci	};
9438c2ecf20Sopenharmony_ci};
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cienum tc_tbf_command {
9468c2ecf20Sopenharmony_ci	TC_TBF_REPLACE,
9478c2ecf20Sopenharmony_ci	TC_TBF_DESTROY,
9488c2ecf20Sopenharmony_ci	TC_TBF_STATS,
9498c2ecf20Sopenharmony_ci};
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistruct tc_tbf_qopt_offload_replace_params {
9528c2ecf20Sopenharmony_ci	struct psched_ratecfg rate;
9538c2ecf20Sopenharmony_ci	u32 max_size;
9548c2ecf20Sopenharmony_ci	struct gnet_stats_queue *qstats;
9558c2ecf20Sopenharmony_ci};
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistruct tc_tbf_qopt_offload {
9588c2ecf20Sopenharmony_ci	enum tc_tbf_command command;
9598c2ecf20Sopenharmony_ci	u32 handle;
9608c2ecf20Sopenharmony_ci	u32 parent;
9618c2ecf20Sopenharmony_ci	union {
9628c2ecf20Sopenharmony_ci		struct tc_tbf_qopt_offload_replace_params replace_params;
9638c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
9648c2ecf20Sopenharmony_ci	};
9658c2ecf20Sopenharmony_ci};
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cienum tc_fifo_command {
9688c2ecf20Sopenharmony_ci	TC_FIFO_REPLACE,
9698c2ecf20Sopenharmony_ci	TC_FIFO_DESTROY,
9708c2ecf20Sopenharmony_ci	TC_FIFO_STATS,
9718c2ecf20Sopenharmony_ci};
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistruct tc_fifo_qopt_offload {
9748c2ecf20Sopenharmony_ci	enum tc_fifo_command command;
9758c2ecf20Sopenharmony_ci	u32 handle;
9768c2ecf20Sopenharmony_ci	u32 parent;
9778c2ecf20Sopenharmony_ci	union {
9788c2ecf20Sopenharmony_ci		struct tc_qopt_offload_stats stats;
9798c2ecf20Sopenharmony_ci	};
9808c2ecf20Sopenharmony_ci};
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci#endif
983