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