1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
21da177e4SLinus Torvalds #ifndef __NET_PKT_SCHED_H
31da177e4SLinus Torvalds #define __NET_PKT_SCHED_H
41da177e4SLinus Torvalds
5538e43a4SPatrick McHardy #include <linux/jiffies.h>
6641b9e0eSPatrick McHardy #include <linux/ktime.h>
7d8b9605dSJiri Pirko #include <linux/if_vlan.h>
8855319beSJiri Pirko #include <linux/netdevice.h>
91da177e4SLinus Torvalds #include <net/sch_generic.h>
10855319beSJiri Pirko #include <net/net_namespace.h>
11861932ecSJiri Pirko #include <uapi/linux/pkt_sched.h>
121da177e4SLinus Torvalds
13d0a81f67SJesper Dangaard Brouer #define DEFAULT_TX_QUEUE_LEN 1000
14b193e15aS王贇 #define STAB_SIZE_LOG_MAX 30
15d0a81f67SJesper Dangaard Brouer
16fd2c3ef7SEric Dumazet struct qdisc_walker {
171da177e4SLinus Torvalds int stop;
181da177e4SLinus Torvalds int skip;
191da177e4SLinus Torvalds int count;
201da177e4SLinus Torvalds int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
211da177e4SLinus Torvalds };
221da177e4SLinus Torvalds
qdisc_priv(struct Qdisc * q)231da177e4SLinus Torvalds static inline void *qdisc_priv(struct Qdisc *q)
241da177e4SLinus Torvalds {
25846e463aSEric Dumazet return &q->privdata;
261da177e4SLinus Torvalds }
271da177e4SLinus Torvalds
qdisc_from_priv(void * priv)286e1978a9SAllen Pais static inline struct Qdisc *qdisc_from_priv(void *priv)
296e1978a9SAllen Pais {
306e1978a9SAllen Pais return container_of(priv, struct Qdisc, privdata);
316e1978a9SAllen Pais }
326e1978a9SAllen Pais
331da177e4SLinus Torvalds /*
341da177e4SLinus Torvalds Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds Normal IP packet size ~ 512byte, hence:
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds 0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for
391da177e4SLinus Torvalds 10Mbit ethernet.
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds 10msec resolution -> <50Kbit/sec.
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds The result: [34]86 is not good choice for QoS router :-(
441da177e4SLinus Torvalds
4525985edcSLucas De Marchi The things are not so bad, because we may use artificial
461da177e4SLinus Torvalds clock evaluated by integration of network data flow
471da177e4SLinus Torvalds in the most critical places.
481da177e4SLinus Torvalds */
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds typedef u64 psched_time_t;
511da177e4SLinus Torvalds typedef long psched_tdiff_t;
521da177e4SLinus Torvalds
53a4a710c4SJarek Poplawski /* Avoid doing 64 bit divide */
54a4a710c4SJarek Poplawski #define PSCHED_SHIFT 6
55ca44d6e6SJarek Poplawski #define PSCHED_TICKS2NS(x) ((s64)(x) << PSCHED_SHIFT)
56ca44d6e6SJarek Poplawski #define PSCHED_NS2TICKS(x) ((x) >> PSCHED_SHIFT)
571da177e4SLinus Torvalds
58ca44d6e6SJarek Poplawski #define PSCHED_TICKS_PER_SEC PSCHED_NS2TICKS(NSEC_PER_SEC)
59a084980dSPatrick McHardy #define PSCHED_PASTPERFECT 0
601da177e4SLinus Torvalds
psched_get_time(void)613bebcda2SPatrick McHardy static inline psched_time_t psched_get_time(void)
623bebcda2SPatrick McHardy {
63d2de875cSEric Dumazet return PSCHED_NS2TICKS(ktime_get_ns());
643bebcda2SPatrick McHardy }
653bebcda2SPatrick McHardy
664179477fSPatrick McHardy struct qdisc_watchdog {
674179477fSPatrick McHardy struct hrtimer timer;
684179477fSPatrick McHardy struct Qdisc *qdisc;
694179477fSPatrick McHardy };
704179477fSPatrick McHardy
71860b642bSVinicius Costa Gomes void qdisc_watchdog_init_clockid(struct qdisc_watchdog *wd, struct Qdisc *qdisc,
72860b642bSVinicius Costa Gomes clockid_t clockid);
735c15257fSJoe Perches void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc);
74efe074c2SEric Dumazet
75efe074c2SEric Dumazet void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
76efe074c2SEric Dumazet u64 delta_ns);
77efe074c2SEric Dumazet
qdisc_watchdog_schedule_ns(struct qdisc_watchdog * wd,u64 expires)78efe074c2SEric Dumazet static inline void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd,
79efe074c2SEric Dumazet u64 expires)
80efe074c2SEric Dumazet {
81efe074c2SEric Dumazet return qdisc_watchdog_schedule_range_ns(wd, expires, 0ULL);
82efe074c2SEric Dumazet }
8334c5d292SJiri Pirko
qdisc_watchdog_schedule(struct qdisc_watchdog * wd,psched_time_t expires)8434c5d292SJiri Pirko static inline void qdisc_watchdog_schedule(struct qdisc_watchdog *wd,
8534c5d292SJiri Pirko psched_time_t expires)
8634c5d292SJiri Pirko {
8745f50bedSEric Dumazet qdisc_watchdog_schedule_ns(wd, PSCHED_TICKS2NS(expires));
8834c5d292SJiri Pirko }
8934c5d292SJiri Pirko
905c15257fSJoe Perches void qdisc_watchdog_cancel(struct qdisc_watchdog *wd);
914179477fSPatrick McHardy
921da177e4SLinus Torvalds extern struct Qdisc_ops pfifo_qdisc_ops;
931da177e4SLinus Torvalds extern struct Qdisc_ops bfifo_qdisc_ops;
9457dbb2d8SHagen Paul Pfeifer extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
951da177e4SLinus Torvalds
965c15257fSJoe Perches int fifo_set_limit(struct Qdisc *q, unsigned int limit);
975c15257fSJoe Perches struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
98a38a9882SAlexander Aring unsigned int limit,
99a38a9882SAlexander Aring struct netlink_ext_ack *extack);
100fb0305ceSPatrick McHardy
1015c15257fSJoe Perches int register_qdisc(struct Qdisc_ops *qops);
10252327d2eSZhengchao Shao void unregister_qdisc(struct Qdisc_ops *qops);
1036da7c8fcSstephen hemminger void qdisc_get_default(char *id, size_t len);
1046da7c8fcSstephen hemminger int qdisc_set_default(const char *id);
1056da7c8fcSstephen hemminger
10649b49971SJiri Kosina void qdisc_hash_add(struct Qdisc *q, bool invisible);
10759cc1f61SJiri Kosina void qdisc_hash_del(struct Qdisc *q);
1085c15257fSJoe Perches struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
1093a7d0d07SVlad Buslov struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle);
1105c15257fSJoe Perches struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
111e9bc3fa2SAlexander Aring struct nlattr *tab,
112e9bc3fa2SAlexander Aring struct netlink_ext_ack *extack);
1135c15257fSJoe Perches void qdisc_put_rtab(struct qdisc_rate_table *tab);
1145c15257fSJoe Perches void qdisc_put_stab(struct qdisc_size_table *tab);
1156e765a00SFlorian Westphal void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
11629b86cdaSJohn Fastabend bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
117bbd8a0d3SKrishna Kumar struct net_device *dev, struct netdev_queue *txq,
11855a93b3eSEric Dumazet spinlock_t *root_lock, bool validate);
1191da177e4SLinus Torvalds
1205c15257fSJoe Perches void __qdisc_run(struct Qdisc *q);
1211da177e4SLinus Torvalds
qdisc_run(struct Qdisc * q)12237437bb2SDavid S. Miller static inline void qdisc_run(struct Qdisc *q)
1231da177e4SLinus Torvalds {
1246c148184SJohn Fastabend if (qdisc_run_begin(q)) {
12537437bb2SDavid S. Miller __qdisc_run(q);
1266c148184SJohn Fastabend qdisc_run_end(q);
1276c148184SJohn Fastabend }
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds
130886bc7d6SEric Dumazet extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
131886bc7d6SEric Dumazet
1321da177e4SLinus Torvalds /* Calculate maximal size of packet seen by hard_start_xmit
1331da177e4SLinus Torvalds routine of this device.
1341da177e4SLinus Torvalds */
psched_mtu(const struct net_device * dev)13595c96174SEric Dumazet static inline unsigned int psched_mtu(const struct net_device *dev)
1361da177e4SLinus Torvalds {
137*150e33e6SPedro Tammela return READ_ONCE(dev->mtu) + dev->hard_header_len;
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds
qdisc_net(struct Qdisc * q)140855319beSJiri Pirko static inline struct net *qdisc_net(struct Qdisc *q)
141855319beSJiri Pirko {
142855319beSJiri Pirko return dev_net(q->dev_queue->dev);
143855319beSJiri Pirko }
144855319beSJiri Pirko
145aac4daa8SVladimir Oltean struct tc_query_caps_base {
146aac4daa8SVladimir Oltean enum tc_setup_type type;
147aac4daa8SVladimir Oltean void *caps;
148aac4daa8SVladimir Oltean };
149aac4daa8SVladimir Oltean
1503d0bd028SVinicius Costa Gomes struct tc_cbs_qopt_offload {
1513d0bd028SVinicius Costa Gomes u8 enable;
1523d0bd028SVinicius Costa Gomes s32 queue;
1533d0bd028SVinicius Costa Gomes s32 hicredit;
1543d0bd028SVinicius Costa Gomes s32 locredit;
1553d0bd028SVinicius Costa Gomes s32 idleslope;
1563d0bd028SVinicius Costa Gomes s32 sendslope;
1573d0bd028SVinicius Costa Gomes };
1583d0bd028SVinicius Costa Gomes
15988cab771SJesus Sanchez-Palencia struct tc_etf_qopt_offload {
16088cab771SJesus Sanchez-Palencia u8 enable;
16188cab771SJesus Sanchez-Palencia s32 queue;
16288cab771SJesus Sanchez-Palencia };
16388cab771SJesus Sanchez-Palencia
16419278d76SVladimir Oltean struct tc_mqprio_caps {
16519278d76SVladimir Oltean bool validate_queue_counts:1;
16619278d76SVladimir Oltean };
16719278d76SVladimir Oltean
1689adafe2bSVladimir Oltean struct tc_mqprio_qopt_offload {
1699adafe2bSVladimir Oltean /* struct tc_mqprio_qopt must always be the first element */
1709adafe2bSVladimir Oltean struct tc_mqprio_qopt qopt;
171c54876cdSVladimir Oltean struct netlink_ext_ack *extack;
1729adafe2bSVladimir Oltean u16 mode;
1739adafe2bSVladimir Oltean u16 shaper;
1749adafe2bSVladimir Oltean u32 flags;
1759adafe2bSVladimir Oltean u64 min_rate[TC_QOPT_MAX_QUEUE];
1769adafe2bSVladimir Oltean u64 max_rate[TC_QOPT_MAX_QUEUE];
177f62af20bSVladimir Oltean unsigned long preemptible_tcs;
1789adafe2bSVladimir Oltean };
1799adafe2bSVladimir Oltean
180a54fc09eSVladimir Oltean struct tc_taprio_caps {
181a54fc09eSVladimir Oltean bool supports_queue_max_sdu:1;
182522d15eaSVladimir Oltean bool gate_mask_per_txq:1;
1832f530df7SVladimir Oltean /* Device expects lower TXQ numbers to have higher priority over higher
1842f530df7SVladimir Oltean * TXQs, regardless of their TC mapping. DO NOT USE FOR NEW DRIVERS,
1852f530df7SVladimir Oltean * INSTEAD ENFORCE A PROPER TC:TXQ MAPPING COMING FROM USER SPACE.
1862f530df7SVladimir Oltean */
1872f530df7SVladimir Oltean bool broken_mqprio:1;
188a54fc09eSVladimir Oltean };
189a54fc09eSVladimir Oltean
1902d800bc5SVladimir Oltean enum tc_taprio_qopt_cmd {
1912d800bc5SVladimir Oltean TAPRIO_CMD_REPLACE,
1922d800bc5SVladimir Oltean TAPRIO_CMD_DESTROY,
1936c1adb65SVladimir Oltean TAPRIO_CMD_STATS,
1942b84960fSVladimir Oltean TAPRIO_CMD_QUEUE_STATS,
1956c1adb65SVladimir Oltean };
1966c1adb65SVladimir Oltean
1976c1adb65SVladimir Oltean /**
1986c1adb65SVladimir Oltean * struct tc_taprio_qopt_stats - IEEE 802.1Qbv statistics
1996c1adb65SVladimir Oltean * @window_drops: Frames that were dropped because they were too large to be
2006c1adb65SVladimir Oltean * transmitted in any of the allotted time windows (open gates) for their
2016c1adb65SVladimir Oltean * traffic class.
2026c1adb65SVladimir Oltean * @tx_overruns: Frames still being transmitted by the MAC after the
2036c1adb65SVladimir Oltean * transmission gate associated with their traffic class has closed.
2046c1adb65SVladimir Oltean * Equivalent to `12.29.1.1.2 TransmissionOverrun` from 802.1Q-2018.
2056c1adb65SVladimir Oltean */
2066c1adb65SVladimir Oltean struct tc_taprio_qopt_stats {
2076c1adb65SVladimir Oltean u64 window_drops;
2086c1adb65SVladimir Oltean u64 tx_overruns;
2096c1adb65SVladimir Oltean };
2106c1adb65SVladimir Oltean
2112b84960fSVladimir Oltean struct tc_taprio_qopt_queue_stats {
2122b84960fSVladimir Oltean int queue;
2136c1adb65SVladimir Oltean struct tc_taprio_qopt_stats stats;
2142d800bc5SVladimir Oltean };
2152d800bc5SVladimir Oltean
2169c66d156SVinicius Costa Gomes struct tc_taprio_sched_entry {
2179c66d156SVinicius Costa Gomes u8 command; /* TC_TAPRIO_CMD_* */
2189c66d156SVinicius Costa Gomes
2199c66d156SVinicius Costa Gomes /* The gate_mask in the offloading side refers to traffic classes */
2209c66d156SVinicius Costa Gomes u32 gate_mask;
2219c66d156SVinicius Costa Gomes u32 interval;
2229c66d156SVinicius Costa Gomes };
2239c66d156SVinicius Costa Gomes
2249c66d156SVinicius Costa Gomes struct tc_taprio_qopt_offload {
2256c1adb65SVladimir Oltean enum tc_taprio_qopt_cmd cmd;
2266c1adb65SVladimir Oltean
2276c1adb65SVladimir Oltean union {
2286c1adb65SVladimir Oltean /* TAPRIO_CMD_STATS */
2296c1adb65SVladimir Oltean struct tc_taprio_qopt_stats stats;
2302b84960fSVladimir Oltean /* TAPRIO_CMD_QUEUE_STATS */
2312b84960fSVladimir Oltean struct tc_taprio_qopt_queue_stats queue_stats;
2326c1adb65SVladimir Oltean /* TAPRIO_CMD_REPLACE */
2336c1adb65SVladimir Oltean struct {
23409c794c0SVladimir Oltean struct tc_mqprio_qopt_offload mqprio;
235c54876cdSVladimir Oltean struct netlink_ext_ack *extack;
2369c66d156SVinicius Costa Gomes ktime_t base_time;
2379c66d156SVinicius Costa Gomes u64 cycle_time;
2389c66d156SVinicius Costa Gomes u64 cycle_time_extension;
239a54fc09eSVladimir Oltean u32 max_sdu[TC_MAX_QUEUE];
2409c66d156SVinicius Costa Gomes
2419c66d156SVinicius Costa Gomes size_t num_entries;
242b90feaffSGustavo A. R. Silva struct tc_taprio_sched_entry entries[];
2439c66d156SVinicius Costa Gomes };
2446c1adb65SVladimir Oltean };
2456c1adb65SVladimir Oltean };
2469c66d156SVinicius Costa Gomes
247d7be266aSVladimir Oltean #if IS_ENABLED(CONFIG_NET_SCH_TAPRIO)
248d7be266aSVladimir Oltean
2499c66d156SVinicius Costa Gomes /* Reference counting */
2509c66d156SVinicius Costa Gomes struct tc_taprio_qopt_offload *taprio_offload_get(struct tc_taprio_qopt_offload
2519c66d156SVinicius Costa Gomes *offload);
2529c66d156SVinicius Costa Gomes void taprio_offload_free(struct tc_taprio_qopt_offload *offload);
2539c66d156SVinicius Costa Gomes
254d7be266aSVladimir Oltean #else
255d7be266aSVladimir Oltean
256d7be266aSVladimir Oltean /* Reference counting */
257d7be266aSVladimir Oltean static inline struct tc_taprio_qopt_offload *
taprio_offload_get(struct tc_taprio_qopt_offload * offload)258d7be266aSVladimir Oltean taprio_offload_get(struct tc_taprio_qopt_offload *offload)
259d7be266aSVladimir Oltean {
260d7be266aSVladimir Oltean return NULL;
261d7be266aSVladimir Oltean }
262d7be266aSVladimir Oltean
taprio_offload_free(struct tc_taprio_qopt_offload * offload)263d7be266aSVladimir Oltean static inline void taprio_offload_free(struct tc_taprio_qopt_offload *offload)
264d7be266aSVladimir Oltean {
265d7be266aSVladimir Oltean }
266d7be266aSVladimir Oltean
267d7be266aSVladimir Oltean #endif
268d7be266aSVladimir Oltean
269847cbfc0SVladimir Oltean /* Ensure skb_mstamp_ns, which might have been populated with the txtime, is
270847cbfc0SVladimir Oltean * not mistaken for a software timestamp, because this will otherwise prevent
271847cbfc0SVladimir Oltean * the dispatch of hardware timestamps to the socket.
272847cbfc0SVladimir Oltean */
skb_txtime_consumed(struct sk_buff * skb)273847cbfc0SVladimir Oltean static inline void skb_txtime_consumed(struct sk_buff *skb)
274847cbfc0SVladimir Oltean {
275847cbfc0SVladimir Oltean skb->tstamp = ktime_set(0, 0);
276847cbfc0SVladimir Oltean }
277847cbfc0SVladimir Oltean
278ec624fe7SPaul Blakey struct tc_skb_cb {
279ec624fe7SPaul Blakey struct qdisc_skb_cb qdisc_cb;
280ec624fe7SPaul Blakey
281ec624fe7SPaul Blakey u16 mru;
2826f022c2dSPaul Blakey u8 post_ct:1;
2836f022c2dSPaul Blakey u8 post_ct_snat:1;
2846f022c2dSPaul Blakey u8 post_ct_dnat:1;
28538495958SPaul Blakey u16 zone; /* Only valid if post_ct = true */
286ec624fe7SPaul Blakey };
287ec624fe7SPaul Blakey
tc_skb_cb(const struct sk_buff * skb)288ec624fe7SPaul Blakey static inline struct tc_skb_cb *tc_skb_cb(const struct sk_buff *skb)
289ec624fe7SPaul Blakey {
290ec624fe7SPaul Blakey struct tc_skb_cb *cb = (struct tc_skb_cb *)skb->cb;
291ec624fe7SPaul Blakey
292ec624fe7SPaul Blakey BUILD_BUG_ON(sizeof(*cb) > sizeof_field(struct sk_buff, cb));
293ec624fe7SPaul Blakey return cb;
294ec624fe7SPaul Blakey }
295ec624fe7SPaul Blakey
tc_qdisc_stats_dump(struct Qdisc * sch,unsigned long cl,struct qdisc_walker * arg)296d7a68e56SZhengchao Shao static inline bool tc_qdisc_stats_dump(struct Qdisc *sch,
297d7a68e56SZhengchao Shao unsigned long cl,
298d7a68e56SZhengchao Shao struct qdisc_walker *arg)
299d7a68e56SZhengchao Shao {
300d7a68e56SZhengchao Shao if (arg->count >= arg->skip && arg->fn(sch, cl, arg) < 0) {
301d7a68e56SZhengchao Shao arg->stop = 1;
302d7a68e56SZhengchao Shao return false;
303d7a68e56SZhengchao Shao }
304d7a68e56SZhengchao Shao
305d7a68e56SZhengchao Shao arg->count++;
306d7a68e56SZhengchao Shao return true;
307d7a68e56SZhengchao Shao }
308d7a68e56SZhengchao Shao
3091da177e4SLinus Torvalds #endif
310