18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/sched/act_police.c	Input police filter
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
68c2ecf20Sopenharmony_ci * 		J Hadi Salim (action changes)
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/string.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
158c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <net/act_api.h>
198c2ecf20Sopenharmony_ci#include <net/netlink.h>
208c2ecf20Sopenharmony_ci#include <net/pkt_cls.h>
218c2ecf20Sopenharmony_ci#include <net/tc_act/tc_police.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Each policer is serialized by its individual spinlock */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic unsigned int police_net_id;
268c2ecf20Sopenharmony_cistatic struct tc_action_ops act_police_ops;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int tcf_police_walker(struct net *net, struct sk_buff *skb,
298c2ecf20Sopenharmony_ci				 struct netlink_callback *cb, int type,
308c2ecf20Sopenharmony_ci				 const struct tc_action_ops *ops,
318c2ecf20Sopenharmony_ci				 struct netlink_ext_ack *extack)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct tc_action_net *tn = net_generic(net, police_net_id);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic const struct nla_policy police_policy[TCA_POLICE_MAX + 1] = {
398c2ecf20Sopenharmony_ci	[TCA_POLICE_RATE]	= { .len = TC_RTAB_SIZE },
408c2ecf20Sopenharmony_ci	[TCA_POLICE_PEAKRATE]	= { .len = TC_RTAB_SIZE },
418c2ecf20Sopenharmony_ci	[TCA_POLICE_AVRATE]	= { .type = NLA_U32 },
428c2ecf20Sopenharmony_ci	[TCA_POLICE_RESULT]	= { .type = NLA_U32 },
438c2ecf20Sopenharmony_ci	[TCA_POLICE_RATE64]     = { .type = NLA_U64 },
448c2ecf20Sopenharmony_ci	[TCA_POLICE_PEAKRATE64] = { .type = NLA_U64 },
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int tcf_police_init(struct net *net, struct nlattr *nla,
488c2ecf20Sopenharmony_ci			       struct nlattr *est, struct tc_action **a,
498c2ecf20Sopenharmony_ci			       int ovr, int bind, bool rtnl_held,
508c2ecf20Sopenharmony_ci			       struct tcf_proto *tp, u32 flags,
518c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int ret = 0, tcfp_result = TC_ACT_OK, err, size;
548c2ecf20Sopenharmony_ci	struct nlattr *tb[TCA_POLICE_MAX + 1];
558c2ecf20Sopenharmony_ci	struct tcf_chain *goto_ch = NULL;
568c2ecf20Sopenharmony_ci	struct tc_police *parm;
578c2ecf20Sopenharmony_ci	struct tcf_police *police;
588c2ecf20Sopenharmony_ci	struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
598c2ecf20Sopenharmony_ci	struct tc_action_net *tn = net_generic(net, police_net_id);
608c2ecf20Sopenharmony_ci	struct tcf_police_params *new;
618c2ecf20Sopenharmony_ci	bool exists = false;
628c2ecf20Sopenharmony_ci	u32 index;
638c2ecf20Sopenharmony_ci	u64 rate64, prate64;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (nla == NULL)
668c2ecf20Sopenharmony_ci		return -EINVAL;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	err = nla_parse_nested_deprecated(tb, TCA_POLICE_MAX, nla,
698c2ecf20Sopenharmony_ci					  police_policy, NULL);
708c2ecf20Sopenharmony_ci	if (err < 0)
718c2ecf20Sopenharmony_ci		return err;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (tb[TCA_POLICE_TBF] == NULL)
748c2ecf20Sopenharmony_ci		return -EINVAL;
758c2ecf20Sopenharmony_ci	size = nla_len(tb[TCA_POLICE_TBF]);
768c2ecf20Sopenharmony_ci	if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
778c2ecf20Sopenharmony_ci		return -EINVAL;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	parm = nla_data(tb[TCA_POLICE_TBF]);
808c2ecf20Sopenharmony_ci	index = parm->index;
818c2ecf20Sopenharmony_ci	err = tcf_idr_check_alloc(tn, &index, a, bind);
828c2ecf20Sopenharmony_ci	if (err < 0)
838c2ecf20Sopenharmony_ci		return err;
848c2ecf20Sopenharmony_ci	exists = err;
858c2ecf20Sopenharmony_ci	if (exists && bind)
868c2ecf20Sopenharmony_ci		return 0;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (!exists) {
898c2ecf20Sopenharmony_ci		ret = tcf_idr_create(tn, index, NULL, a,
908c2ecf20Sopenharmony_ci				     &act_police_ops, bind, true, flags);
918c2ecf20Sopenharmony_ci		if (ret) {
928c2ecf20Sopenharmony_ci			tcf_idr_cleanup(tn, index);
938c2ecf20Sopenharmony_ci			return ret;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci		ret = ACT_P_CREATED;
968c2ecf20Sopenharmony_ci		spin_lock_init(&(to_police(*a)->tcfp_lock));
978c2ecf20Sopenharmony_ci	} else if (!ovr) {
988c2ecf20Sopenharmony_ci		tcf_idr_release(*a, bind);
998c2ecf20Sopenharmony_ci		return -EEXIST;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
1028c2ecf20Sopenharmony_ci	if (err < 0)
1038c2ecf20Sopenharmony_ci		goto release_idr;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	police = to_police(*a);
1068c2ecf20Sopenharmony_ci	if (parm->rate.rate) {
1078c2ecf20Sopenharmony_ci		err = -ENOMEM;
1088c2ecf20Sopenharmony_ci		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE], NULL);
1098c2ecf20Sopenharmony_ci		if (R_tab == NULL)
1108c2ecf20Sopenharmony_ci			goto failure;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		if (parm->peakrate.rate) {
1138c2ecf20Sopenharmony_ci			P_tab = qdisc_get_rtab(&parm->peakrate,
1148c2ecf20Sopenharmony_ci					       tb[TCA_POLICE_PEAKRATE], NULL);
1158c2ecf20Sopenharmony_ci			if (P_tab == NULL)
1168c2ecf20Sopenharmony_ci				goto failure;
1178c2ecf20Sopenharmony_ci		}
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (est) {
1218c2ecf20Sopenharmony_ci		err = gen_replace_estimator(&police->tcf_bstats,
1228c2ecf20Sopenharmony_ci					    police->common.cpu_bstats,
1238c2ecf20Sopenharmony_ci					    &police->tcf_rate_est,
1248c2ecf20Sopenharmony_ci					    &police->tcf_lock,
1258c2ecf20Sopenharmony_ci					    NULL, est);
1268c2ecf20Sopenharmony_ci		if (err)
1278c2ecf20Sopenharmony_ci			goto failure;
1288c2ecf20Sopenharmony_ci	} else if (tb[TCA_POLICE_AVRATE] &&
1298c2ecf20Sopenharmony_ci		   (ret == ACT_P_CREATED ||
1308c2ecf20Sopenharmony_ci		    !gen_estimator_active(&police->tcf_rate_est))) {
1318c2ecf20Sopenharmony_ci		err = -EINVAL;
1328c2ecf20Sopenharmony_ci		goto failure;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (tb[TCA_POLICE_RESULT]) {
1368c2ecf20Sopenharmony_ci		tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
1378c2ecf20Sopenharmony_ci		if (TC_ACT_EXT_CMP(tcfp_result, TC_ACT_GOTO_CHAIN)) {
1388c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack,
1398c2ecf20Sopenharmony_ci				       "goto chain not allowed on fallback");
1408c2ecf20Sopenharmony_ci			err = -EINVAL;
1418c2ecf20Sopenharmony_ci			goto failure;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	new = kzalloc(sizeof(*new), GFP_KERNEL);
1468c2ecf20Sopenharmony_ci	if (unlikely(!new)) {
1478c2ecf20Sopenharmony_ci		err = -ENOMEM;
1488c2ecf20Sopenharmony_ci		goto failure;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* No failure allowed after this point */
1528c2ecf20Sopenharmony_ci	new->tcfp_result = tcfp_result;
1538c2ecf20Sopenharmony_ci	new->tcfp_mtu = parm->mtu;
1548c2ecf20Sopenharmony_ci	if (!new->tcfp_mtu) {
1558c2ecf20Sopenharmony_ci		new->tcfp_mtu = ~0;
1568c2ecf20Sopenharmony_ci		if (R_tab)
1578c2ecf20Sopenharmony_ci			new->tcfp_mtu = 255 << R_tab->rate.cell_log;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	if (R_tab) {
1608c2ecf20Sopenharmony_ci		new->rate_present = true;
1618c2ecf20Sopenharmony_ci		rate64 = tb[TCA_POLICE_RATE64] ?
1628c2ecf20Sopenharmony_ci			 nla_get_u64(tb[TCA_POLICE_RATE64]) : 0;
1638c2ecf20Sopenharmony_ci		psched_ratecfg_precompute(&new->rate, &R_tab->rate, rate64);
1648c2ecf20Sopenharmony_ci		qdisc_put_rtab(R_tab);
1658c2ecf20Sopenharmony_ci	} else {
1668c2ecf20Sopenharmony_ci		new->rate_present = false;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	if (P_tab) {
1698c2ecf20Sopenharmony_ci		new->peak_present = true;
1708c2ecf20Sopenharmony_ci		prate64 = tb[TCA_POLICE_PEAKRATE64] ?
1718c2ecf20Sopenharmony_ci			  nla_get_u64(tb[TCA_POLICE_PEAKRATE64]) : 0;
1728c2ecf20Sopenharmony_ci		psched_ratecfg_precompute(&new->peak, &P_tab->rate, prate64);
1738c2ecf20Sopenharmony_ci		qdisc_put_rtab(P_tab);
1748c2ecf20Sopenharmony_ci	} else {
1758c2ecf20Sopenharmony_ci		new->peak_present = false;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	new->tcfp_burst = PSCHED_TICKS2NS(parm->burst);
1798c2ecf20Sopenharmony_ci	if (new->peak_present)
1808c2ecf20Sopenharmony_ci		new->tcfp_mtu_ptoks = (s64)psched_l2t_ns(&new->peak,
1818c2ecf20Sopenharmony_ci							 new->tcfp_mtu);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (tb[TCA_POLICE_AVRATE])
1848c2ecf20Sopenharmony_ci		new->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	spin_lock_bh(&police->tcf_lock);
1878c2ecf20Sopenharmony_ci	spin_lock_bh(&police->tcfp_lock);
1888c2ecf20Sopenharmony_ci	police->tcfp_t_c = ktime_get_ns();
1898c2ecf20Sopenharmony_ci	police->tcfp_toks = new->tcfp_burst;
1908c2ecf20Sopenharmony_ci	if (new->peak_present)
1918c2ecf20Sopenharmony_ci		police->tcfp_ptoks = new->tcfp_mtu_ptoks;
1928c2ecf20Sopenharmony_ci	spin_unlock_bh(&police->tcfp_lock);
1938c2ecf20Sopenharmony_ci	goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
1948c2ecf20Sopenharmony_ci	new = rcu_replace_pointer(police->params,
1958c2ecf20Sopenharmony_ci				  new,
1968c2ecf20Sopenharmony_ci				  lockdep_is_held(&police->tcf_lock));
1978c2ecf20Sopenharmony_ci	spin_unlock_bh(&police->tcf_lock);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (goto_ch)
2008c2ecf20Sopenharmony_ci		tcf_chain_put_by_act(goto_ch);
2018c2ecf20Sopenharmony_ci	if (new)
2028c2ecf20Sopenharmony_ci		kfree_rcu(new, rcu);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return ret;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cifailure:
2078c2ecf20Sopenharmony_ci	qdisc_put_rtab(P_tab);
2088c2ecf20Sopenharmony_ci	qdisc_put_rtab(R_tab);
2098c2ecf20Sopenharmony_ci	if (goto_ch)
2108c2ecf20Sopenharmony_ci		tcf_chain_put_by_act(goto_ch);
2118c2ecf20Sopenharmony_cirelease_idr:
2128c2ecf20Sopenharmony_ci	tcf_idr_release(*a, bind);
2138c2ecf20Sopenharmony_ci	return err;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic bool tcf_police_mtu_check(struct sk_buff *skb, u32 limit)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	u32 len;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (skb_is_gso(skb))
2218c2ecf20Sopenharmony_ci		return skb_gso_validate_mac_len(skb, limit);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	len = qdisc_pkt_len(skb);
2248c2ecf20Sopenharmony_ci	if (skb_at_tc_ingress(skb))
2258c2ecf20Sopenharmony_ci		len += skb->mac_len;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return len <= limit;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int tcf_police_act(struct sk_buff *skb, const struct tc_action *a,
2318c2ecf20Sopenharmony_ci			  struct tcf_result *res)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct tcf_police *police = to_police(a);
2348c2ecf20Sopenharmony_ci	struct tcf_police_params *p;
2358c2ecf20Sopenharmony_ci	s64 now, toks, ptoks = 0;
2368c2ecf20Sopenharmony_ci	int ret;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	tcf_lastuse_update(&police->tcf_tm);
2398c2ecf20Sopenharmony_ci	bstats_cpu_update(this_cpu_ptr(police->common.cpu_bstats), skb);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	ret = READ_ONCE(police->tcf_action);
2428c2ecf20Sopenharmony_ci	p = rcu_dereference_bh(police->params);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (p->tcfp_ewma_rate) {
2458c2ecf20Sopenharmony_ci		struct gnet_stats_rate_est64 sample;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		if (!gen_estimator_read(&police->tcf_rate_est, &sample) ||
2488c2ecf20Sopenharmony_ci		    sample.bps >= p->tcfp_ewma_rate)
2498c2ecf20Sopenharmony_ci			goto inc_overlimits;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (tcf_police_mtu_check(skb, p->tcfp_mtu)) {
2538c2ecf20Sopenharmony_ci		if (!p->rate_present) {
2548c2ecf20Sopenharmony_ci			ret = p->tcfp_result;
2558c2ecf20Sopenharmony_ci			goto end;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		now = ktime_get_ns();
2598c2ecf20Sopenharmony_ci		spin_lock_bh(&police->tcfp_lock);
2608c2ecf20Sopenharmony_ci		toks = min_t(s64, now - police->tcfp_t_c, p->tcfp_burst);
2618c2ecf20Sopenharmony_ci		if (p->peak_present) {
2628c2ecf20Sopenharmony_ci			ptoks = toks + police->tcfp_ptoks;
2638c2ecf20Sopenharmony_ci			if (ptoks > p->tcfp_mtu_ptoks)
2648c2ecf20Sopenharmony_ci				ptoks = p->tcfp_mtu_ptoks;
2658c2ecf20Sopenharmony_ci			ptoks -= (s64)psched_l2t_ns(&p->peak,
2668c2ecf20Sopenharmony_ci						    qdisc_pkt_len(skb));
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci		toks += police->tcfp_toks;
2698c2ecf20Sopenharmony_ci		if (toks > p->tcfp_burst)
2708c2ecf20Sopenharmony_ci			toks = p->tcfp_burst;
2718c2ecf20Sopenharmony_ci		toks -= (s64)psched_l2t_ns(&p->rate, qdisc_pkt_len(skb));
2728c2ecf20Sopenharmony_ci		if ((toks|ptoks) >= 0) {
2738c2ecf20Sopenharmony_ci			police->tcfp_t_c = now;
2748c2ecf20Sopenharmony_ci			police->tcfp_toks = toks;
2758c2ecf20Sopenharmony_ci			police->tcfp_ptoks = ptoks;
2768c2ecf20Sopenharmony_ci			spin_unlock_bh(&police->tcfp_lock);
2778c2ecf20Sopenharmony_ci			ret = p->tcfp_result;
2788c2ecf20Sopenharmony_ci			goto inc_drops;
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci		spin_unlock_bh(&police->tcfp_lock);
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ciinc_overlimits:
2848c2ecf20Sopenharmony_ci	qstats_overlimit_inc(this_cpu_ptr(police->common.cpu_qstats));
2858c2ecf20Sopenharmony_ciinc_drops:
2868c2ecf20Sopenharmony_ci	if (ret == TC_ACT_SHOT)
2878c2ecf20Sopenharmony_ci		qstats_drop_inc(this_cpu_ptr(police->common.cpu_qstats));
2888c2ecf20Sopenharmony_ciend:
2898c2ecf20Sopenharmony_ci	return ret;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic void tcf_police_cleanup(struct tc_action *a)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct tcf_police *police = to_police(a);
2958c2ecf20Sopenharmony_ci	struct tcf_police_params *p;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	p = rcu_dereference_protected(police->params, 1);
2988c2ecf20Sopenharmony_ci	if (p)
2998c2ecf20Sopenharmony_ci		kfree_rcu(p, rcu);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void tcf_police_stats_update(struct tc_action *a,
3038c2ecf20Sopenharmony_ci				    u64 bytes, u64 packets, u64 drops,
3048c2ecf20Sopenharmony_ci				    u64 lastuse, bool hw)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct tcf_police *police = to_police(a);
3078c2ecf20Sopenharmony_ci	struct tcf_t *tm = &police->tcf_tm;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	tcf_action_update_stats(a, bytes, packets, drops, hw);
3108c2ecf20Sopenharmony_ci	tm->lastuse = max_t(u64, tm->lastuse, lastuse);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int tcf_police_dump(struct sk_buff *skb, struct tc_action *a,
3148c2ecf20Sopenharmony_ci			       int bind, int ref)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	unsigned char *b = skb_tail_pointer(skb);
3178c2ecf20Sopenharmony_ci	struct tcf_police *police = to_police(a);
3188c2ecf20Sopenharmony_ci	struct tcf_police_params *p;
3198c2ecf20Sopenharmony_ci	struct tc_police opt = {
3208c2ecf20Sopenharmony_ci		.index = police->tcf_index,
3218c2ecf20Sopenharmony_ci		.refcnt = refcount_read(&police->tcf_refcnt) - ref,
3228c2ecf20Sopenharmony_ci		.bindcnt = atomic_read(&police->tcf_bindcnt) - bind,
3238c2ecf20Sopenharmony_ci	};
3248c2ecf20Sopenharmony_ci	struct tcf_t t;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	spin_lock_bh(&police->tcf_lock);
3278c2ecf20Sopenharmony_ci	opt.action = police->tcf_action;
3288c2ecf20Sopenharmony_ci	p = rcu_dereference_protected(police->params,
3298c2ecf20Sopenharmony_ci				      lockdep_is_held(&police->tcf_lock));
3308c2ecf20Sopenharmony_ci	opt.mtu = p->tcfp_mtu;
3318c2ecf20Sopenharmony_ci	opt.burst = PSCHED_NS2TICKS(p->tcfp_burst);
3328c2ecf20Sopenharmony_ci	if (p->rate_present) {
3338c2ecf20Sopenharmony_ci		psched_ratecfg_getrate(&opt.rate, &p->rate);
3348c2ecf20Sopenharmony_ci		if ((police->params->rate.rate_bytes_ps >= (1ULL << 32)) &&
3358c2ecf20Sopenharmony_ci		    nla_put_u64_64bit(skb, TCA_POLICE_RATE64,
3368c2ecf20Sopenharmony_ci				      police->params->rate.rate_bytes_ps,
3378c2ecf20Sopenharmony_ci				      TCA_POLICE_PAD))
3388c2ecf20Sopenharmony_ci			goto nla_put_failure;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci	if (p->peak_present) {
3418c2ecf20Sopenharmony_ci		psched_ratecfg_getrate(&opt.peakrate, &p->peak);
3428c2ecf20Sopenharmony_ci		if ((police->params->peak.rate_bytes_ps >= (1ULL << 32)) &&
3438c2ecf20Sopenharmony_ci		    nla_put_u64_64bit(skb, TCA_POLICE_PEAKRATE64,
3448c2ecf20Sopenharmony_ci				      police->params->peak.rate_bytes_ps,
3458c2ecf20Sopenharmony_ci				      TCA_POLICE_PAD))
3468c2ecf20Sopenharmony_ci			goto nla_put_failure;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_POLICE_TBF, sizeof(opt), &opt))
3498c2ecf20Sopenharmony_ci		goto nla_put_failure;
3508c2ecf20Sopenharmony_ci	if (p->tcfp_result &&
3518c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TCA_POLICE_RESULT, p->tcfp_result))
3528c2ecf20Sopenharmony_ci		goto nla_put_failure;
3538c2ecf20Sopenharmony_ci	if (p->tcfp_ewma_rate &&
3548c2ecf20Sopenharmony_ci	    nla_put_u32(skb, TCA_POLICE_AVRATE, p->tcfp_ewma_rate))
3558c2ecf20Sopenharmony_ci		goto nla_put_failure;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	tcf_tm_dump(&t, &police->tcf_tm);
3588c2ecf20Sopenharmony_ci	if (nla_put_64bit(skb, TCA_POLICE_TM, sizeof(t), &t, TCA_POLICE_PAD))
3598c2ecf20Sopenharmony_ci		goto nla_put_failure;
3608c2ecf20Sopenharmony_ci	spin_unlock_bh(&police->tcf_lock);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return skb->len;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cinla_put_failure:
3658c2ecf20Sopenharmony_ci	spin_unlock_bh(&police->tcf_lock);
3668c2ecf20Sopenharmony_ci	nlmsg_trim(skb, b);
3678c2ecf20Sopenharmony_ci	return -1;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct tc_action_net *tn = net_generic(net, police_net_id);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return tcf_idr_search(tn, a, index);
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexey Kuznetsov");
3788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Policing actions");
3798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic struct tc_action_ops act_police_ops = {
3828c2ecf20Sopenharmony_ci	.kind		=	"police",
3838c2ecf20Sopenharmony_ci	.id		=	TCA_ID_POLICE,
3848c2ecf20Sopenharmony_ci	.owner		=	THIS_MODULE,
3858c2ecf20Sopenharmony_ci	.stats_update	=	tcf_police_stats_update,
3868c2ecf20Sopenharmony_ci	.act		=	tcf_police_act,
3878c2ecf20Sopenharmony_ci	.dump		=	tcf_police_dump,
3888c2ecf20Sopenharmony_ci	.init		=	tcf_police_init,
3898c2ecf20Sopenharmony_ci	.walk		=	tcf_police_walker,
3908c2ecf20Sopenharmony_ci	.lookup		=	tcf_police_search,
3918c2ecf20Sopenharmony_ci	.cleanup	=	tcf_police_cleanup,
3928c2ecf20Sopenharmony_ci	.size		=	sizeof(struct tcf_police),
3938c2ecf20Sopenharmony_ci};
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic __net_init int police_init_net(struct net *net)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct tc_action_net *tn = net_generic(net, police_net_id);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	return tc_action_net_init(net, tn, &act_police_ops);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void __net_exit police_exit_net(struct list_head *net_list)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	tc_action_net_exit(net_list, police_net_id);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic struct pernet_operations police_net_ops = {
4088c2ecf20Sopenharmony_ci	.init = police_init_net,
4098c2ecf20Sopenharmony_ci	.exit_batch = police_exit_net,
4108c2ecf20Sopenharmony_ci	.id   = &police_net_id,
4118c2ecf20Sopenharmony_ci	.size = sizeof(struct tc_action_net),
4128c2ecf20Sopenharmony_ci};
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int __init police_init_module(void)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	return tcf_register_action(&act_police_ops, &police_net_ops);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void __exit police_cleanup_module(void)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	tcf_unregister_action(&act_police_ops, &police_net_ops);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cimodule_init(police_init_module);
4258c2ecf20Sopenharmony_cimodule_exit(police_cleanup_module);
426