mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 09:13:38 +00:00
testing: net-drv: add basic shaper test
Leverage a basic/dummy netdevsim implementation to do functional coverage for NL interface. Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Link: https://patch.msgid.link/43092afbf38365c796088bf8fc155e523ab434ae.1728460186.git.pabeni@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
ecd82cfee3
commit
b3ea416419
@ -641,6 +641,7 @@ config NETDEVSIM
|
||||
depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n
|
||||
select NET_DEVLINK
|
||||
select PAGE_POOL
|
||||
select NET_SHAPER
|
||||
help
|
||||
This driver is a developer testing tool and software model that can
|
||||
be used to test various control path networking APIs, especially
|
||||
|
@ -103,8 +103,10 @@ nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
err = netif_set_real_num_queues(dev, ch->combined_count,
|
||||
ch->combined_count);
|
||||
mutex_unlock(&dev->lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <net/netdev_queues.h>
|
||||
#include <net/page_pool/helpers.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/net_shaper.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/udp_tunnel.h>
|
||||
@ -475,6 +476,43 @@ static int nsim_stop(struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nsim_shaper_set(struct net_shaper_binding *binding,
|
||||
const struct net_shaper *shaper,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nsim_shaper_del(struct net_shaper_binding *binding,
|
||||
const struct net_shaper_handle *handle,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nsim_shaper_group(struct net_shaper_binding *binding,
|
||||
int leaves_count,
|
||||
const struct net_shaper *leaves,
|
||||
const struct net_shaper *root,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nsim_shaper_cap(struct net_shaper_binding *binding,
|
||||
enum net_shaper_scope scope,
|
||||
unsigned long *flags)
|
||||
{
|
||||
*flags = ULONG_MAX;
|
||||
}
|
||||
|
||||
static const struct net_shaper_ops nsim_shaper_ops = {
|
||||
.set = nsim_shaper_set,
|
||||
.delete = nsim_shaper_del,
|
||||
.group = nsim_shaper_group,
|
||||
.capabilities = nsim_shaper_cap,
|
||||
};
|
||||
|
||||
static const struct net_device_ops nsim_netdev_ops = {
|
||||
.ndo_start_xmit = nsim_start_xmit,
|
||||
.ndo_set_rx_mode = nsim_set_rx_mode,
|
||||
@ -496,6 +534,7 @@ static const struct net_device_ops nsim_netdev_ops = {
|
||||
.ndo_bpf = nsim_bpf,
|
||||
.ndo_open = nsim_open,
|
||||
.ndo_stop = nsim_stop,
|
||||
.net_shaper_ops = &nsim_shaper_ops,
|
||||
};
|
||||
|
||||
static const struct net_device_ops nsim_vf_netdev_ops = {
|
||||
|
@ -9,6 +9,7 @@ TEST_PROGS := \
|
||||
ping.py \
|
||||
queues.py \
|
||||
stats.py \
|
||||
shaper.py
|
||||
# end of TEST_PROGS
|
||||
|
||||
include ../../lib.mk
|
||||
|
461
tools/testing/selftests/drivers/net/shaper.py
Executable file
461
tools/testing/selftests/drivers/net/shaper.py
Executable file
@ -0,0 +1,461 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_true, KsftSkipEx
|
||||
from lib.py import EthtoolFamily, NetshaperFamily
|
||||
from lib.py import NetDrvEnv
|
||||
from lib.py import NlError
|
||||
from lib.py import cmd
|
||||
|
||||
def get_shapers(cfg, nl_shaper) -> None:
|
||||
try:
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
|
||||
# Default configuration: no shapers configured.
|
||||
ksft_eq(len(shapers), 0)
|
||||
|
||||
def get_caps(cfg, nl_shaper) -> None:
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex}, dump=True)
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
|
||||
# Each device implementing shaper support must support some
|
||||
# features in at least a scope.
|
||||
ksft_true(len(caps)> 0)
|
||||
|
||||
def set_qshapers(cfg, nl_shaper) -> None:
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'queue'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-bw-max' in caps or not 'support-metric-bps' in caps:
|
||||
raise KsftSkipEx("device does not support queue scope shapers with bw_max and metric bps")
|
||||
|
||||
cfg.queues = True;
|
||||
netnl = EthtoolFamily()
|
||||
channels = netnl.channels_get({'header': {'dev-index': cfg.ifindex}})
|
||||
if channels['combined-count'] == 0:
|
||||
cfg.rx_type = 'rx'
|
||||
cfg.nr_queues = channels['rx-count']
|
||||
else:
|
||||
cfg.rx_type = 'combined'
|
||||
cfg.nr_queues = channels['combined-count']
|
||||
if cfg.nr_queues < 3:
|
||||
raise KsftSkipEx(f"device does not support enough queues min 3 found {cfg.nr_queues}")
|
||||
|
||||
nl_shaper.set({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
nl_shaper.set({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 2},
|
||||
'metric': 'bps',
|
||||
'bw-max': 20000})
|
||||
|
||||
# Querying a specific shaper not yet configured must fail.
|
||||
raised = False
|
||||
try:
|
||||
shaper_q0 = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 0}})
|
||||
except (NlError):
|
||||
raised = True
|
||||
ksft_eq(raised, True)
|
||||
|
||||
shaper_q1 = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
ksft_eq(shaper_q1, {'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 2},
|
||||
'metric': 'bps',
|
||||
'bw-max': 20000}])
|
||||
|
||||
def del_qshapers(cfg, nl_shaper) -> None:
|
||||
if not cfg.queues:
|
||||
raise KsftSkipEx("queue shapers not supported by device, skipping delete")
|
||||
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 2}})
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(len(shapers), 0)
|
||||
|
||||
def set_nshapers(cfg, nl_shaper) -> None:
|
||||
# Check required features.
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'netdev'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-bw-max' in caps or not 'support-metric-bps' in caps:
|
||||
raise KsftSkipEx("device does not support nested netdev scope shapers with weight")
|
||||
|
||||
cfg.netdev = True;
|
||||
nl_shaper.set({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'netdev', 'id': 0},
|
||||
'bw-max': 100000})
|
||||
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'netdev'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 100000}])
|
||||
|
||||
def del_nshapers(cfg, nl_shaper) -> None:
|
||||
if not cfg.netdev:
|
||||
raise KsftSkipEx("netdev shaper not supported by device, skipping delete")
|
||||
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'netdev'}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(len(shapers), 0)
|
||||
|
||||
def basic_groups(cfg, nl_shaper) -> None:
|
||||
if not cfg.netdev:
|
||||
raise KsftSkipEx("netdev shaper not supported by the device")
|
||||
if cfg.nr_queues < 3:
|
||||
raise KsftSkipEx(f"netdev does not have enough queues min 3 reported {cfg.nr_queues}")
|
||||
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'queue'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-weight' in caps:
|
||||
raise KsftSkipEx("device does not support queue scope shapers with weight")
|
||||
|
||||
node_handle = nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 1},
|
||||
{'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2}],
|
||||
'handle': {'scope':'netdev'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
ksft_eq(node_handle, {'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'netdev'}})
|
||||
|
||||
shaper = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
ksft_eq(shaper, {'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 1 })
|
||||
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 2}})
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
|
||||
# Deleting all the leaves shaper does not affect the node one
|
||||
# when the latter has 'netdev' scope.
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(len(shapers), 1)
|
||||
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'netdev'}})
|
||||
|
||||
def qgroups(cfg, nl_shaper) -> None:
|
||||
if cfg.nr_queues < 4:
|
||||
raise KsftSkipEx(f"netdev does not have enough queues min 4 reported {cfg.nr_queues}")
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'node'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-bw-max' in caps or not 'support-metric-bps' in caps:
|
||||
raise KsftSkipEx("device does not support node scope shapers with bw_max and metric bps")
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'queue'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-nesting' in caps or not 'support-weight' in caps or not 'support-metric-bps' in caps:
|
||||
raise KsftSkipEx("device does not support nested queue scope shapers with weight")
|
||||
|
||||
cfg.groups = True;
|
||||
node_handle = nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3},
|
||||
{'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2}],
|
||||
'handle': {'scope':'node'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
node_id = node_handle['handle']['id']
|
||||
|
||||
shaper = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
ksft_eq(shaper, {'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3})
|
||||
shaper = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'node', 'id': node_id}})
|
||||
ksft_eq(shaper, {'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'node', 'id': node_id},
|
||||
'parent': {'scope': 'netdev'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
|
||||
# Grouping to a specified, not existing node scope shaper must fail
|
||||
raised = False
|
||||
try:
|
||||
nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 3}],
|
||||
'handle': {'scope':'node', 'id': node_id + 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
|
||||
except (NlError):
|
||||
raised = True
|
||||
ksft_eq(raised, True)
|
||||
|
||||
# Add to an existing node
|
||||
node_handle = nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 4}],
|
||||
'handle': {'scope':'node', 'id': node_id}})
|
||||
ksft_eq(node_handle, {'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'node', 'id': node_id}})
|
||||
|
||||
shaper = nl_shaper.get({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 3}})
|
||||
ksft_eq(shaper, {'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 4})
|
||||
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 2}})
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 1}})
|
||||
|
||||
# Deleting a non empty node will move the leaves downstream.
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'node', 'id': node_id}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 4}])
|
||||
|
||||
# Finish and verify the complete cleanup.
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': 3}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(len(shapers), 0)
|
||||
|
||||
def delegation(cfg, nl_shaper) -> None:
|
||||
if not cfg.groups:
|
||||
raise KsftSkipEx("device does not support node scope")
|
||||
try:
|
||||
caps = nl_shaper.cap_get({'ifindex': cfg.ifindex,
|
||||
'scope':'node'})
|
||||
except NlError as e:
|
||||
if e.error == 95:
|
||||
raise KsftSkipEx("node scope shapers not supported by the device")
|
||||
raise
|
||||
if not 'support-nesting' in caps:
|
||||
raise KsftSkipEx("device does not support node scope shapers nesting")
|
||||
|
||||
node_handle = nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3},
|
||||
{'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2},
|
||||
{'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 1}],
|
||||
'handle': {'scope':'node'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000})
|
||||
node_id = node_handle['handle']['id']
|
||||
|
||||
# Create the nested node and validate the hierarchy
|
||||
nested_node_handle = nl_shaper.group({
|
||||
'ifindex': cfg.ifindex,
|
||||
'leaves':[{'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3},
|
||||
{'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2}],
|
||||
'handle': {'scope':'node'},
|
||||
'metric': 'bps',
|
||||
'bw-max': 5000})
|
||||
nested_node_id = nested_node_handle['handle']['id']
|
||||
ksft_true(nested_node_id != node_id)
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': nested_node_id},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': nested_node_id},
|
||||
'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 1},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'node', 'id': node_id},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'node', 'id': nested_node_id},
|
||||
'metric': 'bps',
|
||||
'bw-max': 5000}])
|
||||
|
||||
# Deleting a non empty node will move the leaves downstream.
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'node', 'id': nested_node_id}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'weight': 3},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 2},
|
||||
'weight': 2},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'node', 'id': node_id},
|
||||
'handle': {'scope': 'queue', 'id': 3},
|
||||
'weight': 1},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'node', 'id': node_id},
|
||||
'metric': 'bps',
|
||||
'bw-max': 10000}])
|
||||
|
||||
# Final cleanup.
|
||||
for i in range(1, 4):
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': i}})
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(len(shapers), 0)
|
||||
|
||||
def queue_update(cfg, nl_shaper) -> None:
|
||||
if cfg.nr_queues < 4:
|
||||
raise KsftSkipEx(f"netdev does not have enough queues min 4 reported {cfg.nr_queues}")
|
||||
if not cfg.queues:
|
||||
raise KsftSkipEx("device does not support queue scope")
|
||||
|
||||
for i in range(3):
|
||||
nl_shaper.set({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': i},
|
||||
'metric': 'bps',
|
||||
'bw-max': (i + 1) * 1000})
|
||||
# Delete a channel, with no shapers configured on top of the related
|
||||
# queue: no changes expected
|
||||
cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} 3", timeout=10)
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 0},
|
||||
'metric': 'bps',
|
||||
'bw-max': 1000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 2000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 2},
|
||||
'metric': 'bps',
|
||||
'bw-max': 3000}])
|
||||
|
||||
# Delete a channel, with a shaper configured on top of the related
|
||||
# queue: the shaper must be deleted, too
|
||||
cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} 2", timeout=10)
|
||||
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 0},
|
||||
'metric': 'bps',
|
||||
'bw-max': 1000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 2000}])
|
||||
|
||||
# Restore the original channels number, no expected changes
|
||||
cmd(f"ethtool -L {cfg.dev['ifname']} {cfg.rx_type} {cfg.nr_queues}", timeout=10)
|
||||
shapers = nl_shaper.get({'ifindex': cfg.ifindex}, dump=True)
|
||||
ksft_eq(shapers, [{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 0},
|
||||
'metric': 'bps',
|
||||
'bw-max': 1000},
|
||||
{'ifindex': cfg.ifindex,
|
||||
'parent': {'scope': 'netdev'},
|
||||
'handle': {'scope': 'queue', 'id': 1},
|
||||
'metric': 'bps',
|
||||
'bw-max': 2000}])
|
||||
|
||||
# Final cleanup.
|
||||
for i in range(0, 2):
|
||||
nl_shaper.delete({'ifindex': cfg.ifindex,
|
||||
'handle': {'scope': 'queue', 'id': i}})
|
||||
|
||||
def main() -> None:
|
||||
with NetDrvEnv(__file__, queue_count=4) as cfg:
|
||||
cfg.queues = False
|
||||
cfg.netdev = False
|
||||
cfg.groups = False
|
||||
cfg.nr_queues = 0
|
||||
ksft_run([get_shapers,
|
||||
get_caps,
|
||||
set_qshapers,
|
||||
del_qshapers,
|
||||
set_nshapers,
|
||||
del_nshapers,
|
||||
basic_groups,
|
||||
qgroups,
|
||||
delegation,
|
||||
queue_update], args=(cfg, NetshaperFamily()))
|
||||
ksft_exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -6,3 +6,4 @@ from .netns import NetNS
|
||||
from .nsim import *
|
||||
from .utils import *
|
||||
from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily
|
||||
from .ynl import NetshaperFamily
|
||||
|
@ -47,3 +47,8 @@ class NetdevFamily(YnlFamily):
|
||||
def __init__(self):
|
||||
super().__init__((SPEC_PATH / Path('netdev.yaml')).as_posix(),
|
||||
schema='')
|
||||
|
||||
class NetshaperFamily(YnlFamily):
|
||||
def __init__(self):
|
||||
super().__init__((SPEC_PATH / Path('net_shaper.yaml')).as_posix(),
|
||||
schema='')
|
||||
|
Loading…
Reference in New Issue
Block a user