Commit 63490217 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-Offload-FIFO'

Ido Schimmel says:

====================
mlxsw: Offload FIFO

Petr says:

If an ETS or PRIO band contains an offloaded qdisc, it is possible to
obtain offloaded counters for that band. However, some of the bands will
likely simply contain the default invisible FIFO qdisc, which does not
present the counters.

To remedy this situation, make FIFO offloadable, and offload it by mlxsw
when below PRIO and ETS for the sole purpose of providing counters for the
bands that do not include other qdiscs.

- In patch #1, FIFO is extended to support offloading.
- Patches #2 and #3 restructure bits of mlxsw to facilitate
  the offload logic.
- Patch #4 then implements the offload itself.
- Patch #5 changes the ETS selftest to use the new counters.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f3588909 b9b72999
......@@ -1783,6 +1783,8 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, enum tc_setup_type type,
return mlxsw_sp_setup_tc_ets(mlxsw_sp_port, type_data);
case TC_SETUP_QDISC_TBF:
return mlxsw_sp_setup_tc_tbf(mlxsw_sp_port, type_data);
case TC_SETUP_QDISC_FIFO:
return mlxsw_sp_setup_tc_fifo(mlxsw_sp_port, type_data);
default:
return -EOPNOTSUPP;
}
......
......@@ -139,6 +139,7 @@ struct mlxsw_sp_port_type_speed_ops;
struct mlxsw_sp_ptp_state;
struct mlxsw_sp_ptp_ops;
struct mlxsw_sp_span_ops;
struct mlxsw_sp_qdisc_state;
struct mlxsw_sp_port_mapping {
u8 module;
......@@ -276,8 +277,7 @@ struct mlxsw_sp_port {
struct mlxsw_sp_port_sample *sample;
struct list_head vlans_list;
struct mlxsw_sp_port_vlan *default_vlan;
struct mlxsw_sp_qdisc *root_qdisc;
struct mlxsw_sp_qdisc *tclass_qdiscs;
struct mlxsw_sp_qdisc_state *qdisc;
unsigned acl_rule_count;
struct mlxsw_sp_acl_block *ing_acl_block;
struct mlxsw_sp_acl_block *eg_acl_block;
......@@ -867,6 +867,8 @@ int mlxsw_sp_setup_tc_ets(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_ets_qopt_offload *p);
int mlxsw_sp_setup_tc_tbf(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_tbf_qopt_offload *p);
int mlxsw_sp_setup_tc_fifo(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_fifo_qopt_offload *p);
/* spectrum_fid.c */
bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
......
......@@ -853,6 +853,7 @@ enum tc_setup_type {
TC_SETUP_FT,
TC_SETUP_QDISC_ETS,
TC_SETUP_QDISC_TBF,
TC_SETUP_QDISC_FIFO,
};
/* These structures hold the attributes of bpf state that are being passed
......
......@@ -881,4 +881,19 @@ struct tc_tbf_qopt_offload {
};
};
enum tc_fifo_command {
TC_FIFO_REPLACE,
TC_FIFO_DESTROY,
TC_FIFO_STATS,
};
struct tc_fifo_qopt_offload {
enum tc_fifo_command command;
u32 handle;
u32 parent;
union {
struct tc_qopt_offload_stats stats;
};
};
#endif
......@@ -12,6 +12,7 @@
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
/* 1 band FIFO pseudo-"scheduler" */
......@@ -51,8 +52,49 @@ static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch,
return NET_XMIT_CN;
}
static int fifo_init(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
static void fifo_offload_init(struct Qdisc *sch)
{
struct net_device *dev = qdisc_dev(sch);
struct tc_fifo_qopt_offload qopt;
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
qopt.command = TC_FIFO_REPLACE;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_FIFO, &qopt);
}
static void fifo_offload_destroy(struct Qdisc *sch)
{
struct net_device *dev = qdisc_dev(sch);
struct tc_fifo_qopt_offload qopt;
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
qopt.command = TC_FIFO_DESTROY;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_QDISC_FIFO, &qopt);
}
static int fifo_offload_dump(struct Qdisc *sch)
{
struct tc_fifo_qopt_offload qopt;
qopt.command = TC_FIFO_STATS;
qopt.handle = sch->handle;
qopt.parent = sch->parent;
qopt.stats.bstats = &sch->bstats;
qopt.stats.qstats = &sch->qstats;
return qdisc_offload_dump_helper(sch, TC_SETUP_QDISC_FIFO, &qopt);
}
static int __fifo_init(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
bool bypass;
bool is_bfifo = sch->ops == &bfifo_qdisc_ops;
......@@ -82,10 +124,35 @@ static int fifo_init(struct Qdisc *sch, struct nlattr *opt,
sch->flags |= TCQ_F_CAN_BYPASS;
else
sch->flags &= ~TCQ_F_CAN_BYPASS;
return 0;
}
static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
static int fifo_init(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
int err;
err = __fifo_init(sch, opt, extack);
if (err)
return err;
fifo_offload_init(sch);
return 0;
}
static int fifo_hd_init(struct Qdisc *sch, struct nlattr *opt,
struct netlink_ext_ack *extack)
{
return __fifo_init(sch, opt, extack);
}
static void fifo_destroy(struct Qdisc *sch)
{
fifo_offload_destroy(sch);
}
static int __fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct tc_fifo_qopt opt = { .limit = sch->limit };
......@@ -97,6 +164,22 @@ static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
return -1;
}
static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb)
{
int err;
err = fifo_offload_dump(sch);
if (err)
return err;
return __fifo_dump(sch, skb);
}
static int fifo_hd_dump(struct Qdisc *sch, struct sk_buff *skb)
{
return __fifo_dump(sch, skb);
}
struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
.id = "pfifo",
.priv_size = 0,
......@@ -104,6 +187,7 @@ struct Qdisc_ops pfifo_qdisc_ops __read_mostly = {
.dequeue = qdisc_dequeue_head,
.peek = qdisc_peek_head,
.init = fifo_init,
.destroy = fifo_destroy,
.reset = qdisc_reset_queue,
.change = fifo_init,
.dump = fifo_dump,
......@@ -118,6 +202,7 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = {
.dequeue = qdisc_dequeue_head,
.peek = qdisc_peek_head,
.init = fifo_init,
.destroy = fifo_destroy,
.reset = qdisc_reset_queue,
.change = fifo_init,
.dump = fifo_dump,
......@@ -131,10 +216,10 @@ struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = {
.enqueue = pfifo_tail_enqueue,
.dequeue = qdisc_dequeue_head,
.peek = qdisc_peek_head,
.init = fifo_init,
.init = fifo_hd_init,
.reset = qdisc_reset_queue,
.change = fifo_init,
.dump = fifo_dump,
.change = fifo_hd_init,
.dump = fifo_hd_dump,
.owner = THIS_MODULE,
};
......
......@@ -56,11 +56,19 @@ switch_destroy()
}
# Callback from sch_ets_tests.sh
get_stats()
collect_stats()
{
local band=$1; shift
local -a streams=("$@")
local stream
ethtool_stats_get "$h2" rx_octets_prio_$band
# Wait for qdisc counter update so that we don't get it mid-way through.
busywait_for_counter 1000 +1 \
qdisc_parent_stats_get $swp2 10:$((${streams[0]} + 1)) .bytes \
> /dev/null
for stream in ${streams[@]}; do
qdisc_parent_stats_get $swp2 10:$((stream + 1)) .bytes
done
}
bail_on_lldpad
......
......@@ -655,6 +655,16 @@ qdisc_stats_get()
| jq '.[] | select(.handle == "'"$handle"'") | '"$selector"
}
qdisc_parent_stats_get()
{
local dev=$1; shift
local parent=$1; shift
local selector=$1; shift
tc -j -s qdisc show dev "$dev" invisible \
| jq '.[] | select(.parent == "'"$parent"'") | '"$selector"
}
humanize()
{
local speed=$1; shift
......
......@@ -34,11 +34,14 @@ switch_destroy()
}
# Callback from sch_ets_tests.sh
get_stats()
collect_stats()
{
local stream=$1; shift
local -a streams=("$@")
local stream
link_stats_get $h2.1$stream rx bytes
for stream in ${streams[@]}; do
qdisc_parent_stats_get $swp2 10:$((stream + 1)) .bytes
done
}
ets_run
......@@ -2,7 +2,7 @@
# Global interface:
# $put -- port under test (e.g. $swp2)
# get_stats($band) -- A function to collect stats for band
# collect_stats($streams...) -- A function to get stats for individual streams
# ets_start_traffic($band) -- Start traffic for this band
# ets_change_qdisc($op, $dev, $nstrict, $quanta...) -- Add or change qdisc
......@@ -94,15 +94,11 @@ __ets_dwrr_test()
sleep 10
t0=($(for stream in ${streams[@]}; do
get_stats $stream
done))
t0=($(collect_stats "${streams[@]}"))
sleep 10
t1=($(for stream in ${streams[@]}; do
get_stats $stream
done))
t1=($(collect_stats "${streams[@]}"))
d=($(for ((i = 0; i < ${#streams[@]}; i++)); do
echo $((${t1[$i]} - ${t0[$i]}))
done))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment