mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 12:03:54 +02:00
Merge branch 'multi-queue-aware-sch_cake'
says: ==================== Multi-queue aware sch_cake This series adds a multi-queue aware variant of the sch_cake scheduler, called 'cake_mq'. Using this makes it possible to scale the rate shaper of sch_cake across multiple CPUs, while still enforcing a single global rate on the interface. The approach taken in this patch series is to implement a separate qdisc called 'cake_mq', which is based on the existing 'mq' qdisc, but differs in a couple of aspects: - It will always install a cake instance on each hardware queue (instead of using the default qdisc for each queue like 'mq' does). - The cake instances on the queues will share their configuration, which can only be modified through the parent cake_mq instance. Doing things this way simplifies user configuration by centralising all configuration through the cake_mq qdisc (which also serves as an obvious way of opting into the multi-queue aware behaviour). The cake_mq qdisc takes all the same configuration parameters as the cake qdisc. An earlier version of this work was presented at this year's Netdevconf: https://netdevconf.info/0x19/sessions/talk/mq-cake-scaling-software-rate-limiting-across-cpu-cores.html The patch series is structured as follows: - Patch 1 exports the mq qdisc functions for reuse. - Patch 2 factors out the sch_cake configuration variables into a separate struct that can be shared between instances. - Patch 3 adds the basic cake_mq qdisc, reusing the exported mq code - Patch 4 adds configuration sharing across the cake instances installed under cake_mq - Patch 5 adds the shared shaper state that enables the multi-core rate shaping - Patch 6 adds selftests for cake_mq A patch to iproute2 to make it aware of the cake_mq qdisc were submitted separately with a previous patch version: https://lore.kernel.org/r/20260105162902.1432940-1-toke@redhat.com ==================== Link: https://patch.msgid.link/20260109-mq-cake-sub-qdisc-v8-0-8d613fece5d8@redhat.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
ff420c568b
|
|
@ -2207,6 +2207,9 @@ attribute-sets:
|
|||
-
|
||||
name: blue-timer-us
|
||||
type: s32
|
||||
-
|
||||
name: active-queues
|
||||
type: u32
|
||||
-
|
||||
name: cake-tin-stats-attrs
|
||||
name-prefix: tca-cake-tin-stats-
|
||||
|
|
|
|||
|
|
@ -25454,6 +25454,7 @@ L: netdev@vger.kernel.org
|
|||
S: Maintained
|
||||
F: include/net/pkt_cls.h
|
||||
F: include/net/pkt_sched.h
|
||||
F: include/net/sch_priv.h
|
||||
F: include/net/tc_act/
|
||||
F: include/uapi/linux/pkt_cls.h
|
||||
F: include/uapi/linux/pkt_sched.h
|
||||
|
|
|
|||
27
include/net/sch_priv.h
Normal file
27
include/net/sch_priv.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __NET_SCHED_PRIV_H
|
||||
#define __NET_SCHED_PRIV_H
|
||||
|
||||
#include <net/sch_generic.h>
|
||||
|
||||
struct mq_sched {
|
||||
struct Qdisc **qdiscs;
|
||||
};
|
||||
|
||||
int mq_init_common(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack,
|
||||
const struct Qdisc_ops *qdisc_ops);
|
||||
void mq_destroy_common(struct Qdisc *sch);
|
||||
void mq_attach(struct Qdisc *sch);
|
||||
void mq_dump_common(struct Qdisc *sch, struct sk_buff *skb);
|
||||
struct netdev_queue *mq_select_queue(struct Qdisc *sch,
|
||||
struct tcmsg *tcm);
|
||||
struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl);
|
||||
unsigned long mq_find(struct Qdisc *sch, u32 classid);
|
||||
int mq_dump_class(struct Qdisc *sch, unsigned long cl,
|
||||
struct sk_buff *skb, struct tcmsg *tcm);
|
||||
int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
struct gnet_dump *d);
|
||||
void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg);
|
||||
|
||||
#endif
|
||||
|
|
@ -1036,6 +1036,7 @@ enum {
|
|||
TCA_CAKE_STATS_DROP_NEXT_US,
|
||||
TCA_CAKE_STATS_P_DROP,
|
||||
TCA_CAKE_STATS_BLUE_TIMER_US,
|
||||
TCA_CAKE_STATS_ACTIVE_QUEUES,
|
||||
__TCA_CAKE_STATS_MAX
|
||||
};
|
||||
#define TCA_CAKE_STATS_MAX (__TCA_CAKE_STATS_MAX - 1)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
#include <linux/if_vlan.h>
|
||||
#include <net/gso.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/sch_priv.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/flow_dissector.h>
|
||||
|
|
@ -197,40 +198,44 @@ struct cake_tin_data {
|
|||
u32 way_collisions;
|
||||
}; /* number of tins is small, so size of this struct doesn't matter much */
|
||||
|
||||
struct cake_sched_config {
|
||||
u64 rate_bps;
|
||||
u64 interval;
|
||||
u64 target;
|
||||
u64 sync_time;
|
||||
u32 buffer_config_limit;
|
||||
u32 fwmark_mask;
|
||||
u16 fwmark_shft;
|
||||
s16 rate_overhead;
|
||||
u16 rate_mpu;
|
||||
u16 rate_flags;
|
||||
u8 tin_mode;
|
||||
u8 flow_mode;
|
||||
u8 atm_mode;
|
||||
u8 ack_filter;
|
||||
u8 is_shared;
|
||||
};
|
||||
|
||||
struct cake_sched_data {
|
||||
struct tcf_proto __rcu *filter_list; /* optional external classifier */
|
||||
struct tcf_block *block;
|
||||
struct cake_tin_data *tins;
|
||||
struct cake_sched_config *config;
|
||||
|
||||
struct cake_heap_entry overflow_heap[CAKE_QUEUES * CAKE_MAX_TINS];
|
||||
u16 overflow_timeout;
|
||||
|
||||
u16 tin_cnt;
|
||||
u8 tin_mode;
|
||||
u8 flow_mode;
|
||||
u8 ack_filter;
|
||||
u8 atm_mode;
|
||||
|
||||
u32 fwmark_mask;
|
||||
u16 fwmark_shft;
|
||||
|
||||
/* time_next = time_this + ((len * rate_ns) >> rate_shft) */
|
||||
u16 rate_shft;
|
||||
ktime_t time_next_packet;
|
||||
ktime_t failsafe_next_packet;
|
||||
u64 rate_ns;
|
||||
u64 rate_bps;
|
||||
u16 rate_flags;
|
||||
s16 rate_overhead;
|
||||
u16 rate_mpu;
|
||||
u64 interval;
|
||||
u64 target;
|
||||
u16 rate_shft;
|
||||
u16 overflow_timeout;
|
||||
u16 tin_cnt;
|
||||
|
||||
/* resource tracking */
|
||||
u32 buffer_used;
|
||||
u32 buffer_max_used;
|
||||
u32 buffer_limit;
|
||||
u32 buffer_config_limit;
|
||||
|
||||
/* indices for dequeue */
|
||||
u16 cur_tin;
|
||||
|
|
@ -254,6 +259,11 @@ struct cake_sched_data {
|
|||
u16 max_adjlen;
|
||||
u16 min_netlen;
|
||||
u16 min_adjlen;
|
||||
|
||||
/* mq sync state */
|
||||
u64 last_checked_active;
|
||||
u64 last_active;
|
||||
u32 active_queues;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -380,6 +390,8 @@ static const u32 inv_sqrt_cache[REC_INV_SQRT_CACHE] = {
|
|||
1239850263, 1191209601, 1147878294, 1108955788
|
||||
};
|
||||
|
||||
static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
|
||||
u64 target_ns, u64 rtt_est_ns);
|
||||
/* http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
|
||||
* new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
|
||||
*
|
||||
|
|
@ -1198,7 +1210,7 @@ static bool cake_tcph_may_drop(const struct tcphdr *tcph,
|
|||
static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
|
||||
struct cake_flow *flow)
|
||||
{
|
||||
bool aggressive = q->ack_filter == CAKE_ACK_AGGRESSIVE;
|
||||
bool aggressive = q->config->ack_filter == CAKE_ACK_AGGRESSIVE;
|
||||
struct sk_buff *elig_ack = NULL, *elig_ack_prev = NULL;
|
||||
struct sk_buff *skb_check, *skb_prev = NULL;
|
||||
const struct ipv6hdr *ipv6h, *ipv6h_check;
|
||||
|
|
@ -1358,15 +1370,17 @@ static u64 cake_ewma(u64 avg, u64 sample, u32 shift)
|
|||
return avg;
|
||||
}
|
||||
|
||||
static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)
|
||||
static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off)
|
||||
{
|
||||
struct cake_sched_config *q = qd->config;
|
||||
|
||||
if (q->rate_flags & CAKE_FLAG_OVERHEAD)
|
||||
len -= off;
|
||||
|
||||
if (q->max_netlen < len)
|
||||
q->max_netlen = len;
|
||||
if (q->min_netlen > len)
|
||||
q->min_netlen = len;
|
||||
if (qd->max_netlen < len)
|
||||
qd->max_netlen = len;
|
||||
if (qd->min_netlen > len)
|
||||
qd->min_netlen = len;
|
||||
|
||||
len += q->rate_overhead;
|
||||
|
||||
|
|
@ -1385,10 +1399,10 @@ static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)
|
|||
len += (len + 63) / 64;
|
||||
}
|
||||
|
||||
if (q->max_adjlen < len)
|
||||
q->max_adjlen = len;
|
||||
if (q->min_adjlen > len)
|
||||
q->min_adjlen = len;
|
||||
if (qd->max_adjlen < len)
|
||||
qd->max_adjlen = len;
|
||||
if (qd->min_adjlen > len)
|
||||
qd->min_adjlen = len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
@ -1586,7 +1600,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
|
|||
flow->dropped++;
|
||||
b->tin_dropped++;
|
||||
|
||||
if (q->rate_flags & CAKE_FLAG_INGRESS)
|
||||
if (q->config->rate_flags & CAKE_FLAG_INGRESS)
|
||||
cake_advance_shaper(q, b, skb, now, true);
|
||||
|
||||
qdisc_drop_reason(skb, sch, to_free, SKB_DROP_REASON_QDISC_OVERLIMIT);
|
||||
|
|
@ -1656,7 +1670,8 @@ static u8 cake_handle_diffserv(struct sk_buff *skb, bool wash)
|
|||
static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
struct cake_sched_config *q = qd->config;
|
||||
u32 tin, mark;
|
||||
bool wash;
|
||||
u8 dscp;
|
||||
|
|
@ -1673,24 +1688,24 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
|
|||
if (q->tin_mode == CAKE_DIFFSERV_BESTEFFORT)
|
||||
tin = 0;
|
||||
|
||||
else if (mark && mark <= q->tin_cnt)
|
||||
tin = q->tin_order[mark - 1];
|
||||
else if (mark && mark <= qd->tin_cnt)
|
||||
tin = qd->tin_order[mark - 1];
|
||||
|
||||
else if (TC_H_MAJ(skb->priority) == sch->handle &&
|
||||
TC_H_MIN(skb->priority) > 0 &&
|
||||
TC_H_MIN(skb->priority) <= q->tin_cnt)
|
||||
tin = q->tin_order[TC_H_MIN(skb->priority) - 1];
|
||||
TC_H_MIN(skb->priority) <= qd->tin_cnt)
|
||||
tin = qd->tin_order[TC_H_MIN(skb->priority) - 1];
|
||||
|
||||
else {
|
||||
if (!wash)
|
||||
dscp = cake_handle_diffserv(skb, wash);
|
||||
tin = q->tin_index[dscp];
|
||||
tin = qd->tin_index[dscp];
|
||||
|
||||
if (unlikely(tin >= q->tin_cnt))
|
||||
if (unlikely(tin >= qd->tin_cnt))
|
||||
tin = 0;
|
||||
}
|
||||
|
||||
return &q->tins[tin];
|
||||
return &qd->tins[tin];
|
||||
}
|
||||
|
||||
static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t,
|
||||
|
|
@ -1746,7 +1761,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
bool same_flow = false;
|
||||
|
||||
/* choose flow to insert into */
|
||||
idx = cake_classify(sch, &b, skb, q->flow_mode, &ret);
|
||||
idx = cake_classify(sch, &b, skb, q->config->flow_mode, &ret);
|
||||
if (idx == 0) {
|
||||
if (ret & __NET_XMIT_BYPASS)
|
||||
qdisc_qstats_drop(sch);
|
||||
|
|
@ -1781,7 +1796,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
if (unlikely(len > b->max_skblen))
|
||||
b->max_skblen = len;
|
||||
|
||||
if (qdisc_pkt_segs(skb) > 1 && q->rate_flags & CAKE_FLAG_SPLIT_GSO) {
|
||||
if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) {
|
||||
struct sk_buff *segs, *nskb;
|
||||
netdev_features_t features = netif_skb_features(skb);
|
||||
unsigned int slen = 0, numsegs = 0;
|
||||
|
|
@ -1823,7 +1838,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb);
|
||||
flow_queue_add(flow, skb);
|
||||
|
||||
if (q->ack_filter)
|
||||
if (q->config->ack_filter)
|
||||
ack = cake_ack_filter(q, flow);
|
||||
|
||||
if (ack) {
|
||||
|
|
@ -1832,7 +1847,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
ack_pkt_len = qdisc_pkt_len(ack);
|
||||
b->bytes += ack_pkt_len;
|
||||
q->buffer_used += skb->truesize - ack->truesize;
|
||||
if (q->rate_flags & CAKE_FLAG_INGRESS)
|
||||
if (q->config->rate_flags & CAKE_FLAG_INGRESS)
|
||||
cake_advance_shaper(q, b, ack, now, true);
|
||||
|
||||
qdisc_tree_reduce_backlog(sch, 1, ack_pkt_len);
|
||||
|
|
@ -1855,7 +1870,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
cake_heapify_up(q, b->overflow_idx[idx]);
|
||||
|
||||
/* incoming bandwidth capacity estimate */
|
||||
if (q->rate_flags & CAKE_FLAG_AUTORATE_INGRESS) {
|
||||
if (q->config->rate_flags & CAKE_FLAG_AUTORATE_INGRESS) {
|
||||
u64 packet_interval = \
|
||||
ktime_to_ns(ktime_sub(now, q->last_packet_time));
|
||||
|
||||
|
|
@ -1887,7 +1902,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
if (ktime_after(now,
|
||||
ktime_add_ms(q->last_reconfig_time,
|
||||
250))) {
|
||||
q->rate_bps = (q->avg_peak_bandwidth * 15) >> 4;
|
||||
q->config->rate_bps = (q->avg_peak_bandwidth * 15) >> 4;
|
||||
cake_reconfigure(sch);
|
||||
}
|
||||
}
|
||||
|
|
@ -1907,7 +1922,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
flow->set = CAKE_SET_SPARSE;
|
||||
b->sparse_flow_count++;
|
||||
|
||||
flow->deficit = cake_get_flow_quantum(b, flow, q->flow_mode);
|
||||
flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode);
|
||||
} else if (flow->set == CAKE_SET_SPARSE_WAIT) {
|
||||
/* this flow was empty, accounted as a sparse flow, but actually
|
||||
* in the bulk rotation.
|
||||
|
|
@ -1916,8 +1931,8 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
|
|||
b->sparse_flow_count--;
|
||||
b->bulk_flow_count++;
|
||||
|
||||
cake_inc_srchost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_inc_dsthost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
}
|
||||
|
||||
if (q->buffer_used > q->buffer_max_used)
|
||||
|
|
@ -1997,6 +2012,40 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
u64 delay;
|
||||
u32 len;
|
||||
|
||||
if (q->config->is_shared && now - q->last_checked_active >= q->config->sync_time) {
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct cake_sched_data *other_priv;
|
||||
u64 new_rate = q->config->rate_bps;
|
||||
u64 other_qlen, other_last_active;
|
||||
struct Qdisc *other_sch;
|
||||
u32 num_active_qs = 1;
|
||||
unsigned int ntx;
|
||||
|
||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||
other_sch = rcu_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
|
||||
other_priv = qdisc_priv(other_sch);
|
||||
|
||||
if (other_priv == q)
|
||||
continue;
|
||||
|
||||
other_qlen = READ_ONCE(other_sch->q.qlen);
|
||||
other_last_active = READ_ONCE(other_priv->last_active);
|
||||
|
||||
if (other_qlen || other_last_active > q->last_checked_active)
|
||||
num_active_qs++;
|
||||
}
|
||||
|
||||
if (num_active_qs > 1)
|
||||
new_rate = div64_u64(q->config->rate_bps, num_active_qs);
|
||||
|
||||
/* mtu = 0 is used to only update the rate and not mess with cobalt params */
|
||||
cake_set_rate(b, new_rate, 0, 0, 0);
|
||||
q->last_checked_active = now;
|
||||
q->active_queues = num_active_qs;
|
||||
q->rate_ns = b->tin_rate_ns;
|
||||
q->rate_shft = b->tin_rate_shft;
|
||||
}
|
||||
|
||||
begin:
|
||||
if (!sch->q.qlen)
|
||||
return NULL;
|
||||
|
|
@ -2104,8 +2153,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
b->sparse_flow_count--;
|
||||
b->bulk_flow_count++;
|
||||
|
||||
cake_inc_srchost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_inc_dsthost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
|
||||
flow->set = CAKE_SET_BULK;
|
||||
} else {
|
||||
|
|
@ -2117,7 +2166,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
}
|
||||
}
|
||||
|
||||
flow->deficit += cake_get_flow_quantum(b, flow, q->flow_mode);
|
||||
flow->deficit += cake_get_flow_quantum(b, flow, q->config->flow_mode);
|
||||
list_move_tail(&flow->flowchain, &b->old_flows);
|
||||
|
||||
goto retry;
|
||||
|
|
@ -2141,8 +2190,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
if (flow->set == CAKE_SET_BULK) {
|
||||
b->bulk_flow_count--;
|
||||
|
||||
cake_dec_srchost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_dec_dsthost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
|
||||
b->decaying_flow_count++;
|
||||
} else if (flow->set == CAKE_SET_SPARSE ||
|
||||
|
|
@ -2160,8 +2209,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
else if (flow->set == CAKE_SET_BULK) {
|
||||
b->bulk_flow_count--;
|
||||
|
||||
cake_dec_srchost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_dec_dsthost_bulk_flow_count(b, flow, q->flow_mode);
|
||||
cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
|
||||
} else
|
||||
b->decaying_flow_count--;
|
||||
|
||||
|
|
@ -2172,14 +2221,14 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
|
||||
reason = cobalt_should_drop(&flow->cvars, &b->cparams, now, skb,
|
||||
(b->bulk_flow_count *
|
||||
!!(q->rate_flags &
|
||||
!!(q->config->rate_flags &
|
||||
CAKE_FLAG_INGRESS)));
|
||||
/* Last packet in queue may be marked, shouldn't be dropped */
|
||||
if (reason == SKB_NOT_DROPPED_YET || !flow->head)
|
||||
break;
|
||||
|
||||
/* drop this packet, get another one */
|
||||
if (q->rate_flags & CAKE_FLAG_INGRESS) {
|
||||
if (q->config->rate_flags & CAKE_FLAG_INGRESS) {
|
||||
len = cake_advance_shaper(q, b, skb,
|
||||
now, true);
|
||||
flow->deficit -= len;
|
||||
|
|
@ -2190,12 +2239,13 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
|
|||
qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
|
||||
qdisc_qstats_drop(sch);
|
||||
qdisc_dequeue_drop(sch, skb, reason);
|
||||
if (q->rate_flags & CAKE_FLAG_INGRESS)
|
||||
if (q->config->rate_flags & CAKE_FLAG_INGRESS)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
b->tin_ecn_mark += !!flow->cvars.ecn_marked;
|
||||
qdisc_bstats_update(sch, skb);
|
||||
WRITE_ONCE(q->last_active, now);
|
||||
|
||||
/* collect delay stats */
|
||||
delay = ktime_to_ns(ktime_sub(now, cobalt_get_enqueue_time(skb)));
|
||||
|
|
@ -2296,6 +2346,9 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
|
|||
b->tin_rate_ns = rate_ns;
|
||||
b->tin_rate_shft = rate_shft;
|
||||
|
||||
if (mtu == 0)
|
||||
return;
|
||||
|
||||
byte_target_ns = (byte_target * rate_ns) >> rate_shft;
|
||||
|
||||
b->cparams.target = max((byte_target_ns * 3) / 2, target_ns);
|
||||
|
|
@ -2312,7 +2365,7 @@ static int cake_config_besteffort(struct Qdisc *sch)
|
|||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
struct cake_tin_data *b = &q->tins[0];
|
||||
u32 mtu = psched_mtu(qdisc_dev(sch));
|
||||
u64 rate = q->rate_bps;
|
||||
u64 rate = q->config->rate_bps;
|
||||
|
||||
q->tin_cnt = 1;
|
||||
|
||||
|
|
@ -2320,7 +2373,7 @@ static int cake_config_besteffort(struct Qdisc *sch)
|
|||
q->tin_order = normal_order;
|
||||
|
||||
cake_set_rate(b, rate, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
b->tin_quantum = 65535;
|
||||
|
||||
return 0;
|
||||
|
|
@ -2331,7 +2384,7 @@ static int cake_config_precedence(struct Qdisc *sch)
|
|||
/* convert high-level (user visible) parameters into internal format */
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
u32 mtu = psched_mtu(qdisc_dev(sch));
|
||||
u64 rate = q->rate_bps;
|
||||
u64 rate = q->config->rate_bps;
|
||||
u32 quantum = 256;
|
||||
u32 i;
|
||||
|
||||
|
|
@ -2342,8 +2395,8 @@ static int cake_config_precedence(struct Qdisc *sch)
|
|||
for (i = 0; i < q->tin_cnt; i++) {
|
||||
struct cake_tin_data *b = &q->tins[i];
|
||||
|
||||
cake_set_rate(b, rate, mtu, us_to_ns(q->target),
|
||||
us_to_ns(q->interval));
|
||||
cake_set_rate(b, rate, mtu, us_to_ns(q->config->target),
|
||||
us_to_ns(q->config->interval));
|
||||
|
||||
b->tin_quantum = max_t(u16, 1U, quantum);
|
||||
|
||||
|
|
@ -2420,7 +2473,7 @@ static int cake_config_diffserv8(struct Qdisc *sch)
|
|||
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
u32 mtu = psched_mtu(qdisc_dev(sch));
|
||||
u64 rate = q->rate_bps;
|
||||
u64 rate = q->config->rate_bps;
|
||||
u32 quantum = 256;
|
||||
u32 i;
|
||||
|
||||
|
|
@ -2434,8 +2487,8 @@ static int cake_config_diffserv8(struct Qdisc *sch)
|
|||
for (i = 0; i < q->tin_cnt; i++) {
|
||||
struct cake_tin_data *b = &q->tins[i];
|
||||
|
||||
cake_set_rate(b, rate, mtu, us_to_ns(q->target),
|
||||
us_to_ns(q->interval));
|
||||
cake_set_rate(b, rate, mtu, us_to_ns(q->config->target),
|
||||
us_to_ns(q->config->interval));
|
||||
|
||||
b->tin_quantum = max_t(u16, 1U, quantum);
|
||||
|
||||
|
|
@ -2464,7 +2517,7 @@ static int cake_config_diffserv4(struct Qdisc *sch)
|
|||
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
u32 mtu = psched_mtu(qdisc_dev(sch));
|
||||
u64 rate = q->rate_bps;
|
||||
u64 rate = q->config->rate_bps;
|
||||
u32 quantum = 1024;
|
||||
|
||||
q->tin_cnt = 4;
|
||||
|
|
@ -2475,13 +2528,13 @@ static int cake_config_diffserv4(struct Qdisc *sch)
|
|||
|
||||
/* class characteristics */
|
||||
cake_set_rate(&q->tins[0], rate, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
cake_set_rate(&q->tins[1], rate >> 4, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
cake_set_rate(&q->tins[2], rate >> 1, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
cake_set_rate(&q->tins[3], rate >> 2, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
|
||||
/* bandwidth-sharing weights */
|
||||
q->tins[0].tin_quantum = quantum;
|
||||
|
|
@ -2501,7 +2554,7 @@ static int cake_config_diffserv3(struct Qdisc *sch)
|
|||
*/
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
u32 mtu = psched_mtu(qdisc_dev(sch));
|
||||
u64 rate = q->rate_bps;
|
||||
u64 rate = q->config->rate_bps;
|
||||
u32 quantum = 1024;
|
||||
|
||||
q->tin_cnt = 3;
|
||||
|
|
@ -2512,11 +2565,11 @@ static int cake_config_diffserv3(struct Qdisc *sch)
|
|||
|
||||
/* class characteristics */
|
||||
cake_set_rate(&q->tins[0], rate, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
cake_set_rate(&q->tins[1], rate >> 4, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
cake_set_rate(&q->tins[2], rate >> 2, mtu,
|
||||
us_to_ns(q->target), us_to_ns(q->interval));
|
||||
us_to_ns(q->config->target), us_to_ns(q->config->interval));
|
||||
|
||||
/* bandwidth-sharing weights */
|
||||
q->tins[0].tin_quantum = quantum;
|
||||
|
|
@ -2528,7 +2581,8 @@ static int cake_config_diffserv3(struct Qdisc *sch)
|
|||
|
||||
static void cake_reconfigure(struct Qdisc *sch)
|
||||
{
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
struct cake_sched_config *q = qd->config;
|
||||
int c, ft;
|
||||
|
||||
switch (q->tin_mode) {
|
||||
|
|
@ -2554,39 +2608,38 @@ static void cake_reconfigure(struct Qdisc *sch)
|
|||
break;
|
||||
}
|
||||
|
||||
for (c = q->tin_cnt; c < CAKE_MAX_TINS; c++) {
|
||||
for (c = qd->tin_cnt; c < CAKE_MAX_TINS; c++) {
|
||||
cake_clear_tin(sch, c);
|
||||
q->tins[c].cparams.mtu_time = q->tins[ft].cparams.mtu_time;
|
||||
qd->tins[c].cparams.mtu_time = qd->tins[ft].cparams.mtu_time;
|
||||
}
|
||||
|
||||
q->rate_ns = q->tins[ft].tin_rate_ns;
|
||||
q->rate_shft = q->tins[ft].tin_rate_shft;
|
||||
qd->rate_ns = qd->tins[ft].tin_rate_ns;
|
||||
qd->rate_shft = qd->tins[ft].tin_rate_shft;
|
||||
|
||||
if (q->buffer_config_limit) {
|
||||
q->buffer_limit = q->buffer_config_limit;
|
||||
qd->buffer_limit = q->buffer_config_limit;
|
||||
} else if (q->rate_bps) {
|
||||
u64 t = q->rate_bps * q->interval;
|
||||
|
||||
do_div(t, USEC_PER_SEC / 4);
|
||||
q->buffer_limit = max_t(u32, t, 4U << 20);
|
||||
qd->buffer_limit = max_t(u32, t, 4U << 20);
|
||||
} else {
|
||||
q->buffer_limit = ~0;
|
||||
qd->buffer_limit = ~0;
|
||||
}
|
||||
|
||||
sch->flags &= ~TCQ_F_CAN_BYPASS;
|
||||
|
||||
q->buffer_limit = min(q->buffer_limit,
|
||||
max(sch->limit * psched_mtu(qdisc_dev(sch)),
|
||||
q->buffer_config_limit));
|
||||
qd->buffer_limit = min(qd->buffer_limit,
|
||||
max(sch->limit * psched_mtu(qdisc_dev(sch)),
|
||||
q->buffer_config_limit));
|
||||
}
|
||||
|
||||
static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
static int cake_config_change(struct cake_sched_config *q, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack, bool *overhead_changed)
|
||||
{
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
struct nlattr *tb[TCA_CAKE_MAX + 1];
|
||||
u16 rate_flags;
|
||||
u8 flow_mode;
|
||||
u16 rate_flags = q->rate_flags;
|
||||
u8 flow_mode = q->flow_mode;
|
||||
int err;
|
||||
|
||||
err = nla_parse_nested_deprecated(tb, TCA_CAKE_MAX, opt, cake_policy,
|
||||
|
|
@ -2594,7 +2647,6 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
flow_mode = q->flow_mode;
|
||||
if (tb[TCA_CAKE_NAT]) {
|
||||
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
|
||||
flow_mode &= ~CAKE_FLOW_NAT_FLAG;
|
||||
|
|
@ -2607,6 +2659,19 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
#endif
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_AUTORATE]) {
|
||||
if (!!nla_get_u32(tb[TCA_CAKE_AUTORATE])) {
|
||||
if (q->is_shared) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, tb[TCA_CAKE_AUTORATE],
|
||||
"Can't use autorate-ingress with cake_mq");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
rate_flags |= CAKE_FLAG_AUTORATE_INGRESS;
|
||||
} else {
|
||||
rate_flags &= ~CAKE_FLAG_AUTORATE_INGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_BASE_RATE64])
|
||||
WRITE_ONCE(q->rate_bps,
|
||||
nla_get_u64(tb[TCA_CAKE_BASE_RATE64]));
|
||||
|
|
@ -2615,7 +2680,6 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
WRITE_ONCE(q->tin_mode,
|
||||
nla_get_u32(tb[TCA_CAKE_DIFFSERV_MODE]));
|
||||
|
||||
rate_flags = q->rate_flags;
|
||||
if (tb[TCA_CAKE_WASH]) {
|
||||
if (!!nla_get_u32(tb[TCA_CAKE_WASH]))
|
||||
rate_flags |= CAKE_FLAG_WASH;
|
||||
|
|
@ -2636,20 +2700,12 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
WRITE_ONCE(q->rate_overhead,
|
||||
nla_get_s32(tb[TCA_CAKE_OVERHEAD]));
|
||||
rate_flags |= CAKE_FLAG_OVERHEAD;
|
||||
|
||||
q->max_netlen = 0;
|
||||
q->max_adjlen = 0;
|
||||
q->min_netlen = ~0;
|
||||
q->min_adjlen = ~0;
|
||||
*overhead_changed = true;
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_RAW]) {
|
||||
rate_flags &= ~CAKE_FLAG_OVERHEAD;
|
||||
|
||||
q->max_netlen = 0;
|
||||
q->max_adjlen = 0;
|
||||
q->min_netlen = ~0;
|
||||
q->min_adjlen = ~0;
|
||||
*overhead_changed = true;
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_MPU])
|
||||
|
|
@ -2668,13 +2724,6 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
WRITE_ONCE(q->target, max(target, 1U));
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_AUTORATE]) {
|
||||
if (!!nla_get_u32(tb[TCA_CAKE_AUTORATE]))
|
||||
rate_flags |= CAKE_FLAG_AUTORATE_INGRESS;
|
||||
else
|
||||
rate_flags &= ~CAKE_FLAG_AUTORATE_INGRESS;
|
||||
}
|
||||
|
||||
if (tb[TCA_CAKE_INGRESS]) {
|
||||
if (!!nla_get_u32(tb[TCA_CAKE_INGRESS]))
|
||||
rate_flags |= CAKE_FLAG_INGRESS;
|
||||
|
|
@ -2705,7 +2754,35 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
|
||||
WRITE_ONCE(q->rate_flags, rate_flags);
|
||||
WRITE_ONCE(q->flow_mode, flow_mode);
|
||||
if (q->tins) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cake_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
struct cake_sched_config *q = qd->config;
|
||||
bool overhead_changed = false;
|
||||
int ret;
|
||||
|
||||
if (q->is_shared) {
|
||||
NL_SET_ERR_MSG(extack, "can't reconfigure cake_mq sub-qdiscs");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = cake_config_change(q, opt, extack, &overhead_changed);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (overhead_changed) {
|
||||
qd->max_netlen = 0;
|
||||
qd->max_adjlen = 0;
|
||||
qd->min_netlen = ~0;
|
||||
qd->min_adjlen = ~0;
|
||||
}
|
||||
|
||||
if (qd->tins) {
|
||||
sch_tree_lock(sch);
|
||||
cake_reconfigure(sch);
|
||||
sch_tree_unlock(sch);
|
||||
|
|
@ -2721,17 +2798,12 @@ static void cake_destroy(struct Qdisc *sch)
|
|||
qdisc_watchdog_cancel(&q->watchdog);
|
||||
tcf_block_put(q->block);
|
||||
kvfree(q->tins);
|
||||
if (q->config && !q->config->is_shared)
|
||||
kvfree(q->config);
|
||||
}
|
||||
|
||||
static int cake_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
static void cake_config_init(struct cake_sched_config *q, bool is_shared)
|
||||
{
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
int i, j, err;
|
||||
|
||||
sch->limit = 10240;
|
||||
sch->flags |= TCQ_F_DEQUEUE_DROPS;
|
||||
|
||||
q->tin_mode = CAKE_DIFFSERV_DIFFSERV3;
|
||||
q->flow_mode = CAKE_FLOW_TRIPLE;
|
||||
|
||||
|
|
@ -2742,33 +2814,56 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
|
|||
* for 5 to 10% of interval
|
||||
*/
|
||||
q->rate_flags |= CAKE_FLAG_SPLIT_GSO;
|
||||
q->cur_tin = 0;
|
||||
q->cur_flow = 0;
|
||||
q->is_shared = is_shared;
|
||||
q->sync_time = 200 * NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
qdisc_watchdog_init(&q->watchdog, sch);
|
||||
static int cake_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
struct cake_sched_config *q;
|
||||
int i, j, err;
|
||||
|
||||
q = kzalloc(sizeof(*q), GFP_KERNEL);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
cake_config_init(q, false);
|
||||
|
||||
sch->limit = 10240;
|
||||
sch->flags |= TCQ_F_DEQUEUE_DROPS;
|
||||
|
||||
qd->cur_tin = 0;
|
||||
qd->cur_flow = 0;
|
||||
qd->config = q;
|
||||
|
||||
qdisc_watchdog_init(&qd->watchdog, sch);
|
||||
|
||||
if (opt) {
|
||||
err = cake_change(sch, opt, extack);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
goto err;
|
||||
}
|
||||
|
||||
err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
|
||||
err = tcf_block_get(&qd->block, &qd->filter_list, sch, extack);
|
||||
if (err)
|
||||
return err;
|
||||
goto err;
|
||||
|
||||
quantum_div[0] = ~0;
|
||||
for (i = 1; i <= CAKE_QUEUES; i++)
|
||||
quantum_div[i] = 65535 / i;
|
||||
|
||||
q->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
|
||||
GFP_KERNEL);
|
||||
if (!q->tins)
|
||||
return -ENOMEM;
|
||||
qd->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
|
||||
GFP_KERNEL);
|
||||
if (!qd->tins) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < CAKE_MAX_TINS; i++) {
|
||||
struct cake_tin_data *b = q->tins + i;
|
||||
struct cake_tin_data *b = qd->tins + i;
|
||||
|
||||
INIT_LIST_HEAD(&b->new_flows);
|
||||
INIT_LIST_HEAD(&b->old_flows);
|
||||
|
|
@ -2784,22 +2879,41 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
|
|||
INIT_LIST_HEAD(&flow->flowchain);
|
||||
cobalt_vars_init(&flow->cvars);
|
||||
|
||||
q->overflow_heap[k].t = i;
|
||||
q->overflow_heap[k].b = j;
|
||||
qd->overflow_heap[k].t = i;
|
||||
qd->overflow_heap[k].b = j;
|
||||
b->overflow_idx[j] = k;
|
||||
}
|
||||
}
|
||||
|
||||
cake_reconfigure(sch);
|
||||
q->avg_peak_bandwidth = q->rate_bps;
|
||||
q->min_netlen = ~0;
|
||||
q->min_adjlen = ~0;
|
||||
qd->avg_peak_bandwidth = q->rate_bps;
|
||||
qd->min_netlen = ~0;
|
||||
qd->min_adjlen = ~0;
|
||||
qd->active_queues = 0;
|
||||
qd->last_checked_active = 0;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kvfree(qd->config);
|
||||
qd->config = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
static void cake_config_replace(struct Qdisc *sch, struct cake_sched_config *cfg)
|
||||
{
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
struct cake_sched_config *q = qd->config;
|
||||
|
||||
qd->config = cfg;
|
||||
|
||||
if (!q->is_shared)
|
||||
kvfree(q);
|
||||
|
||||
cake_reconfigure(sch);
|
||||
}
|
||||
|
||||
static int cake_config_dump(struct cake_sched_config *q, struct sk_buff *skb)
|
||||
{
|
||||
struct cake_sched_data *q = qdisc_priv(sch);
|
||||
struct nlattr *opts;
|
||||
u16 rate_flags;
|
||||
u8 flow_mode;
|
||||
|
|
@ -2875,6 +2989,13 @@ static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
{
|
||||
struct cake_sched_data *qd = qdisc_priv(sch);
|
||||
|
||||
return cake_config_dump(qd->config, skb);
|
||||
}
|
||||
|
||||
static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
|
||||
{
|
||||
struct nlattr *stats = nla_nest_start_noflag(d->skb, TCA_STATS_APP);
|
||||
|
|
@ -2903,6 +3024,7 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
|
|||
PUT_STAT_U32(MAX_ADJLEN, q->max_adjlen);
|
||||
PUT_STAT_U32(MIN_NETLEN, q->min_netlen);
|
||||
PUT_STAT_U32(MIN_ADJLEN, q->min_adjlen);
|
||||
PUT_STAT_U32(ACTIVE_QUEUES, q->active_queues);
|
||||
|
||||
#undef PUT_STAT_U32
|
||||
#undef PUT_STAT_U64
|
||||
|
|
@ -3136,14 +3258,133 @@ static struct Qdisc_ops cake_qdisc_ops __read_mostly = {
|
|||
};
|
||||
MODULE_ALIAS_NET_SCH("cake");
|
||||
|
||||
struct cake_mq_sched {
|
||||
struct mq_sched mq_priv; /* must be first */
|
||||
struct cake_sched_config cake_config;
|
||||
};
|
||||
|
||||
static void cake_mq_destroy(struct Qdisc *sch)
|
||||
{
|
||||
mq_destroy_common(sch);
|
||||
}
|
||||
|
||||
static int cake_mq_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cake_mq_sched *priv = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
int ret, ntx;
|
||||
bool _unused;
|
||||
|
||||
cake_config_init(&priv->cake_config, true);
|
||||
if (opt) {
|
||||
ret = cake_config_change(&priv->cake_config, opt, extack, &_unused);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mq_init_common(sch, opt, extack, &cake_qdisc_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++)
|
||||
cake_config_replace(priv->mq_priv.qdiscs[ntx], &priv->cake_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cake_mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
{
|
||||
struct cake_mq_sched *priv = qdisc_priv(sch);
|
||||
|
||||
mq_dump_common(sch, skb);
|
||||
return cake_config_dump(&priv->cake_config, skb);
|
||||
}
|
||||
|
||||
static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cake_mq_sched *priv = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
bool overhead_changed = false;
|
||||
unsigned int ntx;
|
||||
int ret;
|
||||
|
||||
ret = cake_config_change(&priv->cake_config, opt, extack, &overhead_changed);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||
struct Qdisc *chld = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
|
||||
struct cake_sched_data *qd = qdisc_priv(chld);
|
||||
|
||||
if (overhead_changed) {
|
||||
qd->max_netlen = 0;
|
||||
qd->max_adjlen = 0;
|
||||
qd->min_netlen = ~0;
|
||||
qd->min_adjlen = ~0;
|
||||
}
|
||||
|
||||
if (qd->tins) {
|
||||
sch_tree_lock(chld);
|
||||
cake_reconfigure(chld);
|
||||
sch_tree_unlock(chld);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cake_mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
|
||||
struct Qdisc **old, struct netlink_ext_ack *extack)
|
||||
{
|
||||
NL_SET_ERR_MSG(extack, "can't replace cake_mq sub-qdiscs");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct Qdisc_class_ops cake_mq_class_ops = {
|
||||
.select_queue = mq_select_queue,
|
||||
.graft = cake_mq_graft,
|
||||
.leaf = mq_leaf,
|
||||
.find = mq_find,
|
||||
.walk = mq_walk,
|
||||
.dump = mq_dump_class,
|
||||
.dump_stats = mq_dump_class_stats,
|
||||
};
|
||||
|
||||
static struct Qdisc_ops cake_mq_qdisc_ops __read_mostly = {
|
||||
.cl_ops = &cake_mq_class_ops,
|
||||
.id = "cake_mq",
|
||||
.priv_size = sizeof(struct cake_mq_sched),
|
||||
.init = cake_mq_init,
|
||||
.destroy = cake_mq_destroy,
|
||||
.attach = mq_attach,
|
||||
.change = cake_mq_change,
|
||||
.change_real_num_tx = mq_change_real_num_tx,
|
||||
.dump = cake_mq_dump,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
MODULE_ALIAS_NET_SCH("cake_mq");
|
||||
|
||||
static int __init cake_module_init(void)
|
||||
{
|
||||
return register_qdisc(&cake_qdisc_ops);
|
||||
int ret;
|
||||
|
||||
ret = register_qdisc(&cake_qdisc_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = register_qdisc(&cake_mq_qdisc_ops);
|
||||
if (ret)
|
||||
unregister_qdisc(&cake_qdisc_ops);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit cake_module_exit(void)
|
||||
{
|
||||
unregister_qdisc(&cake_qdisc_ops);
|
||||
unregister_qdisc(&cake_mq_qdisc_ops);
|
||||
}
|
||||
|
||||
module_init(cake_module_init)
|
||||
|
|
@ -3151,3 +3392,4 @@ module_exit(cake_module_exit)
|
|||
MODULE_AUTHOR("Jonathan Morton");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("The CAKE shaper.");
|
||||
MODULE_IMPORT_NS("NET_SCHED_INTERNAL");
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@
|
|||
#include <net/netlink.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/pkt_sched.h>
|
||||
#include <net/sch_generic.h>
|
||||
|
||||
struct mq_sched {
|
||||
struct Qdisc **qdiscs;
|
||||
};
|
||||
#include <net/sch_priv.h>
|
||||
|
||||
static int mq_offload(struct Qdisc *sch, enum tc_mq_command cmd)
|
||||
{
|
||||
|
|
@ -49,23 +45,29 @@ static int mq_offload_stats(struct Qdisc *sch)
|
|||
return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_MQ, &opt);
|
||||
}
|
||||
|
||||
static void mq_destroy(struct Qdisc *sch)
|
||||
void mq_destroy_common(struct Qdisc *sch)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct mq_sched *priv = qdisc_priv(sch);
|
||||
unsigned int ntx;
|
||||
|
||||
mq_offload(sch, TC_MQ_DESTROY);
|
||||
|
||||
if (!priv->qdiscs)
|
||||
return;
|
||||
for (ntx = 0; ntx < dev->num_tx_queues && priv->qdiscs[ntx]; ntx++)
|
||||
qdisc_put(priv->qdiscs[ntx]);
|
||||
kfree(priv->qdiscs);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_destroy_common, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
static void mq_destroy(struct Qdisc *sch)
|
||||
{
|
||||
mq_offload(sch, TC_MQ_DESTROY);
|
||||
mq_destroy_common(sch);
|
||||
}
|
||||
|
||||
int mq_init_common(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack,
|
||||
const struct Qdisc_ops *qdisc_ops)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct mq_sched *priv = qdisc_priv(sch);
|
||||
|
|
@ -87,7 +89,8 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt,
|
|||
|
||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||
dev_queue = netdev_get_tx_queue(dev, ntx);
|
||||
qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx),
|
||||
qdisc = qdisc_create_dflt(dev_queue,
|
||||
qdisc_ops ?: get_default_qdisc_ops(dev, ntx),
|
||||
TC_H_MAKE(TC_H_MAJ(sch->handle),
|
||||
TC_H_MIN(ntx + 1)),
|
||||
extack);
|
||||
|
|
@ -98,12 +101,24 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt,
|
|||
}
|
||||
|
||||
sch->flags |= TCQ_F_MQROOT;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_init_common, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_init(struct Qdisc *sch, struct nlattr *opt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mq_init_common(sch, opt, extack, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mq_offload(sch, TC_MQ_CREATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mq_attach(struct Qdisc *sch)
|
||||
void mq_attach(struct Qdisc *sch)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct mq_sched *priv = qdisc_priv(sch);
|
||||
|
|
@ -124,8 +139,9 @@ static void mq_attach(struct Qdisc *sch)
|
|||
kfree(priv->qdiscs);
|
||||
priv->qdiscs = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_attach, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
void mq_dump_common(struct Qdisc *sch, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
struct Qdisc *qdisc;
|
||||
|
|
@ -152,7 +168,12 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
|||
|
||||
spin_unlock_bh(qdisc_lock(qdisc));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_dump_common, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
{
|
||||
mq_dump_common(sch, skb);
|
||||
return mq_offload_stats(sch);
|
||||
}
|
||||
|
||||
|
|
@ -166,11 +187,12 @@ static struct netdev_queue *mq_queue_get(struct Qdisc *sch, unsigned long cl)
|
|||
return netdev_get_tx_queue(dev, ntx);
|
||||
}
|
||||
|
||||
static struct netdev_queue *mq_select_queue(struct Qdisc *sch,
|
||||
struct tcmsg *tcm)
|
||||
struct netdev_queue *mq_select_queue(struct Qdisc *sch,
|
||||
struct tcmsg *tcm)
|
||||
{
|
||||
return mq_queue_get(sch, TC_H_MIN(tcm->tcm_parent));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_select_queue, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
|
||||
struct Qdisc **old, struct netlink_ext_ack *extack)
|
||||
|
|
@ -198,14 +220,15 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl)
|
||||
struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl)
|
||||
{
|
||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||
|
||||
return rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_leaf, "NET_SCHED_INTERNAL");
|
||||
|
||||
static unsigned long mq_find(struct Qdisc *sch, u32 classid)
|
||||
unsigned long mq_find(struct Qdisc *sch, u32 classid)
|
||||
{
|
||||
unsigned int ntx = TC_H_MIN(classid);
|
||||
|
||||
|
|
@ -213,9 +236,10 @@ static unsigned long mq_find(struct Qdisc *sch, u32 classid)
|
|||
return 0;
|
||||
return ntx;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_find, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_dump_class(struct Qdisc *sch, unsigned long cl,
|
||||
struct sk_buff *skb, struct tcmsg *tcm)
|
||||
int mq_dump_class(struct Qdisc *sch, unsigned long cl,
|
||||
struct sk_buff *skb, struct tcmsg *tcm)
|
||||
{
|
||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||
|
||||
|
|
@ -224,9 +248,10 @@ static int mq_dump_class(struct Qdisc *sch, unsigned long cl,
|
|||
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_dump_class, "NET_SCHED_INTERNAL");
|
||||
|
||||
static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
struct gnet_dump *d)
|
||||
int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
||||
struct gnet_dump *d)
|
||||
{
|
||||
struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
|
||||
|
||||
|
|
@ -236,8 +261,9 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
|||
return -1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_dump_class_stats, "NET_SCHED_INTERNAL");
|
||||
|
||||
static void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
|
||||
void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
|
||||
{
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
unsigned int ntx;
|
||||
|
|
@ -251,6 +277,7 @@ static void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
|
|||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(mq_walk, "NET_SCHED_INTERNAL");
|
||||
|
||||
static const struct Qdisc_class_ops mq_class_ops = {
|
||||
.select_queue = mq_select_queue,
|
||||
|
|
|
|||
559
tools/testing/selftests/tc-testing/tc-tests/qdiscs/cake_mq.json
Normal file
559
tools/testing/selftests/tc-testing/tc-tests/qdiscs/cake_mq.json
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
[
|
||||
{
|
||||
"id": "684b",
|
||||
"name": "Create CAKE_MQ with default setting (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device || true",
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7ee8",
|
||||
"name": "Create CAKE_MQ with bandwidth limit (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq bandwidth 1000",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth 1Kbit diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1f87",
|
||||
"name": "Create CAKE_MQ with rtt time (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq rtt 200",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 200us raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e9cf",
|
||||
"name": "Create CAKE_MQ with besteffort flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq besteffort",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited besteffort triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7c05",
|
||||
"name": "Create CAKE_MQ with diffserv8 flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq diffserv8",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv8 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5a77",
|
||||
"name": "Create CAKE_MQ with diffserv4 flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq diffserv4",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv4 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "8f7a",
|
||||
"name": "Create CAKE_MQ with flowblind flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq flowblind",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 flowblind nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7ef7",
|
||||
"name": "Create CAKE_MQ with dsthost and nat flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq dsthost nat",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 dsthost nat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2e4d",
|
||||
"name": "Create CAKE_MQ with wash flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq hosts wash",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 hosts nonat wash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b3e6",
|
||||
"name": "Create CAKE_MQ with flowblind and no-split-gso flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq flowblind no-split-gso",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 flowblind nonat nowash no-ack-filter no-split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "62cd",
|
||||
"name": "Create CAKE_MQ with dual-srchost and ack-filter flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq dual-srchost ack-filter",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 dual-srchost nonat nowash ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "0df3",
|
||||
"name": "Create CAKE_MQ with dual-dsthost and ack-filter-aggressive flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq dual-dsthost ack-filter-aggressive",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 dual-dsthost nonat nowash ack-filter-aggressive split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "9a75",
|
||||
"name": "Create CAKE_MQ with memlimit and ptm flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq memlimit 10000 ptm",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw ptm overhead 0 memlimit 10000b ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "cdef",
|
||||
"name": "Create CAKE_MQ with fwmark and atm flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq fwmark 8 atm",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw atm overhead 0 fwmark 0x8 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "93dd",
|
||||
"name": "Create CAKE_MQ with overhead 0 and mpu (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq overhead 128 mpu 256",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms noatm overhead 128 mpu 256 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "1475",
|
||||
"name": "Create CAKE_MQ with conservative and ingress flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq conservative ingress",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash ingress no-ack-filter split-gso rtt 100ms atm overhead 48 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7bf1",
|
||||
"name": "Delete CAKE_MQ with conservative and ingress flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq conservative ingress"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc del dev $ETH handle 1: root",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash ingress no-ack-filter split-gso rtt 100ms atm overhead 48 ",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ee55",
|
||||
"name": "Replace CAKE_MQ with mpu (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq overhead 128 mpu 256"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH handle 1: root cake_mq mpu 128",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms noatm overhead 128 mpu 128 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6df9",
|
||||
"name": "Change CAKE_MQ with mpu (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq overhead 128 mpu 256"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc change dev $ETH handle 1: root cake_mq mpu 128",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms noatm overhead 128 mpu 128 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "67e2",
|
||||
"name": "Show CAKE_MQ class (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC class show dev $ETH",
|
||||
"matchPattern": "class cake_mq",
|
||||
"matchCount": "4",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2de4",
|
||||
"name": "Change bandwidth of CAKE_MQ (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH handle 1: root cake_mq bandwidth 1000",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth 1Kbit diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5f62",
|
||||
"name": "Fail to create CAKE_MQ with autorate-ingress flag (4 queues)",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq autorate-ingress",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited autorate-ingress diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "038e",
|
||||
"name": "Fail to change setting of sub-qdisc under CAKE_MQ",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH parent 1:1 cake besteffort flows",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7bdc",
|
||||
"name": "Fail to replace sub-qdisc under CAKE_MQ",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 4\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc add dev $ETH handle 1: root cake_mq"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH parent 1:1 fq",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "5",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "18e0",
|
||||
"name": "Fail to install CAKE_MQ on single queue device",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"cake_mq"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 1\" > /sys/bus/netdevsim/new_device"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc add dev $ETH handle 1: root cake_mq",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "$TC qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc (cake_mq 1: root|cake 0: parent 1:[1-4]) bandwidth unlimited diffserv3 triple-isolate nonat nowash no-ack-filter split-gso rtt 100ms raw overhead 0 ",
|
||||
"matchCount": "0",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue
Block a user