xref: /OK3568_Linux_fs/kernel/net/sched/act_gate.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* Copyright 2020 NXP */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/module.h>
5*4882a593Smuzhiyun #include <linux/types.h>
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/string.h>
8*4882a593Smuzhiyun #include <linux/errno.h>
9*4882a593Smuzhiyun #include <linux/skbuff.h>
10*4882a593Smuzhiyun #include <linux/rtnetlink.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <net/act_api.h>
14*4882a593Smuzhiyun #include <net/netlink.h>
15*4882a593Smuzhiyun #include <net/pkt_cls.h>
16*4882a593Smuzhiyun #include <net/tc_act/tc_gate.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static unsigned int gate_net_id;
19*4882a593Smuzhiyun static struct tc_action_ops act_gate_ops;
20*4882a593Smuzhiyun 
gate_get_time(struct tcf_gate * gact)21*4882a593Smuzhiyun static ktime_t gate_get_time(struct tcf_gate *gact)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	ktime_t mono = ktime_get();
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	switch (gact->tk_offset) {
26*4882a593Smuzhiyun 	case TK_OFFS_MAX:
27*4882a593Smuzhiyun 		return mono;
28*4882a593Smuzhiyun 	default:
29*4882a593Smuzhiyun 		return ktime_mono_to_any(mono, gact->tk_offset);
30*4882a593Smuzhiyun 	}
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	return KTIME_MAX;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
gate_get_start_time(struct tcf_gate * gact,ktime_t * start)35*4882a593Smuzhiyun static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun 	struct tcf_gate_params *param = &gact->param;
38*4882a593Smuzhiyun 	ktime_t now, base, cycle;
39*4882a593Smuzhiyun 	u64 n;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	base = ns_to_ktime(param->tcfg_basetime);
42*4882a593Smuzhiyun 	now = gate_get_time(gact);
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (ktime_after(base, now)) {
45*4882a593Smuzhiyun 		*start = base;
46*4882a593Smuzhiyun 		return;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	cycle = param->tcfg_cycletime;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	n = div64_u64(ktime_sub_ns(now, base), cycle);
52*4882a593Smuzhiyun 	*start = ktime_add_ns(base, (n + 1) * cycle);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
gate_start_timer(struct tcf_gate * gact,ktime_t start)55*4882a593Smuzhiyun static void gate_start_timer(struct tcf_gate *gact, ktime_t start)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	ktime_t expires;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	expires = hrtimer_get_expires(&gact->hitimer);
60*4882a593Smuzhiyun 	if (expires == 0)
61*4882a593Smuzhiyun 		expires = KTIME_MAX;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	start = min_t(ktime_t, start, expires);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	hrtimer_start(&gact->hitimer, start, HRTIMER_MODE_ABS_SOFT);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
gate_timer_func(struct hrtimer * timer)68*4882a593Smuzhiyun static enum hrtimer_restart gate_timer_func(struct hrtimer *timer)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	struct tcf_gate *gact = container_of(timer, struct tcf_gate,
71*4882a593Smuzhiyun 					     hitimer);
72*4882a593Smuzhiyun 	struct tcf_gate_params *p = &gact->param;
73*4882a593Smuzhiyun 	struct tcfg_gate_entry *next;
74*4882a593Smuzhiyun 	ktime_t close_time, now;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	spin_lock(&gact->tcf_lock);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	next = gact->next_entry;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* cycle start, clear pending bit, clear total octets */
81*4882a593Smuzhiyun 	gact->current_gate_status = next->gate_state ? GATE_ACT_GATE_OPEN : 0;
82*4882a593Smuzhiyun 	gact->current_entry_octets = 0;
83*4882a593Smuzhiyun 	gact->current_max_octets = next->maxoctets;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	gact->current_close_time = ktime_add_ns(gact->current_close_time,
86*4882a593Smuzhiyun 						next->interval);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	close_time = gact->current_close_time;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (list_is_last(&next->list, &p->entries))
91*4882a593Smuzhiyun 		next = list_first_entry(&p->entries,
92*4882a593Smuzhiyun 					struct tcfg_gate_entry, list);
93*4882a593Smuzhiyun 	else
94*4882a593Smuzhiyun 		next = list_next_entry(next, list);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	now = gate_get_time(gact);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (ktime_after(now, close_time)) {
99*4882a593Smuzhiyun 		ktime_t cycle, base;
100*4882a593Smuzhiyun 		u64 n;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 		cycle = p->tcfg_cycletime;
103*4882a593Smuzhiyun 		base = ns_to_ktime(p->tcfg_basetime);
104*4882a593Smuzhiyun 		n = div64_u64(ktime_sub_ns(now, base), cycle);
105*4882a593Smuzhiyun 		close_time = ktime_add_ns(base, (n + 1) * cycle);
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	gact->next_entry = next;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	hrtimer_set_expires(&gact->hitimer, close_time);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	spin_unlock(&gact->tcf_lock);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	return HRTIMER_RESTART;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
tcf_gate_act(struct sk_buff * skb,const struct tc_action * a,struct tcf_result * res)117*4882a593Smuzhiyun static int tcf_gate_act(struct sk_buff *skb, const struct tc_action *a,
118*4882a593Smuzhiyun 			struct tcf_result *res)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	struct tcf_gate *gact = to_gate(a);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	spin_lock(&gact->tcf_lock);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	tcf_lastuse_update(&gact->tcf_tm);
125*4882a593Smuzhiyun 	bstats_update(&gact->tcf_bstats, skb);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	if (unlikely(gact->current_gate_status & GATE_ACT_PENDING)) {
128*4882a593Smuzhiyun 		spin_unlock(&gact->tcf_lock);
129*4882a593Smuzhiyun 		return gact->tcf_action;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (!(gact->current_gate_status & GATE_ACT_GATE_OPEN))
133*4882a593Smuzhiyun 		goto drop;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (gact->current_max_octets >= 0) {
136*4882a593Smuzhiyun 		gact->current_entry_octets += qdisc_pkt_len(skb);
137*4882a593Smuzhiyun 		if (gact->current_entry_octets > gact->current_max_octets) {
138*4882a593Smuzhiyun 			gact->tcf_qstats.overlimits++;
139*4882a593Smuzhiyun 			goto drop;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	spin_unlock(&gact->tcf_lock);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return gact->tcf_action;
146*4882a593Smuzhiyun drop:
147*4882a593Smuzhiyun 	gact->tcf_qstats.drops++;
148*4882a593Smuzhiyun 	spin_unlock(&gact->tcf_lock);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return TC_ACT_SHOT;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static const struct nla_policy entry_policy[TCA_GATE_ENTRY_MAX + 1] = {
154*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_INDEX]		= { .type = NLA_U32 },
155*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_GATE]		= { .type = NLA_FLAG },
156*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_INTERVAL]	= { .type = NLA_U32 },
157*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_IPV]		= { .type = NLA_S32 },
158*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_MAX_OCTETS]	= { .type = NLA_S32 },
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun static const struct nla_policy gate_policy[TCA_GATE_MAX + 1] = {
162*4882a593Smuzhiyun 	[TCA_GATE_PARMS]		=
163*4882a593Smuzhiyun 		NLA_POLICY_EXACT_LEN(sizeof(struct tc_gate)),
164*4882a593Smuzhiyun 	[TCA_GATE_PRIORITY]		= { .type = NLA_S32 },
165*4882a593Smuzhiyun 	[TCA_GATE_ENTRY_LIST]		= { .type = NLA_NESTED },
166*4882a593Smuzhiyun 	[TCA_GATE_BASE_TIME]		= { .type = NLA_U64 },
167*4882a593Smuzhiyun 	[TCA_GATE_CYCLE_TIME]		= { .type = NLA_U64 },
168*4882a593Smuzhiyun 	[TCA_GATE_CYCLE_TIME_EXT]	= { .type = NLA_U64 },
169*4882a593Smuzhiyun 	[TCA_GATE_FLAGS]		= { .type = NLA_U32 },
170*4882a593Smuzhiyun 	[TCA_GATE_CLOCKID]		= { .type = NLA_S32 },
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
fill_gate_entry(struct nlattr ** tb,struct tcfg_gate_entry * entry,struct netlink_ext_ack * extack)173*4882a593Smuzhiyun static int fill_gate_entry(struct nlattr **tb, struct tcfg_gate_entry *entry,
174*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	u32 interval = 0;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	entry->gate_state = nla_get_flag(tb[TCA_GATE_ENTRY_GATE]);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (tb[TCA_GATE_ENTRY_INTERVAL])
181*4882a593Smuzhiyun 		interval = nla_get_u32(tb[TCA_GATE_ENTRY_INTERVAL]);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (interval == 0) {
184*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Invalid interval for schedule entry");
185*4882a593Smuzhiyun 		return -EINVAL;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	entry->interval = interval;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (tb[TCA_GATE_ENTRY_IPV])
191*4882a593Smuzhiyun 		entry->ipv = nla_get_s32(tb[TCA_GATE_ENTRY_IPV]);
192*4882a593Smuzhiyun 	else
193*4882a593Smuzhiyun 		entry->ipv = -1;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	if (tb[TCA_GATE_ENTRY_MAX_OCTETS])
196*4882a593Smuzhiyun 		entry->maxoctets = nla_get_s32(tb[TCA_GATE_ENTRY_MAX_OCTETS]);
197*4882a593Smuzhiyun 	else
198*4882a593Smuzhiyun 		entry->maxoctets = -1;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	return 0;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
parse_gate_entry(struct nlattr * n,struct tcfg_gate_entry * entry,int index,struct netlink_ext_ack * extack)203*4882a593Smuzhiyun static int parse_gate_entry(struct nlattr *n, struct  tcfg_gate_entry *entry,
204*4882a593Smuzhiyun 			    int index, struct netlink_ext_ack *extack)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	struct nlattr *tb[TCA_GATE_ENTRY_MAX + 1] = { };
207*4882a593Smuzhiyun 	int err;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	err = nla_parse_nested(tb, TCA_GATE_ENTRY_MAX, n, entry_policy, extack);
210*4882a593Smuzhiyun 	if (err < 0) {
211*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Could not parse nested entry");
212*4882a593Smuzhiyun 		return -EINVAL;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	entry->index = index;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return fill_gate_entry(tb, entry, extack);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
release_entry_list(struct list_head * entries)220*4882a593Smuzhiyun static void release_entry_list(struct list_head *entries)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct tcfg_gate_entry *entry, *e;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	list_for_each_entry_safe(entry, e, entries, list) {
225*4882a593Smuzhiyun 		list_del(&entry->list);
226*4882a593Smuzhiyun 		kfree(entry);
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
parse_gate_list(struct nlattr * list_attr,struct tcf_gate_params * sched,struct netlink_ext_ack * extack)230*4882a593Smuzhiyun static int parse_gate_list(struct nlattr *list_attr,
231*4882a593Smuzhiyun 			   struct tcf_gate_params *sched,
232*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	struct tcfg_gate_entry *entry;
235*4882a593Smuzhiyun 	struct nlattr *n;
236*4882a593Smuzhiyun 	int err, rem;
237*4882a593Smuzhiyun 	int i = 0;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (!list_attr)
240*4882a593Smuzhiyun 		return -EINVAL;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	nla_for_each_nested(n, list_attr, rem) {
243*4882a593Smuzhiyun 		if (nla_type(n) != TCA_GATE_ONE_ENTRY) {
244*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Attribute isn't type 'entry'");
245*4882a593Smuzhiyun 			continue;
246*4882a593Smuzhiyun 		}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
249*4882a593Smuzhiyun 		if (!entry) {
250*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Not enough memory for entry");
251*4882a593Smuzhiyun 			err = -ENOMEM;
252*4882a593Smuzhiyun 			goto release_list;
253*4882a593Smuzhiyun 		}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		err = parse_gate_entry(n, entry, i, extack);
256*4882a593Smuzhiyun 		if (err < 0) {
257*4882a593Smuzhiyun 			kfree(entry);
258*4882a593Smuzhiyun 			goto release_list;
259*4882a593Smuzhiyun 		}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		list_add_tail(&entry->list, &sched->entries);
262*4882a593Smuzhiyun 		i++;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	sched->num_entries = i;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return i;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun release_list:
270*4882a593Smuzhiyun 	release_entry_list(&sched->entries);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return err;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
gate_setup_timer(struct tcf_gate * gact,u64 basetime,enum tk_offsets tko,s32 clockid,bool do_init)275*4882a593Smuzhiyun static void gate_setup_timer(struct tcf_gate *gact, u64 basetime,
276*4882a593Smuzhiyun 			     enum tk_offsets tko, s32 clockid,
277*4882a593Smuzhiyun 			     bool do_init)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	if (!do_init) {
280*4882a593Smuzhiyun 		if (basetime == gact->param.tcfg_basetime &&
281*4882a593Smuzhiyun 		    tko == gact->tk_offset &&
282*4882a593Smuzhiyun 		    clockid == gact->param.tcfg_clockid)
283*4882a593Smuzhiyun 			return;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 		spin_unlock_bh(&gact->tcf_lock);
286*4882a593Smuzhiyun 		hrtimer_cancel(&gact->hitimer);
287*4882a593Smuzhiyun 		spin_lock_bh(&gact->tcf_lock);
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	gact->param.tcfg_basetime = basetime;
290*4882a593Smuzhiyun 	gact->param.tcfg_clockid = clockid;
291*4882a593Smuzhiyun 	gact->tk_offset = tko;
292*4882a593Smuzhiyun 	hrtimer_init(&gact->hitimer, clockid, HRTIMER_MODE_ABS_SOFT);
293*4882a593Smuzhiyun 	gact->hitimer.function = gate_timer_func;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
tcf_gate_init(struct net * net,struct nlattr * nla,struct nlattr * est,struct tc_action ** a,int ovr,int bind,bool rtnl_held,struct tcf_proto * tp,u32 flags,struct netlink_ext_ack * extack)296*4882a593Smuzhiyun static int tcf_gate_init(struct net *net, struct nlattr *nla,
297*4882a593Smuzhiyun 			 struct nlattr *est, struct tc_action **a,
298*4882a593Smuzhiyun 			 int ovr, int bind, bool rtnl_held,
299*4882a593Smuzhiyun 			 struct tcf_proto *tp, u32 flags,
300*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, gate_net_id);
303*4882a593Smuzhiyun 	enum tk_offsets tk_offset = TK_OFFS_TAI;
304*4882a593Smuzhiyun 	struct nlattr *tb[TCA_GATE_MAX + 1];
305*4882a593Smuzhiyun 	struct tcf_chain *goto_ch = NULL;
306*4882a593Smuzhiyun 	u64 cycletime = 0, basetime = 0;
307*4882a593Smuzhiyun 	struct tcf_gate_params *p;
308*4882a593Smuzhiyun 	s32 clockid = CLOCK_TAI;
309*4882a593Smuzhiyun 	struct tcf_gate *gact;
310*4882a593Smuzhiyun 	struct tc_gate *parm;
311*4882a593Smuzhiyun 	int ret = 0, err;
312*4882a593Smuzhiyun 	u32 gflags = 0;
313*4882a593Smuzhiyun 	s32 prio = -1;
314*4882a593Smuzhiyun 	ktime_t start;
315*4882a593Smuzhiyun 	u32 index;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (!nla)
318*4882a593Smuzhiyun 		return -EINVAL;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	err = nla_parse_nested(tb, TCA_GATE_MAX, nla, gate_policy, extack);
321*4882a593Smuzhiyun 	if (err < 0)
322*4882a593Smuzhiyun 		return err;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (!tb[TCA_GATE_PARMS])
325*4882a593Smuzhiyun 		return -EINVAL;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (tb[TCA_GATE_CLOCKID]) {
328*4882a593Smuzhiyun 		clockid = nla_get_s32(tb[TCA_GATE_CLOCKID]);
329*4882a593Smuzhiyun 		switch (clockid) {
330*4882a593Smuzhiyun 		case CLOCK_REALTIME:
331*4882a593Smuzhiyun 			tk_offset = TK_OFFS_REAL;
332*4882a593Smuzhiyun 			break;
333*4882a593Smuzhiyun 		case CLOCK_MONOTONIC:
334*4882a593Smuzhiyun 			tk_offset = TK_OFFS_MAX;
335*4882a593Smuzhiyun 			break;
336*4882a593Smuzhiyun 		case CLOCK_BOOTTIME:
337*4882a593Smuzhiyun 			tk_offset = TK_OFFS_BOOT;
338*4882a593Smuzhiyun 			break;
339*4882a593Smuzhiyun 		case CLOCK_TAI:
340*4882a593Smuzhiyun 			tk_offset = TK_OFFS_TAI;
341*4882a593Smuzhiyun 			break;
342*4882a593Smuzhiyun 		default:
343*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
344*4882a593Smuzhiyun 			return -EINVAL;
345*4882a593Smuzhiyun 		}
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	parm = nla_data(tb[TCA_GATE_PARMS]);
349*4882a593Smuzhiyun 	index = parm->index;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	err = tcf_idr_check_alloc(tn, &index, a, bind);
352*4882a593Smuzhiyun 	if (err < 0)
353*4882a593Smuzhiyun 		return err;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (err && bind)
356*4882a593Smuzhiyun 		return 0;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	if (!err) {
359*4882a593Smuzhiyun 		ret = tcf_idr_create(tn, index, est, a,
360*4882a593Smuzhiyun 				     &act_gate_ops, bind, false, 0);
361*4882a593Smuzhiyun 		if (ret) {
362*4882a593Smuzhiyun 			tcf_idr_cleanup(tn, index);
363*4882a593Smuzhiyun 			return ret;
364*4882a593Smuzhiyun 		}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		ret = ACT_P_CREATED;
367*4882a593Smuzhiyun 	} else if (!ovr) {
368*4882a593Smuzhiyun 		tcf_idr_release(*a, bind);
369*4882a593Smuzhiyun 		return -EEXIST;
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (tb[TCA_GATE_PRIORITY])
373*4882a593Smuzhiyun 		prio = nla_get_s32(tb[TCA_GATE_PRIORITY]);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (tb[TCA_GATE_BASE_TIME])
376*4882a593Smuzhiyun 		basetime = nla_get_u64(tb[TCA_GATE_BASE_TIME]);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (tb[TCA_GATE_FLAGS])
379*4882a593Smuzhiyun 		gflags = nla_get_u32(tb[TCA_GATE_FLAGS]);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	gact = to_gate(*a);
382*4882a593Smuzhiyun 	if (ret == ACT_P_CREATED)
383*4882a593Smuzhiyun 		INIT_LIST_HEAD(&gact->param.entries);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
386*4882a593Smuzhiyun 	if (err < 0)
387*4882a593Smuzhiyun 		goto release_idr;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	spin_lock_bh(&gact->tcf_lock);
390*4882a593Smuzhiyun 	p = &gact->param;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	if (tb[TCA_GATE_CYCLE_TIME])
393*4882a593Smuzhiyun 		cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (tb[TCA_GATE_ENTRY_LIST]) {
396*4882a593Smuzhiyun 		err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
397*4882a593Smuzhiyun 		if (err < 0)
398*4882a593Smuzhiyun 			goto chain_put;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (!cycletime) {
402*4882a593Smuzhiyun 		struct tcfg_gate_entry *entry;
403*4882a593Smuzhiyun 		ktime_t cycle = 0;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		list_for_each_entry(entry, &p->entries, list)
406*4882a593Smuzhiyun 			cycle = ktime_add_ns(cycle, entry->interval);
407*4882a593Smuzhiyun 		cycletime = cycle;
408*4882a593Smuzhiyun 		if (!cycletime) {
409*4882a593Smuzhiyun 			err = -EINVAL;
410*4882a593Smuzhiyun 			goto chain_put;
411*4882a593Smuzhiyun 		}
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 	p->tcfg_cycletime = cycletime;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (tb[TCA_GATE_CYCLE_TIME_EXT])
416*4882a593Smuzhiyun 		p->tcfg_cycletime_ext =
417*4882a593Smuzhiyun 			nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	gate_setup_timer(gact, basetime, tk_offset, clockid,
420*4882a593Smuzhiyun 			 ret == ACT_P_CREATED);
421*4882a593Smuzhiyun 	p->tcfg_priority = prio;
422*4882a593Smuzhiyun 	p->tcfg_flags = gflags;
423*4882a593Smuzhiyun 	gate_get_start_time(gact, &start);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	gact->current_close_time = start;
426*4882a593Smuzhiyun 	gact->current_gate_status = GATE_ACT_GATE_OPEN | GATE_ACT_PENDING;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	gact->next_entry = list_first_entry(&p->entries,
429*4882a593Smuzhiyun 					    struct tcfg_gate_entry, list);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	gate_start_timer(gact, start);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	spin_unlock_bh(&gact->tcf_lock);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	if (goto_ch)
438*4882a593Smuzhiyun 		tcf_chain_put_by_act(goto_ch);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	return ret;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun chain_put:
443*4882a593Smuzhiyun 	spin_unlock_bh(&gact->tcf_lock);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	if (goto_ch)
446*4882a593Smuzhiyun 		tcf_chain_put_by_act(goto_ch);
447*4882a593Smuzhiyun release_idr:
448*4882a593Smuzhiyun 	/* action is not inserted in any list: it's safe to init hitimer
449*4882a593Smuzhiyun 	 * without taking tcf_lock.
450*4882a593Smuzhiyun 	 */
451*4882a593Smuzhiyun 	if (ret == ACT_P_CREATED)
452*4882a593Smuzhiyun 		gate_setup_timer(gact, gact->param.tcfg_basetime,
453*4882a593Smuzhiyun 				 gact->tk_offset, gact->param.tcfg_clockid,
454*4882a593Smuzhiyun 				 true);
455*4882a593Smuzhiyun 	tcf_idr_release(*a, bind);
456*4882a593Smuzhiyun 	return err;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
tcf_gate_cleanup(struct tc_action * a)459*4882a593Smuzhiyun static void tcf_gate_cleanup(struct tc_action *a)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	struct tcf_gate *gact = to_gate(a);
462*4882a593Smuzhiyun 	struct tcf_gate_params *p;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	p = &gact->param;
465*4882a593Smuzhiyun 	hrtimer_cancel(&gact->hitimer);
466*4882a593Smuzhiyun 	release_entry_list(&p->entries);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
dumping_entry(struct sk_buff * skb,struct tcfg_gate_entry * entry)469*4882a593Smuzhiyun static int dumping_entry(struct sk_buff *skb,
470*4882a593Smuzhiyun 			 struct tcfg_gate_entry *entry)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	struct nlattr *item;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	item = nla_nest_start_noflag(skb, TCA_GATE_ONE_ENTRY);
475*4882a593Smuzhiyun 	if (!item)
476*4882a593Smuzhiyun 		return -ENOSPC;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	if (nla_put_u32(skb, TCA_GATE_ENTRY_INDEX, entry->index))
479*4882a593Smuzhiyun 		goto nla_put_failure;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (entry->gate_state && nla_put_flag(skb, TCA_GATE_ENTRY_GATE))
482*4882a593Smuzhiyun 		goto nla_put_failure;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (nla_put_u32(skb, TCA_GATE_ENTRY_INTERVAL, entry->interval))
485*4882a593Smuzhiyun 		goto nla_put_failure;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	if (nla_put_s32(skb, TCA_GATE_ENTRY_MAX_OCTETS, entry->maxoctets))
488*4882a593Smuzhiyun 		goto nla_put_failure;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	if (nla_put_s32(skb, TCA_GATE_ENTRY_IPV, entry->ipv))
491*4882a593Smuzhiyun 		goto nla_put_failure;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	return nla_nest_end(skb, item);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun nla_put_failure:
496*4882a593Smuzhiyun 	nla_nest_cancel(skb, item);
497*4882a593Smuzhiyun 	return -1;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
tcf_gate_dump(struct sk_buff * skb,struct tc_action * a,int bind,int ref)500*4882a593Smuzhiyun static int tcf_gate_dump(struct sk_buff *skb, struct tc_action *a,
501*4882a593Smuzhiyun 			 int bind, int ref)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	unsigned char *b = skb_tail_pointer(skb);
504*4882a593Smuzhiyun 	struct tcf_gate *gact = to_gate(a);
505*4882a593Smuzhiyun 	struct tc_gate opt = {
506*4882a593Smuzhiyun 		.index    = gact->tcf_index,
507*4882a593Smuzhiyun 		.refcnt   = refcount_read(&gact->tcf_refcnt) - ref,
508*4882a593Smuzhiyun 		.bindcnt  = atomic_read(&gact->tcf_bindcnt) - bind,
509*4882a593Smuzhiyun 	};
510*4882a593Smuzhiyun 	struct tcfg_gate_entry *entry;
511*4882a593Smuzhiyun 	struct tcf_gate_params *p;
512*4882a593Smuzhiyun 	struct nlattr *entry_list;
513*4882a593Smuzhiyun 	struct tcf_t t;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	spin_lock_bh(&gact->tcf_lock);
516*4882a593Smuzhiyun 	opt.action = gact->tcf_action;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	p = &gact->param;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (nla_put(skb, TCA_GATE_PARMS, sizeof(opt), &opt))
521*4882a593Smuzhiyun 		goto nla_put_failure;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	if (nla_put_u64_64bit(skb, TCA_GATE_BASE_TIME,
524*4882a593Smuzhiyun 			      p->tcfg_basetime, TCA_GATE_PAD))
525*4882a593Smuzhiyun 		goto nla_put_failure;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	if (nla_put_u64_64bit(skb, TCA_GATE_CYCLE_TIME,
528*4882a593Smuzhiyun 			      p->tcfg_cycletime, TCA_GATE_PAD))
529*4882a593Smuzhiyun 		goto nla_put_failure;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (nla_put_u64_64bit(skb, TCA_GATE_CYCLE_TIME_EXT,
532*4882a593Smuzhiyun 			      p->tcfg_cycletime_ext, TCA_GATE_PAD))
533*4882a593Smuzhiyun 		goto nla_put_failure;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	if (nla_put_s32(skb, TCA_GATE_CLOCKID, p->tcfg_clockid))
536*4882a593Smuzhiyun 		goto nla_put_failure;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	if (nla_put_u32(skb, TCA_GATE_FLAGS, p->tcfg_flags))
539*4882a593Smuzhiyun 		goto nla_put_failure;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	if (nla_put_s32(skb, TCA_GATE_PRIORITY, p->tcfg_priority))
542*4882a593Smuzhiyun 		goto nla_put_failure;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	entry_list = nla_nest_start_noflag(skb, TCA_GATE_ENTRY_LIST);
545*4882a593Smuzhiyun 	if (!entry_list)
546*4882a593Smuzhiyun 		goto nla_put_failure;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	list_for_each_entry(entry, &p->entries, list) {
549*4882a593Smuzhiyun 		if (dumping_entry(skb, entry) < 0)
550*4882a593Smuzhiyun 			goto nla_put_failure;
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	nla_nest_end(skb, entry_list);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	tcf_tm_dump(&t, &gact->tcf_tm);
556*4882a593Smuzhiyun 	if (nla_put_64bit(skb, TCA_GATE_TM, sizeof(t), &t, TCA_GATE_PAD))
557*4882a593Smuzhiyun 		goto nla_put_failure;
558*4882a593Smuzhiyun 	spin_unlock_bh(&gact->tcf_lock);
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	return skb->len;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun nla_put_failure:
563*4882a593Smuzhiyun 	spin_unlock_bh(&gact->tcf_lock);
564*4882a593Smuzhiyun 	nlmsg_trim(skb, b);
565*4882a593Smuzhiyun 	return -1;
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun 
tcf_gate_walker(struct net * net,struct sk_buff * skb,struct netlink_callback * cb,int type,const struct tc_action_ops * ops,struct netlink_ext_ack * extack)568*4882a593Smuzhiyun static int tcf_gate_walker(struct net *net, struct sk_buff *skb,
569*4882a593Smuzhiyun 			   struct netlink_callback *cb, int type,
570*4882a593Smuzhiyun 			   const struct tc_action_ops *ops,
571*4882a593Smuzhiyun 			   struct netlink_ext_ack *extack)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, gate_net_id);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
tcf_gate_stats_update(struct tc_action * a,u64 bytes,u64 packets,u64 drops,u64 lastuse,bool hw)578*4882a593Smuzhiyun static void tcf_gate_stats_update(struct tc_action *a, u64 bytes, u64 packets,
579*4882a593Smuzhiyun 				  u64 drops, u64 lastuse, bool hw)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	struct tcf_gate *gact = to_gate(a);
582*4882a593Smuzhiyun 	struct tcf_t *tm = &gact->tcf_tm;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	tcf_action_update_stats(a, bytes, packets, drops, hw);
585*4882a593Smuzhiyun 	tm->lastuse = max_t(u64, tm->lastuse, lastuse);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
tcf_gate_search(struct net * net,struct tc_action ** a,u32 index)588*4882a593Smuzhiyun static int tcf_gate_search(struct net *net, struct tc_action **a, u32 index)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, gate_net_id);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	return tcf_idr_search(tn, a, index);
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
tcf_gate_get_fill_size(const struct tc_action * act)595*4882a593Smuzhiyun static size_t tcf_gate_get_fill_size(const struct tc_action *act)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	return nla_total_size(sizeof(struct tc_gate));
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun static struct tc_action_ops act_gate_ops = {
601*4882a593Smuzhiyun 	.kind		=	"gate",
602*4882a593Smuzhiyun 	.id		=	TCA_ID_GATE,
603*4882a593Smuzhiyun 	.owner		=	THIS_MODULE,
604*4882a593Smuzhiyun 	.act		=	tcf_gate_act,
605*4882a593Smuzhiyun 	.dump		=	tcf_gate_dump,
606*4882a593Smuzhiyun 	.init		=	tcf_gate_init,
607*4882a593Smuzhiyun 	.cleanup	=	tcf_gate_cleanup,
608*4882a593Smuzhiyun 	.walk		=	tcf_gate_walker,
609*4882a593Smuzhiyun 	.stats_update	=	tcf_gate_stats_update,
610*4882a593Smuzhiyun 	.get_fill_size	=	tcf_gate_get_fill_size,
611*4882a593Smuzhiyun 	.lookup		=	tcf_gate_search,
612*4882a593Smuzhiyun 	.size		=	sizeof(struct tcf_gate),
613*4882a593Smuzhiyun };
614*4882a593Smuzhiyun 
gate_init_net(struct net * net)615*4882a593Smuzhiyun static __net_init int gate_init_net(struct net *net)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct tc_action_net *tn = net_generic(net, gate_net_id);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	return tc_action_net_init(net, tn, &act_gate_ops);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun 
gate_exit_net(struct list_head * net_list)622*4882a593Smuzhiyun static void __net_exit gate_exit_net(struct list_head *net_list)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun 	tc_action_net_exit(net_list, gate_net_id);
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun static struct pernet_operations gate_net_ops = {
628*4882a593Smuzhiyun 	.init = gate_init_net,
629*4882a593Smuzhiyun 	.exit_batch = gate_exit_net,
630*4882a593Smuzhiyun 	.id   = &gate_net_id,
631*4882a593Smuzhiyun 	.size = sizeof(struct tc_action_net),
632*4882a593Smuzhiyun };
633*4882a593Smuzhiyun 
gate_init_module(void)634*4882a593Smuzhiyun static int __init gate_init_module(void)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	return tcf_register_action(&act_gate_ops, &gate_net_ops);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun 
gate_cleanup_module(void)639*4882a593Smuzhiyun static void __exit gate_cleanup_module(void)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	tcf_unregister_action(&act_gate_ops, &gate_net_ops);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun module_init(gate_init_module);
645*4882a593Smuzhiyun module_exit(gate_cleanup_module);
646*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
647