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