xref: /OK3568_Linux_fs/kernel/net/sched/sch_etf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun /* net/sched/sch_etf.c  Earliest TxTime First queueing discipline.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors:	Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
6*4882a593Smuzhiyun  *		Vinicius Costa Gomes <vinicius.gomes@intel.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/string.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/errqueue.h>
15*4882a593Smuzhiyun #include <linux/rbtree.h>
16*4882a593Smuzhiyun #include <linux/skbuff.h>
17*4882a593Smuzhiyun #include <linux/posix-timers.h>
18*4882a593Smuzhiyun #include <net/netlink.h>
19*4882a593Smuzhiyun #include <net/sch_generic.h>
20*4882a593Smuzhiyun #include <net/pkt_sched.h>
21*4882a593Smuzhiyun #include <net/sock.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define DEADLINE_MODE_IS_ON(x) ((x)->flags & TC_ETF_DEADLINE_MODE_ON)
24*4882a593Smuzhiyun #define OFFLOAD_IS_ON(x) ((x)->flags & TC_ETF_OFFLOAD_ON)
25*4882a593Smuzhiyun #define SKIP_SOCK_CHECK_IS_SET(x) ((x)->flags & TC_ETF_SKIP_SOCK_CHECK)
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun struct etf_sched_data {
28*4882a593Smuzhiyun 	bool offload;
29*4882a593Smuzhiyun 	bool deadline_mode;
30*4882a593Smuzhiyun 	bool skip_sock_check;
31*4882a593Smuzhiyun 	int clockid;
32*4882a593Smuzhiyun 	int queue;
33*4882a593Smuzhiyun 	s32 delta; /* in ns */
34*4882a593Smuzhiyun 	ktime_t last; /* The txtime of the last skb sent to the netdevice. */
35*4882a593Smuzhiyun 	struct rb_root_cached head;
36*4882a593Smuzhiyun 	struct qdisc_watchdog watchdog;
37*4882a593Smuzhiyun 	ktime_t (*get_time)(void);
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static const struct nla_policy etf_policy[TCA_ETF_MAX + 1] = {
41*4882a593Smuzhiyun 	[TCA_ETF_PARMS]	= { .len = sizeof(struct tc_etf_qopt) },
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
validate_input_params(struct tc_etf_qopt * qopt,struct netlink_ext_ack * extack)44*4882a593Smuzhiyun static inline int validate_input_params(struct tc_etf_qopt *qopt,
45*4882a593Smuzhiyun 					struct netlink_ext_ack *extack)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	/* Check if params comply to the following rules:
48*4882a593Smuzhiyun 	 *	* Clockid and delta must be valid.
49*4882a593Smuzhiyun 	 *
50*4882a593Smuzhiyun 	 *	* Dynamic clockids are not supported.
51*4882a593Smuzhiyun 	 *
52*4882a593Smuzhiyun 	 *	* Delta must be a positive integer.
53*4882a593Smuzhiyun 	 *
54*4882a593Smuzhiyun 	 * Also note that for the HW offload case, we must
55*4882a593Smuzhiyun 	 * expect that system clocks have been synchronized to PHC.
56*4882a593Smuzhiyun 	 */
57*4882a593Smuzhiyun 	if (qopt->clockid < 0) {
58*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Dynamic clockids are not supported");
59*4882a593Smuzhiyun 		return -ENOTSUPP;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	if (qopt->clockid != CLOCK_TAI) {
63*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Invalid clockid. CLOCK_TAI must be used");
64*4882a593Smuzhiyun 		return -EINVAL;
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (qopt->delta < 0) {
68*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Delta must be positive");
69*4882a593Smuzhiyun 		return -EINVAL;
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	return 0;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
is_packet_valid(struct Qdisc * sch,struct sk_buff * nskb)75*4882a593Smuzhiyun static bool is_packet_valid(struct Qdisc *sch, struct sk_buff *nskb)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
78*4882a593Smuzhiyun 	ktime_t txtime = nskb->tstamp;
79*4882a593Smuzhiyun 	struct sock *sk = nskb->sk;
80*4882a593Smuzhiyun 	ktime_t now;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (q->skip_sock_check)
83*4882a593Smuzhiyun 		goto skip;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (!sk || !sk_fullsock(sk))
86*4882a593Smuzhiyun 		return false;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (!sock_flag(sk, SOCK_TXTIME))
89*4882a593Smuzhiyun 		return false;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	/* We don't perform crosstimestamping.
92*4882a593Smuzhiyun 	 * Drop if packet's clockid differs from qdisc's.
93*4882a593Smuzhiyun 	 */
94*4882a593Smuzhiyun 	if (sk->sk_clockid != q->clockid)
95*4882a593Smuzhiyun 		return false;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (sk->sk_txtime_deadline_mode != q->deadline_mode)
98*4882a593Smuzhiyun 		return false;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun skip:
101*4882a593Smuzhiyun 	now = q->get_time();
102*4882a593Smuzhiyun 	if (ktime_before(txtime, now) || ktime_before(txtime, q->last))
103*4882a593Smuzhiyun 		return false;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return true;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
etf_peek_timesortedlist(struct Qdisc * sch)108*4882a593Smuzhiyun static struct sk_buff *etf_peek_timesortedlist(struct Qdisc *sch)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
111*4882a593Smuzhiyun 	struct rb_node *p;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	p = rb_first_cached(&q->head);
114*4882a593Smuzhiyun 	if (!p)
115*4882a593Smuzhiyun 		return NULL;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return rb_to_skb(p);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
reset_watchdog(struct Qdisc * sch)120*4882a593Smuzhiyun static void reset_watchdog(struct Qdisc *sch)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
123*4882a593Smuzhiyun 	struct sk_buff *skb = etf_peek_timesortedlist(sch);
124*4882a593Smuzhiyun 	ktime_t next;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	if (!skb) {
127*4882a593Smuzhiyun 		qdisc_watchdog_cancel(&q->watchdog);
128*4882a593Smuzhiyun 		return;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	next = ktime_sub_ns(skb->tstamp, q->delta);
132*4882a593Smuzhiyun 	qdisc_watchdog_schedule_ns(&q->watchdog, ktime_to_ns(next));
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
report_sock_error(struct sk_buff * skb,u32 err,u8 code)135*4882a593Smuzhiyun static void report_sock_error(struct sk_buff *skb, u32 err, u8 code)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct sock_exterr_skb *serr;
138*4882a593Smuzhiyun 	struct sk_buff *clone;
139*4882a593Smuzhiyun 	ktime_t txtime = skb->tstamp;
140*4882a593Smuzhiyun 	struct sock *sk = skb->sk;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (!sk || !sk_fullsock(sk) || !(sk->sk_txtime_report_errors))
143*4882a593Smuzhiyun 		return;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	clone = skb_clone(skb, GFP_ATOMIC);
146*4882a593Smuzhiyun 	if (!clone)
147*4882a593Smuzhiyun 		return;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	serr = SKB_EXT_ERR(clone);
150*4882a593Smuzhiyun 	serr->ee.ee_errno = err;
151*4882a593Smuzhiyun 	serr->ee.ee_origin = SO_EE_ORIGIN_TXTIME;
152*4882a593Smuzhiyun 	serr->ee.ee_type = 0;
153*4882a593Smuzhiyun 	serr->ee.ee_code = code;
154*4882a593Smuzhiyun 	serr->ee.ee_pad = 0;
155*4882a593Smuzhiyun 	serr->ee.ee_data = (txtime >> 32); /* high part of tstamp */
156*4882a593Smuzhiyun 	serr->ee.ee_info = txtime; /* low part of tstamp */
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	if (sock_queue_err_skb(sk, clone))
159*4882a593Smuzhiyun 		kfree_skb(clone);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
etf_enqueue_timesortedlist(struct sk_buff * nskb,struct Qdisc * sch,struct sk_buff ** to_free)162*4882a593Smuzhiyun static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
163*4882a593Smuzhiyun 				      struct sk_buff **to_free)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
166*4882a593Smuzhiyun 	struct rb_node **p = &q->head.rb_root.rb_node, *parent = NULL;
167*4882a593Smuzhiyun 	ktime_t txtime = nskb->tstamp;
168*4882a593Smuzhiyun 	bool leftmost = true;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (!is_packet_valid(sch, nskb)) {
171*4882a593Smuzhiyun 		report_sock_error(nskb, EINVAL,
172*4882a593Smuzhiyun 				  SO_EE_CODE_TXTIME_INVALID_PARAM);
173*4882a593Smuzhiyun 		return qdisc_drop(nskb, sch, to_free);
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	while (*p) {
177*4882a593Smuzhiyun 		struct sk_buff *skb;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		parent = *p;
180*4882a593Smuzhiyun 		skb = rb_to_skb(parent);
181*4882a593Smuzhiyun 		if (ktime_compare(txtime, skb->tstamp) >= 0) {
182*4882a593Smuzhiyun 			p = &parent->rb_right;
183*4882a593Smuzhiyun 			leftmost = false;
184*4882a593Smuzhiyun 		} else {
185*4882a593Smuzhiyun 			p = &parent->rb_left;
186*4882a593Smuzhiyun 		}
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 	rb_link_node(&nskb->rbnode, parent, p);
189*4882a593Smuzhiyun 	rb_insert_color_cached(&nskb->rbnode, &q->head, leftmost);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	qdisc_qstats_backlog_inc(sch, nskb);
192*4882a593Smuzhiyun 	sch->q.qlen++;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* Now we may need to re-arm the qdisc watchdog for the next packet. */
195*4882a593Smuzhiyun 	reset_watchdog(sch);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return NET_XMIT_SUCCESS;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
timesortedlist_drop(struct Qdisc * sch,struct sk_buff * skb,ktime_t now)200*4882a593Smuzhiyun static void timesortedlist_drop(struct Qdisc *sch, struct sk_buff *skb,
201*4882a593Smuzhiyun 				ktime_t now)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
204*4882a593Smuzhiyun 	struct sk_buff *to_free = NULL;
205*4882a593Smuzhiyun 	struct sk_buff *tmp = NULL;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	skb_rbtree_walk_from_safe(skb, tmp) {
208*4882a593Smuzhiyun 		if (ktime_after(skb->tstamp, now))
209*4882a593Smuzhiyun 			break;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		rb_erase_cached(&skb->rbnode, &q->head);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 		/* The rbnode field in the skb re-uses these fields, now that
214*4882a593Smuzhiyun 		 * we are done with the rbnode, reset them.
215*4882a593Smuzhiyun 		 */
216*4882a593Smuzhiyun 		skb->next = NULL;
217*4882a593Smuzhiyun 		skb->prev = NULL;
218*4882a593Smuzhiyun 		skb->dev = qdisc_dev(sch);
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 		report_sock_error(skb, ECANCELED, SO_EE_CODE_TXTIME_MISSED);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 		qdisc_qstats_backlog_dec(sch, skb);
223*4882a593Smuzhiyun 		qdisc_drop(skb, sch, &to_free);
224*4882a593Smuzhiyun 		qdisc_qstats_overlimit(sch);
225*4882a593Smuzhiyun 		sch->q.qlen--;
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	kfree_skb_list(to_free);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
timesortedlist_remove(struct Qdisc * sch,struct sk_buff * skb)231*4882a593Smuzhiyun static void timesortedlist_remove(struct Qdisc *sch, struct sk_buff *skb)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	rb_erase_cached(&skb->rbnode, &q->head);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* The rbnode field in the skb re-uses these fields, now that
238*4882a593Smuzhiyun 	 * we are done with the rbnode, reset them.
239*4882a593Smuzhiyun 	 */
240*4882a593Smuzhiyun 	skb->next = NULL;
241*4882a593Smuzhiyun 	skb->prev = NULL;
242*4882a593Smuzhiyun 	skb->dev = qdisc_dev(sch);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	qdisc_qstats_backlog_dec(sch, skb);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	qdisc_bstats_update(sch, skb);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	q->last = skb->tstamp;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	sch->q.qlen--;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
etf_dequeue_timesortedlist(struct Qdisc * sch)253*4882a593Smuzhiyun static struct sk_buff *etf_dequeue_timesortedlist(struct Qdisc *sch)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
256*4882a593Smuzhiyun 	struct sk_buff *skb;
257*4882a593Smuzhiyun 	ktime_t now, next;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	skb = etf_peek_timesortedlist(sch);
260*4882a593Smuzhiyun 	if (!skb)
261*4882a593Smuzhiyun 		return NULL;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	now = q->get_time();
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* Drop if packet has expired while in queue. */
266*4882a593Smuzhiyun 	if (ktime_before(skb->tstamp, now)) {
267*4882a593Smuzhiyun 		timesortedlist_drop(sch, skb, now);
268*4882a593Smuzhiyun 		skb = NULL;
269*4882a593Smuzhiyun 		goto out;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	/* When in deadline mode, dequeue as soon as possible and change the
273*4882a593Smuzhiyun 	 * txtime from deadline to (now + delta).
274*4882a593Smuzhiyun 	 */
275*4882a593Smuzhiyun 	if (q->deadline_mode) {
276*4882a593Smuzhiyun 		timesortedlist_remove(sch, skb);
277*4882a593Smuzhiyun 		skb->tstamp = now;
278*4882a593Smuzhiyun 		goto out;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	next = ktime_sub_ns(skb->tstamp, q->delta);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* Dequeue only if now is within the [txtime - delta, txtime] range. */
284*4882a593Smuzhiyun 	if (ktime_after(now, next))
285*4882a593Smuzhiyun 		timesortedlist_remove(sch, skb);
286*4882a593Smuzhiyun 	else
287*4882a593Smuzhiyun 		skb = NULL;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun out:
290*4882a593Smuzhiyun 	/* Now we may need to re-arm the qdisc watchdog for the next packet. */
291*4882a593Smuzhiyun 	reset_watchdog(sch);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	return skb;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
etf_disable_offload(struct net_device * dev,struct etf_sched_data * q)296*4882a593Smuzhiyun static void etf_disable_offload(struct net_device *dev,
297*4882a593Smuzhiyun 				struct etf_sched_data *q)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct tc_etf_qopt_offload etf = { };
300*4882a593Smuzhiyun 	const struct net_device_ops *ops;
301*4882a593Smuzhiyun 	int err;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (!q->offload)
304*4882a593Smuzhiyun 		return;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	ops = dev->netdev_ops;
307*4882a593Smuzhiyun 	if (!ops->ndo_setup_tc)
308*4882a593Smuzhiyun 		return;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	etf.queue = q->queue;
311*4882a593Smuzhiyun 	etf.enable = 0;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
314*4882a593Smuzhiyun 	if (err < 0)
315*4882a593Smuzhiyun 		pr_warn("Couldn't disable ETF offload for queue %d\n",
316*4882a593Smuzhiyun 			etf.queue);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
etf_enable_offload(struct net_device * dev,struct etf_sched_data * q,struct netlink_ext_ack * extack)319*4882a593Smuzhiyun static int etf_enable_offload(struct net_device *dev, struct etf_sched_data *q,
320*4882a593Smuzhiyun 			      struct netlink_ext_ack *extack)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	const struct net_device_ops *ops = dev->netdev_ops;
323*4882a593Smuzhiyun 	struct tc_etf_qopt_offload etf = { };
324*4882a593Smuzhiyun 	int err;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (q->offload)
327*4882a593Smuzhiyun 		return 0;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	if (!ops->ndo_setup_tc) {
330*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Specified device does not support ETF offload");
331*4882a593Smuzhiyun 		return -EOPNOTSUPP;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	etf.queue = q->queue;
335*4882a593Smuzhiyun 	etf.enable = 1;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_ETF, &etf);
338*4882a593Smuzhiyun 	if (err < 0) {
339*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Specified device failed to setup ETF hardware offload");
340*4882a593Smuzhiyun 		return err;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	return 0;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
etf_init(struct Qdisc * sch,struct nlattr * opt,struct netlink_ext_ack * extack)346*4882a593Smuzhiyun static int etf_init(struct Qdisc *sch, struct nlattr *opt,
347*4882a593Smuzhiyun 		    struct netlink_ext_ack *extack)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
350*4882a593Smuzhiyun 	struct net_device *dev = qdisc_dev(sch);
351*4882a593Smuzhiyun 	struct nlattr *tb[TCA_ETF_MAX + 1];
352*4882a593Smuzhiyun 	struct tc_etf_qopt *qopt;
353*4882a593Smuzhiyun 	int err;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (!opt) {
356*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
357*4882a593Smuzhiyun 			       "Missing ETF qdisc options which are mandatory");
358*4882a593Smuzhiyun 		return -EINVAL;
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	err = nla_parse_nested_deprecated(tb, TCA_ETF_MAX, opt, etf_policy,
362*4882a593Smuzhiyun 					  extack);
363*4882a593Smuzhiyun 	if (err < 0)
364*4882a593Smuzhiyun 		return err;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	if (!tb[TCA_ETF_PARMS]) {
367*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Missing mandatory ETF parameters");
368*4882a593Smuzhiyun 		return -EINVAL;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	qopt = nla_data(tb[TCA_ETF_PARMS]);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	pr_debug("delta %d clockid %d offload %s deadline %s\n",
374*4882a593Smuzhiyun 		 qopt->delta, qopt->clockid,
375*4882a593Smuzhiyun 		 OFFLOAD_IS_ON(qopt) ? "on" : "off",
376*4882a593Smuzhiyun 		 DEADLINE_MODE_IS_ON(qopt) ? "on" : "off");
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	err = validate_input_params(qopt, extack);
379*4882a593Smuzhiyun 	if (err < 0)
380*4882a593Smuzhiyun 		return err;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (OFFLOAD_IS_ON(qopt)) {
385*4882a593Smuzhiyun 		err = etf_enable_offload(dev, q, extack);
386*4882a593Smuzhiyun 		if (err < 0)
387*4882a593Smuzhiyun 			return err;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	/* Everything went OK, save the parameters used. */
391*4882a593Smuzhiyun 	q->delta = qopt->delta;
392*4882a593Smuzhiyun 	q->clockid = qopt->clockid;
393*4882a593Smuzhiyun 	q->offload = OFFLOAD_IS_ON(qopt);
394*4882a593Smuzhiyun 	q->deadline_mode = DEADLINE_MODE_IS_ON(qopt);
395*4882a593Smuzhiyun 	q->skip_sock_check = SKIP_SOCK_CHECK_IS_SET(qopt);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	switch (q->clockid) {
398*4882a593Smuzhiyun 	case CLOCK_REALTIME:
399*4882a593Smuzhiyun 		q->get_time = ktime_get_real;
400*4882a593Smuzhiyun 		break;
401*4882a593Smuzhiyun 	case CLOCK_MONOTONIC:
402*4882a593Smuzhiyun 		q->get_time = ktime_get;
403*4882a593Smuzhiyun 		break;
404*4882a593Smuzhiyun 	case CLOCK_BOOTTIME:
405*4882a593Smuzhiyun 		q->get_time = ktime_get_boottime;
406*4882a593Smuzhiyun 		break;
407*4882a593Smuzhiyun 	case CLOCK_TAI:
408*4882a593Smuzhiyun 		q->get_time = ktime_get_clocktai;
409*4882a593Smuzhiyun 		break;
410*4882a593Smuzhiyun 	default:
411*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Clockid is not supported");
412*4882a593Smuzhiyun 		return -ENOTSUPP;
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	qdisc_watchdog_init_clockid(&q->watchdog, sch, q->clockid);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
timesortedlist_clear(struct Qdisc * sch)420*4882a593Smuzhiyun static void timesortedlist_clear(struct Qdisc *sch)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
423*4882a593Smuzhiyun 	struct rb_node *p = rb_first_cached(&q->head);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	while (p) {
426*4882a593Smuzhiyun 		struct sk_buff *skb = rb_to_skb(p);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 		p = rb_next(p);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 		rb_erase_cached(&skb->rbnode, &q->head);
431*4882a593Smuzhiyun 		rtnl_kfree_skbs(skb, skb);
432*4882a593Smuzhiyun 		sch->q.qlen--;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
etf_reset(struct Qdisc * sch)436*4882a593Smuzhiyun static void etf_reset(struct Qdisc *sch)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/* Only cancel watchdog if it's been initialized. */
441*4882a593Smuzhiyun 	if (q->watchdog.qdisc == sch)
442*4882a593Smuzhiyun 		qdisc_watchdog_cancel(&q->watchdog);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	/* No matter which mode we are on, it's safe to clear both lists. */
445*4882a593Smuzhiyun 	timesortedlist_clear(sch);
446*4882a593Smuzhiyun 	__qdisc_reset_queue(&sch->q);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	q->last = 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
etf_destroy(struct Qdisc * sch)451*4882a593Smuzhiyun static void etf_destroy(struct Qdisc *sch)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
454*4882a593Smuzhiyun 	struct net_device *dev = qdisc_dev(sch);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	/* Only cancel watchdog if it's been initialized. */
457*4882a593Smuzhiyun 	if (q->watchdog.qdisc == sch)
458*4882a593Smuzhiyun 		qdisc_watchdog_cancel(&q->watchdog);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	etf_disable_offload(dev, q);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
etf_dump(struct Qdisc * sch,struct sk_buff * skb)463*4882a593Smuzhiyun static int etf_dump(struct Qdisc *sch, struct sk_buff *skb)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	struct etf_sched_data *q = qdisc_priv(sch);
466*4882a593Smuzhiyun 	struct tc_etf_qopt opt = { };
467*4882a593Smuzhiyun 	struct nlattr *nest;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
470*4882a593Smuzhiyun 	if (!nest)
471*4882a593Smuzhiyun 		goto nla_put_failure;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	opt.delta = q->delta;
474*4882a593Smuzhiyun 	opt.clockid = q->clockid;
475*4882a593Smuzhiyun 	if (q->offload)
476*4882a593Smuzhiyun 		opt.flags |= TC_ETF_OFFLOAD_ON;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	if (q->deadline_mode)
479*4882a593Smuzhiyun 		opt.flags |= TC_ETF_DEADLINE_MODE_ON;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (q->skip_sock_check)
482*4882a593Smuzhiyun 		opt.flags |= TC_ETF_SKIP_SOCK_CHECK;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (nla_put(skb, TCA_ETF_PARMS, sizeof(opt), &opt))
485*4882a593Smuzhiyun 		goto nla_put_failure;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	return nla_nest_end(skb, nest);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun nla_put_failure:
490*4882a593Smuzhiyun 	nla_nest_cancel(skb, nest);
491*4882a593Smuzhiyun 	return -1;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static struct Qdisc_ops etf_qdisc_ops __read_mostly = {
495*4882a593Smuzhiyun 	.id		=	"etf",
496*4882a593Smuzhiyun 	.priv_size	=	sizeof(struct etf_sched_data),
497*4882a593Smuzhiyun 	.enqueue	=	etf_enqueue_timesortedlist,
498*4882a593Smuzhiyun 	.dequeue	=	etf_dequeue_timesortedlist,
499*4882a593Smuzhiyun 	.peek		=	etf_peek_timesortedlist,
500*4882a593Smuzhiyun 	.init		=	etf_init,
501*4882a593Smuzhiyun 	.reset		=	etf_reset,
502*4882a593Smuzhiyun 	.destroy	=	etf_destroy,
503*4882a593Smuzhiyun 	.dump		=	etf_dump,
504*4882a593Smuzhiyun 	.owner		=	THIS_MODULE,
505*4882a593Smuzhiyun };
506*4882a593Smuzhiyun 
etf_module_init(void)507*4882a593Smuzhiyun static int __init etf_module_init(void)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	return register_qdisc(&etf_qdisc_ops);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun 
etf_module_exit(void)512*4882a593Smuzhiyun static void __exit etf_module_exit(void)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun 	unregister_qdisc(&etf_qdisc_ops);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun module_init(etf_module_init)
517*4882a593Smuzhiyun module_exit(etf_module_exit)
518*4882a593Smuzhiyun MODULE_LICENSE("GPL");
519