This adds support for configuring the cake_mq instance directly, sharing the config across the cake sub-qdiscs. Signed-off-by: Toke Høiland-Jørgensen --- net/sched/sch_cake.c | 147 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 118 insertions(+), 29 deletions(-) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index d17d7669de389bb21ca6ce3b209e0272cfaa5112..7ceccbfaa9b6b4cdeaf17b416c2b65709c22a60a 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -211,6 +211,7 @@ struct cake_sched_config { u8 flow_mode; u8 atm_mode; u8 ack_filter; + u8 is_shared; }; struct cake_sched_data { @@ -2585,11 +2586,9 @@ static void cake_reconfigure(struct Qdisc *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 *qd = qdisc_priv(sch); - struct cake_sched_config *q = qd->config; struct nlattr *tb[TCA_CAKE_MAX + 1]; u16 rate_flags; u8 flow_mode; @@ -2642,20 +2641,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; - - qd->max_netlen = 0; - qd->max_adjlen = 0; - qd->min_netlen = ~0; - qd->min_adjlen = ~0; + *overhead_changed = true; } if (tb[TCA_CAKE_RAW]) { rate_flags &= ~CAKE_FLAG_OVERHEAD; - - qd->max_netlen = 0; - qd->max_adjlen = 0; - qd->min_netlen = ~0; - qd->min_adjlen = ~0; + *overhead_changed = true; } if (tb[TCA_CAKE_MPU]) @@ -2711,6 +2702,34 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt, WRITE_ONCE(q->rate_flags, rate_flags); WRITE_ONCE(q->flow_mode, flow_mode); + + 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); @@ -2727,7 +2746,23 @@ static void cake_destroy(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); tcf_block_put(q->block); kvfree(q->tins); - kvfree(q->config); + if (!q->config->is_shared) + kvfree(q->config); +} + +static void cake_config_init(struct cake_sched_config *q, bool is_shared) +{ + q->tin_mode = CAKE_DIFFSERV_DIFFSERV3; + q->flow_mode = CAKE_FLOW_TRIPLE; + + q->rate_bps = 0; /* unlimited by default */ + + q->interval = 100000; /* 100ms default */ + q->target = 5000; /* 5ms: codel RFC argues + * for 5 to 10% of interval + */ + q->rate_flags |= CAKE_FLAG_SPLIT_GSO; + q->is_shared = is_shared; } static int cake_init(struct Qdisc *sch, struct nlattr *opt, @@ -2741,17 +2776,9 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt, if (!q) return -ENOMEM; + cake_config_init(q, false); + sch->limit = 10240; - q->tin_mode = CAKE_DIFFSERV_DIFFSERV3; - q->flow_mode = CAKE_FLOW_TRIPLE; - - q->rate_bps = 0; /* unlimited by default */ - - q->interval = 100000; /* 100ms default */ - q->target = 5000; /* 5ms: codel RFC argues - * for 5 to 10% of interval - */ - q->rate_flags |= CAKE_FLAG_SPLIT_GSO; qd->cur_tin = 0; qd->cur_flow = 0; qd->config = q; @@ -2814,10 +2841,21 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt, 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 nlattr *opts; u16 rate_flags; u8 flow_mode; @@ -2893,6 +2931,14 @@ 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); + struct cake_sched_config *q = qd->config; + + return cake_config_dump(q, 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); @@ -3155,7 +3201,8 @@ static struct Qdisc_ops cake_qdisc_ops __read_mostly = { MODULE_ALIAS_NET_SCH("cake"); struct cake_mq_sched { - struct Qdisc **qdiscs; + struct Qdisc **qdiscs; + struct cake_sched_config cake_config; }; static void cake_mq_destroy(struct Qdisc *sch) @@ -3179,6 +3226,8 @@ static int cake_mq_init(struct Qdisc *sch, struct nlattr *opt, struct netdev_queue *dev_queue; struct Qdisc *qdisc; unsigned int ntx; + bool _unused; + int ret; if (sch->parent != TC_H_ROOT) return -EOPNOTSUPP; @@ -3186,6 +3235,11 @@ static int cake_mq_init(struct Qdisc *sch, struct nlattr *opt, if (!netif_is_multiqueue(dev)) return -EOPNOTSUPP; + cake_config_init(&priv->cake_config, true); + ret = cake_config_change(&priv->cake_config, opt, extack, &_unused); + if (ret) + return ret; + /* pre-allocate qdiscs, attachment can't fail */ priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), GFP_KERNEL); @@ -3204,6 +3258,7 @@ static int cake_mq_init(struct Qdisc *sch, struct nlattr *opt, } priv->qdiscs[ntx] = qdisc; qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + cake_config_replace(qdisc, &priv->cake_config); } sch->flags |= TCQ_F_MQROOT; @@ -3232,8 +3287,42 @@ static void cake_mq_attach(struct Qdisc *sch) priv->qdiscs = NULL; } +static int cake_mq_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) +{ + struct net_device *dev = qdisc_dev(sch); + struct cake_mq_sched *priv = qdisc_priv(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; + + sch_tree_lock(sch); + 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) + cake_reconfigure(chld); + } + sch_tree_unlock(sch); + + return 0; +} + static int cake_mq_dump(struct Qdisc *sch, struct sk_buff *skb) { + struct cake_mq_sched *qd = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); struct Qdisc *qdisc; unsigned int ntx; @@ -3260,7 +3349,7 @@ static int cake_mq_dump(struct Qdisc *sch, struct sk_buff *skb) spin_unlock_bh(qdisc_lock(qdisc)); } - return 0; + return cake_config_dump(&qd->cake_config, skb); } static struct netdev_queue *cake_mq_queue_get(struct Qdisc *sch, unsigned long cl) @@ -3357,7 +3446,7 @@ static struct Qdisc_ops cake_mq_qdisc_ops __read_mostly = { .init = cake_mq_init, .destroy = cake_mq_destroy, .attach = cake_mq_attach, - // .change = cake_mq_change, + .change = cake_mq_change, .change_real_num_tx = mq_change_real_num_tx, .dump = cake_mq_dump, .owner = THIS_MODULE, -- 2.51.0