Merge branch 'improve-the-taprio-qdisc-s-relationship-with-its-children'
Vladimir Oltean says:
====================
Improve the taprio qdisc's relationship with its children
v1: https://lore.kernel.org/lkml/20230531173928.1942027-1-vladimir.oltean@nxp.com/
Prompted by Vinicius' request to consolidate some child Qdisc
dereferences in taprio:
https://lore.kernel.org/netdev/87edmxv7x2.fsf@intel.com/
I remembered that I had left some unfinished work in this Qdisc, namely
commit af7b29b1de
("Revert "net/sched: taprio: make qdisc_leaf() see
the per-netdev-queue pfifo child qdiscs"").
This patch set represents another stab at, essentially, what's in the
title. Not only does taprio not properly detect when it's grafted as a
non-root qdisc, but it also returns incorrect per-class stats.
Eventually, Vinicius' request is addressed too, although in a different
form than the one he requested (which was purely cosmetic).
Review from people more experienced with Qdiscs than me would be
appreciated. I tried my best to explain what I consider to be problems.
I am deliberately targeting net-next because the changes are too
invasive for net - they were reverted from stable once already.
====================
Link: https://lore.kernel.org/r/20230807193324.4128292-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
29afcd6967
|
@ -17170,6 +17170,13 @@ F: drivers/ptp/*
|
|||
F: include/linux/ptp_cl*
|
||||
K: (?:\b|_)ptp(?:\b|_)
|
||||
|
||||
PTP MOCKUP CLOCK SUPPORT
|
||||
M: Vladimir Oltean <vladimir.oltean@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/ptp/ptp_mock.c
|
||||
F: include/linux/ptp_mock.h
|
||||
|
||||
PTP VIRTUAL CLOCK SUPPORT
|
||||
M: Yangbo Lu <yangbo.lu@nxp.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
|
@ -592,6 +592,7 @@ config NETDEVSIM
|
|||
depends on INET
|
||||
depends on IPV6 || IPV6=n
|
||||
depends on PSAMPLE || PSAMPLE=n
|
||||
depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n
|
||||
select NET_DEVLINK
|
||||
help
|
||||
This driver is a developer testing tool and software model that can
|
||||
|
|
|
@ -140,6 +140,16 @@ nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nsim_get_ts_info(struct net_device *dev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
info->phc_index = mock_phc_index(ns->phc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops nsim_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS,
|
||||
.get_pause_stats = nsim_get_pause_stats,
|
||||
|
@ -153,6 +163,7 @@ static const struct ethtool_ops nsim_ethtool_ops = {
|
|||
.set_channels = nsim_set_channels,
|
||||
.get_fecparam = nsim_get_fecparam,
|
||||
.set_fecparam = nsim_set_fecparam,
|
||||
.get_ts_info = nsim_get_ts_info,
|
||||
};
|
||||
|
||||
static void nsim_ethtool_ring_init(struct netdevsim *ns)
|
||||
|
|
|
@ -209,6 +209,31 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void nsim_taprio_stats(struct tc_taprio_qopt_stats *stats)
|
||||
{
|
||||
stats->window_drops = 0;
|
||||
stats->tx_overruns = 0;
|
||||
}
|
||||
|
||||
static int nsim_setup_tc_taprio(struct net_device *dev,
|
||||
struct tc_taprio_qopt_offload *offload)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (offload->cmd) {
|
||||
case TAPRIO_CMD_REPLACE:
|
||||
case TAPRIO_CMD_DESTROY:
|
||||
break;
|
||||
case TAPRIO_CMD_STATS:
|
||||
nsim_taprio_stats(&offload->stats);
|
||||
break;
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static LIST_HEAD(nsim_block_cb_list);
|
||||
|
||||
static int
|
||||
|
@ -217,6 +242,8 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
|
|||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
switch (type) {
|
||||
case TC_SETUP_QDISC_TAPRIO:
|
||||
return nsim_setup_tc_taprio(dev, type_data);
|
||||
case TC_SETUP_BLOCK:
|
||||
return flow_block_cb_setup_simple(type_data,
|
||||
&nsim_block_cb_list,
|
||||
|
@ -291,13 +318,19 @@ static void nsim_setup(struct net_device *dev)
|
|||
|
||||
static int nsim_init_netdevsim(struct netdevsim *ns)
|
||||
{
|
||||
struct mock_phc *phc;
|
||||
int err;
|
||||
|
||||
phc = mock_phc_create(&ns->nsim_bus_dev->dev);
|
||||
if (IS_ERR(phc))
|
||||
return PTR_ERR(phc);
|
||||
|
||||
ns->phc = phc;
|
||||
ns->netdev->netdev_ops = &nsim_netdev_ops;
|
||||
|
||||
err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_phc_destroy;
|
||||
|
||||
rtnl_lock();
|
||||
err = nsim_bpf_init(ns);
|
||||
|
@ -320,6 +353,8 @@ err_ipsec_teardown:
|
|||
err_utn_destroy:
|
||||
rtnl_unlock();
|
||||
nsim_udp_tunnels_info_destroy(ns->netdev);
|
||||
err_phc_destroy:
|
||||
mock_phc_destroy(ns->phc);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -383,6 +418,7 @@ void nsim_destroy(struct netdevsim *ns)
|
|||
rtnl_unlock();
|
||||
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
|
||||
nsim_udp_tunnels_info_destroy(dev);
|
||||
mock_phc_destroy(ns->phc);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ptp_mock.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/devlink.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
|
@ -93,6 +94,7 @@ struct netdevsim {
|
|||
struct net_device *netdev;
|
||||
struct nsim_dev *nsim_dev;
|
||||
struct nsim_dev_port *nsim_dev_port;
|
||||
struct mock_phc *phc;
|
||||
|
||||
u64 tx_packets;
|
||||
u64 tx_bytes;
|
||||
|
|
|
@ -155,6 +155,17 @@ config PTP_1588_CLOCK_IDTCM
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called ptp_clockmatrix.
|
||||
|
||||
config PTP_1588_CLOCK_MOCK
|
||||
tristate "Mock-up PTP clock"
|
||||
depends on PTP_1588_CLOCK
|
||||
help
|
||||
This driver offers a set of PTP clock manipulation operations over
|
||||
the system monotonic time. It can be used by virtual network device
|
||||
drivers to emulate PTP capabilities.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ptp_mock.
|
||||
|
||||
config PTP_1588_CLOCK_VMW
|
||||
tristate "VMware virtual PTP clock"
|
||||
depends on ACPI && HYPERVISOR_GUEST && X86
|
||||
|
|
|
@ -16,6 +16,7 @@ ptp-qoriq-y += ptp_qoriq.o
|
|||
ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o
|
||||
obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o
|
||||
obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o
|
||||
obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o
|
||||
obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o
|
||||
obj-$(CONFIG_PTP_1588_CLOCK_OCP) += ptp_ocp.o
|
||||
obj-$(CONFIG_PTP_DFL_TOD) += ptp_dfl_tod.o
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2023 NXP
|
||||
*
|
||||
* Mock-up PTP Hardware Clock driver for virtual network devices
|
||||
*
|
||||
* Create a PTP clock which offers PTP time manipulation operations
|
||||
* using a timecounter/cyclecounter on top of CLOCK_MONOTONIC_RAW.
|
||||
*/
|
||||
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/ptp_mock.h>
|
||||
#include <linux/timecounter.h>
|
||||
|
||||
/* Clamp scaled_ppm between -2,097,152,000 and 2,097,152,000,
|
||||
* and thus "adj" between -68,719,476 and 68,719,476
|
||||
*/
|
||||
#define MOCK_PHC_MAX_ADJ_PPB 32000000
|
||||
/* Timestamps from ktime_get_raw() have 1 ns resolution, so the scale factor
|
||||
* (MULT >> SHIFT) needs to be 1. Pick SHIFT as 31 bits, which translates
|
||||
* MULT(freq 0) into 0x80000000.
|
||||
*/
|
||||
#define MOCK_PHC_CC_SHIFT 31
|
||||
#define MOCK_PHC_CC_MULT (1 << MOCK_PHC_CC_SHIFT)
|
||||
#define MOCK_PHC_FADJ_SHIFT 9
|
||||
#define MOCK_PHC_FADJ_DENOMINATOR 15625ULL
|
||||
|
||||
/* The largest cycle_delta that timecounter_read_delta() can handle without a
|
||||
* 64-bit overflow during the multiplication with cc->mult, given the max "adj"
|
||||
* we permit, is ~8.3 seconds. Make sure readouts are more frequent than that.
|
||||
*/
|
||||
#define MOCK_PHC_REFRESH_INTERVAL (HZ * 5)
|
||||
|
||||
#define info_to_phc(d) container_of((d), struct mock_phc, info)
|
||||
|
||||
struct mock_phc {
|
||||
struct ptp_clock_info info;
|
||||
struct ptp_clock *clock;
|
||||
struct timecounter tc;
|
||||
struct cyclecounter cc;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static u64 mock_phc_cc_read(const struct cyclecounter *cc)
|
||||
{
|
||||
return ktime_get_raw_ns();
|
||||
}
|
||||
|
||||
static int mock_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
|
||||
{
|
||||
struct mock_phc *phc = info_to_phc(info);
|
||||
s64 adj;
|
||||
|
||||
adj = (s64)scaled_ppm << MOCK_PHC_FADJ_SHIFT;
|
||||
adj = div_s64(adj, MOCK_PHC_FADJ_DENOMINATOR);
|
||||
|
||||
spin_lock(&phc->lock);
|
||||
timecounter_read(&phc->tc);
|
||||
phc->cc.mult = MOCK_PHC_CC_MULT + adj;
|
||||
spin_unlock(&phc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mock_phc_adjtime(struct ptp_clock_info *info, s64 delta)
|
||||
{
|
||||
struct mock_phc *phc = info_to_phc(info);
|
||||
|
||||
spin_lock(&phc->lock);
|
||||
timecounter_adjtime(&phc->tc, delta);
|
||||
spin_unlock(&phc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mock_phc_settime64(struct ptp_clock_info *info,
|
||||
const struct timespec64 *ts)
|
||||
{
|
||||
struct mock_phc *phc = info_to_phc(info);
|
||||
u64 ns = timespec64_to_ns(ts);
|
||||
|
||||
spin_lock(&phc->lock);
|
||||
timecounter_init(&phc->tc, &phc->cc, ns);
|
||||
spin_unlock(&phc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mock_phc_gettime64(struct ptp_clock_info *info, struct timespec64 *ts)
|
||||
{
|
||||
struct mock_phc *phc = info_to_phc(info);
|
||||
u64 ns;
|
||||
|
||||
spin_lock(&phc->lock);
|
||||
ns = timecounter_read(&phc->tc);
|
||||
spin_unlock(&phc->lock);
|
||||
|
||||
*ts = ns_to_timespec64(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long mock_phc_refresh(struct ptp_clock_info *info)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
|
||||
mock_phc_gettime64(info, &ts);
|
||||
|
||||
return MOCK_PHC_REFRESH_INTERVAL;
|
||||
}
|
||||
|
||||
int mock_phc_index(struct mock_phc *phc)
|
||||
{
|
||||
return ptp_clock_index(phc->clock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mock_phc_index);
|
||||
|
||||
struct mock_phc *mock_phc_create(struct device *dev)
|
||||
{
|
||||
struct mock_phc *phc;
|
||||
int err;
|
||||
|
||||
phc = kzalloc(sizeof(*phc), GFP_KERNEL);
|
||||
if (!phc) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phc->info = (struct ptp_clock_info) {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Mock-up PTP clock",
|
||||
.max_adj = MOCK_PHC_MAX_ADJ_PPB,
|
||||
.adjfine = mock_phc_adjfine,
|
||||
.adjtime = mock_phc_adjtime,
|
||||
.gettime64 = mock_phc_gettime64,
|
||||
.settime64 = mock_phc_settime64,
|
||||
.do_aux_work = mock_phc_refresh,
|
||||
};
|
||||
|
||||
phc->cc = (struct cyclecounter) {
|
||||
.read = mock_phc_cc_read,
|
||||
.mask = CYCLECOUNTER_MASK(64),
|
||||
.mult = MOCK_PHC_CC_MULT,
|
||||
.shift = MOCK_PHC_CC_SHIFT,
|
||||
};
|
||||
|
||||
spin_lock_init(&phc->lock);
|
||||
timecounter_init(&phc->tc, &phc->cc, 0);
|
||||
|
||||
phc->clock = ptp_clock_register(&phc->info, dev);
|
||||
if (IS_ERR(phc->clock)) {
|
||||
err = PTR_ERR(phc->clock);
|
||||
goto out_free_phc;
|
||||
}
|
||||
|
||||
ptp_schedule_worker(phc->clock, MOCK_PHC_REFRESH_INTERVAL);
|
||||
|
||||
return phc;
|
||||
|
||||
out_free_phc:
|
||||
kfree(phc);
|
||||
out:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mock_phc_create);
|
||||
|
||||
void mock_phc_destroy(struct mock_phc *phc)
|
||||
{
|
||||
ptp_clock_unregister(phc->clock);
|
||||
kfree(phc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mock_phc_destroy);
|
||||
|
||||
MODULE_DESCRIPTION("Mock-up PTP Hardware Clock driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,38 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Mock-up PTP Hardware Clock driver for virtual network devices
|
||||
*
|
||||
* Copyright 2023 NXP
|
||||
*/
|
||||
|
||||
#ifndef _PTP_MOCK_H_
|
||||
#define _PTP_MOCK_H_
|
||||
|
||||
struct device;
|
||||
struct mock_phc;
|
||||
|
||||
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK_MOCK)
|
||||
|
||||
struct mock_phc *mock_phc_create(struct device *dev);
|
||||
void mock_phc_destroy(struct mock_phc *phc);
|
||||
int mock_phc_index(struct mock_phc *phc);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct mock_phc *mock_phc_create(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void mock_phc_destroy(struct mock_phc *phc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mock_phc_index(struct mock_phc *phc)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _PTP_MOCK_H_ */
|
|
@ -2099,11 +2099,8 @@ static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* pre-allocate qdisc, attachment can't fail */
|
||||
q->qdiscs = kcalloc(dev->num_tx_queues,
|
||||
sizeof(q->qdiscs[0]),
|
||||
q->qdiscs = kcalloc(dev->num_tx_queues, sizeof(q->qdiscs[0]),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!q->qdiscs)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2145,25 +2142,32 @@ static void taprio_attach(struct Qdisc *sch)
|
|||
|
||||
/* Attach underlying qdisc */
|
||||
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
|
||||
struct Qdisc *qdisc = q->qdiscs[ntx];
|
||||
struct Qdisc *old;
|
||||
struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, ntx);
|
||||
struct Qdisc *old, *dev_queue_qdisc;
|
||||
|
||||
if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
|
||||
struct Qdisc *qdisc = q->qdiscs[ntx];
|
||||
|
||||
/* In offload mode, the root taprio qdisc is bypassed
|
||||
* and the netdev TX queues see the children directly
|
||||
*/
|
||||
qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
|
||||
old = dev_graft_qdisc(qdisc->dev_queue, qdisc);
|
||||
dev_queue_qdisc = qdisc;
|
||||
} else {
|
||||
old = dev_graft_qdisc(qdisc->dev_queue, sch);
|
||||
qdisc_refcount_inc(sch);
|
||||
/* In software mode, attach the root taprio qdisc
|
||||
* to all netdev TX queues, so that dev_qdisc_enqueue()
|
||||
* goes through taprio_enqueue().
|
||||
*/
|
||||
dev_queue_qdisc = sch;
|
||||
}
|
||||
old = dev_graft_qdisc(dev_queue, dev_queue_qdisc);
|
||||
/* The qdisc's refcount requires to be elevated once
|
||||
* for each netdev TX queue it is grafted onto
|
||||
*/
|
||||
qdisc_refcount_inc(dev_queue_qdisc);
|
||||
if (old)
|
||||
qdisc_put(old);
|
||||
}
|
||||
|
||||
/* access to the child qdiscs is not needed in offload mode */
|
||||
if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
|
||||
kfree(q->qdiscs);
|
||||
q->qdiscs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct netdev_queue *taprio_queue_get(struct Qdisc *sch,
|
||||
|
@ -2192,13 +2196,23 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,
|
|||
if (dev->flags & IFF_UP)
|
||||
dev_deactivate(dev);
|
||||
|
||||
/* In offload mode, the child Qdisc is directly attached to the netdev
|
||||
* TX queue, and thus, we need to keep its refcount elevated in order
|
||||
* to counteract qdisc_graft()'s call to qdisc_put() once per TX queue.
|
||||
* However, save the reference to the new qdisc in the private array in
|
||||
* both software and offload cases, to have an up-to-date reference to
|
||||
* our children.
|
||||
*/
|
||||
*old = q->qdiscs[cl - 1];
|
||||
if (FULL_OFFLOAD_IS_ENABLED(q->flags)) {
|
||||
*old = dev_graft_qdisc(dev_queue, new);
|
||||
} else {
|
||||
*old = q->qdiscs[cl - 1];
|
||||
q->qdiscs[cl - 1] = new;
|
||||
WARN_ON_ONCE(dev_graft_qdisc(dev_queue, new) != *old);
|
||||
if (new)
|
||||
qdisc_refcount_inc(new);
|
||||
if (*old)
|
||||
qdisc_put(*old);
|
||||
}
|
||||
|
||||
q->qdiscs[cl - 1] = new;
|
||||
if (new)
|
||||
new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
|
||||
|
||||
|
@ -2436,12 +2450,14 @@ start_error:
|
|||
|
||||
static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
|
||||
{
|
||||
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
||||
struct taprio_sched *q = qdisc_priv(sch);
|
||||
struct net_device *dev = qdisc_dev(sch);
|
||||
unsigned int ntx = cl - 1;
|
||||
|
||||
if (!dev_queue)
|
||||
if (ntx >= dev->num_tx_queues)
|
||||
return NULL;
|
||||
|
||||
return rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
return q->qdiscs[ntx];
|
||||
}
|
||||
|
||||
static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
|
||||
|
@ -2456,11 +2472,11 @@ static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
|
|||
static int taprio_dump_class(struct Qdisc *sch, unsigned long cl,
|
||||
struct sk_buff *skb, struct tcmsg *tcm)
|
||||
{
|
||||
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
||||
struct Qdisc *child = taprio_leaf(sch, cl);
|
||||
|
||||
tcm->tcm_parent = TC_H_ROOT;
|
||||
tcm->tcm_handle |= TC_H_MIN(cl);
|
||||
tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
|
||||
tcm->tcm_info = child->handle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2470,16 +2486,14 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
|
|||
__releases(d->lock)
|
||||
__acquires(d->lock)
|
||||
{
|
||||
struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
|
||||
struct Qdisc *child = taprio_leaf(sch, cl);
|
||||
struct tc_taprio_qopt_offload offload = {
|
||||
.cmd = TAPRIO_CMD_QUEUE_STATS,
|
||||
.queue_stats = {
|
||||
.queue = cl - 1,
|
||||
},
|
||||
};
|
||||
struct Qdisc *child;
|
||||
|
||||
child = rtnl_dereference(dev_queue->qdisc_sleeping);
|
||||
if (gnet_stats_copy_basic(d, NULL, &child->bstats, true) < 0 ||
|
||||
qdisc_qstats_copy(d, child) < 0)
|
||||
return -1;
|
||||
|
|
|
@ -96,10 +96,11 @@ CONFIG_NET_SCH_FIFO=y
|
|||
CONFIG_NET_SCH_ETS=m
|
||||
CONFIG_NET_SCH_RED=m
|
||||
CONFIG_NET_SCH_FQ_PIE=m
|
||||
CONFIG_NETDEVSIM=m
|
||||
|
||||
#
|
||||
## Network testing
|
||||
#
|
||||
CONFIG_CAN=m
|
||||
CONFIG_ATM=y
|
||||
CONFIG_NETDEVSIM=m
|
||||
CONFIG_PTP_1588_CLOCK_MOCK=m
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
TC="$1"; shift
|
||||
ETH="$1"; shift
|
||||
|
||||
# The taprio architecture changes the admin schedule from a hrtimer and not
|
||||
# from process context, so we need to wait in order to make sure that any
|
||||
# schedule change actually took place.
|
||||
while :; do
|
||||
has_admin="$($TC -j qdisc show dev $ETH root | jq '.[].options | has("admin")')"
|
||||
if [ "$has_admin" = "false" ]; then
|
||||
break;
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
done
|
|
@ -104,7 +104,7 @@
|
|||
"cmdUnderTest": "$TC qdisc add dev $ETH root handle 1: taprio num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@0 1@0 base-time 1000000000 sched-entry S 01 300000 flags 0x1 clockid CLOCK_TAI",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC class show dev $ETH",
|
||||
"matchPattern": "class taprio 1:[0-9]+ root leaf 1:",
|
||||
"matchPattern": "class taprio 1:[0-9]+ root",
|
||||
"matchCount": "8",
|
||||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
|
@ -156,5 +156,105 @@
|
|||
"teardown": [
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "39b4",
|
||||
"name": "Reject grafting taprio as child qdisc of software taprio",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"taprio"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 clockid CLOCK_TAI",
|
||||
"./taprio_wait_for_admin.sh $TC $ETH"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH parent 8001:7 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 200 sched-entry S ff 20000000 clockid CLOCK_TAI",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "bash -c \"./taprio_wait_for_admin.sh $TC $ETH && $TC -j qdisc show dev $ETH root | jq '.[].options.base_time'\"",
|
||||
"matchPattern": "0",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC qdisc del dev $ETH root",
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e8a1",
|
||||
"name": "Reject grafting taprio as child qdisc of offloaded taprio",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"taprio"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 flags 0x2",
|
||||
"./taprio_wait_for_admin.sh $TC $ETH"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH parent 8001:7 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 200 sched-entry S ff 20000000 flags 0x2",
|
||||
"expExitCode": "2",
|
||||
"verifyCmd": "bash -c \"./taprio_wait_for_admin.sh $TC $ETH && $TC -j qdisc show dev $ETH root | jq '.[].options.base_time'\"",
|
||||
"matchPattern": "0",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC qdisc del dev $ETH root",
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a7bf",
|
||||
"name": "Graft cbs as child of software taprio",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"taprio",
|
||||
"cbs"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 clockid CLOCK_TAI"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH handle 8002: parent 8001:8 cbs idleslope 20000 sendslope -980000 hicredit 30 locredit -1470",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC -d qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc cbs 8002: parent 8001:8 hicredit 30 locredit -1470 sendslope -980000 idleslope 20000 offload 0",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC qdisc del dev $ETH root",
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6a83",
|
||||
"name": "Graft cbs as child of offloaded taprio",
|
||||
"category": [
|
||||
"qdisc",
|
||||
"taprio",
|
||||
"cbs"
|
||||
],
|
||||
"plugins": {
|
||||
"requires": "nsPlugin"
|
||||
},
|
||||
"setup": [
|
||||
"echo \"1 1 8\" > /sys/bus/netdevsim/new_device",
|
||||
"$TC qdisc replace dev $ETH handle 8001: parent root stab overhead 24 taprio num_tc 8 map 0 1 2 3 4 5 6 7 queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 base-time 0 sched-entry S ff 20000000 flags 0x2"
|
||||
],
|
||||
"cmdUnderTest": "$TC qdisc replace dev $ETH handle 8002: parent 8001:8 cbs idleslope 20000 sendslope -980000 hicredit 30 locredit -1470",
|
||||
"expExitCode": "0",
|
||||
"verifyCmd": "$TC -d qdisc show dev $ETH",
|
||||
"matchPattern": "qdisc cbs 8002: parent 8001:8 refcnt 2 hicredit 30 locredit -1470 sendslope -980000 idleslope 20000 offload 0",
|
||||
"matchCount": "1",
|
||||
"teardown": [
|
||||
"$TC qdisc del dev $ETH root",
|
||||
"echo \"1\" > /sys/bus/netdevsim/del_device"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue