18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* COMMON Applications Kept Enhanced (CAKE) discipline 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2018 Jonathan Morton <chromatix99@gmail.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Toke Høiland-Jørgensen <toke@toke.dk> 78c2ecf20Sopenharmony_ci * Copyright (C) 2014-2018 Dave Täht <dave.taht@gmail.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Sebastian Moeller <moeller0@gmx.de> 98c2ecf20Sopenharmony_ci * (C) 2015-2018 Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk> 108c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Ryan Mounce <ryan@mounce.com.au> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * The CAKE Principles: 138c2ecf20Sopenharmony_ci * (or, how to have your cake and eat it too) 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This is a combination of several shaping, AQM and FQ techniques into one 168c2ecf20Sopenharmony_ci * easy-to-use package: 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - An overall bandwidth shaper, to move the bottleneck away from dumb CPE 198c2ecf20Sopenharmony_ci * equipment and bloated MACs. This operates in deficit mode (as in sch_fq), 208c2ecf20Sopenharmony_ci * eliminating the need for any sort of burst parameter (eg. token bucket 218c2ecf20Sopenharmony_ci * depth). Burst support is limited to that necessary to overcome scheduling 228c2ecf20Sopenharmony_ci * latency. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * - A Diffserv-aware priority queue, giving more priority to certain classes, 258c2ecf20Sopenharmony_ci * up to a specified fraction of bandwidth. Above that bandwidth threshold, 268c2ecf20Sopenharmony_ci * the priority is reduced to avoid starving other tins. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * - Each priority tin has a separate Flow Queue system, to isolate traffic 298c2ecf20Sopenharmony_ci * flows from each other. This prevents a burst on one flow from increasing 308c2ecf20Sopenharmony_ci * the delay to another. Flows are distributed to queues using a 318c2ecf20Sopenharmony_ci * set-associative hash function. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * - Each queue is actively managed by Cobalt, which is a combination of the 348c2ecf20Sopenharmony_ci * Codel and Blue AQM algorithms. This serves flows fairly, and signals 358c2ecf20Sopenharmony_ci * congestion early via ECN (if available) and/or packet drops, to keep 368c2ecf20Sopenharmony_ci * latency low. The codel parameters are auto-tuned based on the bandwidth 378c2ecf20Sopenharmony_ci * setting, as is necessary at low bandwidths. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * The configuration parameters are kept deliberately simple for ease of use. 408c2ecf20Sopenharmony_ci * Everything has sane defaults. Complete generality of configuration is *not* 418c2ecf20Sopenharmony_ci * a goal. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * The priority queue operates according to a weighted DRR scheme, combined with 448c2ecf20Sopenharmony_ci * a bandwidth tracker which reuses the shaper logic to detect which side of the 458c2ecf20Sopenharmony_ci * bandwidth sharing threshold the tin is operating. This determines whether a 468c2ecf20Sopenharmony_ci * priority-based weight (high) or a bandwidth-based weight (low) is used for 478c2ecf20Sopenharmony_ci * that tin in the current pass. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * This qdisc was inspired by Eric Dumazet's fq_codel code, which he kindly 508c2ecf20Sopenharmony_ci * granted us permission to leverage. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <linux/module.h> 548c2ecf20Sopenharmony_ci#include <linux/types.h> 558c2ecf20Sopenharmony_ci#include <linux/kernel.h> 568c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 578c2ecf20Sopenharmony_ci#include <linux/string.h> 588c2ecf20Sopenharmony_ci#include <linux/in.h> 598c2ecf20Sopenharmony_ci#include <linux/errno.h> 608c2ecf20Sopenharmony_ci#include <linux/init.h> 618c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 628c2ecf20Sopenharmony_ci#include <linux/jhash.h> 638c2ecf20Sopenharmony_ci#include <linux/slab.h> 648c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 658c2ecf20Sopenharmony_ci#include <linux/reciprocal_div.h> 668c2ecf20Sopenharmony_ci#include <net/netlink.h> 678c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 688c2ecf20Sopenharmony_ci#include <net/pkt_sched.h> 698c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 708c2ecf20Sopenharmony_ci#include <net/tcp.h> 718c2ecf20Sopenharmony_ci#include <net/flow_dissector.h> 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_CONNTRACK) 748c2ecf20Sopenharmony_ci#include <net/netfilter/nf_conntrack_core.h> 758c2ecf20Sopenharmony_ci#endif 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define CAKE_SET_WAYS (8) 788c2ecf20Sopenharmony_ci#define CAKE_MAX_TINS (8) 798c2ecf20Sopenharmony_ci#define CAKE_QUEUES (1024) 808c2ecf20Sopenharmony_ci#define CAKE_FLOW_MASK 63 818c2ecf20Sopenharmony_ci#define CAKE_FLOW_NAT_FLAG 64 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* struct cobalt_params - contains codel and blue parameters 848c2ecf20Sopenharmony_ci * @interval: codel initial drop rate 858c2ecf20Sopenharmony_ci * @target: maximum persistent sojourn time & blue update rate 868c2ecf20Sopenharmony_ci * @mtu_time: serialisation delay of maximum-size packet 878c2ecf20Sopenharmony_ci * @p_inc: increment of blue drop probability (0.32 fxp) 888c2ecf20Sopenharmony_ci * @p_dec: decrement of blue drop probability (0.32 fxp) 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistruct cobalt_params { 918c2ecf20Sopenharmony_ci u64 interval; 928c2ecf20Sopenharmony_ci u64 target; 938c2ecf20Sopenharmony_ci u64 mtu_time; 948c2ecf20Sopenharmony_ci u32 p_inc; 958c2ecf20Sopenharmony_ci u32 p_dec; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* struct cobalt_vars - contains codel and blue variables 998c2ecf20Sopenharmony_ci * @count: codel dropping frequency 1008c2ecf20Sopenharmony_ci * @rec_inv_sqrt: reciprocal value of sqrt(count) >> 1 1018c2ecf20Sopenharmony_ci * @drop_next: time to drop next packet, or when we dropped last 1028c2ecf20Sopenharmony_ci * @blue_timer: Blue time to next drop 1038c2ecf20Sopenharmony_ci * @p_drop: BLUE drop probability (0.32 fxp) 1048c2ecf20Sopenharmony_ci * @dropping: set if in dropping state 1058c2ecf20Sopenharmony_ci * @ecn_marked: set if marked 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistruct cobalt_vars { 1088c2ecf20Sopenharmony_ci u32 count; 1098c2ecf20Sopenharmony_ci u32 rec_inv_sqrt; 1108c2ecf20Sopenharmony_ci ktime_t drop_next; 1118c2ecf20Sopenharmony_ci ktime_t blue_timer; 1128c2ecf20Sopenharmony_ci u32 p_drop; 1138c2ecf20Sopenharmony_ci bool dropping; 1148c2ecf20Sopenharmony_ci bool ecn_marked; 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cienum { 1188c2ecf20Sopenharmony_ci CAKE_SET_NONE = 0, 1198c2ecf20Sopenharmony_ci CAKE_SET_SPARSE, 1208c2ecf20Sopenharmony_ci CAKE_SET_SPARSE_WAIT, /* counted in SPARSE, actually in BULK */ 1218c2ecf20Sopenharmony_ci CAKE_SET_BULK, 1228c2ecf20Sopenharmony_ci CAKE_SET_DECAYING 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistruct cake_flow { 1268c2ecf20Sopenharmony_ci /* this stuff is all needed per-flow at dequeue time */ 1278c2ecf20Sopenharmony_ci struct sk_buff *head; 1288c2ecf20Sopenharmony_ci struct sk_buff *tail; 1298c2ecf20Sopenharmony_ci struct list_head flowchain; 1308c2ecf20Sopenharmony_ci s32 deficit; 1318c2ecf20Sopenharmony_ci u32 dropped; 1328c2ecf20Sopenharmony_ci struct cobalt_vars cvars; 1338c2ecf20Sopenharmony_ci u16 srchost; /* index into cake_host table */ 1348c2ecf20Sopenharmony_ci u16 dsthost; 1358c2ecf20Sopenharmony_ci u8 set; 1368c2ecf20Sopenharmony_ci}; /* please try to keep this structure <= 64 bytes */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistruct cake_host { 1398c2ecf20Sopenharmony_ci u32 srchost_tag; 1408c2ecf20Sopenharmony_ci u32 dsthost_tag; 1418c2ecf20Sopenharmony_ci u16 srchost_bulk_flow_count; 1428c2ecf20Sopenharmony_ci u16 dsthost_bulk_flow_count; 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistruct cake_heap_entry { 1468c2ecf20Sopenharmony_ci u16 t:3, b:10; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistruct cake_tin_data { 1508c2ecf20Sopenharmony_ci struct cake_flow flows[CAKE_QUEUES]; 1518c2ecf20Sopenharmony_ci u32 backlogs[CAKE_QUEUES]; 1528c2ecf20Sopenharmony_ci u32 tags[CAKE_QUEUES]; /* for set association */ 1538c2ecf20Sopenharmony_ci u16 overflow_idx[CAKE_QUEUES]; 1548c2ecf20Sopenharmony_ci struct cake_host hosts[CAKE_QUEUES]; /* for triple isolation */ 1558c2ecf20Sopenharmony_ci u16 flow_quantum; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci struct cobalt_params cparams; 1588c2ecf20Sopenharmony_ci u32 drop_overlimit; 1598c2ecf20Sopenharmony_ci u16 bulk_flow_count; 1608c2ecf20Sopenharmony_ci u16 sparse_flow_count; 1618c2ecf20Sopenharmony_ci u16 decaying_flow_count; 1628c2ecf20Sopenharmony_ci u16 unresponsive_flow_count; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci u32 max_skblen; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci struct list_head new_flows; 1678c2ecf20Sopenharmony_ci struct list_head old_flows; 1688c2ecf20Sopenharmony_ci struct list_head decaying_flows; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* time_next = time_this + ((len * rate_ns) >> rate_shft) */ 1718c2ecf20Sopenharmony_ci ktime_t time_next_packet; 1728c2ecf20Sopenharmony_ci u64 tin_rate_ns; 1738c2ecf20Sopenharmony_ci u64 tin_rate_bps; 1748c2ecf20Sopenharmony_ci u16 tin_rate_shft; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci u16 tin_quantum; 1778c2ecf20Sopenharmony_ci s32 tin_deficit; 1788c2ecf20Sopenharmony_ci u32 tin_backlog; 1798c2ecf20Sopenharmony_ci u32 tin_dropped; 1808c2ecf20Sopenharmony_ci u32 tin_ecn_mark; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci u32 packets; 1838c2ecf20Sopenharmony_ci u64 bytes; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci u32 ack_drops; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* moving averages */ 1888c2ecf20Sopenharmony_ci u64 avge_delay; 1898c2ecf20Sopenharmony_ci u64 peak_delay; 1908c2ecf20Sopenharmony_ci u64 base_delay; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* hash function stats */ 1938c2ecf20Sopenharmony_ci u32 way_directs; 1948c2ecf20Sopenharmony_ci u32 way_hits; 1958c2ecf20Sopenharmony_ci u32 way_misses; 1968c2ecf20Sopenharmony_ci u32 way_collisions; 1978c2ecf20Sopenharmony_ci}; /* number of tins is small, so size of this struct doesn't matter much */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistruct cake_sched_data { 2008c2ecf20Sopenharmony_ci struct tcf_proto __rcu *filter_list; /* optional external classifier */ 2018c2ecf20Sopenharmony_ci struct tcf_block *block; 2028c2ecf20Sopenharmony_ci struct cake_tin_data *tins; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci struct cake_heap_entry overflow_heap[CAKE_QUEUES * CAKE_MAX_TINS]; 2058c2ecf20Sopenharmony_ci u16 overflow_timeout; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci u16 tin_cnt; 2088c2ecf20Sopenharmony_ci u8 tin_mode; 2098c2ecf20Sopenharmony_ci u8 flow_mode; 2108c2ecf20Sopenharmony_ci u8 ack_filter; 2118c2ecf20Sopenharmony_ci u8 atm_mode; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci u32 fwmark_mask; 2148c2ecf20Sopenharmony_ci u16 fwmark_shft; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* time_next = time_this + ((len * rate_ns) >> rate_shft) */ 2178c2ecf20Sopenharmony_ci u16 rate_shft; 2188c2ecf20Sopenharmony_ci ktime_t time_next_packet; 2198c2ecf20Sopenharmony_ci ktime_t failsafe_next_packet; 2208c2ecf20Sopenharmony_ci u64 rate_ns; 2218c2ecf20Sopenharmony_ci u64 rate_bps; 2228c2ecf20Sopenharmony_ci u16 rate_flags; 2238c2ecf20Sopenharmony_ci s16 rate_overhead; 2248c2ecf20Sopenharmony_ci u16 rate_mpu; 2258c2ecf20Sopenharmony_ci u64 interval; 2268c2ecf20Sopenharmony_ci u64 target; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* resource tracking */ 2298c2ecf20Sopenharmony_ci u32 buffer_used; 2308c2ecf20Sopenharmony_ci u32 buffer_max_used; 2318c2ecf20Sopenharmony_ci u32 buffer_limit; 2328c2ecf20Sopenharmony_ci u32 buffer_config_limit; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* indices for dequeue */ 2358c2ecf20Sopenharmony_ci u16 cur_tin; 2368c2ecf20Sopenharmony_ci u16 cur_flow; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci struct qdisc_watchdog watchdog; 2398c2ecf20Sopenharmony_ci const u8 *tin_index; 2408c2ecf20Sopenharmony_ci const u8 *tin_order; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* bandwidth capacity estimate */ 2438c2ecf20Sopenharmony_ci ktime_t last_packet_time; 2448c2ecf20Sopenharmony_ci ktime_t avg_window_begin; 2458c2ecf20Sopenharmony_ci u64 avg_packet_interval; 2468c2ecf20Sopenharmony_ci u64 avg_window_bytes; 2478c2ecf20Sopenharmony_ci u64 avg_peak_bandwidth; 2488c2ecf20Sopenharmony_ci ktime_t last_reconfig_time; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* packet length stats */ 2518c2ecf20Sopenharmony_ci u32 avg_netoff; 2528c2ecf20Sopenharmony_ci u16 max_netlen; 2538c2ecf20Sopenharmony_ci u16 max_adjlen; 2548c2ecf20Sopenharmony_ci u16 min_netlen; 2558c2ecf20Sopenharmony_ci u16 min_adjlen; 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cienum { 2598c2ecf20Sopenharmony_ci CAKE_FLAG_OVERHEAD = BIT(0), 2608c2ecf20Sopenharmony_ci CAKE_FLAG_AUTORATE_INGRESS = BIT(1), 2618c2ecf20Sopenharmony_ci CAKE_FLAG_INGRESS = BIT(2), 2628c2ecf20Sopenharmony_ci CAKE_FLAG_WASH = BIT(3), 2638c2ecf20Sopenharmony_ci CAKE_FLAG_SPLIT_GSO = BIT(4) 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* COBALT operates the Codel and BLUE algorithms in parallel, in order to 2678c2ecf20Sopenharmony_ci * obtain the best features of each. Codel is excellent on flows which 2688c2ecf20Sopenharmony_ci * respond to congestion signals in a TCP-like way. BLUE is more effective on 2698c2ecf20Sopenharmony_ci * unresponsive flows. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistruct cobalt_skb_cb { 2738c2ecf20Sopenharmony_ci ktime_t enqueue_time; 2748c2ecf20Sopenharmony_ci u32 adjusted_len; 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic u64 us_to_ns(u64 us) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return us * NSEC_PER_USEC; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic struct cobalt_skb_cb *get_cobalt_cb(const struct sk_buff *skb) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci qdisc_cb_private_validate(skb, sizeof(struct cobalt_skb_cb)); 2858c2ecf20Sopenharmony_ci return (struct cobalt_skb_cb *)qdisc_skb_cb(skb)->data; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic ktime_t cobalt_get_enqueue_time(const struct sk_buff *skb) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci return get_cobalt_cb(skb)->enqueue_time; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void cobalt_set_enqueue_time(struct sk_buff *skb, 2948c2ecf20Sopenharmony_ci ktime_t now) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci get_cobalt_cb(skb)->enqueue_time = now; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic u16 quantum_div[CAKE_QUEUES + 1] = {0}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* Diffserv lookup tables */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const u8 precedence[] = { 3048c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3058c2ecf20Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 3068c2ecf20Sopenharmony_ci 2, 2, 2, 2, 2, 2, 2, 2, 3078c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3088c2ecf20Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 3098c2ecf20Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 3108c2ecf20Sopenharmony_ci 6, 6, 6, 6, 6, 6, 6, 6, 3118c2ecf20Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 3128c2ecf20Sopenharmony_ci}; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic const u8 diffserv8[] = { 3158c2ecf20Sopenharmony_ci 2, 0, 1, 2, 4, 2, 2, 2, 3168c2ecf20Sopenharmony_ci 1, 2, 1, 2, 1, 2, 1, 2, 3178c2ecf20Sopenharmony_ci 5, 2, 4, 2, 4, 2, 4, 2, 3188c2ecf20Sopenharmony_ci 3, 2, 3, 2, 3, 2, 3, 2, 3198c2ecf20Sopenharmony_ci 6, 2, 3, 2, 3, 2, 3, 2, 3208c2ecf20Sopenharmony_ci 6, 2, 2, 2, 6, 2, 6, 2, 3218c2ecf20Sopenharmony_ci 7, 2, 2, 2, 2, 2, 2, 2, 3228c2ecf20Sopenharmony_ci 7, 2, 2, 2, 2, 2, 2, 2, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic const u8 diffserv4[] = { 3268c2ecf20Sopenharmony_ci 0, 1, 0, 0, 2, 0, 0, 0, 3278c2ecf20Sopenharmony_ci 1, 0, 0, 0, 0, 0, 0, 0, 3288c2ecf20Sopenharmony_ci 2, 0, 2, 0, 2, 0, 2, 0, 3298c2ecf20Sopenharmony_ci 2, 0, 2, 0, 2, 0, 2, 0, 3308c2ecf20Sopenharmony_ci 3, 0, 2, 0, 2, 0, 2, 0, 3318c2ecf20Sopenharmony_ci 3, 0, 0, 0, 3, 0, 3, 0, 3328c2ecf20Sopenharmony_ci 3, 0, 0, 0, 0, 0, 0, 0, 3338c2ecf20Sopenharmony_ci 3, 0, 0, 0, 0, 0, 0, 0, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const u8 diffserv3[] = { 3378c2ecf20Sopenharmony_ci 0, 1, 0, 0, 2, 0, 0, 0, 3388c2ecf20Sopenharmony_ci 1, 0, 0, 0, 0, 0, 0, 0, 3398c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3408c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3418c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3428c2ecf20Sopenharmony_ci 0, 0, 0, 0, 2, 0, 2, 0, 3438c2ecf20Sopenharmony_ci 2, 0, 0, 0, 0, 0, 0, 0, 3448c2ecf20Sopenharmony_ci 2, 0, 0, 0, 0, 0, 0, 0, 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const u8 besteffort[] = { 3488c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3498c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3508c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3518c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3528c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3538c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3548c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3558c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* tin priority order for stats dumping */ 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic const u8 normal_order[] = {0, 1, 2, 3, 4, 5, 6, 7}; 3618c2ecf20Sopenharmony_cistatic const u8 bulk_order[] = {1, 0, 2, 3}; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci#define REC_INV_SQRT_CACHE (16) 3648c2ecf20Sopenharmony_cistatic u32 cobalt_rec_inv_sqrt_cache[REC_INV_SQRT_CACHE] = {0}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* http://en.wikipedia.org/wiki/Methods_of_computing_square_roots 3678c2ecf20Sopenharmony_ci * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2) 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic void cobalt_newton_step(struct cobalt_vars *vars) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci u32 invsqrt, invsqrt2; 3758c2ecf20Sopenharmony_ci u64 val; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci invsqrt = vars->rec_inv_sqrt; 3788c2ecf20Sopenharmony_ci invsqrt2 = ((u64)invsqrt * invsqrt) >> 32; 3798c2ecf20Sopenharmony_ci val = (3LL << 32) - ((u64)vars->count * invsqrt2); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci val >>= 2; /* avoid overflow in following multiply */ 3828c2ecf20Sopenharmony_ci val = (val * invsqrt) >> (32 - 2 + 1); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci vars->rec_inv_sqrt = val; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void cobalt_invsqrt(struct cobalt_vars *vars) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (vars->count < REC_INV_SQRT_CACHE) 3908c2ecf20Sopenharmony_ci vars->rec_inv_sqrt = cobalt_rec_inv_sqrt_cache[vars->count]; 3918c2ecf20Sopenharmony_ci else 3928c2ecf20Sopenharmony_ci cobalt_newton_step(vars); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* There is a big difference in timing between the accurate values placed in 3968c2ecf20Sopenharmony_ci * the cache and the approximations given by a single Newton step for small 3978c2ecf20Sopenharmony_ci * count values, particularly when stepping from count 1 to 2 or vice versa. 3988c2ecf20Sopenharmony_ci * Above 16, a single Newton step gives sufficient accuracy in either 3998c2ecf20Sopenharmony_ci * direction, given the precision stored. 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * The magnitude of the error when stepping up to count 2 is such as to give 4028c2ecf20Sopenharmony_ci * the value that *should* have been produced at count 4. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void cobalt_cache_init(void) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct cobalt_vars v; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci memset(&v, 0, sizeof(v)); 4108c2ecf20Sopenharmony_ci v.rec_inv_sqrt = ~0U; 4118c2ecf20Sopenharmony_ci cobalt_rec_inv_sqrt_cache[0] = v.rec_inv_sqrt; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci for (v.count = 1; v.count < REC_INV_SQRT_CACHE; v.count++) { 4148c2ecf20Sopenharmony_ci cobalt_newton_step(&v); 4158c2ecf20Sopenharmony_ci cobalt_newton_step(&v); 4168c2ecf20Sopenharmony_ci cobalt_newton_step(&v); 4178c2ecf20Sopenharmony_ci cobalt_newton_step(&v); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci cobalt_rec_inv_sqrt_cache[v.count] = v.rec_inv_sqrt; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void cobalt_vars_init(struct cobalt_vars *vars) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci memset(vars, 0, sizeof(*vars)); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (!cobalt_rec_inv_sqrt_cache[0]) { 4288c2ecf20Sopenharmony_ci cobalt_cache_init(); 4298c2ecf20Sopenharmony_ci cobalt_rec_inv_sqrt_cache[0] = ~0; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci/* CoDel control_law is t + interval/sqrt(count) 4348c2ecf20Sopenharmony_ci * We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid 4358c2ecf20Sopenharmony_ci * both sqrt() and divide operation. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_cistatic ktime_t cobalt_control(ktime_t t, 4388c2ecf20Sopenharmony_ci u64 interval, 4398c2ecf20Sopenharmony_ci u32 rec_inv_sqrt) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci return ktime_add_ns(t, reciprocal_scale(interval, 4428c2ecf20Sopenharmony_ci rec_inv_sqrt)); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci/* Call this when a packet had to be dropped due to queue overflow. Returns 4468c2ecf20Sopenharmony_ci * true if the BLUE state was quiescent before but active after this call. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistatic bool cobalt_queue_full(struct cobalt_vars *vars, 4498c2ecf20Sopenharmony_ci struct cobalt_params *p, 4508c2ecf20Sopenharmony_ci ktime_t now) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci bool up = false; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (ktime_to_ns(ktime_sub(now, vars->blue_timer)) > p->target) { 4558c2ecf20Sopenharmony_ci up = !vars->p_drop; 4568c2ecf20Sopenharmony_ci vars->p_drop += p->p_inc; 4578c2ecf20Sopenharmony_ci if (vars->p_drop < p->p_inc) 4588c2ecf20Sopenharmony_ci vars->p_drop = ~0; 4598c2ecf20Sopenharmony_ci vars->blue_timer = now; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci vars->dropping = true; 4628c2ecf20Sopenharmony_ci vars->drop_next = now; 4638c2ecf20Sopenharmony_ci if (!vars->count) 4648c2ecf20Sopenharmony_ci vars->count = 1; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return up; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/* Call this when the queue was serviced but turned out to be empty. Returns 4708c2ecf20Sopenharmony_ci * true if the BLUE state was active before but quiescent after this call. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistatic bool cobalt_queue_empty(struct cobalt_vars *vars, 4738c2ecf20Sopenharmony_ci struct cobalt_params *p, 4748c2ecf20Sopenharmony_ci ktime_t now) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci bool down = false; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (vars->p_drop && 4798c2ecf20Sopenharmony_ci ktime_to_ns(ktime_sub(now, vars->blue_timer)) > p->target) { 4808c2ecf20Sopenharmony_ci if (vars->p_drop < p->p_dec) 4818c2ecf20Sopenharmony_ci vars->p_drop = 0; 4828c2ecf20Sopenharmony_ci else 4838c2ecf20Sopenharmony_ci vars->p_drop -= p->p_dec; 4848c2ecf20Sopenharmony_ci vars->blue_timer = now; 4858c2ecf20Sopenharmony_ci down = !vars->p_drop; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci vars->dropping = false; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (vars->count && ktime_to_ns(ktime_sub(now, vars->drop_next)) >= 0) { 4908c2ecf20Sopenharmony_ci vars->count--; 4918c2ecf20Sopenharmony_ci cobalt_invsqrt(vars); 4928c2ecf20Sopenharmony_ci vars->drop_next = cobalt_control(vars->drop_next, 4938c2ecf20Sopenharmony_ci p->interval, 4948c2ecf20Sopenharmony_ci vars->rec_inv_sqrt); 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return down; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/* Call this with a freshly dequeued packet for possible congestion marking. 5018c2ecf20Sopenharmony_ci * Returns true as an instruction to drop the packet, false for delivery. 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_cistatic bool cobalt_should_drop(struct cobalt_vars *vars, 5048c2ecf20Sopenharmony_ci struct cobalt_params *p, 5058c2ecf20Sopenharmony_ci ktime_t now, 5068c2ecf20Sopenharmony_ci struct sk_buff *skb, 5078c2ecf20Sopenharmony_ci u32 bulk_flows) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci bool next_due, over_target, drop = false; 5108c2ecf20Sopenharmony_ci ktime_t schedule; 5118c2ecf20Sopenharmony_ci u64 sojourn; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* The 'schedule' variable records, in its sign, whether 'now' is before or 5148c2ecf20Sopenharmony_ci * after 'drop_next'. This allows 'drop_next' to be updated before the next 5158c2ecf20Sopenharmony_ci * scheduling decision is actually branched, without destroying that 5168c2ecf20Sopenharmony_ci * information. Similarly, the first 'schedule' value calculated is preserved 5178c2ecf20Sopenharmony_ci * in the boolean 'next_due'. 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * As for 'drop_next', we take advantage of the fact that 'interval' is both 5208c2ecf20Sopenharmony_ci * the delay between first exceeding 'target' and the first signalling event, 5218c2ecf20Sopenharmony_ci * *and* the scaling factor for the signalling frequency. It's therefore very 5228c2ecf20Sopenharmony_ci * natural to use a single mechanism for both purposes, and eliminates a 5238c2ecf20Sopenharmony_ci * significant amount of reference Codel's spaghetti code. To help with this, 5248c2ecf20Sopenharmony_ci * both the '0' and '1' entries in the invsqrt cache are 0xFFFFFFFF, as close 5258c2ecf20Sopenharmony_ci * as possible to 1.0 in fixed-point. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci sojourn = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); 5298c2ecf20Sopenharmony_ci schedule = ktime_sub(now, vars->drop_next); 5308c2ecf20Sopenharmony_ci over_target = sojourn > p->target && 5318c2ecf20Sopenharmony_ci sojourn > p->mtu_time * bulk_flows * 2 && 5328c2ecf20Sopenharmony_ci sojourn > p->mtu_time * 4; 5338c2ecf20Sopenharmony_ci next_due = vars->count && ktime_to_ns(schedule) >= 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci vars->ecn_marked = false; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (over_target) { 5388c2ecf20Sopenharmony_ci if (!vars->dropping) { 5398c2ecf20Sopenharmony_ci vars->dropping = true; 5408c2ecf20Sopenharmony_ci vars->drop_next = cobalt_control(now, 5418c2ecf20Sopenharmony_ci p->interval, 5428c2ecf20Sopenharmony_ci vars->rec_inv_sqrt); 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci if (!vars->count) 5458c2ecf20Sopenharmony_ci vars->count = 1; 5468c2ecf20Sopenharmony_ci } else if (vars->dropping) { 5478c2ecf20Sopenharmony_ci vars->dropping = false; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (next_due && vars->dropping) { 5518c2ecf20Sopenharmony_ci /* Use ECN mark if possible, otherwise drop */ 5528c2ecf20Sopenharmony_ci drop = !(vars->ecn_marked = INET_ECN_set_ce(skb)); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci vars->count++; 5558c2ecf20Sopenharmony_ci if (!vars->count) 5568c2ecf20Sopenharmony_ci vars->count--; 5578c2ecf20Sopenharmony_ci cobalt_invsqrt(vars); 5588c2ecf20Sopenharmony_ci vars->drop_next = cobalt_control(vars->drop_next, 5598c2ecf20Sopenharmony_ci p->interval, 5608c2ecf20Sopenharmony_ci vars->rec_inv_sqrt); 5618c2ecf20Sopenharmony_ci schedule = ktime_sub(now, vars->drop_next); 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci while (next_due) { 5648c2ecf20Sopenharmony_ci vars->count--; 5658c2ecf20Sopenharmony_ci cobalt_invsqrt(vars); 5668c2ecf20Sopenharmony_ci vars->drop_next = cobalt_control(vars->drop_next, 5678c2ecf20Sopenharmony_ci p->interval, 5688c2ecf20Sopenharmony_ci vars->rec_inv_sqrt); 5698c2ecf20Sopenharmony_ci schedule = ktime_sub(now, vars->drop_next); 5708c2ecf20Sopenharmony_ci next_due = vars->count && ktime_to_ns(schedule) >= 0; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Simple BLUE implementation. Lack of ECN is deliberate. */ 5758c2ecf20Sopenharmony_ci if (vars->p_drop) 5768c2ecf20Sopenharmony_ci drop |= (prandom_u32() < vars->p_drop); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Overload the drop_next field as an activity timeout */ 5798c2ecf20Sopenharmony_ci if (!vars->count) 5808c2ecf20Sopenharmony_ci vars->drop_next = ktime_add_ns(now, p->interval); 5818c2ecf20Sopenharmony_ci else if (ktime_to_ns(schedule) > 0 && !drop) 5828c2ecf20Sopenharmony_ci vars->drop_next = now; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return drop; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic bool cake_update_flowkeys(struct flow_keys *keys, 5888c2ecf20Sopenharmony_ci const struct sk_buff *skb) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_CONNTRACK) 5918c2ecf20Sopenharmony_ci struct nf_conntrack_tuple tuple = {}; 5928c2ecf20Sopenharmony_ci bool rev = !skb->_nfct, upd = false; 5938c2ecf20Sopenharmony_ci __be32 ip; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (skb_protocol(skb, true) != htons(ETH_P_IP)) 5968c2ecf20Sopenharmony_ci return false; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!nf_ct_get_tuple_skb(&tuple, skb)) 5998c2ecf20Sopenharmony_ci return false; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci ip = rev ? tuple.dst.u3.ip : tuple.src.u3.ip; 6028c2ecf20Sopenharmony_ci if (ip != keys->addrs.v4addrs.src) { 6038c2ecf20Sopenharmony_ci keys->addrs.v4addrs.src = ip; 6048c2ecf20Sopenharmony_ci upd = true; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci ip = rev ? tuple.src.u3.ip : tuple.dst.u3.ip; 6078c2ecf20Sopenharmony_ci if (ip != keys->addrs.v4addrs.dst) { 6088c2ecf20Sopenharmony_ci keys->addrs.v4addrs.dst = ip; 6098c2ecf20Sopenharmony_ci upd = true; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (keys->ports.ports) { 6138c2ecf20Sopenharmony_ci __be16 port; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci port = rev ? tuple.dst.u.all : tuple.src.u.all; 6168c2ecf20Sopenharmony_ci if (port != keys->ports.src) { 6178c2ecf20Sopenharmony_ci keys->ports.src = port; 6188c2ecf20Sopenharmony_ci upd = true; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci port = rev ? tuple.src.u.all : tuple.dst.u.all; 6218c2ecf20Sopenharmony_ci if (port != keys->ports.dst) { 6228c2ecf20Sopenharmony_ci port = keys->ports.dst; 6238c2ecf20Sopenharmony_ci upd = true; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci return upd; 6278c2ecf20Sopenharmony_ci#else 6288c2ecf20Sopenharmony_ci return false; 6298c2ecf20Sopenharmony_ci#endif 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci/* Cake has several subtle multiple bit settings. In these cases you 6338c2ecf20Sopenharmony_ci * would be matching triple isolate mode as well. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic bool cake_dsrc(int flow_mode) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci return (flow_mode & CAKE_FLOW_DUAL_SRC) == CAKE_FLOW_DUAL_SRC; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic bool cake_ddst(int flow_mode) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci return (flow_mode & CAKE_FLOW_DUAL_DST) == CAKE_FLOW_DUAL_DST; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic u32 cake_hash(struct cake_tin_data *q, const struct sk_buff *skb, 6478c2ecf20Sopenharmony_ci int flow_mode, u16 flow_override, u16 host_override) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci bool hash_flows = (!flow_override && !!(flow_mode & CAKE_FLOW_FLOWS)); 6508c2ecf20Sopenharmony_ci bool hash_hosts = (!host_override && !!(flow_mode & CAKE_FLOW_HOSTS)); 6518c2ecf20Sopenharmony_ci bool nat_enabled = !!(flow_mode & CAKE_FLOW_NAT_FLAG); 6528c2ecf20Sopenharmony_ci u32 flow_hash = 0, srchost_hash = 0, dsthost_hash = 0; 6538c2ecf20Sopenharmony_ci u16 reduced_hash, srchost_idx, dsthost_idx; 6548c2ecf20Sopenharmony_ci struct flow_keys keys, host_keys; 6558c2ecf20Sopenharmony_ci bool use_skbhash = skb->l4_hash; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (unlikely(flow_mode == CAKE_FLOW_NONE)) 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* If both overrides are set, or we can use the SKB hash and nat mode is 6618c2ecf20Sopenharmony_ci * disabled, we can skip packet dissection entirely. If nat mode is 6628c2ecf20Sopenharmony_ci * enabled there's another check below after doing the conntrack lookup. 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci if ((!hash_flows || (use_skbhash && !nat_enabled)) && !hash_hosts) 6658c2ecf20Sopenharmony_ci goto skip_hash; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci skb_flow_dissect_flow_keys(skb, &keys, 6688c2ecf20Sopenharmony_ci FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Don't use the SKB hash if we change the lookup keys from conntrack */ 6718c2ecf20Sopenharmony_ci if (nat_enabled && cake_update_flowkeys(&keys, skb)) 6728c2ecf20Sopenharmony_ci use_skbhash = false; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* If we can still use the SKB hash and don't need the host hash, we can 6758c2ecf20Sopenharmony_ci * skip the rest of the hashing procedure 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci if (use_skbhash && !hash_hosts) 6788c2ecf20Sopenharmony_ci goto skip_hash; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* flow_hash_from_keys() sorts the addresses by value, so we have 6818c2ecf20Sopenharmony_ci * to preserve their order in a separate data structure to treat 6828c2ecf20Sopenharmony_ci * src and dst host addresses as independently selectable. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci host_keys = keys; 6858c2ecf20Sopenharmony_ci host_keys.ports.ports = 0; 6868c2ecf20Sopenharmony_ci host_keys.basic.ip_proto = 0; 6878c2ecf20Sopenharmony_ci host_keys.keyid.keyid = 0; 6888c2ecf20Sopenharmony_ci host_keys.tags.flow_label = 0; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci switch (host_keys.control.addr_type) { 6918c2ecf20Sopenharmony_ci case FLOW_DISSECTOR_KEY_IPV4_ADDRS: 6928c2ecf20Sopenharmony_ci host_keys.addrs.v4addrs.src = 0; 6938c2ecf20Sopenharmony_ci dsthost_hash = flow_hash_from_keys(&host_keys); 6948c2ecf20Sopenharmony_ci host_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src; 6958c2ecf20Sopenharmony_ci host_keys.addrs.v4addrs.dst = 0; 6968c2ecf20Sopenharmony_ci srchost_hash = flow_hash_from_keys(&host_keys); 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci case FLOW_DISSECTOR_KEY_IPV6_ADDRS: 7008c2ecf20Sopenharmony_ci memset(&host_keys.addrs.v6addrs.src, 0, 7018c2ecf20Sopenharmony_ci sizeof(host_keys.addrs.v6addrs.src)); 7028c2ecf20Sopenharmony_ci dsthost_hash = flow_hash_from_keys(&host_keys); 7038c2ecf20Sopenharmony_ci host_keys.addrs.v6addrs.src = keys.addrs.v6addrs.src; 7048c2ecf20Sopenharmony_ci memset(&host_keys.addrs.v6addrs.dst, 0, 7058c2ecf20Sopenharmony_ci sizeof(host_keys.addrs.v6addrs.dst)); 7068c2ecf20Sopenharmony_ci srchost_hash = flow_hash_from_keys(&host_keys); 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci default: 7108c2ecf20Sopenharmony_ci dsthost_hash = 0; 7118c2ecf20Sopenharmony_ci srchost_hash = 0; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* This *must* be after the above switch, since as a 7158c2ecf20Sopenharmony_ci * side-effect it sorts the src and dst addresses. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci if (hash_flows && !use_skbhash) 7188c2ecf20Sopenharmony_ci flow_hash = flow_hash_from_keys(&keys); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciskip_hash: 7218c2ecf20Sopenharmony_ci if (flow_override) 7228c2ecf20Sopenharmony_ci flow_hash = flow_override - 1; 7238c2ecf20Sopenharmony_ci else if (use_skbhash && (flow_mode & CAKE_FLOW_FLOWS)) 7248c2ecf20Sopenharmony_ci flow_hash = skb->hash; 7258c2ecf20Sopenharmony_ci if (host_override) { 7268c2ecf20Sopenharmony_ci dsthost_hash = host_override - 1; 7278c2ecf20Sopenharmony_ci srchost_hash = host_override - 1; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (!(flow_mode & CAKE_FLOW_FLOWS)) { 7318c2ecf20Sopenharmony_ci if (flow_mode & CAKE_FLOW_SRC_IP) 7328c2ecf20Sopenharmony_ci flow_hash ^= srchost_hash; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (flow_mode & CAKE_FLOW_DST_IP) 7358c2ecf20Sopenharmony_ci flow_hash ^= dsthost_hash; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci reduced_hash = flow_hash % CAKE_QUEUES; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* set-associative hashing */ 7418c2ecf20Sopenharmony_ci /* fast path if no hash collision (direct lookup succeeds) */ 7428c2ecf20Sopenharmony_ci if (likely(q->tags[reduced_hash] == flow_hash && 7438c2ecf20Sopenharmony_ci q->flows[reduced_hash].set)) { 7448c2ecf20Sopenharmony_ci q->way_directs++; 7458c2ecf20Sopenharmony_ci } else { 7468c2ecf20Sopenharmony_ci u32 inner_hash = reduced_hash % CAKE_SET_WAYS; 7478c2ecf20Sopenharmony_ci u32 outer_hash = reduced_hash - inner_hash; 7488c2ecf20Sopenharmony_ci bool allocate_src = false; 7498c2ecf20Sopenharmony_ci bool allocate_dst = false; 7508c2ecf20Sopenharmony_ci u32 i, k; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* check if any active queue in the set is reserved for 7538c2ecf20Sopenharmony_ci * this flow. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci for (i = 0, k = inner_hash; i < CAKE_SET_WAYS; 7568c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 7578c2ecf20Sopenharmony_ci if (q->tags[outer_hash + k] == flow_hash) { 7588c2ecf20Sopenharmony_ci if (i) 7598c2ecf20Sopenharmony_ci q->way_hits++; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!q->flows[outer_hash + k].set) { 7628c2ecf20Sopenharmony_ci /* need to increment host refcnts */ 7638c2ecf20Sopenharmony_ci allocate_src = cake_dsrc(flow_mode); 7648c2ecf20Sopenharmony_ci allocate_dst = cake_ddst(flow_mode); 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci goto found; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* no queue is reserved for this flow, look for an 7728c2ecf20Sopenharmony_ci * empty one. 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci for (i = 0; i < CAKE_SET_WAYS; 7758c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 7768c2ecf20Sopenharmony_ci if (!q->flows[outer_hash + k].set) { 7778c2ecf20Sopenharmony_ci q->way_misses++; 7788c2ecf20Sopenharmony_ci allocate_src = cake_dsrc(flow_mode); 7798c2ecf20Sopenharmony_ci allocate_dst = cake_ddst(flow_mode); 7808c2ecf20Sopenharmony_ci goto found; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* With no empty queues, default to the original 7858c2ecf20Sopenharmony_ci * queue, accept the collision, update the host tags. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_ci q->way_collisions++; 7888c2ecf20Sopenharmony_ci if (q->flows[outer_hash + k].set == CAKE_SET_BULK) { 7898c2ecf20Sopenharmony_ci q->hosts[q->flows[reduced_hash].srchost].srchost_bulk_flow_count--; 7908c2ecf20Sopenharmony_ci q->hosts[q->flows[reduced_hash].dsthost].dsthost_bulk_flow_count--; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci allocate_src = cake_dsrc(flow_mode); 7938c2ecf20Sopenharmony_ci allocate_dst = cake_ddst(flow_mode); 7948c2ecf20Sopenharmony_cifound: 7958c2ecf20Sopenharmony_ci /* reserve queue for future packets in same flow */ 7968c2ecf20Sopenharmony_ci reduced_hash = outer_hash + k; 7978c2ecf20Sopenharmony_ci q->tags[reduced_hash] = flow_hash; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (allocate_src) { 8008c2ecf20Sopenharmony_ci srchost_idx = srchost_hash % CAKE_QUEUES; 8018c2ecf20Sopenharmony_ci inner_hash = srchost_idx % CAKE_SET_WAYS; 8028c2ecf20Sopenharmony_ci outer_hash = srchost_idx - inner_hash; 8038c2ecf20Sopenharmony_ci for (i = 0, k = inner_hash; i < CAKE_SET_WAYS; 8048c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 8058c2ecf20Sopenharmony_ci if (q->hosts[outer_hash + k].srchost_tag == 8068c2ecf20Sopenharmony_ci srchost_hash) 8078c2ecf20Sopenharmony_ci goto found_src; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci for (i = 0; i < CAKE_SET_WAYS; 8108c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 8118c2ecf20Sopenharmony_ci if (!q->hosts[outer_hash + k].srchost_bulk_flow_count) 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci q->hosts[outer_hash + k].srchost_tag = srchost_hash; 8158c2ecf20Sopenharmony_cifound_src: 8168c2ecf20Sopenharmony_ci srchost_idx = outer_hash + k; 8178c2ecf20Sopenharmony_ci if (q->flows[reduced_hash].set == CAKE_SET_BULK) 8188c2ecf20Sopenharmony_ci q->hosts[srchost_idx].srchost_bulk_flow_count++; 8198c2ecf20Sopenharmony_ci q->flows[reduced_hash].srchost = srchost_idx; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (allocate_dst) { 8238c2ecf20Sopenharmony_ci dsthost_idx = dsthost_hash % CAKE_QUEUES; 8248c2ecf20Sopenharmony_ci inner_hash = dsthost_idx % CAKE_SET_WAYS; 8258c2ecf20Sopenharmony_ci outer_hash = dsthost_idx - inner_hash; 8268c2ecf20Sopenharmony_ci for (i = 0, k = inner_hash; i < CAKE_SET_WAYS; 8278c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 8288c2ecf20Sopenharmony_ci if (q->hosts[outer_hash + k].dsthost_tag == 8298c2ecf20Sopenharmony_ci dsthost_hash) 8308c2ecf20Sopenharmony_ci goto found_dst; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci for (i = 0; i < CAKE_SET_WAYS; 8338c2ecf20Sopenharmony_ci i++, k = (k + 1) % CAKE_SET_WAYS) { 8348c2ecf20Sopenharmony_ci if (!q->hosts[outer_hash + k].dsthost_bulk_flow_count) 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci q->hosts[outer_hash + k].dsthost_tag = dsthost_hash; 8388c2ecf20Sopenharmony_cifound_dst: 8398c2ecf20Sopenharmony_ci dsthost_idx = outer_hash + k; 8408c2ecf20Sopenharmony_ci if (q->flows[reduced_hash].set == CAKE_SET_BULK) 8418c2ecf20Sopenharmony_ci q->hosts[dsthost_idx].dsthost_bulk_flow_count++; 8428c2ecf20Sopenharmony_ci q->flows[reduced_hash].dsthost = dsthost_idx; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return reduced_hash; 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci/* helper functions : might be changed when/if skb use a standard list_head */ 8508c2ecf20Sopenharmony_ci/* remove one skb from head of slot queue */ 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic struct sk_buff *dequeue_head(struct cake_flow *flow) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct sk_buff *skb = flow->head; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (skb) { 8578c2ecf20Sopenharmony_ci flow->head = skb->next; 8588c2ecf20Sopenharmony_ci skb_mark_not_on_list(skb); 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci return skb; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci/* add skb to flow queue (tail add) */ 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void flow_queue_add(struct cake_flow *flow, struct sk_buff *skb) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci if (!flow->head) 8698c2ecf20Sopenharmony_ci flow->head = skb; 8708c2ecf20Sopenharmony_ci else 8718c2ecf20Sopenharmony_ci flow->tail->next = skb; 8728c2ecf20Sopenharmony_ci flow->tail = skb; 8738c2ecf20Sopenharmony_ci skb->next = NULL; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic struct iphdr *cake_get_iphdr(const struct sk_buff *skb, 8778c2ecf20Sopenharmony_ci struct ipv6hdr *buf) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci unsigned int offset = skb_network_offset(skb); 8808c2ecf20Sopenharmony_ci struct iphdr *iph; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci iph = skb_header_pointer(skb, offset, sizeof(struct iphdr), buf); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (!iph) 8858c2ecf20Sopenharmony_ci return NULL; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (iph->version == 4 && iph->protocol == IPPROTO_IPV6) 8888c2ecf20Sopenharmony_ci return skb_header_pointer(skb, offset + iph->ihl * 4, 8898c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr), buf); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci else if (iph->version == 4) 8928c2ecf20Sopenharmony_ci return iph; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci else if (iph->version == 6) 8958c2ecf20Sopenharmony_ci return skb_header_pointer(skb, offset, sizeof(struct ipv6hdr), 8968c2ecf20Sopenharmony_ci buf); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return NULL; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic struct tcphdr *cake_get_tcphdr(const struct sk_buff *skb, 9028c2ecf20Sopenharmony_ci void *buf, unsigned int bufsize) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci unsigned int offset = skb_network_offset(skb); 9058c2ecf20Sopenharmony_ci const struct ipv6hdr *ipv6h; 9068c2ecf20Sopenharmony_ci const struct tcphdr *tcph; 9078c2ecf20Sopenharmony_ci const struct iphdr *iph; 9088c2ecf20Sopenharmony_ci struct ipv6hdr _ipv6h; 9098c2ecf20Sopenharmony_ci struct tcphdr _tcph; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci ipv6h = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!ipv6h) 9148c2ecf20Sopenharmony_ci return NULL; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (ipv6h->version == 4) { 9178c2ecf20Sopenharmony_ci iph = (struct iphdr *)ipv6h; 9188c2ecf20Sopenharmony_ci offset += iph->ihl * 4; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* special-case 6in4 tunnelling, as that is a common way to get 9218c2ecf20Sopenharmony_ci * v6 connectivity in the home 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci if (iph->protocol == IPPROTO_IPV6) { 9248c2ecf20Sopenharmony_ci ipv6h = skb_header_pointer(skb, offset, 9258c2ecf20Sopenharmony_ci sizeof(_ipv6h), &_ipv6h); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (!ipv6h || ipv6h->nexthdr != IPPROTO_TCP) 9288c2ecf20Sopenharmony_ci return NULL; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci offset += sizeof(struct ipv6hdr); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci } else if (iph->protocol != IPPROTO_TCP) { 9338c2ecf20Sopenharmony_ci return NULL; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci } else if (ipv6h->version == 6) { 9378c2ecf20Sopenharmony_ci if (ipv6h->nexthdr != IPPROTO_TCP) 9388c2ecf20Sopenharmony_ci return NULL; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci offset += sizeof(struct ipv6hdr); 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci return NULL; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci tcph = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 9468c2ecf20Sopenharmony_ci if (!tcph || tcph->doff < 5) 9478c2ecf20Sopenharmony_ci return NULL; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci return skb_header_pointer(skb, offset, 9508c2ecf20Sopenharmony_ci min(__tcp_hdrlen(tcph), bufsize), buf); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic const void *cake_get_tcpopt(const struct tcphdr *tcph, 9548c2ecf20Sopenharmony_ci int code, int *oplen) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci /* inspired by tcp_parse_options in tcp_input.c */ 9578c2ecf20Sopenharmony_ci int length = __tcp_hdrlen(tcph) - sizeof(struct tcphdr); 9588c2ecf20Sopenharmony_ci const u8 *ptr = (const u8 *)(tcph + 1); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci while (length > 0) { 9618c2ecf20Sopenharmony_ci int opcode = *ptr++; 9628c2ecf20Sopenharmony_ci int opsize; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (opcode == TCPOPT_EOL) 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci if (opcode == TCPOPT_NOP) { 9678c2ecf20Sopenharmony_ci length--; 9688c2ecf20Sopenharmony_ci continue; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci if (length < 2) 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci opsize = *ptr++; 9738c2ecf20Sopenharmony_ci if (opsize < 2 || opsize > length) 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (opcode == code) { 9778c2ecf20Sopenharmony_ci *oplen = opsize; 9788c2ecf20Sopenharmony_ci return ptr; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci ptr += opsize - 2; 9828c2ecf20Sopenharmony_ci length -= opsize; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci return NULL; 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci/* Compare two SACK sequences. A sequence is considered greater if it SACKs more 9898c2ecf20Sopenharmony_ci * bytes than the other. In the case where both sequences ACKs bytes that the 9908c2ecf20Sopenharmony_ci * other doesn't, A is considered greater. DSACKs in A also makes A be 9918c2ecf20Sopenharmony_ci * considered greater. 9928c2ecf20Sopenharmony_ci * 9938c2ecf20Sopenharmony_ci * @return -1, 0 or 1 as normal compare functions 9948c2ecf20Sopenharmony_ci */ 9958c2ecf20Sopenharmony_cistatic int cake_tcph_sack_compare(const struct tcphdr *tcph_a, 9968c2ecf20Sopenharmony_ci const struct tcphdr *tcph_b) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci const struct tcp_sack_block_wire *sack_a, *sack_b; 9998c2ecf20Sopenharmony_ci u32 ack_seq_a = ntohl(tcph_a->ack_seq); 10008c2ecf20Sopenharmony_ci u32 bytes_a = 0, bytes_b = 0; 10018c2ecf20Sopenharmony_ci int oplen_a, oplen_b; 10028c2ecf20Sopenharmony_ci bool first = true; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci sack_a = cake_get_tcpopt(tcph_a, TCPOPT_SACK, &oplen_a); 10058c2ecf20Sopenharmony_ci sack_b = cake_get_tcpopt(tcph_b, TCPOPT_SACK, &oplen_b); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci /* pointers point to option contents */ 10088c2ecf20Sopenharmony_ci oplen_a -= TCPOLEN_SACK_BASE; 10098c2ecf20Sopenharmony_ci oplen_b -= TCPOLEN_SACK_BASE; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (sack_a && oplen_a >= sizeof(*sack_a) && 10128c2ecf20Sopenharmony_ci (!sack_b || oplen_b < sizeof(*sack_b))) 10138c2ecf20Sopenharmony_ci return -1; 10148c2ecf20Sopenharmony_ci else if (sack_b && oplen_b >= sizeof(*sack_b) && 10158c2ecf20Sopenharmony_ci (!sack_a || oplen_a < sizeof(*sack_a))) 10168c2ecf20Sopenharmony_ci return 1; 10178c2ecf20Sopenharmony_ci else if ((!sack_a || oplen_a < sizeof(*sack_a)) && 10188c2ecf20Sopenharmony_ci (!sack_b || oplen_b < sizeof(*sack_b))) 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci while (oplen_a >= sizeof(*sack_a)) { 10228c2ecf20Sopenharmony_ci const struct tcp_sack_block_wire *sack_tmp = sack_b; 10238c2ecf20Sopenharmony_ci u32 start_a = get_unaligned_be32(&sack_a->start_seq); 10248c2ecf20Sopenharmony_ci u32 end_a = get_unaligned_be32(&sack_a->end_seq); 10258c2ecf20Sopenharmony_ci int oplen_tmp = oplen_b; 10268c2ecf20Sopenharmony_ci bool found = false; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* DSACK; always considered greater to prevent dropping */ 10298c2ecf20Sopenharmony_ci if (before(start_a, ack_seq_a)) 10308c2ecf20Sopenharmony_ci return -1; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci bytes_a += end_a - start_a; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci while (oplen_tmp >= sizeof(*sack_tmp)) { 10358c2ecf20Sopenharmony_ci u32 start_b = get_unaligned_be32(&sack_tmp->start_seq); 10368c2ecf20Sopenharmony_ci u32 end_b = get_unaligned_be32(&sack_tmp->end_seq); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* first time through we count the total size */ 10398c2ecf20Sopenharmony_ci if (first) 10408c2ecf20Sopenharmony_ci bytes_b += end_b - start_b; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (!after(start_b, start_a) && !before(end_b, end_a)) { 10438c2ecf20Sopenharmony_ci found = true; 10448c2ecf20Sopenharmony_ci if (!first) 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci oplen_tmp -= sizeof(*sack_tmp); 10488c2ecf20Sopenharmony_ci sack_tmp++; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (!found) 10528c2ecf20Sopenharmony_ci return -1; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci oplen_a -= sizeof(*sack_a); 10558c2ecf20Sopenharmony_ci sack_a++; 10568c2ecf20Sopenharmony_ci first = false; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* If we made it this far, all ranges SACKed by A are covered by B, so 10608c2ecf20Sopenharmony_ci * either the SACKs are equal, or B SACKs more bytes. 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci return bytes_b > bytes_a ? 1 : 0; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic void cake_tcph_get_tstamp(const struct tcphdr *tcph, 10668c2ecf20Sopenharmony_ci u32 *tsval, u32 *tsecr) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci const u8 *ptr; 10698c2ecf20Sopenharmony_ci int opsize; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ptr = cake_get_tcpopt(tcph, TCPOPT_TIMESTAMP, &opsize); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (ptr && opsize == TCPOLEN_TIMESTAMP) { 10748c2ecf20Sopenharmony_ci *tsval = get_unaligned_be32(ptr); 10758c2ecf20Sopenharmony_ci *tsecr = get_unaligned_be32(ptr + 4); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic bool cake_tcph_may_drop(const struct tcphdr *tcph, 10808c2ecf20Sopenharmony_ci u32 tstamp_new, u32 tsecr_new) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci /* inspired by tcp_parse_options in tcp_input.c */ 10838c2ecf20Sopenharmony_ci int length = __tcp_hdrlen(tcph) - sizeof(struct tcphdr); 10848c2ecf20Sopenharmony_ci const u8 *ptr = (const u8 *)(tcph + 1); 10858c2ecf20Sopenharmony_ci u32 tstamp, tsecr; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* 3 reserved flags must be unset to avoid future breakage 10888c2ecf20Sopenharmony_ci * ACK must be set 10898c2ecf20Sopenharmony_ci * ECE/CWR are handled separately 10908c2ecf20Sopenharmony_ci * All other flags URG/PSH/RST/SYN/FIN must be unset 10918c2ecf20Sopenharmony_ci * 0x0FFF0000 = all TCP flags (confirm ACK=1, others zero) 10928c2ecf20Sopenharmony_ci * 0x00C00000 = CWR/ECE (handled separately) 10938c2ecf20Sopenharmony_ci * 0x0F3F0000 = 0x0FFF0000 & ~0x00C00000 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_ci if (((tcp_flag_word(tcph) & 10968c2ecf20Sopenharmony_ci cpu_to_be32(0x0F3F0000)) != TCP_FLAG_ACK)) 10978c2ecf20Sopenharmony_ci return false; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci while (length > 0) { 11008c2ecf20Sopenharmony_ci int opcode = *ptr++; 11018c2ecf20Sopenharmony_ci int opsize; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (opcode == TCPOPT_EOL) 11048c2ecf20Sopenharmony_ci break; 11058c2ecf20Sopenharmony_ci if (opcode == TCPOPT_NOP) { 11068c2ecf20Sopenharmony_ci length--; 11078c2ecf20Sopenharmony_ci continue; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci if (length < 2) 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci opsize = *ptr++; 11128c2ecf20Sopenharmony_ci if (opsize < 2 || opsize > length) 11138c2ecf20Sopenharmony_ci break; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci switch (opcode) { 11168c2ecf20Sopenharmony_ci case TCPOPT_MD5SIG: /* doesn't influence state */ 11178c2ecf20Sopenharmony_ci break; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci case TCPOPT_SACK: /* stricter checking performed later */ 11208c2ecf20Sopenharmony_ci if (opsize % 8 != 2) 11218c2ecf20Sopenharmony_ci return false; 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci case TCPOPT_TIMESTAMP: 11258c2ecf20Sopenharmony_ci /* only drop timestamps lower than new */ 11268c2ecf20Sopenharmony_ci if (opsize != TCPOLEN_TIMESTAMP) 11278c2ecf20Sopenharmony_ci return false; 11288c2ecf20Sopenharmony_ci tstamp = get_unaligned_be32(ptr); 11298c2ecf20Sopenharmony_ci tsecr = get_unaligned_be32(ptr + 4); 11308c2ecf20Sopenharmony_ci if (after(tstamp, tstamp_new) || 11318c2ecf20Sopenharmony_ci after(tsecr, tsecr_new)) 11328c2ecf20Sopenharmony_ci return false; 11338c2ecf20Sopenharmony_ci break; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci case TCPOPT_MSS: /* these should only be set on SYN */ 11368c2ecf20Sopenharmony_ci case TCPOPT_WINDOW: 11378c2ecf20Sopenharmony_ci case TCPOPT_SACK_PERM: 11388c2ecf20Sopenharmony_ci case TCPOPT_FASTOPEN: 11398c2ecf20Sopenharmony_ci case TCPOPT_EXP: 11408c2ecf20Sopenharmony_ci default: /* don't drop if any unknown options are present */ 11418c2ecf20Sopenharmony_ci return false; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci ptr += opsize - 2; 11458c2ecf20Sopenharmony_ci length -= opsize; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return true; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic struct sk_buff *cake_ack_filter(struct cake_sched_data *q, 11528c2ecf20Sopenharmony_ci struct cake_flow *flow) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci bool aggressive = q->ack_filter == CAKE_ACK_AGGRESSIVE; 11558c2ecf20Sopenharmony_ci struct sk_buff *elig_ack = NULL, *elig_ack_prev = NULL; 11568c2ecf20Sopenharmony_ci struct sk_buff *skb_check, *skb_prev = NULL; 11578c2ecf20Sopenharmony_ci const struct ipv6hdr *ipv6h, *ipv6h_check; 11588c2ecf20Sopenharmony_ci unsigned char _tcph[64], _tcph_check[64]; 11598c2ecf20Sopenharmony_ci const struct tcphdr *tcph, *tcph_check; 11608c2ecf20Sopenharmony_ci const struct iphdr *iph, *iph_check; 11618c2ecf20Sopenharmony_ci struct ipv6hdr _iph, _iph_check; 11628c2ecf20Sopenharmony_ci const struct sk_buff *skb; 11638c2ecf20Sopenharmony_ci int seglen, num_found = 0; 11648c2ecf20Sopenharmony_ci u32 tstamp = 0, tsecr = 0; 11658c2ecf20Sopenharmony_ci __be32 elig_flags = 0; 11668c2ecf20Sopenharmony_ci int sack_comp; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* no other possible ACKs to filter */ 11698c2ecf20Sopenharmony_ci if (flow->head == flow->tail) 11708c2ecf20Sopenharmony_ci return NULL; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci skb = flow->tail; 11738c2ecf20Sopenharmony_ci tcph = cake_get_tcphdr(skb, _tcph, sizeof(_tcph)); 11748c2ecf20Sopenharmony_ci iph = cake_get_iphdr(skb, &_iph); 11758c2ecf20Sopenharmony_ci if (!tcph) 11768c2ecf20Sopenharmony_ci return NULL; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci cake_tcph_get_tstamp(tcph, &tstamp, &tsecr); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci /* the 'triggering' packet need only have the ACK flag set. 11818c2ecf20Sopenharmony_ci * also check that SYN is not set, as there won't be any previous ACKs. 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci if ((tcp_flag_word(tcph) & 11848c2ecf20Sopenharmony_ci (TCP_FLAG_ACK | TCP_FLAG_SYN)) != TCP_FLAG_ACK) 11858c2ecf20Sopenharmony_ci return NULL; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* the 'triggering' ACK is at the tail of the queue, we have already 11888c2ecf20Sopenharmony_ci * returned if it is the only packet in the flow. loop through the rest 11898c2ecf20Sopenharmony_ci * of the queue looking for pure ACKs with the same 5-tuple as the 11908c2ecf20Sopenharmony_ci * triggering one. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci for (skb_check = flow->head; 11938c2ecf20Sopenharmony_ci skb_check && skb_check != skb; 11948c2ecf20Sopenharmony_ci skb_prev = skb_check, skb_check = skb_check->next) { 11958c2ecf20Sopenharmony_ci iph_check = cake_get_iphdr(skb_check, &_iph_check); 11968c2ecf20Sopenharmony_ci tcph_check = cake_get_tcphdr(skb_check, &_tcph_check, 11978c2ecf20Sopenharmony_ci sizeof(_tcph_check)); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* only TCP packets with matching 5-tuple are eligible, and only 12008c2ecf20Sopenharmony_ci * drop safe headers 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci if (!tcph_check || iph->version != iph_check->version || 12038c2ecf20Sopenharmony_ci tcph_check->source != tcph->source || 12048c2ecf20Sopenharmony_ci tcph_check->dest != tcph->dest) 12058c2ecf20Sopenharmony_ci continue; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (iph_check->version == 4) { 12088c2ecf20Sopenharmony_ci if (iph_check->saddr != iph->saddr || 12098c2ecf20Sopenharmony_ci iph_check->daddr != iph->daddr) 12108c2ecf20Sopenharmony_ci continue; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci seglen = ntohs(iph_check->tot_len) - 12138c2ecf20Sopenharmony_ci (4 * iph_check->ihl); 12148c2ecf20Sopenharmony_ci } else if (iph_check->version == 6) { 12158c2ecf20Sopenharmony_ci ipv6h = (struct ipv6hdr *)iph; 12168c2ecf20Sopenharmony_ci ipv6h_check = (struct ipv6hdr *)iph_check; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (ipv6_addr_cmp(&ipv6h_check->saddr, &ipv6h->saddr) || 12198c2ecf20Sopenharmony_ci ipv6_addr_cmp(&ipv6h_check->daddr, &ipv6h->daddr)) 12208c2ecf20Sopenharmony_ci continue; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci seglen = ntohs(ipv6h_check->payload_len); 12238c2ecf20Sopenharmony_ci } else { 12248c2ecf20Sopenharmony_ci WARN_ON(1); /* shouldn't happen */ 12258c2ecf20Sopenharmony_ci continue; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* If the ECE/CWR flags changed from the previous eligible 12298c2ecf20Sopenharmony_ci * packet in the same flow, we should no longer be dropping that 12308c2ecf20Sopenharmony_ci * previous packet as this would lose information. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci if (elig_ack && (tcp_flag_word(tcph_check) & 12338c2ecf20Sopenharmony_ci (TCP_FLAG_ECE | TCP_FLAG_CWR)) != elig_flags) { 12348c2ecf20Sopenharmony_ci elig_ack = NULL; 12358c2ecf20Sopenharmony_ci elig_ack_prev = NULL; 12368c2ecf20Sopenharmony_ci num_found--; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* Check TCP options and flags, don't drop ACKs with segment 12408c2ecf20Sopenharmony_ci * data, and don't drop ACKs with a higher cumulative ACK 12418c2ecf20Sopenharmony_ci * counter than the triggering packet. Check ACK seqno here to 12428c2ecf20Sopenharmony_ci * avoid parsing SACK options of packets we are going to exclude 12438c2ecf20Sopenharmony_ci * anyway. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ci if (!cake_tcph_may_drop(tcph_check, tstamp, tsecr) || 12468c2ecf20Sopenharmony_ci (seglen - __tcp_hdrlen(tcph_check)) != 0 || 12478c2ecf20Sopenharmony_ci after(ntohl(tcph_check->ack_seq), ntohl(tcph->ack_seq))) 12488c2ecf20Sopenharmony_ci continue; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* Check SACK options. The triggering packet must SACK more data 12518c2ecf20Sopenharmony_ci * than the ACK under consideration, or SACK the same range but 12528c2ecf20Sopenharmony_ci * have a larger cumulative ACK counter. The latter is a 12538c2ecf20Sopenharmony_ci * pathological case, but is contained in the following check 12548c2ecf20Sopenharmony_ci * anyway, just to be safe. 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci sack_comp = cake_tcph_sack_compare(tcph_check, tcph); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (sack_comp < 0 || 12598c2ecf20Sopenharmony_ci (ntohl(tcph_check->ack_seq) == ntohl(tcph->ack_seq) && 12608c2ecf20Sopenharmony_ci sack_comp == 0)) 12618c2ecf20Sopenharmony_ci continue; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* At this point we have found an eligible pure ACK to drop; if 12648c2ecf20Sopenharmony_ci * we are in aggressive mode, we are done. Otherwise, keep 12658c2ecf20Sopenharmony_ci * searching unless this is the second eligible ACK we 12668c2ecf20Sopenharmony_ci * found. 12678c2ecf20Sopenharmony_ci * 12688c2ecf20Sopenharmony_ci * Since we want to drop ACK closest to the head of the queue, 12698c2ecf20Sopenharmony_ci * save the first eligible ACK we find, even if we need to loop 12708c2ecf20Sopenharmony_ci * again. 12718c2ecf20Sopenharmony_ci */ 12728c2ecf20Sopenharmony_ci if (!elig_ack) { 12738c2ecf20Sopenharmony_ci elig_ack = skb_check; 12748c2ecf20Sopenharmony_ci elig_ack_prev = skb_prev; 12758c2ecf20Sopenharmony_ci elig_flags = (tcp_flag_word(tcph_check) 12768c2ecf20Sopenharmony_ci & (TCP_FLAG_ECE | TCP_FLAG_CWR)); 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (num_found++ > 0) 12808c2ecf20Sopenharmony_ci goto found; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* We made it through the queue without finding two eligible ACKs . If 12848c2ecf20Sopenharmony_ci * we found a single eligible ACK we can drop it in aggressive mode if 12858c2ecf20Sopenharmony_ci * we can guarantee that this does not interfere with ECN flag 12868c2ecf20Sopenharmony_ci * information. We ensure this by dropping it only if the enqueued 12878c2ecf20Sopenharmony_ci * packet is consecutive with the eligible ACK, and their flags match. 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_ci if (elig_ack && aggressive && elig_ack->next == skb && 12908c2ecf20Sopenharmony_ci (elig_flags == (tcp_flag_word(tcph) & 12918c2ecf20Sopenharmony_ci (TCP_FLAG_ECE | TCP_FLAG_CWR)))) 12928c2ecf20Sopenharmony_ci goto found; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci return NULL; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cifound: 12978c2ecf20Sopenharmony_ci if (elig_ack_prev) 12988c2ecf20Sopenharmony_ci elig_ack_prev->next = elig_ack->next; 12998c2ecf20Sopenharmony_ci else 13008c2ecf20Sopenharmony_ci flow->head = elig_ack->next; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci skb_mark_not_on_list(elig_ack); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci return elig_ack; 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic u64 cake_ewma(u64 avg, u64 sample, u32 shift) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci avg -= avg >> shift; 13108c2ecf20Sopenharmony_ci avg += sample >> shift; 13118c2ecf20Sopenharmony_ci return avg; 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cistatic u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off) 13158c2ecf20Sopenharmony_ci{ 13168c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_OVERHEAD) 13178c2ecf20Sopenharmony_ci len -= off; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (q->max_netlen < len) 13208c2ecf20Sopenharmony_ci q->max_netlen = len; 13218c2ecf20Sopenharmony_ci if (q->min_netlen > len) 13228c2ecf20Sopenharmony_ci q->min_netlen = len; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci len += q->rate_overhead; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (len < q->rate_mpu) 13278c2ecf20Sopenharmony_ci len = q->rate_mpu; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (q->atm_mode == CAKE_ATM_ATM) { 13308c2ecf20Sopenharmony_ci len += 47; 13318c2ecf20Sopenharmony_ci len /= 48; 13328c2ecf20Sopenharmony_ci len *= 53; 13338c2ecf20Sopenharmony_ci } else if (q->atm_mode == CAKE_ATM_PTM) { 13348c2ecf20Sopenharmony_ci /* Add one byte per 64 bytes or part thereof. 13358c2ecf20Sopenharmony_ci * This is conservative and easier to calculate than the 13368c2ecf20Sopenharmony_ci * precise value. 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci len += (len + 63) / 64; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (q->max_adjlen < len) 13428c2ecf20Sopenharmony_ci q->max_adjlen = len; 13438c2ecf20Sopenharmony_ci if (q->min_adjlen > len) 13448c2ecf20Sopenharmony_ci q->min_adjlen = len; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci return len; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic u32 cake_overhead(struct cake_sched_data *q, const struct sk_buff *skb) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci const struct skb_shared_info *shinfo = skb_shinfo(skb); 13528c2ecf20Sopenharmony_ci unsigned int hdr_len, last_len = 0; 13538c2ecf20Sopenharmony_ci u32 off = skb_network_offset(skb); 13548c2ecf20Sopenharmony_ci u32 len = qdisc_pkt_len(skb); 13558c2ecf20Sopenharmony_ci u16 segs = 1; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci q->avg_netoff = cake_ewma(q->avg_netoff, off << 16, 8); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (!shinfo->gso_size) 13608c2ecf20Sopenharmony_ci return cake_calc_overhead(q, len, off); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* borrowed from qdisc_pkt_len_init() */ 13638c2ecf20Sopenharmony_ci hdr_len = skb_transport_header(skb) - skb_mac_header(skb); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* + transport layer */ 13668c2ecf20Sopenharmony_ci if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | 13678c2ecf20Sopenharmony_ci SKB_GSO_TCPV6))) { 13688c2ecf20Sopenharmony_ci const struct tcphdr *th; 13698c2ecf20Sopenharmony_ci struct tcphdr _tcphdr; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci th = skb_header_pointer(skb, skb_transport_offset(skb), 13728c2ecf20Sopenharmony_ci sizeof(_tcphdr), &_tcphdr); 13738c2ecf20Sopenharmony_ci if (likely(th)) 13748c2ecf20Sopenharmony_ci hdr_len += __tcp_hdrlen(th); 13758c2ecf20Sopenharmony_ci } else { 13768c2ecf20Sopenharmony_ci struct udphdr _udphdr; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (skb_header_pointer(skb, skb_transport_offset(skb), 13798c2ecf20Sopenharmony_ci sizeof(_udphdr), &_udphdr)) 13808c2ecf20Sopenharmony_ci hdr_len += sizeof(struct udphdr); 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (unlikely(shinfo->gso_type & SKB_GSO_DODGY)) 13848c2ecf20Sopenharmony_ci segs = DIV_ROUND_UP(skb->len - hdr_len, 13858c2ecf20Sopenharmony_ci shinfo->gso_size); 13868c2ecf20Sopenharmony_ci else 13878c2ecf20Sopenharmony_ci segs = shinfo->gso_segs; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci len = shinfo->gso_size + hdr_len; 13908c2ecf20Sopenharmony_ci last_len = skb->len - shinfo->gso_size * (segs - 1); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci return (cake_calc_overhead(q, len, off) * (segs - 1) + 13938c2ecf20Sopenharmony_ci cake_calc_overhead(q, last_len, off)); 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic void cake_heap_swap(struct cake_sched_data *q, u16 i, u16 j) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci struct cake_heap_entry ii = q->overflow_heap[i]; 13998c2ecf20Sopenharmony_ci struct cake_heap_entry jj = q->overflow_heap[j]; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci q->overflow_heap[i] = jj; 14028c2ecf20Sopenharmony_ci q->overflow_heap[j] = ii; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci q->tins[ii.t].overflow_idx[ii.b] = j; 14058c2ecf20Sopenharmony_ci q->tins[jj.t].overflow_idx[jj.b] = i; 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic u32 cake_heap_get_backlog(const struct cake_sched_data *q, u16 i) 14098c2ecf20Sopenharmony_ci{ 14108c2ecf20Sopenharmony_ci struct cake_heap_entry ii = q->overflow_heap[i]; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return q->tins[ii.t].backlogs[ii.b]; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic void cake_heapify(struct cake_sched_data *q, u16 i) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci static const u32 a = CAKE_MAX_TINS * CAKE_QUEUES; 14188c2ecf20Sopenharmony_ci u32 mb = cake_heap_get_backlog(q, i); 14198c2ecf20Sopenharmony_ci u32 m = i; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci while (m < a) { 14228c2ecf20Sopenharmony_ci u32 l = m + m + 1; 14238c2ecf20Sopenharmony_ci u32 r = l + 1; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (l < a) { 14268c2ecf20Sopenharmony_ci u32 lb = cake_heap_get_backlog(q, l); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (lb > mb) { 14298c2ecf20Sopenharmony_ci m = l; 14308c2ecf20Sopenharmony_ci mb = lb; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (r < a) { 14358c2ecf20Sopenharmony_ci u32 rb = cake_heap_get_backlog(q, r); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (rb > mb) { 14388c2ecf20Sopenharmony_ci m = r; 14398c2ecf20Sopenharmony_ci mb = rb; 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (m != i) { 14448c2ecf20Sopenharmony_ci cake_heap_swap(q, i, m); 14458c2ecf20Sopenharmony_ci i = m; 14468c2ecf20Sopenharmony_ci } else { 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic void cake_heapify_up(struct cake_sched_data *q, u16 i) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci while (i > 0 && i < CAKE_MAX_TINS * CAKE_QUEUES) { 14558c2ecf20Sopenharmony_ci u16 p = (i - 1) >> 1; 14568c2ecf20Sopenharmony_ci u32 ib = cake_heap_get_backlog(q, i); 14578c2ecf20Sopenharmony_ci u32 pb = cake_heap_get_backlog(q, p); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (ib > pb) { 14608c2ecf20Sopenharmony_ci cake_heap_swap(q, i, p); 14618c2ecf20Sopenharmony_ci i = p; 14628c2ecf20Sopenharmony_ci } else { 14638c2ecf20Sopenharmony_ci break; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic int cake_advance_shaper(struct cake_sched_data *q, 14698c2ecf20Sopenharmony_ci struct cake_tin_data *b, 14708c2ecf20Sopenharmony_ci struct sk_buff *skb, 14718c2ecf20Sopenharmony_ci ktime_t now, bool drop) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci u32 len = get_cobalt_cb(skb)->adjusted_len; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* charge packet bandwidth to this tin 14768c2ecf20Sopenharmony_ci * and to the global shaper. 14778c2ecf20Sopenharmony_ci */ 14788c2ecf20Sopenharmony_ci if (q->rate_ns) { 14798c2ecf20Sopenharmony_ci u64 tin_dur = (len * b->tin_rate_ns) >> b->tin_rate_shft; 14808c2ecf20Sopenharmony_ci u64 global_dur = (len * q->rate_ns) >> q->rate_shft; 14818c2ecf20Sopenharmony_ci u64 failsafe_dur = global_dur + (global_dur >> 1); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (ktime_before(b->time_next_packet, now)) 14848c2ecf20Sopenharmony_ci b->time_next_packet = ktime_add_ns(b->time_next_packet, 14858c2ecf20Sopenharmony_ci tin_dur); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci else if (ktime_before(b->time_next_packet, 14888c2ecf20Sopenharmony_ci ktime_add_ns(now, tin_dur))) 14898c2ecf20Sopenharmony_ci b->time_next_packet = ktime_add_ns(now, tin_dur); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci q->time_next_packet = ktime_add_ns(q->time_next_packet, 14928c2ecf20Sopenharmony_ci global_dur); 14938c2ecf20Sopenharmony_ci if (!drop) 14948c2ecf20Sopenharmony_ci q->failsafe_next_packet = \ 14958c2ecf20Sopenharmony_ci ktime_add_ns(q->failsafe_next_packet, 14968c2ecf20Sopenharmony_ci failsafe_dur); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci return len; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) 15028c2ecf20Sopenharmony_ci{ 15038c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 15048c2ecf20Sopenharmony_ci ktime_t now = ktime_get(); 15058c2ecf20Sopenharmony_ci u32 idx = 0, tin = 0, len; 15068c2ecf20Sopenharmony_ci struct cake_heap_entry qq; 15078c2ecf20Sopenharmony_ci struct cake_tin_data *b; 15088c2ecf20Sopenharmony_ci struct cake_flow *flow; 15098c2ecf20Sopenharmony_ci struct sk_buff *skb; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if (!q->overflow_timeout) { 15128c2ecf20Sopenharmony_ci int i; 15138c2ecf20Sopenharmony_ci /* Build fresh max-heap */ 15148c2ecf20Sopenharmony_ci for (i = CAKE_MAX_TINS * CAKE_QUEUES / 2; i >= 0; i--) 15158c2ecf20Sopenharmony_ci cake_heapify(q, i); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci q->overflow_timeout = 65535; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* select longest queue for pruning */ 15208c2ecf20Sopenharmony_ci qq = q->overflow_heap[0]; 15218c2ecf20Sopenharmony_ci tin = qq.t; 15228c2ecf20Sopenharmony_ci idx = qq.b; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci b = &q->tins[tin]; 15258c2ecf20Sopenharmony_ci flow = &b->flows[idx]; 15268c2ecf20Sopenharmony_ci skb = dequeue_head(flow); 15278c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 15288c2ecf20Sopenharmony_ci /* heap has gone wrong, rebuild it next time */ 15298c2ecf20Sopenharmony_ci q->overflow_timeout = 0; 15308c2ecf20Sopenharmony_ci return idx + (tin << 16); 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (cobalt_queue_full(&flow->cvars, &b->cparams, now)) 15348c2ecf20Sopenharmony_ci b->unresponsive_flow_count++; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci len = qdisc_pkt_len(skb); 15378c2ecf20Sopenharmony_ci q->buffer_used -= skb->truesize; 15388c2ecf20Sopenharmony_ci b->backlogs[idx] -= len; 15398c2ecf20Sopenharmony_ci b->tin_backlog -= len; 15408c2ecf20Sopenharmony_ci sch->qstats.backlog -= len; 15418c2ecf20Sopenharmony_ci qdisc_tree_reduce_backlog(sch, 1, len); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci flow->dropped++; 15448c2ecf20Sopenharmony_ci b->tin_dropped++; 15458c2ecf20Sopenharmony_ci sch->qstats.drops++; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_INGRESS) 15488c2ecf20Sopenharmony_ci cake_advance_shaper(q, b, skb, now, true); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci __qdisc_drop(skb, to_free); 15518c2ecf20Sopenharmony_ci sch->q.qlen--; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci cake_heapify(q, 0); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci return idx + (tin << 16); 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic u8 cake_handle_diffserv(struct sk_buff *skb, bool wash) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci const int offset = skb_network_offset(skb); 15618c2ecf20Sopenharmony_ci u16 *buf, buf_; 15628c2ecf20Sopenharmony_ci u8 dscp; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci switch (skb_protocol(skb, true)) { 15658c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 15668c2ecf20Sopenharmony_ci buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_); 15678c2ecf20Sopenharmony_ci if (unlikely(!buf)) 15688c2ecf20Sopenharmony_ci return 0; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci /* ToS is in the second byte of iphdr */ 15718c2ecf20Sopenharmony_ci dscp = ipv4_get_dsfield((struct iphdr *)buf) >> 2; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (wash && dscp) { 15748c2ecf20Sopenharmony_ci const int wlen = offset + sizeof(struct iphdr); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, wlen) || 15778c2ecf20Sopenharmony_ci skb_try_make_writable(skb, wlen)) 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, 0); 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci return dscp; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 15868c2ecf20Sopenharmony_ci buf = skb_header_pointer(skb, offset, sizeof(buf_), &buf_); 15878c2ecf20Sopenharmony_ci if (unlikely(!buf)) 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* Traffic class is in the first and second bytes of ipv6hdr */ 15918c2ecf20Sopenharmony_ci dscp = ipv6_get_dsfield((struct ipv6hdr *)buf) >> 2; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (wash && dscp) { 15948c2ecf20Sopenharmony_ci const int wlen = offset + sizeof(struct ipv6hdr); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, wlen) || 15978c2ecf20Sopenharmony_ci skb_try_make_writable(skb, wlen)) 15988c2ecf20Sopenharmony_ci return 0; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci ipv6_change_dsfield(ipv6_hdr(skb), INET_ECN_MASK, 0); 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return dscp; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci case htons(ETH_P_ARP): 16068c2ecf20Sopenharmony_ci return 0x38; /* CS7 - Net Control */ 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci default: 16098c2ecf20Sopenharmony_ci /* If there is no Diffserv field, treat as best-effort */ 16108c2ecf20Sopenharmony_ci return 0; 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic struct cake_tin_data *cake_select_tin(struct Qdisc *sch, 16158c2ecf20Sopenharmony_ci struct sk_buff *skb) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 16188c2ecf20Sopenharmony_ci u32 tin, mark; 16198c2ecf20Sopenharmony_ci bool wash; 16208c2ecf20Sopenharmony_ci u8 dscp; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* Tin selection: Default to diffserv-based selection, allow overriding 16238c2ecf20Sopenharmony_ci * using firewall marks or skb->priority. Call DSCP parsing early if 16248c2ecf20Sopenharmony_ci * wash is enabled, otherwise defer to below to skip unneeded parsing. 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ci mark = (skb->mark & q->fwmark_mask) >> q->fwmark_shft; 16278c2ecf20Sopenharmony_ci wash = !!(q->rate_flags & CAKE_FLAG_WASH); 16288c2ecf20Sopenharmony_ci if (wash) 16298c2ecf20Sopenharmony_ci dscp = cake_handle_diffserv(skb, wash); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (q->tin_mode == CAKE_DIFFSERV_BESTEFFORT) 16328c2ecf20Sopenharmony_ci tin = 0; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci else if (mark && mark <= q->tin_cnt) 16358c2ecf20Sopenharmony_ci tin = q->tin_order[mark - 1]; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci else if (TC_H_MAJ(skb->priority) == sch->handle && 16388c2ecf20Sopenharmony_ci TC_H_MIN(skb->priority) > 0 && 16398c2ecf20Sopenharmony_ci TC_H_MIN(skb->priority) <= q->tin_cnt) 16408c2ecf20Sopenharmony_ci tin = q->tin_order[TC_H_MIN(skb->priority) - 1]; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci else { 16438c2ecf20Sopenharmony_ci if (!wash) 16448c2ecf20Sopenharmony_ci dscp = cake_handle_diffserv(skb, wash); 16458c2ecf20Sopenharmony_ci tin = q->tin_index[dscp]; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (unlikely(tin >= q->tin_cnt)) 16488c2ecf20Sopenharmony_ci tin = 0; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci return &q->tins[tin]; 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t, 16558c2ecf20Sopenharmony_ci struct sk_buff *skb, int flow_mode, int *qerr) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 16588c2ecf20Sopenharmony_ci struct tcf_proto *filter; 16598c2ecf20Sopenharmony_ci struct tcf_result res; 16608c2ecf20Sopenharmony_ci u16 flow = 0, host = 0; 16618c2ecf20Sopenharmony_ci int result; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci filter = rcu_dereference_bh(q->filter_list); 16648c2ecf20Sopenharmony_ci if (!filter) 16658c2ecf20Sopenharmony_ci goto hash; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; 16688c2ecf20Sopenharmony_ci result = tcf_classify(skb, filter, &res, false); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci if (result >= 0) { 16718c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_CLS_ACT 16728c2ecf20Sopenharmony_ci switch (result) { 16738c2ecf20Sopenharmony_ci case TC_ACT_STOLEN: 16748c2ecf20Sopenharmony_ci case TC_ACT_QUEUED: 16758c2ecf20Sopenharmony_ci case TC_ACT_TRAP: 16768c2ecf20Sopenharmony_ci *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; 16778c2ecf20Sopenharmony_ci fallthrough; 16788c2ecf20Sopenharmony_ci case TC_ACT_SHOT: 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci#endif 16828c2ecf20Sopenharmony_ci if (TC_H_MIN(res.classid) <= CAKE_QUEUES) 16838c2ecf20Sopenharmony_ci flow = TC_H_MIN(res.classid); 16848c2ecf20Sopenharmony_ci if (TC_H_MAJ(res.classid) <= (CAKE_QUEUES << 16)) 16858c2ecf20Sopenharmony_ci host = TC_H_MAJ(res.classid) >> 16; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_cihash: 16888c2ecf20Sopenharmony_ci *t = cake_select_tin(sch, skb); 16898c2ecf20Sopenharmony_ci return cake_hash(*t, skb, flow_mode, flow, host) + 1; 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic void cake_reconfigure(struct Qdisc *sch); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, 16958c2ecf20Sopenharmony_ci struct sk_buff **to_free) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 16988c2ecf20Sopenharmony_ci int len = qdisc_pkt_len(skb); 16998c2ecf20Sopenharmony_ci int ret; 17008c2ecf20Sopenharmony_ci struct sk_buff *ack = NULL; 17018c2ecf20Sopenharmony_ci ktime_t now = ktime_get(); 17028c2ecf20Sopenharmony_ci struct cake_tin_data *b; 17038c2ecf20Sopenharmony_ci struct cake_flow *flow; 17048c2ecf20Sopenharmony_ci u32 idx; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci /* choose flow to insert into */ 17078c2ecf20Sopenharmony_ci idx = cake_classify(sch, &b, skb, q->flow_mode, &ret); 17088c2ecf20Sopenharmony_ci if (idx == 0) { 17098c2ecf20Sopenharmony_ci if (ret & __NET_XMIT_BYPASS) 17108c2ecf20Sopenharmony_ci qdisc_qstats_drop(sch); 17118c2ecf20Sopenharmony_ci __qdisc_drop(skb, to_free); 17128c2ecf20Sopenharmony_ci return ret; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci idx--; 17158c2ecf20Sopenharmony_ci flow = &b->flows[idx]; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci /* ensure shaper state isn't stale */ 17188c2ecf20Sopenharmony_ci if (!b->tin_backlog) { 17198c2ecf20Sopenharmony_ci if (ktime_before(b->time_next_packet, now)) 17208c2ecf20Sopenharmony_ci b->time_next_packet = now; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci if (!sch->q.qlen) { 17238c2ecf20Sopenharmony_ci if (ktime_before(q->time_next_packet, now)) { 17248c2ecf20Sopenharmony_ci q->failsafe_next_packet = now; 17258c2ecf20Sopenharmony_ci q->time_next_packet = now; 17268c2ecf20Sopenharmony_ci } else if (ktime_after(q->time_next_packet, now) && 17278c2ecf20Sopenharmony_ci ktime_after(q->failsafe_next_packet, now)) { 17288c2ecf20Sopenharmony_ci u64 next = \ 17298c2ecf20Sopenharmony_ci min(ktime_to_ns(q->time_next_packet), 17308c2ecf20Sopenharmony_ci ktime_to_ns( 17318c2ecf20Sopenharmony_ci q->failsafe_next_packet)); 17328c2ecf20Sopenharmony_ci sch->qstats.overlimits++; 17338c2ecf20Sopenharmony_ci qdisc_watchdog_schedule_ns(&q->watchdog, next); 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (unlikely(len > b->max_skblen)) 17398c2ecf20Sopenharmony_ci b->max_skblen = len; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (skb_is_gso(skb) && q->rate_flags & CAKE_FLAG_SPLIT_GSO) { 17428c2ecf20Sopenharmony_ci struct sk_buff *segs, *nskb; 17438c2ecf20Sopenharmony_ci netdev_features_t features = netif_skb_features(skb); 17448c2ecf20Sopenharmony_ci unsigned int slen = 0, numsegs = 0; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); 17478c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(segs)) 17488c2ecf20Sopenharmony_ci return qdisc_drop(skb, sch, to_free); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci skb_list_walk_safe(segs, segs, nskb) { 17518c2ecf20Sopenharmony_ci skb_mark_not_on_list(segs); 17528c2ecf20Sopenharmony_ci qdisc_skb_cb(segs)->pkt_len = segs->len; 17538c2ecf20Sopenharmony_ci cobalt_set_enqueue_time(segs, now); 17548c2ecf20Sopenharmony_ci get_cobalt_cb(segs)->adjusted_len = cake_overhead(q, 17558c2ecf20Sopenharmony_ci segs); 17568c2ecf20Sopenharmony_ci flow_queue_add(flow, segs); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci sch->q.qlen++; 17598c2ecf20Sopenharmony_ci numsegs++; 17608c2ecf20Sopenharmony_ci slen += segs->len; 17618c2ecf20Sopenharmony_ci q->buffer_used += segs->truesize; 17628c2ecf20Sopenharmony_ci b->packets++; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci /* stats */ 17668c2ecf20Sopenharmony_ci b->bytes += slen; 17678c2ecf20Sopenharmony_ci b->backlogs[idx] += slen; 17688c2ecf20Sopenharmony_ci b->tin_backlog += slen; 17698c2ecf20Sopenharmony_ci sch->qstats.backlog += slen; 17708c2ecf20Sopenharmony_ci q->avg_window_bytes += slen; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); 17738c2ecf20Sopenharmony_ci consume_skb(skb); 17748c2ecf20Sopenharmony_ci } else { 17758c2ecf20Sopenharmony_ci /* not splitting */ 17768c2ecf20Sopenharmony_ci cobalt_set_enqueue_time(skb, now); 17778c2ecf20Sopenharmony_ci get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb); 17788c2ecf20Sopenharmony_ci flow_queue_add(flow, skb); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (q->ack_filter) 17818c2ecf20Sopenharmony_ci ack = cake_ack_filter(q, flow); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (ack) { 17848c2ecf20Sopenharmony_ci b->ack_drops++; 17858c2ecf20Sopenharmony_ci sch->qstats.drops++; 17868c2ecf20Sopenharmony_ci b->bytes += qdisc_pkt_len(ack); 17878c2ecf20Sopenharmony_ci len -= qdisc_pkt_len(ack); 17888c2ecf20Sopenharmony_ci q->buffer_used += skb->truesize - ack->truesize; 17898c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_INGRESS) 17908c2ecf20Sopenharmony_ci cake_advance_shaper(q, b, ack, now, true); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(ack)); 17938c2ecf20Sopenharmony_ci consume_skb(ack); 17948c2ecf20Sopenharmony_ci } else { 17958c2ecf20Sopenharmony_ci sch->q.qlen++; 17968c2ecf20Sopenharmony_ci q->buffer_used += skb->truesize; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* stats */ 18008c2ecf20Sopenharmony_ci b->packets++; 18018c2ecf20Sopenharmony_ci b->bytes += len; 18028c2ecf20Sopenharmony_ci b->backlogs[idx] += len; 18038c2ecf20Sopenharmony_ci b->tin_backlog += len; 18048c2ecf20Sopenharmony_ci sch->qstats.backlog += len; 18058c2ecf20Sopenharmony_ci q->avg_window_bytes += len; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (q->overflow_timeout) 18098c2ecf20Sopenharmony_ci cake_heapify_up(q, b->overflow_idx[idx]); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* incoming bandwidth capacity estimate */ 18128c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_AUTORATE_INGRESS) { 18138c2ecf20Sopenharmony_ci u64 packet_interval = \ 18148c2ecf20Sopenharmony_ci ktime_to_ns(ktime_sub(now, q->last_packet_time)); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (packet_interval > NSEC_PER_SEC) 18178c2ecf20Sopenharmony_ci packet_interval = NSEC_PER_SEC; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci /* filter out short-term bursts, eg. wifi aggregation */ 18208c2ecf20Sopenharmony_ci q->avg_packet_interval = \ 18218c2ecf20Sopenharmony_ci cake_ewma(q->avg_packet_interval, 18228c2ecf20Sopenharmony_ci packet_interval, 18238c2ecf20Sopenharmony_ci (packet_interval > q->avg_packet_interval ? 18248c2ecf20Sopenharmony_ci 2 : 8)); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci q->last_packet_time = now; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (packet_interval > q->avg_packet_interval) { 18298c2ecf20Sopenharmony_ci u64 window_interval = \ 18308c2ecf20Sopenharmony_ci ktime_to_ns(ktime_sub(now, 18318c2ecf20Sopenharmony_ci q->avg_window_begin)); 18328c2ecf20Sopenharmony_ci u64 b = q->avg_window_bytes * (u64)NSEC_PER_SEC; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci b = div64_u64(b, window_interval); 18358c2ecf20Sopenharmony_ci q->avg_peak_bandwidth = 18368c2ecf20Sopenharmony_ci cake_ewma(q->avg_peak_bandwidth, b, 18378c2ecf20Sopenharmony_ci b > q->avg_peak_bandwidth ? 2 : 8); 18388c2ecf20Sopenharmony_ci q->avg_window_bytes = 0; 18398c2ecf20Sopenharmony_ci q->avg_window_begin = now; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (ktime_after(now, 18428c2ecf20Sopenharmony_ci ktime_add_ms(q->last_reconfig_time, 18438c2ecf20Sopenharmony_ci 250))) { 18448c2ecf20Sopenharmony_ci q->rate_bps = (q->avg_peak_bandwidth * 15) >> 4; 18458c2ecf20Sopenharmony_ci cake_reconfigure(sch); 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci } else { 18498c2ecf20Sopenharmony_ci q->avg_window_bytes = 0; 18508c2ecf20Sopenharmony_ci q->last_packet_time = now; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci /* flowchain */ 18548c2ecf20Sopenharmony_ci if (!flow->set || flow->set == CAKE_SET_DECAYING) { 18558c2ecf20Sopenharmony_ci struct cake_host *srchost = &b->hosts[flow->srchost]; 18568c2ecf20Sopenharmony_ci struct cake_host *dsthost = &b->hosts[flow->dsthost]; 18578c2ecf20Sopenharmony_ci u16 host_load = 1; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci if (!flow->set) { 18608c2ecf20Sopenharmony_ci list_add_tail(&flow->flowchain, &b->new_flows); 18618c2ecf20Sopenharmony_ci } else { 18628c2ecf20Sopenharmony_ci b->decaying_flow_count--; 18638c2ecf20Sopenharmony_ci list_move_tail(&flow->flowchain, &b->new_flows); 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci flow->set = CAKE_SET_SPARSE; 18668c2ecf20Sopenharmony_ci b->sparse_flow_count++; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 18698c2ecf20Sopenharmony_ci host_load = max(host_load, srchost->srchost_bulk_flow_count); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 18728c2ecf20Sopenharmony_ci host_load = max(host_load, dsthost->dsthost_bulk_flow_count); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci flow->deficit = (b->flow_quantum * 18758c2ecf20Sopenharmony_ci quantum_div[host_load]) >> 16; 18768c2ecf20Sopenharmony_ci } else if (flow->set == CAKE_SET_SPARSE_WAIT) { 18778c2ecf20Sopenharmony_ci struct cake_host *srchost = &b->hosts[flow->srchost]; 18788c2ecf20Sopenharmony_ci struct cake_host *dsthost = &b->hosts[flow->dsthost]; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci /* this flow was empty, accounted as a sparse flow, but actually 18818c2ecf20Sopenharmony_ci * in the bulk rotation. 18828c2ecf20Sopenharmony_ci */ 18838c2ecf20Sopenharmony_ci flow->set = CAKE_SET_BULK; 18848c2ecf20Sopenharmony_ci b->sparse_flow_count--; 18858c2ecf20Sopenharmony_ci b->bulk_flow_count++; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 18888c2ecf20Sopenharmony_ci srchost->srchost_bulk_flow_count++; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 18918c2ecf20Sopenharmony_ci dsthost->dsthost_bulk_flow_count++; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (q->buffer_used > q->buffer_max_used) 18968c2ecf20Sopenharmony_ci q->buffer_max_used = q->buffer_used; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (q->buffer_used > q->buffer_limit) { 18998c2ecf20Sopenharmony_ci u32 dropped = 0; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci while (q->buffer_used > q->buffer_limit) { 19028c2ecf20Sopenharmony_ci dropped++; 19038c2ecf20Sopenharmony_ci cake_drop(sch, to_free); 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci b->drop_overlimit += dropped; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci return NET_XMIT_SUCCESS; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic struct sk_buff *cake_dequeue_one(struct Qdisc *sch) 19118c2ecf20Sopenharmony_ci{ 19128c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 19138c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[q->cur_tin]; 19148c2ecf20Sopenharmony_ci struct cake_flow *flow = &b->flows[q->cur_flow]; 19158c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 19168c2ecf20Sopenharmony_ci u32 len; 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (flow->head) { 19198c2ecf20Sopenharmony_ci skb = dequeue_head(flow); 19208c2ecf20Sopenharmony_ci len = qdisc_pkt_len(skb); 19218c2ecf20Sopenharmony_ci b->backlogs[q->cur_flow] -= len; 19228c2ecf20Sopenharmony_ci b->tin_backlog -= len; 19238c2ecf20Sopenharmony_ci sch->qstats.backlog -= len; 19248c2ecf20Sopenharmony_ci q->buffer_used -= skb->truesize; 19258c2ecf20Sopenharmony_ci sch->q.qlen--; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (q->overflow_timeout) 19288c2ecf20Sopenharmony_ci cake_heapify(q, b->overflow_idx[q->cur_flow]); 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci return skb; 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci/* Discard leftover packets from a tin no longer in use. */ 19348c2ecf20Sopenharmony_cistatic void cake_clear_tin(struct Qdisc *sch, u16 tin) 19358c2ecf20Sopenharmony_ci{ 19368c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 19378c2ecf20Sopenharmony_ci struct sk_buff *skb; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci q->cur_tin = tin; 19408c2ecf20Sopenharmony_ci for (q->cur_flow = 0; q->cur_flow < CAKE_QUEUES; q->cur_flow++) 19418c2ecf20Sopenharmony_ci while (!!(skb = cake_dequeue_one(sch))) 19428c2ecf20Sopenharmony_ci kfree_skb(skb); 19438c2ecf20Sopenharmony_ci} 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_cistatic struct sk_buff *cake_dequeue(struct Qdisc *sch) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 19488c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[q->cur_tin]; 19498c2ecf20Sopenharmony_ci struct cake_host *srchost, *dsthost; 19508c2ecf20Sopenharmony_ci ktime_t now = ktime_get(); 19518c2ecf20Sopenharmony_ci struct cake_flow *flow; 19528c2ecf20Sopenharmony_ci struct list_head *head; 19538c2ecf20Sopenharmony_ci bool first_flow = true; 19548c2ecf20Sopenharmony_ci struct sk_buff *skb; 19558c2ecf20Sopenharmony_ci u16 host_load; 19568c2ecf20Sopenharmony_ci u64 delay; 19578c2ecf20Sopenharmony_ci u32 len; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cibegin: 19608c2ecf20Sopenharmony_ci if (!sch->q.qlen) 19618c2ecf20Sopenharmony_ci return NULL; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci /* global hard shaper */ 19648c2ecf20Sopenharmony_ci if (ktime_after(q->time_next_packet, now) && 19658c2ecf20Sopenharmony_ci ktime_after(q->failsafe_next_packet, now)) { 19668c2ecf20Sopenharmony_ci u64 next = min(ktime_to_ns(q->time_next_packet), 19678c2ecf20Sopenharmony_ci ktime_to_ns(q->failsafe_next_packet)); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci sch->qstats.overlimits++; 19708c2ecf20Sopenharmony_ci qdisc_watchdog_schedule_ns(&q->watchdog, next); 19718c2ecf20Sopenharmony_ci return NULL; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* Choose a class to work on. */ 19758c2ecf20Sopenharmony_ci if (!q->rate_ns) { 19768c2ecf20Sopenharmony_ci /* In unlimited mode, can't rely on shaper timings, just balance 19778c2ecf20Sopenharmony_ci * with DRR 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci bool wrapped = false, empty = true; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci while (b->tin_deficit < 0 || 19828c2ecf20Sopenharmony_ci !(b->sparse_flow_count + b->bulk_flow_count)) { 19838c2ecf20Sopenharmony_ci if (b->tin_deficit <= 0) 19848c2ecf20Sopenharmony_ci b->tin_deficit += b->tin_quantum; 19858c2ecf20Sopenharmony_ci if (b->sparse_flow_count + b->bulk_flow_count) 19868c2ecf20Sopenharmony_ci empty = false; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci q->cur_tin++; 19898c2ecf20Sopenharmony_ci b++; 19908c2ecf20Sopenharmony_ci if (q->cur_tin >= q->tin_cnt) { 19918c2ecf20Sopenharmony_ci q->cur_tin = 0; 19928c2ecf20Sopenharmony_ci b = q->tins; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci if (wrapped) { 19958c2ecf20Sopenharmony_ci /* It's possible for q->qlen to be 19968c2ecf20Sopenharmony_ci * nonzero when we actually have no 19978c2ecf20Sopenharmony_ci * packets anywhere. 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ci if (empty) 20008c2ecf20Sopenharmony_ci return NULL; 20018c2ecf20Sopenharmony_ci } else { 20028c2ecf20Sopenharmony_ci wrapped = true; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci } else { 20078c2ecf20Sopenharmony_ci /* In shaped mode, choose: 20088c2ecf20Sopenharmony_ci * - Highest-priority tin with queue and meeting schedule, or 20098c2ecf20Sopenharmony_ci * - The earliest-scheduled tin with queue. 20108c2ecf20Sopenharmony_ci */ 20118c2ecf20Sopenharmony_ci ktime_t best_time = KTIME_MAX; 20128c2ecf20Sopenharmony_ci int tin, best_tin = 0; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci for (tin = 0; tin < q->tin_cnt; tin++) { 20158c2ecf20Sopenharmony_ci b = q->tins + tin; 20168c2ecf20Sopenharmony_ci if ((b->sparse_flow_count + b->bulk_flow_count) > 0) { 20178c2ecf20Sopenharmony_ci ktime_t time_to_pkt = \ 20188c2ecf20Sopenharmony_ci ktime_sub(b->time_next_packet, now); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (ktime_to_ns(time_to_pkt) <= 0 || 20218c2ecf20Sopenharmony_ci ktime_compare(time_to_pkt, 20228c2ecf20Sopenharmony_ci best_time) <= 0) { 20238c2ecf20Sopenharmony_ci best_time = time_to_pkt; 20248c2ecf20Sopenharmony_ci best_tin = tin; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci q->cur_tin = best_tin; 20308c2ecf20Sopenharmony_ci b = q->tins + best_tin; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* No point in going further if no packets to deliver. */ 20338c2ecf20Sopenharmony_ci if (unlikely(!(b->sparse_flow_count + b->bulk_flow_count))) 20348c2ecf20Sopenharmony_ci return NULL; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ciretry: 20388c2ecf20Sopenharmony_ci /* service this class */ 20398c2ecf20Sopenharmony_ci head = &b->decaying_flows; 20408c2ecf20Sopenharmony_ci if (!first_flow || list_empty(head)) { 20418c2ecf20Sopenharmony_ci head = &b->new_flows; 20428c2ecf20Sopenharmony_ci if (list_empty(head)) { 20438c2ecf20Sopenharmony_ci head = &b->old_flows; 20448c2ecf20Sopenharmony_ci if (unlikely(list_empty(head))) { 20458c2ecf20Sopenharmony_ci head = &b->decaying_flows; 20468c2ecf20Sopenharmony_ci if (unlikely(list_empty(head))) 20478c2ecf20Sopenharmony_ci goto begin; 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci flow = list_first_entry(head, struct cake_flow, flowchain); 20528c2ecf20Sopenharmony_ci q->cur_flow = flow - b->flows; 20538c2ecf20Sopenharmony_ci first_flow = false; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* triple isolation (modified DRR++) */ 20568c2ecf20Sopenharmony_ci srchost = &b->hosts[flow->srchost]; 20578c2ecf20Sopenharmony_ci dsthost = &b->hosts[flow->dsthost]; 20588c2ecf20Sopenharmony_ci host_load = 1; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* flow isolation (DRR++) */ 20618c2ecf20Sopenharmony_ci if (flow->deficit <= 0) { 20628c2ecf20Sopenharmony_ci /* Keep all flows with deficits out of the sparse and decaying 20638c2ecf20Sopenharmony_ci * rotations. No non-empty flow can go into the decaying 20648c2ecf20Sopenharmony_ci * rotation, so they can't get deficits 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_ci if (flow->set == CAKE_SET_SPARSE) { 20678c2ecf20Sopenharmony_ci if (flow->head) { 20688c2ecf20Sopenharmony_ci b->sparse_flow_count--; 20698c2ecf20Sopenharmony_ci b->bulk_flow_count++; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 20728c2ecf20Sopenharmony_ci srchost->srchost_bulk_flow_count++; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 20758c2ecf20Sopenharmony_ci dsthost->dsthost_bulk_flow_count++; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci flow->set = CAKE_SET_BULK; 20788c2ecf20Sopenharmony_ci } else { 20798c2ecf20Sopenharmony_ci /* we've moved it to the bulk rotation for 20808c2ecf20Sopenharmony_ci * correct deficit accounting but we still want 20818c2ecf20Sopenharmony_ci * to count it as a sparse flow, not a bulk one. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ci flow->set = CAKE_SET_SPARSE_WAIT; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 20888c2ecf20Sopenharmony_ci host_load = max(host_load, srchost->srchost_bulk_flow_count); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 20918c2ecf20Sopenharmony_ci host_load = max(host_load, dsthost->dsthost_bulk_flow_count); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci WARN_ON(host_load > CAKE_QUEUES); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci /* The shifted prandom_u32() is a way to apply dithering to 20968c2ecf20Sopenharmony_ci * avoid accumulating roundoff errors 20978c2ecf20Sopenharmony_ci */ 20988c2ecf20Sopenharmony_ci flow->deficit += (b->flow_quantum * quantum_div[host_load] + 20998c2ecf20Sopenharmony_ci (prandom_u32() >> 16)) >> 16; 21008c2ecf20Sopenharmony_ci list_move_tail(&flow->flowchain, &b->old_flows); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci goto retry; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* Retrieve a packet via the AQM */ 21068c2ecf20Sopenharmony_ci while (1) { 21078c2ecf20Sopenharmony_ci skb = cake_dequeue_one(sch); 21088c2ecf20Sopenharmony_ci if (!skb) { 21098c2ecf20Sopenharmony_ci /* this queue was actually empty */ 21108c2ecf20Sopenharmony_ci if (cobalt_queue_empty(&flow->cvars, &b->cparams, now)) 21118c2ecf20Sopenharmony_ci b->unresponsive_flow_count--; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (flow->cvars.p_drop || flow->cvars.count || 21148c2ecf20Sopenharmony_ci ktime_before(now, flow->cvars.drop_next)) { 21158c2ecf20Sopenharmony_ci /* keep in the flowchain until the state has 21168c2ecf20Sopenharmony_ci * decayed to rest 21178c2ecf20Sopenharmony_ci */ 21188c2ecf20Sopenharmony_ci list_move_tail(&flow->flowchain, 21198c2ecf20Sopenharmony_ci &b->decaying_flows); 21208c2ecf20Sopenharmony_ci if (flow->set == CAKE_SET_BULK) { 21218c2ecf20Sopenharmony_ci b->bulk_flow_count--; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 21248c2ecf20Sopenharmony_ci srchost->srchost_bulk_flow_count--; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 21278c2ecf20Sopenharmony_ci dsthost->dsthost_bulk_flow_count--; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci b->decaying_flow_count++; 21308c2ecf20Sopenharmony_ci } else if (flow->set == CAKE_SET_SPARSE || 21318c2ecf20Sopenharmony_ci flow->set == CAKE_SET_SPARSE_WAIT) { 21328c2ecf20Sopenharmony_ci b->sparse_flow_count--; 21338c2ecf20Sopenharmony_ci b->decaying_flow_count++; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci flow->set = CAKE_SET_DECAYING; 21368c2ecf20Sopenharmony_ci } else { 21378c2ecf20Sopenharmony_ci /* remove empty queue from the flowchain */ 21388c2ecf20Sopenharmony_ci list_del_init(&flow->flowchain); 21398c2ecf20Sopenharmony_ci if (flow->set == CAKE_SET_SPARSE || 21408c2ecf20Sopenharmony_ci flow->set == CAKE_SET_SPARSE_WAIT) 21418c2ecf20Sopenharmony_ci b->sparse_flow_count--; 21428c2ecf20Sopenharmony_ci else if (flow->set == CAKE_SET_BULK) { 21438c2ecf20Sopenharmony_ci b->bulk_flow_count--; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (cake_dsrc(q->flow_mode)) 21468c2ecf20Sopenharmony_ci srchost->srchost_bulk_flow_count--; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci if (cake_ddst(q->flow_mode)) 21498c2ecf20Sopenharmony_ci dsthost->dsthost_bulk_flow_count--; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci } else 21528c2ecf20Sopenharmony_ci b->decaying_flow_count--; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci flow->set = CAKE_SET_NONE; 21558c2ecf20Sopenharmony_ci } 21568c2ecf20Sopenharmony_ci goto begin; 21578c2ecf20Sopenharmony_ci } 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* Last packet in queue may be marked, shouldn't be dropped */ 21608c2ecf20Sopenharmony_ci if (!cobalt_should_drop(&flow->cvars, &b->cparams, now, skb, 21618c2ecf20Sopenharmony_ci (b->bulk_flow_count * 21628c2ecf20Sopenharmony_ci !!(q->rate_flags & 21638c2ecf20Sopenharmony_ci CAKE_FLAG_INGRESS))) || 21648c2ecf20Sopenharmony_ci !flow->head) 21658c2ecf20Sopenharmony_ci break; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci /* drop this packet, get another one */ 21688c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_INGRESS) { 21698c2ecf20Sopenharmony_ci len = cake_advance_shaper(q, b, skb, 21708c2ecf20Sopenharmony_ci now, true); 21718c2ecf20Sopenharmony_ci flow->deficit -= len; 21728c2ecf20Sopenharmony_ci b->tin_deficit -= len; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci flow->dropped++; 21758c2ecf20Sopenharmony_ci b->tin_dropped++; 21768c2ecf20Sopenharmony_ci qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb)); 21778c2ecf20Sopenharmony_ci qdisc_qstats_drop(sch); 21788c2ecf20Sopenharmony_ci kfree_skb(skb); 21798c2ecf20Sopenharmony_ci if (q->rate_flags & CAKE_FLAG_INGRESS) 21808c2ecf20Sopenharmony_ci goto retry; 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci b->tin_ecn_mark += !!flow->cvars.ecn_marked; 21848c2ecf20Sopenharmony_ci qdisc_bstats_update(sch, skb); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci /* collect delay stats */ 21878c2ecf20Sopenharmony_ci delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb))); 21888c2ecf20Sopenharmony_ci b->avge_delay = cake_ewma(b->avge_delay, delay, 8); 21898c2ecf20Sopenharmony_ci b->peak_delay = cake_ewma(b->peak_delay, delay, 21908c2ecf20Sopenharmony_ci delay > b->peak_delay ? 2 : 8); 21918c2ecf20Sopenharmony_ci b->base_delay = cake_ewma(b->base_delay, delay, 21928c2ecf20Sopenharmony_ci delay < b->base_delay ? 2 : 8); 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci len = cake_advance_shaper(q, b, skb, now, false); 21958c2ecf20Sopenharmony_ci flow->deficit -= len; 21968c2ecf20Sopenharmony_ci b->tin_deficit -= len; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (ktime_after(q->time_next_packet, now) && sch->q.qlen) { 21998c2ecf20Sopenharmony_ci u64 next = min(ktime_to_ns(q->time_next_packet), 22008c2ecf20Sopenharmony_ci ktime_to_ns(q->failsafe_next_packet)); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci qdisc_watchdog_schedule_ns(&q->watchdog, next); 22038c2ecf20Sopenharmony_ci } else if (!sch->q.qlen) { 22048c2ecf20Sopenharmony_ci int i; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci for (i = 0; i < q->tin_cnt; i++) { 22078c2ecf20Sopenharmony_ci if (q->tins[i].decaying_flow_count) { 22088c2ecf20Sopenharmony_ci ktime_t next = \ 22098c2ecf20Sopenharmony_ci ktime_add_ns(now, 22108c2ecf20Sopenharmony_ci q->tins[i].cparams.target); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci qdisc_watchdog_schedule_ns(&q->watchdog, 22138c2ecf20Sopenharmony_ci ktime_to_ns(next)); 22148c2ecf20Sopenharmony_ci break; 22158c2ecf20Sopenharmony_ci } 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci if (q->overflow_timeout) 22208c2ecf20Sopenharmony_ci q->overflow_timeout--; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci return skb; 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_cistatic void cake_reset(struct Qdisc *sch) 22268c2ecf20Sopenharmony_ci{ 22278c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 22288c2ecf20Sopenharmony_ci u32 c; 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (!q->tins) 22318c2ecf20Sopenharmony_ci return; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci for (c = 0; c < CAKE_MAX_TINS; c++) 22348c2ecf20Sopenharmony_ci cake_clear_tin(sch, c); 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_cistatic const struct nla_policy cake_policy[TCA_CAKE_MAX + 1] = { 22388c2ecf20Sopenharmony_ci [TCA_CAKE_BASE_RATE64] = { .type = NLA_U64 }, 22398c2ecf20Sopenharmony_ci [TCA_CAKE_DIFFSERV_MODE] = { .type = NLA_U32 }, 22408c2ecf20Sopenharmony_ci [TCA_CAKE_ATM] = { .type = NLA_U32 }, 22418c2ecf20Sopenharmony_ci [TCA_CAKE_FLOW_MODE] = { .type = NLA_U32 }, 22428c2ecf20Sopenharmony_ci [TCA_CAKE_OVERHEAD] = { .type = NLA_S32 }, 22438c2ecf20Sopenharmony_ci [TCA_CAKE_RTT] = { .type = NLA_U32 }, 22448c2ecf20Sopenharmony_ci [TCA_CAKE_TARGET] = { .type = NLA_U32 }, 22458c2ecf20Sopenharmony_ci [TCA_CAKE_AUTORATE] = { .type = NLA_U32 }, 22468c2ecf20Sopenharmony_ci [TCA_CAKE_MEMORY] = { .type = NLA_U32 }, 22478c2ecf20Sopenharmony_ci [TCA_CAKE_NAT] = { .type = NLA_U32 }, 22488c2ecf20Sopenharmony_ci [TCA_CAKE_RAW] = { .type = NLA_U32 }, 22498c2ecf20Sopenharmony_ci [TCA_CAKE_WASH] = { .type = NLA_U32 }, 22508c2ecf20Sopenharmony_ci [TCA_CAKE_MPU] = { .type = NLA_U32 }, 22518c2ecf20Sopenharmony_ci [TCA_CAKE_INGRESS] = { .type = NLA_U32 }, 22528c2ecf20Sopenharmony_ci [TCA_CAKE_ACK_FILTER] = { .type = NLA_U32 }, 22538c2ecf20Sopenharmony_ci [TCA_CAKE_SPLIT_GSO] = { .type = NLA_U32 }, 22548c2ecf20Sopenharmony_ci [TCA_CAKE_FWMARK] = { .type = NLA_U32 }, 22558c2ecf20Sopenharmony_ci}; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_cistatic void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, 22588c2ecf20Sopenharmony_ci u64 target_ns, u64 rtt_est_ns) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci /* convert byte-rate into time-per-byte 22618c2ecf20Sopenharmony_ci * so it will always unwedge in reasonable time. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci static const u64 MIN_RATE = 64; 22648c2ecf20Sopenharmony_ci u32 byte_target = mtu; 22658c2ecf20Sopenharmony_ci u64 byte_target_ns; 22668c2ecf20Sopenharmony_ci u8 rate_shft = 0; 22678c2ecf20Sopenharmony_ci u64 rate_ns = 0; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci b->flow_quantum = 1514; 22708c2ecf20Sopenharmony_ci if (rate) { 22718c2ecf20Sopenharmony_ci b->flow_quantum = max(min(rate >> 12, 1514ULL), 300ULL); 22728c2ecf20Sopenharmony_ci rate_shft = 34; 22738c2ecf20Sopenharmony_ci rate_ns = ((u64)NSEC_PER_SEC) << rate_shft; 22748c2ecf20Sopenharmony_ci rate_ns = div64_u64(rate_ns, max(MIN_RATE, rate)); 22758c2ecf20Sopenharmony_ci while (!!(rate_ns >> 34)) { 22768c2ecf20Sopenharmony_ci rate_ns >>= 1; 22778c2ecf20Sopenharmony_ci rate_shft--; 22788c2ecf20Sopenharmony_ci } 22798c2ecf20Sopenharmony_ci } /* else unlimited, ie. zero delay */ 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci b->tin_rate_bps = rate; 22828c2ecf20Sopenharmony_ci b->tin_rate_ns = rate_ns; 22838c2ecf20Sopenharmony_ci b->tin_rate_shft = rate_shft; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci byte_target_ns = (byte_target * rate_ns) >> rate_shft; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci b->cparams.target = max((byte_target_ns * 3) / 2, target_ns); 22888c2ecf20Sopenharmony_ci b->cparams.interval = max(rtt_est_ns + 22898c2ecf20Sopenharmony_ci b->cparams.target - target_ns, 22908c2ecf20Sopenharmony_ci b->cparams.target * 2); 22918c2ecf20Sopenharmony_ci b->cparams.mtu_time = byte_target_ns; 22928c2ecf20Sopenharmony_ci b->cparams.p_inc = 1 << 24; /* 1/256 */ 22938c2ecf20Sopenharmony_ci b->cparams.p_dec = 1 << 20; /* 1/4096 */ 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic int cake_config_besteffort(struct Qdisc *sch) 22978c2ecf20Sopenharmony_ci{ 22988c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 22998c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[0]; 23008c2ecf20Sopenharmony_ci u32 mtu = psched_mtu(qdisc_dev(sch)); 23018c2ecf20Sopenharmony_ci u64 rate = q->rate_bps; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci q->tin_cnt = 1; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci q->tin_index = besteffort; 23068c2ecf20Sopenharmony_ci q->tin_order = normal_order; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci cake_set_rate(b, rate, mtu, 23098c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 23108c2ecf20Sopenharmony_ci b->tin_quantum = 65535; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci return 0; 23138c2ecf20Sopenharmony_ci} 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_cistatic int cake_config_precedence(struct Qdisc *sch) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci /* convert high-level (user visible) parameters into internal format */ 23188c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 23198c2ecf20Sopenharmony_ci u32 mtu = psched_mtu(qdisc_dev(sch)); 23208c2ecf20Sopenharmony_ci u64 rate = q->rate_bps; 23218c2ecf20Sopenharmony_ci u32 quantum = 256; 23228c2ecf20Sopenharmony_ci u32 i; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci q->tin_cnt = 8; 23258c2ecf20Sopenharmony_ci q->tin_index = precedence; 23268c2ecf20Sopenharmony_ci q->tin_order = normal_order; 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci for (i = 0; i < q->tin_cnt; i++) { 23298c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[i]; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci cake_set_rate(b, rate, mtu, us_to_ns(q->target), 23328c2ecf20Sopenharmony_ci us_to_ns(q->interval)); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci b->tin_quantum = max_t(u16, 1U, quantum); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci /* calculate next class's parameters */ 23378c2ecf20Sopenharmony_ci rate *= 7; 23388c2ecf20Sopenharmony_ci rate >>= 3; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci quantum *= 7; 23418c2ecf20Sopenharmony_ci quantum >>= 3; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci return 0; 23458c2ecf20Sopenharmony_ci} 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci/* List of known Diffserv codepoints: 23488c2ecf20Sopenharmony_ci * 23498c2ecf20Sopenharmony_ci * Least Effort (CS1) 23508c2ecf20Sopenharmony_ci * Best Effort (CS0) 23518c2ecf20Sopenharmony_ci * Max Reliability & LLT "Lo" (TOS1) 23528c2ecf20Sopenharmony_ci * Max Throughput (TOS2) 23538c2ecf20Sopenharmony_ci * Min Delay (TOS4) 23548c2ecf20Sopenharmony_ci * LLT "La" (TOS5) 23558c2ecf20Sopenharmony_ci * Assured Forwarding 1 (AF1x) - x3 23568c2ecf20Sopenharmony_ci * Assured Forwarding 2 (AF2x) - x3 23578c2ecf20Sopenharmony_ci * Assured Forwarding 3 (AF3x) - x3 23588c2ecf20Sopenharmony_ci * Assured Forwarding 4 (AF4x) - x3 23598c2ecf20Sopenharmony_ci * Precedence Class 2 (CS2) 23608c2ecf20Sopenharmony_ci * Precedence Class 3 (CS3) 23618c2ecf20Sopenharmony_ci * Precedence Class 4 (CS4) 23628c2ecf20Sopenharmony_ci * Precedence Class 5 (CS5) 23638c2ecf20Sopenharmony_ci * Precedence Class 6 (CS6) 23648c2ecf20Sopenharmony_ci * Precedence Class 7 (CS7) 23658c2ecf20Sopenharmony_ci * Voice Admit (VA) 23668c2ecf20Sopenharmony_ci * Expedited Forwarding (EF) 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci * Total 25 codepoints. 23698c2ecf20Sopenharmony_ci */ 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci/* List of traffic classes in RFC 4594: 23728c2ecf20Sopenharmony_ci * (roughly descending order of contended priority) 23738c2ecf20Sopenharmony_ci * (roughly ascending order of uncontended throughput) 23748c2ecf20Sopenharmony_ci * 23758c2ecf20Sopenharmony_ci * Network Control (CS6,CS7) - routing traffic 23768c2ecf20Sopenharmony_ci * Telephony (EF,VA) - aka. VoIP streams 23778c2ecf20Sopenharmony_ci * Signalling (CS5) - VoIP setup 23788c2ecf20Sopenharmony_ci * Multimedia Conferencing (AF4x) - aka. video calls 23798c2ecf20Sopenharmony_ci * Realtime Interactive (CS4) - eg. games 23808c2ecf20Sopenharmony_ci * Multimedia Streaming (AF3x) - eg. YouTube, NetFlix, Twitch 23818c2ecf20Sopenharmony_ci * Broadcast Video (CS3) 23828c2ecf20Sopenharmony_ci * Low Latency Data (AF2x,TOS4) - eg. database 23838c2ecf20Sopenharmony_ci * Ops, Admin, Management (CS2,TOS1) - eg. ssh 23848c2ecf20Sopenharmony_ci * Standard Service (CS0 & unrecognised codepoints) 23858c2ecf20Sopenharmony_ci * High Throughput Data (AF1x,TOS2) - eg. web traffic 23868c2ecf20Sopenharmony_ci * Low Priority Data (CS1) - eg. BitTorrent 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci * Total 12 traffic classes. 23898c2ecf20Sopenharmony_ci */ 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_cistatic int cake_config_diffserv8(struct Qdisc *sch) 23928c2ecf20Sopenharmony_ci{ 23938c2ecf20Sopenharmony_ci/* Pruned list of traffic classes for typical applications: 23948c2ecf20Sopenharmony_ci * 23958c2ecf20Sopenharmony_ci * Network Control (CS6, CS7) 23968c2ecf20Sopenharmony_ci * Minimum Latency (EF, VA, CS5, CS4) 23978c2ecf20Sopenharmony_ci * Interactive Shell (CS2, TOS1) 23988c2ecf20Sopenharmony_ci * Low Latency Transactions (AF2x, TOS4) 23998c2ecf20Sopenharmony_ci * Video Streaming (AF4x, AF3x, CS3) 24008c2ecf20Sopenharmony_ci * Bog Standard (CS0 etc.) 24018c2ecf20Sopenharmony_ci * High Throughput (AF1x, TOS2) 24028c2ecf20Sopenharmony_ci * Background Traffic (CS1) 24038c2ecf20Sopenharmony_ci * 24048c2ecf20Sopenharmony_ci * Total 8 traffic classes. 24058c2ecf20Sopenharmony_ci */ 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 24088c2ecf20Sopenharmony_ci u32 mtu = psched_mtu(qdisc_dev(sch)); 24098c2ecf20Sopenharmony_ci u64 rate = q->rate_bps; 24108c2ecf20Sopenharmony_ci u32 quantum = 256; 24118c2ecf20Sopenharmony_ci u32 i; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci q->tin_cnt = 8; 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci /* codepoint to class mapping */ 24168c2ecf20Sopenharmony_ci q->tin_index = diffserv8; 24178c2ecf20Sopenharmony_ci q->tin_order = normal_order; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci /* class characteristics */ 24208c2ecf20Sopenharmony_ci for (i = 0; i < q->tin_cnt; i++) { 24218c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[i]; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci cake_set_rate(b, rate, mtu, us_to_ns(q->target), 24248c2ecf20Sopenharmony_ci us_to_ns(q->interval)); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci b->tin_quantum = max_t(u16, 1U, quantum); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci /* calculate next class's parameters */ 24298c2ecf20Sopenharmony_ci rate *= 7; 24308c2ecf20Sopenharmony_ci rate >>= 3; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci quantum *= 7; 24338c2ecf20Sopenharmony_ci quantum >>= 3; 24348c2ecf20Sopenharmony_ci } 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci return 0; 24378c2ecf20Sopenharmony_ci} 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_cistatic int cake_config_diffserv4(struct Qdisc *sch) 24408c2ecf20Sopenharmony_ci{ 24418c2ecf20Sopenharmony_ci/* Further pruned list of traffic classes for four-class system: 24428c2ecf20Sopenharmony_ci * 24438c2ecf20Sopenharmony_ci * Latency Sensitive (CS7, CS6, EF, VA, CS5, CS4) 24448c2ecf20Sopenharmony_ci * Streaming Media (AF4x, AF3x, CS3, AF2x, TOS4, CS2, TOS1) 24458c2ecf20Sopenharmony_ci * Best Effort (CS0, AF1x, TOS2, and those not specified) 24468c2ecf20Sopenharmony_ci * Background Traffic (CS1) 24478c2ecf20Sopenharmony_ci * 24488c2ecf20Sopenharmony_ci * Total 4 traffic classes. 24498c2ecf20Sopenharmony_ci */ 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 24528c2ecf20Sopenharmony_ci u32 mtu = psched_mtu(qdisc_dev(sch)); 24538c2ecf20Sopenharmony_ci u64 rate = q->rate_bps; 24548c2ecf20Sopenharmony_ci u32 quantum = 1024; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci q->tin_cnt = 4; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci /* codepoint to class mapping */ 24598c2ecf20Sopenharmony_ci q->tin_index = diffserv4; 24608c2ecf20Sopenharmony_ci q->tin_order = bulk_order; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci /* class characteristics */ 24638c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[0], rate, mtu, 24648c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 24658c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[1], rate >> 4, mtu, 24668c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 24678c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[2], rate >> 1, mtu, 24688c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 24698c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[3], rate >> 2, mtu, 24708c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci /* bandwidth-sharing weights */ 24738c2ecf20Sopenharmony_ci q->tins[0].tin_quantum = quantum; 24748c2ecf20Sopenharmony_ci q->tins[1].tin_quantum = quantum >> 4; 24758c2ecf20Sopenharmony_ci q->tins[2].tin_quantum = quantum >> 1; 24768c2ecf20Sopenharmony_ci q->tins[3].tin_quantum = quantum >> 2; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci return 0; 24798c2ecf20Sopenharmony_ci} 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_cistatic int cake_config_diffserv3(struct Qdisc *sch) 24828c2ecf20Sopenharmony_ci{ 24838c2ecf20Sopenharmony_ci/* Simplified Diffserv structure with 3 tins. 24848c2ecf20Sopenharmony_ci * Low Priority (CS1) 24858c2ecf20Sopenharmony_ci * Best Effort 24868c2ecf20Sopenharmony_ci * Latency Sensitive (TOS4, VA, EF, CS6, CS7) 24878c2ecf20Sopenharmony_ci */ 24888c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 24898c2ecf20Sopenharmony_ci u32 mtu = psched_mtu(qdisc_dev(sch)); 24908c2ecf20Sopenharmony_ci u64 rate = q->rate_bps; 24918c2ecf20Sopenharmony_ci u32 quantum = 1024; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci q->tin_cnt = 3; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci /* codepoint to class mapping */ 24968c2ecf20Sopenharmony_ci q->tin_index = diffserv3; 24978c2ecf20Sopenharmony_ci q->tin_order = bulk_order; 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci /* class characteristics */ 25008c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[0], rate, mtu, 25018c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 25028c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[1], rate >> 4, mtu, 25038c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 25048c2ecf20Sopenharmony_ci cake_set_rate(&q->tins[2], rate >> 2, mtu, 25058c2ecf20Sopenharmony_ci us_to_ns(q->target), us_to_ns(q->interval)); 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci /* bandwidth-sharing weights */ 25088c2ecf20Sopenharmony_ci q->tins[0].tin_quantum = quantum; 25098c2ecf20Sopenharmony_ci q->tins[1].tin_quantum = quantum >> 4; 25108c2ecf20Sopenharmony_ci q->tins[2].tin_quantum = quantum >> 2; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci return 0; 25138c2ecf20Sopenharmony_ci} 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_cistatic void cake_reconfigure(struct Qdisc *sch) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 25188c2ecf20Sopenharmony_ci int c, ft; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci switch (q->tin_mode) { 25218c2ecf20Sopenharmony_ci case CAKE_DIFFSERV_BESTEFFORT: 25228c2ecf20Sopenharmony_ci ft = cake_config_besteffort(sch); 25238c2ecf20Sopenharmony_ci break; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci case CAKE_DIFFSERV_PRECEDENCE: 25268c2ecf20Sopenharmony_ci ft = cake_config_precedence(sch); 25278c2ecf20Sopenharmony_ci break; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci case CAKE_DIFFSERV_DIFFSERV8: 25308c2ecf20Sopenharmony_ci ft = cake_config_diffserv8(sch); 25318c2ecf20Sopenharmony_ci break; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci case CAKE_DIFFSERV_DIFFSERV4: 25348c2ecf20Sopenharmony_ci ft = cake_config_diffserv4(sch); 25358c2ecf20Sopenharmony_ci break; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci case CAKE_DIFFSERV_DIFFSERV3: 25388c2ecf20Sopenharmony_ci default: 25398c2ecf20Sopenharmony_ci ft = cake_config_diffserv3(sch); 25408c2ecf20Sopenharmony_ci break; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci for (c = q->tin_cnt; c < CAKE_MAX_TINS; c++) { 25448c2ecf20Sopenharmony_ci cake_clear_tin(sch, c); 25458c2ecf20Sopenharmony_ci q->tins[c].cparams.mtu_time = q->tins[ft].cparams.mtu_time; 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci q->rate_ns = q->tins[ft].tin_rate_ns; 25498c2ecf20Sopenharmony_ci q->rate_shft = q->tins[ft].tin_rate_shft; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci if (q->buffer_config_limit) { 25528c2ecf20Sopenharmony_ci q->buffer_limit = q->buffer_config_limit; 25538c2ecf20Sopenharmony_ci } else if (q->rate_bps) { 25548c2ecf20Sopenharmony_ci u64 t = q->rate_bps * q->interval; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci do_div(t, USEC_PER_SEC / 4); 25578c2ecf20Sopenharmony_ci q->buffer_limit = max_t(u32, t, 4U << 20); 25588c2ecf20Sopenharmony_ci } else { 25598c2ecf20Sopenharmony_ci q->buffer_limit = ~0; 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci sch->flags &= ~TCQ_F_CAN_BYPASS; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci q->buffer_limit = min(q->buffer_limit, 25658c2ecf20Sopenharmony_ci max(sch->limit * psched_mtu(qdisc_dev(sch)), 25668c2ecf20Sopenharmony_ci q->buffer_config_limit)); 25678c2ecf20Sopenharmony_ci} 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_cistatic int cake_change(struct Qdisc *sch, struct nlattr *opt, 25708c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 25718c2ecf20Sopenharmony_ci{ 25728c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 25738c2ecf20Sopenharmony_ci struct nlattr *tb[TCA_CAKE_MAX + 1]; 25748c2ecf20Sopenharmony_ci int err; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci if (!opt) 25778c2ecf20Sopenharmony_ci return -EINVAL; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(tb, TCA_CAKE_MAX, opt, cake_policy, 25808c2ecf20Sopenharmony_ci extack); 25818c2ecf20Sopenharmony_ci if (err < 0) 25828c2ecf20Sopenharmony_ci return err; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_NAT]) { 25858c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_CONNTRACK) 25868c2ecf20Sopenharmony_ci q->flow_mode &= ~CAKE_FLOW_NAT_FLAG; 25878c2ecf20Sopenharmony_ci q->flow_mode |= CAKE_FLOW_NAT_FLAG * 25888c2ecf20Sopenharmony_ci !!nla_get_u32(tb[TCA_CAKE_NAT]); 25898c2ecf20Sopenharmony_ci#else 25908c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_ATTR(extack, tb[TCA_CAKE_NAT], 25918c2ecf20Sopenharmony_ci "No conntrack support in kernel"); 25928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25938c2ecf20Sopenharmony_ci#endif 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_BASE_RATE64]) 25978c2ecf20Sopenharmony_ci q->rate_bps = nla_get_u64(tb[TCA_CAKE_BASE_RATE64]); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_DIFFSERV_MODE]) 26008c2ecf20Sopenharmony_ci q->tin_mode = nla_get_u32(tb[TCA_CAKE_DIFFSERV_MODE]); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_WASH]) { 26038c2ecf20Sopenharmony_ci if (!!nla_get_u32(tb[TCA_CAKE_WASH])) 26048c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_WASH; 26058c2ecf20Sopenharmony_ci else 26068c2ecf20Sopenharmony_ci q->rate_flags &= ~CAKE_FLAG_WASH; 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_FLOW_MODE]) 26108c2ecf20Sopenharmony_ci q->flow_mode = ((q->flow_mode & CAKE_FLOW_NAT_FLAG) | 26118c2ecf20Sopenharmony_ci (nla_get_u32(tb[TCA_CAKE_FLOW_MODE]) & 26128c2ecf20Sopenharmony_ci CAKE_FLOW_MASK)); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_ATM]) 26158c2ecf20Sopenharmony_ci q->atm_mode = nla_get_u32(tb[TCA_CAKE_ATM]); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_OVERHEAD]) { 26188c2ecf20Sopenharmony_ci q->rate_overhead = nla_get_s32(tb[TCA_CAKE_OVERHEAD]); 26198c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_OVERHEAD; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci q->max_netlen = 0; 26228c2ecf20Sopenharmony_ci q->max_adjlen = 0; 26238c2ecf20Sopenharmony_ci q->min_netlen = ~0; 26248c2ecf20Sopenharmony_ci q->min_adjlen = ~0; 26258c2ecf20Sopenharmony_ci } 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_RAW]) { 26288c2ecf20Sopenharmony_ci q->rate_flags &= ~CAKE_FLAG_OVERHEAD; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci q->max_netlen = 0; 26318c2ecf20Sopenharmony_ci q->max_adjlen = 0; 26328c2ecf20Sopenharmony_ci q->min_netlen = ~0; 26338c2ecf20Sopenharmony_ci q->min_adjlen = ~0; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_MPU]) 26378c2ecf20Sopenharmony_ci q->rate_mpu = nla_get_u32(tb[TCA_CAKE_MPU]); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_RTT]) { 26408c2ecf20Sopenharmony_ci q->interval = nla_get_u32(tb[TCA_CAKE_RTT]); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci if (!q->interval) 26438c2ecf20Sopenharmony_ci q->interval = 1; 26448c2ecf20Sopenharmony_ci } 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_TARGET]) { 26478c2ecf20Sopenharmony_ci q->target = nla_get_u32(tb[TCA_CAKE_TARGET]); 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci if (!q->target) 26508c2ecf20Sopenharmony_ci q->target = 1; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_AUTORATE]) { 26548c2ecf20Sopenharmony_ci if (!!nla_get_u32(tb[TCA_CAKE_AUTORATE])) 26558c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_AUTORATE_INGRESS; 26568c2ecf20Sopenharmony_ci else 26578c2ecf20Sopenharmony_ci q->rate_flags &= ~CAKE_FLAG_AUTORATE_INGRESS; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_INGRESS]) { 26618c2ecf20Sopenharmony_ci if (!!nla_get_u32(tb[TCA_CAKE_INGRESS])) 26628c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_INGRESS; 26638c2ecf20Sopenharmony_ci else 26648c2ecf20Sopenharmony_ci q->rate_flags &= ~CAKE_FLAG_INGRESS; 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_ACK_FILTER]) 26688c2ecf20Sopenharmony_ci q->ack_filter = nla_get_u32(tb[TCA_CAKE_ACK_FILTER]); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_MEMORY]) 26718c2ecf20Sopenharmony_ci q->buffer_config_limit = nla_get_u32(tb[TCA_CAKE_MEMORY]); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_SPLIT_GSO]) { 26748c2ecf20Sopenharmony_ci if (!!nla_get_u32(tb[TCA_CAKE_SPLIT_GSO])) 26758c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_SPLIT_GSO; 26768c2ecf20Sopenharmony_ci else 26778c2ecf20Sopenharmony_ci q->rate_flags &= ~CAKE_FLAG_SPLIT_GSO; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci if (tb[TCA_CAKE_FWMARK]) { 26818c2ecf20Sopenharmony_ci q->fwmark_mask = nla_get_u32(tb[TCA_CAKE_FWMARK]); 26828c2ecf20Sopenharmony_ci q->fwmark_shft = q->fwmark_mask ? __ffs(q->fwmark_mask) : 0; 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci if (q->tins) { 26868c2ecf20Sopenharmony_ci sch_tree_lock(sch); 26878c2ecf20Sopenharmony_ci cake_reconfigure(sch); 26888c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 26898c2ecf20Sopenharmony_ci } 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci return 0; 26928c2ecf20Sopenharmony_ci} 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_cistatic void cake_destroy(struct Qdisc *sch) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci qdisc_watchdog_cancel(&q->watchdog); 26998c2ecf20Sopenharmony_ci tcf_block_put(q->block); 27008c2ecf20Sopenharmony_ci kvfree(q->tins); 27018c2ecf20Sopenharmony_ci} 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_cistatic int cake_init(struct Qdisc *sch, struct nlattr *opt, 27048c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 27078c2ecf20Sopenharmony_ci int i, j, err; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci sch->limit = 10240; 27108c2ecf20Sopenharmony_ci q->tin_mode = CAKE_DIFFSERV_DIFFSERV3; 27118c2ecf20Sopenharmony_ci q->flow_mode = CAKE_FLOW_TRIPLE; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci q->rate_bps = 0; /* unlimited by default */ 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci q->interval = 100000; /* 100ms default */ 27168c2ecf20Sopenharmony_ci q->target = 5000; /* 5ms: codel RFC argues 27178c2ecf20Sopenharmony_ci * for 5 to 10% of interval 27188c2ecf20Sopenharmony_ci */ 27198c2ecf20Sopenharmony_ci q->rate_flags |= CAKE_FLAG_SPLIT_GSO; 27208c2ecf20Sopenharmony_ci q->cur_tin = 0; 27218c2ecf20Sopenharmony_ci q->cur_flow = 0; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci qdisc_watchdog_init(&q->watchdog, sch); 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci if (opt) { 27268c2ecf20Sopenharmony_ci err = cake_change(sch, opt, extack); 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci if (err) 27298c2ecf20Sopenharmony_ci return err; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci err = tcf_block_get(&q->block, &q->filter_list, sch, extack); 27338c2ecf20Sopenharmony_ci if (err) 27348c2ecf20Sopenharmony_ci return err; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci quantum_div[0] = ~0; 27378c2ecf20Sopenharmony_ci for (i = 1; i <= CAKE_QUEUES; i++) 27388c2ecf20Sopenharmony_ci quantum_div[i] = 65535 / i; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci q->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data), 27418c2ecf20Sopenharmony_ci GFP_KERNEL); 27428c2ecf20Sopenharmony_ci if (!q->tins) 27438c2ecf20Sopenharmony_ci return -ENOMEM; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci for (i = 0; i < CAKE_MAX_TINS; i++) { 27468c2ecf20Sopenharmony_ci struct cake_tin_data *b = q->tins + i; 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&b->new_flows); 27498c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&b->old_flows); 27508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&b->decaying_flows); 27518c2ecf20Sopenharmony_ci b->sparse_flow_count = 0; 27528c2ecf20Sopenharmony_ci b->bulk_flow_count = 0; 27538c2ecf20Sopenharmony_ci b->decaying_flow_count = 0; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci for (j = 0; j < CAKE_QUEUES; j++) { 27568c2ecf20Sopenharmony_ci struct cake_flow *flow = b->flows + j; 27578c2ecf20Sopenharmony_ci u32 k = j * CAKE_MAX_TINS + i; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&flow->flowchain); 27608c2ecf20Sopenharmony_ci cobalt_vars_init(&flow->cvars); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci q->overflow_heap[k].t = i; 27638c2ecf20Sopenharmony_ci q->overflow_heap[k].b = j; 27648c2ecf20Sopenharmony_ci b->overflow_idx[j] = k; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci } 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci cake_reconfigure(sch); 27698c2ecf20Sopenharmony_ci q->avg_peak_bandwidth = q->rate_bps; 27708c2ecf20Sopenharmony_ci q->min_netlen = ~0; 27718c2ecf20Sopenharmony_ci q->min_adjlen = ~0; 27728c2ecf20Sopenharmony_ci return 0; 27738c2ecf20Sopenharmony_ci} 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_cistatic int cake_dump(struct Qdisc *sch, struct sk_buff *skb) 27768c2ecf20Sopenharmony_ci{ 27778c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 27788c2ecf20Sopenharmony_ci struct nlattr *opts; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci opts = nla_nest_start_noflag(skb, TCA_OPTIONS); 27818c2ecf20Sopenharmony_ci if (!opts) 27828c2ecf20Sopenharmony_ci goto nla_put_failure; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(skb, TCA_CAKE_BASE_RATE64, q->rate_bps, 27858c2ecf20Sopenharmony_ci TCA_CAKE_PAD)) 27868c2ecf20Sopenharmony_ci goto nla_put_failure; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_FLOW_MODE, 27898c2ecf20Sopenharmony_ci q->flow_mode & CAKE_FLOW_MASK)) 27908c2ecf20Sopenharmony_ci goto nla_put_failure; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_RTT, q->interval)) 27938c2ecf20Sopenharmony_ci goto nla_put_failure; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_TARGET, q->target)) 27968c2ecf20Sopenharmony_ci goto nla_put_failure; 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_MEMORY, q->buffer_config_limit)) 27998c2ecf20Sopenharmony_ci goto nla_put_failure; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_AUTORATE, 28028c2ecf20Sopenharmony_ci !!(q->rate_flags & CAKE_FLAG_AUTORATE_INGRESS))) 28038c2ecf20Sopenharmony_ci goto nla_put_failure; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_INGRESS, 28068c2ecf20Sopenharmony_ci !!(q->rate_flags & CAKE_FLAG_INGRESS))) 28078c2ecf20Sopenharmony_ci goto nla_put_failure; 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_ACK_FILTER, q->ack_filter)) 28108c2ecf20Sopenharmony_ci goto nla_put_failure; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_NAT, 28138c2ecf20Sopenharmony_ci !!(q->flow_mode & CAKE_FLOW_NAT_FLAG))) 28148c2ecf20Sopenharmony_ci goto nla_put_failure; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_DIFFSERV_MODE, q->tin_mode)) 28178c2ecf20Sopenharmony_ci goto nla_put_failure; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_WASH, 28208c2ecf20Sopenharmony_ci !!(q->rate_flags & CAKE_FLAG_WASH))) 28218c2ecf20Sopenharmony_ci goto nla_put_failure; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_OVERHEAD, q->rate_overhead)) 28248c2ecf20Sopenharmony_ci goto nla_put_failure; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci if (!(q->rate_flags & CAKE_FLAG_OVERHEAD)) 28278c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_RAW, 0)) 28288c2ecf20Sopenharmony_ci goto nla_put_failure; 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_ATM, q->atm_mode)) 28318c2ecf20Sopenharmony_ci goto nla_put_failure; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_MPU, q->rate_mpu)) 28348c2ecf20Sopenharmony_ci goto nla_put_failure; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_SPLIT_GSO, 28378c2ecf20Sopenharmony_ci !!(q->rate_flags & CAKE_FLAG_SPLIT_GSO))) 28388c2ecf20Sopenharmony_ci goto nla_put_failure; 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci if (nla_put_u32(skb, TCA_CAKE_FWMARK, q->fwmark_mask)) 28418c2ecf20Sopenharmony_ci goto nla_put_failure; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci return nla_nest_end(skb, opts); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_cinla_put_failure: 28468c2ecf20Sopenharmony_ci return -1; 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_cistatic int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci struct nlattr *stats = nla_nest_start_noflag(d->skb, TCA_STATS_APP); 28528c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 28538c2ecf20Sopenharmony_ci struct nlattr *tstats, *ts; 28548c2ecf20Sopenharmony_ci int i; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci if (!stats) 28578c2ecf20Sopenharmony_ci return -1; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci#define PUT_STAT_U32(attr, data) do { \ 28608c2ecf20Sopenharmony_ci if (nla_put_u32(d->skb, TCA_CAKE_STATS_ ## attr, data)) \ 28618c2ecf20Sopenharmony_ci goto nla_put_failure; \ 28628c2ecf20Sopenharmony_ci } while (0) 28638c2ecf20Sopenharmony_ci#define PUT_STAT_U64(attr, data) do { \ 28648c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(d->skb, TCA_CAKE_STATS_ ## attr, \ 28658c2ecf20Sopenharmony_ci data, TCA_CAKE_STATS_PAD)) \ 28668c2ecf20Sopenharmony_ci goto nla_put_failure; \ 28678c2ecf20Sopenharmony_ci } while (0) 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci PUT_STAT_U64(CAPACITY_ESTIMATE64, q->avg_peak_bandwidth); 28708c2ecf20Sopenharmony_ci PUT_STAT_U32(MEMORY_LIMIT, q->buffer_limit); 28718c2ecf20Sopenharmony_ci PUT_STAT_U32(MEMORY_USED, q->buffer_max_used); 28728c2ecf20Sopenharmony_ci PUT_STAT_U32(AVG_NETOFF, ((q->avg_netoff + 0x8000) >> 16)); 28738c2ecf20Sopenharmony_ci PUT_STAT_U32(MAX_NETLEN, q->max_netlen); 28748c2ecf20Sopenharmony_ci PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen); 28758c2ecf20Sopenharmony_ci PUT_STAT_U32(MIN_NETLEN, q->min_netlen); 28768c2ecf20Sopenharmony_ci PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci#undef PUT_STAT_U32 28798c2ecf20Sopenharmony_ci#undef PUT_STAT_U64 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci tstats = nla_nest_start_noflag(d->skb, TCA_CAKE_STATS_TIN_STATS); 28828c2ecf20Sopenharmony_ci if (!tstats) 28838c2ecf20Sopenharmony_ci goto nla_put_failure; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci#define PUT_TSTAT_U32(attr, data) do { \ 28868c2ecf20Sopenharmony_ci if (nla_put_u32(d->skb, TCA_CAKE_TIN_STATS_ ## attr, data)) \ 28878c2ecf20Sopenharmony_ci goto nla_put_failure; \ 28888c2ecf20Sopenharmony_ci } while (0) 28898c2ecf20Sopenharmony_ci#define PUT_TSTAT_U64(attr, data) do { \ 28908c2ecf20Sopenharmony_ci if (nla_put_u64_64bit(d->skb, TCA_CAKE_TIN_STATS_ ## attr, \ 28918c2ecf20Sopenharmony_ci data, TCA_CAKE_TIN_STATS_PAD)) \ 28928c2ecf20Sopenharmony_ci goto nla_put_failure; \ 28938c2ecf20Sopenharmony_ci } while (0) 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci for (i = 0; i < q->tin_cnt; i++) { 28968c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[q->tin_order[i]]; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci ts = nla_nest_start_noflag(d->skb, i + 1); 28998c2ecf20Sopenharmony_ci if (!ts) 29008c2ecf20Sopenharmony_ci goto nla_put_failure; 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci PUT_TSTAT_U64(THRESHOLD_RATE64, b->tin_rate_bps); 29038c2ecf20Sopenharmony_ci PUT_TSTAT_U64(SENT_BYTES64, b->bytes); 29048c2ecf20Sopenharmony_ci PUT_TSTAT_U32(BACKLOG_BYTES, b->tin_backlog); 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci PUT_TSTAT_U32(TARGET_US, 29078c2ecf20Sopenharmony_ci ktime_to_us(ns_to_ktime(b->cparams.target))); 29088c2ecf20Sopenharmony_ci PUT_TSTAT_U32(INTERVAL_US, 29098c2ecf20Sopenharmony_ci ktime_to_us(ns_to_ktime(b->cparams.interval))); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci PUT_TSTAT_U32(SENT_PACKETS, b->packets); 29128c2ecf20Sopenharmony_ci PUT_TSTAT_U32(DROPPED_PACKETS, b->tin_dropped); 29138c2ecf20Sopenharmony_ci PUT_TSTAT_U32(ECN_MARKED_PACKETS, b->tin_ecn_mark); 29148c2ecf20Sopenharmony_ci PUT_TSTAT_U32(ACKS_DROPPED_PACKETS, b->ack_drops); 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci PUT_TSTAT_U32(PEAK_DELAY_US, 29178c2ecf20Sopenharmony_ci ktime_to_us(ns_to_ktime(b->peak_delay))); 29188c2ecf20Sopenharmony_ci PUT_TSTAT_U32(AVG_DELAY_US, 29198c2ecf20Sopenharmony_ci ktime_to_us(ns_to_ktime(b->avge_delay))); 29208c2ecf20Sopenharmony_ci PUT_TSTAT_U32(BASE_DELAY_US, 29218c2ecf20Sopenharmony_ci ktime_to_us(ns_to_ktime(b->base_delay))); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci PUT_TSTAT_U32(WAY_INDIRECT_HITS, b->way_hits); 29248c2ecf20Sopenharmony_ci PUT_TSTAT_U32(WAY_MISSES, b->way_misses); 29258c2ecf20Sopenharmony_ci PUT_TSTAT_U32(WAY_COLLISIONS, b->way_collisions); 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci PUT_TSTAT_U32(SPARSE_FLOWS, b->sparse_flow_count + 29288c2ecf20Sopenharmony_ci b->decaying_flow_count); 29298c2ecf20Sopenharmony_ci PUT_TSTAT_U32(BULK_FLOWS, b->bulk_flow_count); 29308c2ecf20Sopenharmony_ci PUT_TSTAT_U32(UNRESPONSIVE_FLOWS, b->unresponsive_flow_count); 29318c2ecf20Sopenharmony_ci PUT_TSTAT_U32(MAX_SKBLEN, b->max_skblen); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci PUT_TSTAT_U32(FLOW_QUANTUM, b->flow_quantum); 29348c2ecf20Sopenharmony_ci nla_nest_end(d->skb, ts); 29358c2ecf20Sopenharmony_ci } 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci#undef PUT_TSTAT_U32 29388c2ecf20Sopenharmony_ci#undef PUT_TSTAT_U64 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci nla_nest_end(d->skb, tstats); 29418c2ecf20Sopenharmony_ci return nla_nest_end(d->skb, stats); 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_cinla_put_failure: 29448c2ecf20Sopenharmony_ci nla_nest_cancel(d->skb, stats); 29458c2ecf20Sopenharmony_ci return -1; 29468c2ecf20Sopenharmony_ci} 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_cistatic struct Qdisc *cake_leaf(struct Qdisc *sch, unsigned long arg) 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci return NULL; 29518c2ecf20Sopenharmony_ci} 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_cistatic unsigned long cake_find(struct Qdisc *sch, u32 classid) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci return 0; 29568c2ecf20Sopenharmony_ci} 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_cistatic unsigned long cake_bind(struct Qdisc *sch, unsigned long parent, 29598c2ecf20Sopenharmony_ci u32 classid) 29608c2ecf20Sopenharmony_ci{ 29618c2ecf20Sopenharmony_ci return 0; 29628c2ecf20Sopenharmony_ci} 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_cistatic void cake_unbind(struct Qdisc *q, unsigned long cl) 29658c2ecf20Sopenharmony_ci{ 29668c2ecf20Sopenharmony_ci} 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_cistatic struct tcf_block *cake_tcf_block(struct Qdisc *sch, unsigned long cl, 29698c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 29708c2ecf20Sopenharmony_ci{ 29718c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci if (cl) 29748c2ecf20Sopenharmony_ci return NULL; 29758c2ecf20Sopenharmony_ci return q->block; 29768c2ecf20Sopenharmony_ci} 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_cistatic int cake_dump_class(struct Qdisc *sch, unsigned long cl, 29798c2ecf20Sopenharmony_ci struct sk_buff *skb, struct tcmsg *tcm) 29808c2ecf20Sopenharmony_ci{ 29818c2ecf20Sopenharmony_ci tcm->tcm_handle |= TC_H_MIN(cl); 29828c2ecf20Sopenharmony_ci return 0; 29838c2ecf20Sopenharmony_ci} 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_cistatic int cake_dump_class_stats(struct Qdisc *sch, unsigned long cl, 29868c2ecf20Sopenharmony_ci struct gnet_dump *d) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 29898c2ecf20Sopenharmony_ci const struct cake_flow *flow = NULL; 29908c2ecf20Sopenharmony_ci struct gnet_stats_queue qs = { 0 }; 29918c2ecf20Sopenharmony_ci struct nlattr *stats; 29928c2ecf20Sopenharmony_ci u32 idx = cl - 1; 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci if (idx < CAKE_QUEUES * q->tin_cnt) { 29958c2ecf20Sopenharmony_ci const struct cake_tin_data *b = \ 29968c2ecf20Sopenharmony_ci &q->tins[q->tin_order[idx / CAKE_QUEUES]]; 29978c2ecf20Sopenharmony_ci const struct sk_buff *skb; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci flow = &b->flows[idx % CAKE_QUEUES]; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci if (flow->head) { 30028c2ecf20Sopenharmony_ci sch_tree_lock(sch); 30038c2ecf20Sopenharmony_ci skb = flow->head; 30048c2ecf20Sopenharmony_ci while (skb) { 30058c2ecf20Sopenharmony_ci qs.qlen++; 30068c2ecf20Sopenharmony_ci skb = skb->next; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci sch_tree_unlock(sch); 30098c2ecf20Sopenharmony_ci } 30108c2ecf20Sopenharmony_ci qs.backlog = b->backlogs[idx % CAKE_QUEUES]; 30118c2ecf20Sopenharmony_ci qs.drops = flow->dropped; 30128c2ecf20Sopenharmony_ci } 30138c2ecf20Sopenharmony_ci if (gnet_stats_copy_queue(d, NULL, &qs, qs.qlen) < 0) 30148c2ecf20Sopenharmony_ci return -1; 30158c2ecf20Sopenharmony_ci if (flow) { 30168c2ecf20Sopenharmony_ci ktime_t now = ktime_get(); 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci stats = nla_nest_start_noflag(d->skb, TCA_STATS_APP); 30198c2ecf20Sopenharmony_ci if (!stats) 30208c2ecf20Sopenharmony_ci return -1; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci#define PUT_STAT_U32(attr, data) do { \ 30238c2ecf20Sopenharmony_ci if (nla_put_u32(d->skb, TCA_CAKE_STATS_ ## attr, data)) \ 30248c2ecf20Sopenharmony_ci goto nla_put_failure; \ 30258c2ecf20Sopenharmony_ci } while (0) 30268c2ecf20Sopenharmony_ci#define PUT_STAT_S32(attr, data) do { \ 30278c2ecf20Sopenharmony_ci if (nla_put_s32(d->skb, TCA_CAKE_STATS_ ## attr, data)) \ 30288c2ecf20Sopenharmony_ci goto nla_put_failure; \ 30298c2ecf20Sopenharmony_ci } while (0) 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci PUT_STAT_S32(DEFICIT, flow->deficit); 30328c2ecf20Sopenharmony_ci PUT_STAT_U32(DROPPING, flow->cvars.dropping); 30338c2ecf20Sopenharmony_ci PUT_STAT_U32(COBALT_COUNT, flow->cvars.count); 30348c2ecf20Sopenharmony_ci PUT_STAT_U32(P_DROP, flow->cvars.p_drop); 30358c2ecf20Sopenharmony_ci if (flow->cvars.p_drop) { 30368c2ecf20Sopenharmony_ci PUT_STAT_S32(BLUE_TIMER_US, 30378c2ecf20Sopenharmony_ci ktime_to_us( 30388c2ecf20Sopenharmony_ci ktime_sub(now, 30398c2ecf20Sopenharmony_ci flow->cvars.blue_timer))); 30408c2ecf20Sopenharmony_ci } 30418c2ecf20Sopenharmony_ci if (flow->cvars.dropping) { 30428c2ecf20Sopenharmony_ci PUT_STAT_S32(DROP_NEXT_US, 30438c2ecf20Sopenharmony_ci ktime_to_us( 30448c2ecf20Sopenharmony_ci ktime_sub(now, 30458c2ecf20Sopenharmony_ci flow->cvars.drop_next))); 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if (nla_nest_end(d->skb, stats) < 0) 30498c2ecf20Sopenharmony_ci return -1; 30508c2ecf20Sopenharmony_ci } 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci return 0; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_cinla_put_failure: 30558c2ecf20Sopenharmony_ci nla_nest_cancel(d->skb, stats); 30568c2ecf20Sopenharmony_ci return -1; 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_cistatic void cake_walk(struct Qdisc *sch, struct qdisc_walker *arg) 30608c2ecf20Sopenharmony_ci{ 30618c2ecf20Sopenharmony_ci struct cake_sched_data *q = qdisc_priv(sch); 30628c2ecf20Sopenharmony_ci unsigned int i, j; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci if (arg->stop) 30658c2ecf20Sopenharmony_ci return; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci for (i = 0; i < q->tin_cnt; i++) { 30688c2ecf20Sopenharmony_ci struct cake_tin_data *b = &q->tins[q->tin_order[i]]; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci for (j = 0; j < CAKE_QUEUES; j++) { 30718c2ecf20Sopenharmony_ci if (list_empty(&b->flows[j].flowchain) || 30728c2ecf20Sopenharmony_ci arg->count < arg->skip) { 30738c2ecf20Sopenharmony_ci arg->count++; 30748c2ecf20Sopenharmony_ci continue; 30758c2ecf20Sopenharmony_ci } 30768c2ecf20Sopenharmony_ci if (arg->fn(sch, i * CAKE_QUEUES + j + 1, arg) < 0) { 30778c2ecf20Sopenharmony_ci arg->stop = 1; 30788c2ecf20Sopenharmony_ci break; 30798c2ecf20Sopenharmony_ci } 30808c2ecf20Sopenharmony_ci arg->count++; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci } 30838c2ecf20Sopenharmony_ci} 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_cistatic const struct Qdisc_class_ops cake_class_ops = { 30868c2ecf20Sopenharmony_ci .leaf = cake_leaf, 30878c2ecf20Sopenharmony_ci .find = cake_find, 30888c2ecf20Sopenharmony_ci .tcf_block = cake_tcf_block, 30898c2ecf20Sopenharmony_ci .bind_tcf = cake_bind, 30908c2ecf20Sopenharmony_ci .unbind_tcf = cake_unbind, 30918c2ecf20Sopenharmony_ci .dump = cake_dump_class, 30928c2ecf20Sopenharmony_ci .dump_stats = cake_dump_class_stats, 30938c2ecf20Sopenharmony_ci .walk = cake_walk, 30948c2ecf20Sopenharmony_ci}; 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_cistatic struct Qdisc_ops cake_qdisc_ops __read_mostly = { 30978c2ecf20Sopenharmony_ci .cl_ops = &cake_class_ops, 30988c2ecf20Sopenharmony_ci .id = "cake", 30998c2ecf20Sopenharmony_ci .priv_size = sizeof(struct cake_sched_data), 31008c2ecf20Sopenharmony_ci .enqueue = cake_enqueue, 31018c2ecf20Sopenharmony_ci .dequeue = cake_dequeue, 31028c2ecf20Sopenharmony_ci .peek = qdisc_peek_dequeued, 31038c2ecf20Sopenharmony_ci .init = cake_init, 31048c2ecf20Sopenharmony_ci .reset = cake_reset, 31058c2ecf20Sopenharmony_ci .destroy = cake_destroy, 31068c2ecf20Sopenharmony_ci .change = cake_change, 31078c2ecf20Sopenharmony_ci .dump = cake_dump, 31088c2ecf20Sopenharmony_ci .dump_stats = cake_dump_stats, 31098c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 31108c2ecf20Sopenharmony_ci}; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_cistatic int __init cake_module_init(void) 31138c2ecf20Sopenharmony_ci{ 31148c2ecf20Sopenharmony_ci return register_qdisc(&cake_qdisc_ops); 31158c2ecf20Sopenharmony_ci} 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_cistatic void __exit cake_module_exit(void) 31188c2ecf20Sopenharmony_ci{ 31198c2ecf20Sopenharmony_ci unregister_qdisc(&cake_qdisc_ops); 31208c2ecf20Sopenharmony_ci} 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_cimodule_init(cake_module_init) 31238c2ecf20Sopenharmony_cimodule_exit(cake_module_exit) 31248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jonathan Morton"); 31258c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 31268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("The CAKE shaper."); 3127