Skip to content

Commit

Permalink
Merge branch 'mlxsw-Offload-TC-action-skbedit-priority'
Browse files Browse the repository at this point in the history
Ido Schimmel says:

====================
mlxsw: Offload TC action skbedit priority

Petr says:

The TC action "skbedit priority P" has the effect of assigning skbprio of P
to SKBs that it's applied on. In HW datapath of a switch, the corresponding
action is assignment of internal switch priority. Spectrum switches allow
setting of packet priority based on an ACL action, which is good match for
the skbedit priority gadget. This patchset therefore implements offloading
of this action to the Spectrum ACL engine.

After a bit of refactoring in patch #1, patch #2 extends the skbedit action
to support offloading of "priority" subcommand.

On mlxsw side, in patch #3, the QOS_ACTION flexible action is added, with
fields necessary for priority adjustment. In patch #4, "skbedit priority"
is connected to that action.

Patch #5 implements a new forwarding selftest, suitable for both SW- and
HW-datapath testing.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Mar 20, 2020
2 parents 3fd177c + 26d9f0c commit 9096a03
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 14 deletions.
53 changes: 53 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,59 @@ mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u8 local_in_port,
}
EXPORT_SYMBOL(mlxsw_afa_block_append_mirror);

/* QoS Action
* ----------
* The QOS_ACTION is used for manipulating the QoS attributes of a packet. It
* can be used to change the DCSP, ECN, Color and Switch Priority of the packet.
* Note that PCP field can be changed using the VLAN action.
*/

#define MLXSW_AFA_QOS_CODE 0x06
#define MLXSW_AFA_QOS_SIZE 1

enum mlxsw_afa_qos_cmd {
/* Do nothing */
MLXSW_AFA_QOS_CMD_NOP,
/* Set a field */
MLXSW_AFA_QOS_CMD_SET,
};

/* afa_qos_switch_prio_cmd
* Switch Priority command as per mlxsw_afa_qos_cmd.
*/
MLXSW_ITEM32(afa, qos, switch_prio_cmd, 0x08, 14, 2);

/* afa_qos_switch_prio
* Switch Priority.
*/
MLXSW_ITEM32(afa, qos, switch_prio, 0x08, 0, 4);

static inline void
mlxsw_afa_qos_switch_prio_pack(char *payload,
enum mlxsw_afa_qos_cmd prio_cmd, u8 prio)
{
mlxsw_afa_qos_switch_prio_cmd_set(payload, prio_cmd);
mlxsw_afa_qos_switch_prio_set(payload, prio);
}

int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block,
u8 prio,
struct netlink_ext_ack *extack)
{
char *act = mlxsw_afa_block_append_action(block,
MLXSW_AFA_QOS_CODE,
MLXSW_AFA_QOS_SIZE);

if (IS_ERR(act)) {
NL_SET_ERR_MSG_MOD(extack, "Cannot append QOS action");
return PTR_ERR(act);
}
mlxsw_afa_qos_switch_prio_pack(act, MLXSW_AFA_QOS_CMD_SET,
prio);
return 0;
}
EXPORT_SYMBOL(mlxsw_afa_block_append_qos_switch_prio);

/* Forwarding Action
* -----------------
* Forwarding Action can be used to implement Policy Based Switching (PBS)
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block,
int mlxsw_afa_block_append_vlan_modify(struct mlxsw_afa_block *block,
u16 vid, u8 pcp, u8 et,
struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_qos_switch_prio(struct mlxsw_afa_block *block,
u8 prio,
struct netlink_ext_ack *extack);
int mlxsw_afa_block_append_allocated_counter(struct mlxsw_afa_block *block,
u32 counter_index);
int mlxsw_afa_block_append_counter(struct mlxsw_afa_block *block,
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,9 @@ int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 action, u16 vid, u16 proto, u8 prio,
struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_priority(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 prio, struct netlink_ext_ack *extack);
int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
struct netlink_ext_ack *extack);
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,23 @@ int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp,
}
}

int mlxsw_sp_acl_rulei_act_priority(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
u32 prio, struct netlink_ext_ack *extack)
{
/* Even though both Linux and Spectrum switches support 16 priorities,
* spectrum_qdisc only processes the first eight priomap elements, and
* the DCB and PFC features are tied to 8 priorities as well. Therefore
* bounce attempts to prioritize packets to higher priorities.
*/
if (prio >= IEEE_8021QAZ_MAX_TCS) {
NL_SET_ERR_MSG_MOD(extack, "Only priorities 0..7 are supported");
return -EINVAL;
}
return mlxsw_afa_block_append_qos_switch_prio(rulei->act_block, prio,
extack);
}

int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_rule_info *rulei,
struct netlink_ext_ack *extack)
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
act->id, vid,
proto, prio, extack);
}
case FLOW_ACTION_PRIORITY:
return mlxsw_sp_acl_rulei_act_priority(mlxsw_sp, rulei,
act->priority,
extack);
default:
NL_SET_ERR_MSG_MOD(extack, "Unsupported action");
dev_err(mlxsw_sp->bus_info->dev, "Unsupported action\n");
Expand Down
2 changes: 2 additions & 0 deletions include/net/flow_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ enum flow_action_id {
FLOW_ACTION_CSUM,
FLOW_ACTION_MARK,
FLOW_ACTION_PTYPE,
FLOW_ACTION_PRIORITY,
FLOW_ACTION_WAKE,
FLOW_ACTION_QUEUE,
FLOW_ACTION_SAMPLE,
Expand Down Expand Up @@ -211,6 +212,7 @@ struct flow_action_entry {
u32 csum_flags; /* FLOW_ACTION_CSUM */
u32 mark; /* FLOW_ACTION_MARK */
u16 ptype; /* FLOW_ACTION_PTYPE */
u32 priority; /* FLOW_ACTION_PRIORITY */
struct { /* FLOW_ACTION_QUEUE */
u32 ctx;
u32 index;
Expand Down
41 changes: 27 additions & 14 deletions include/net/tc_act/tc_skbedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ struct tcf_skbedit {
};
#define to_skbedit(a) ((struct tcf_skbedit *)a)

/* Return true iff action is mark */
static inline bool is_tcf_skbedit_mark(const struct tc_action *a)
/* Return true iff action is the one identified by FLAG. */
static inline bool is_tcf_skbedit_with_flag(const struct tc_action *a, u32 flag)
{
#ifdef CONFIG_NET_CLS_ACT
u32 flags;
Expand All @@ -37,12 +37,18 @@ static inline bool is_tcf_skbedit_mark(const struct tc_action *a)
rcu_read_lock();
flags = rcu_dereference(to_skbedit(a)->params)->flags;
rcu_read_unlock();
return flags == SKBEDIT_F_MARK;
return flags == flag;
}
#endif
return false;
}

/* Return true iff action is mark */
static inline bool is_tcf_skbedit_mark(const struct tc_action *a)
{
return is_tcf_skbedit_with_flag(a, SKBEDIT_F_MARK);
}

static inline u32 tcf_skbedit_mark(const struct tc_action *a)
{
u32 mark;
Expand All @@ -57,17 +63,7 @@ static inline u32 tcf_skbedit_mark(const struct tc_action *a)
/* Return true iff action is ptype */
static inline bool is_tcf_skbedit_ptype(const struct tc_action *a)
{
#ifdef CONFIG_NET_CLS_ACT
u32 flags;

if (a->ops && a->ops->id == TCA_ID_SKBEDIT) {
rcu_read_lock();
flags = rcu_dereference(to_skbedit(a)->params)->flags;
rcu_read_unlock();
return flags == SKBEDIT_F_PTYPE;
}
#endif
return false;
return is_tcf_skbedit_with_flag(a, SKBEDIT_F_PTYPE);
}

static inline u32 tcf_skbedit_ptype(const struct tc_action *a)
Expand All @@ -81,4 +77,21 @@ static inline u32 tcf_skbedit_ptype(const struct tc_action *a)
return ptype;
}

/* Return true iff action is priority */
static inline bool is_tcf_skbedit_priority(const struct tc_action *a)
{
return is_tcf_skbedit_with_flag(a, SKBEDIT_F_PRIORITY);
}

static inline u32 tcf_skbedit_priority(const struct tc_action *a)
{
u32 priority;

rcu_read_lock();
priority = rcu_dereference(to_skbedit(a)->params)->priority;
rcu_read_unlock();

return priority;
}

#endif /* __NET_TC_SKBEDIT_H */
3 changes: 3 additions & 0 deletions net/sched/cls_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3665,6 +3665,9 @@ int tc_setup_flow_action(struct flow_action *flow_action,
} else if (is_tcf_skbedit_ptype(act)) {
entry->id = FLOW_ACTION_PTYPE;
entry->ptype = tcf_skbedit_ptype(act);
} else if (is_tcf_skbedit_priority(act)) {
entry->id = FLOW_ACTION_PRIORITY;
entry->priority = tcf_skbedit_priority(act);
} else {
err = -EOPNOTSUPP;
goto err_out_locked;
Expand Down
163 changes: 163 additions & 0 deletions tools/testing/selftests/net/forwarding/skbedit_priority.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

# This test sends traffic from H1 to H2. Either on ingress of $swp1, or on
# egress of $swp2, the traffic is acted upon by an action skbedit priority. The
# new priority should be taken into account when classifying traffic on the PRIO
# qdisc at $swp2. The test verifies that for different priority values, the
# traffic ends up in expected PRIO band.
#
# +----------------------+ +----------------------+
# | H1 | | H2 |
# | + $h1 | | $h2 + |
# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
# +----|-----------------+ +----------------|-----+
# | |
# +----|----------------------------------------------------------------|-----+
# | SW | | |
# | +-|----------------------------------------------------------------|-+ |
# | | + $swp1 BR $swp2 + | |
# | | PRIO | |
# | +--------------------------------------------------------------------+ |
# +---------------------------------------------------------------------------+

ALL_TESTS="
ping_ipv4
test_ingress
test_egress
"

NUM_NETIFS=4
source lib.sh

: ${HIT_TIMEOUT:=2000} # ms

h1_create()
{
simple_if_init $h1 192.0.2.1/28
}

h1_destroy()
{
simple_if_fini $h1 192.0.2.1/28
}

h2_create()
{
simple_if_init $h2 192.0.2.2/28
}

h2_destroy()
{
simple_if_fini $h2 192.0.2.2/28
}

switch_create()
{
ip link add name br1 up type bridge vlan_filtering 1
ip link set dev $swp1 master br1
ip link set dev $swp1 up
ip link set dev $swp2 master br1
ip link set dev $swp2 up

tc qdisc add dev $swp1 clsact
tc qdisc add dev $swp2 clsact
tc qdisc add dev $swp2 root handle 10: \
prio bands 8 priomap 7 6 5 4 3 2 1 0
}

switch_destroy()
{
tc qdisc del dev $swp2 root
tc qdisc del dev $swp2 clsact
tc qdisc del dev $swp1 clsact

ip link set dev $swp2 nomaster
ip link set dev $swp1 nomaster
ip link del dev br1
}

setup_prepare()
{
h1=${NETIFS[p1]}
swp1=${NETIFS[p2]}

swp2=${NETIFS[p3]}
h2=${NETIFS[p4]}

h2mac=$(mac_get $h2)

vrf_prepare
h1_create
h2_create
switch_create
}

cleanup()
{
pre_cleanup

switch_destroy
h2_destroy
h1_destroy
vrf_cleanup
}

ping_ipv4()
{
ping_test $h1 192.0.2.2
}

test_skbedit_priority_one()
{
local locus=$1; shift
local prio=$1; shift
local classid=$1; shift

RET=0

tc filter add $locus handle 101 pref 1 \
flower action skbedit priority $prio

local pkt0=$(qdisc_parent_stats_get $swp2 $classid .packets)
$MZ $h1 -t udp "sp=54321,dp=12345" -c 10 -d 20msec -p 100 \
-a own -b $h2mac -A 192.0.2.1 -B 192.0.2.2 -q
local pkt1
pkt1=$(busywait "$HIT_TIMEOUT" until_counter_is ">= $((pkt0 + 10))" \
qdisc_parent_stats_get $swp2 $classid .packets)

check_err $? "Expected to get 10 packets on class $classid, but got
$((pkt1 - pkt0))."
log_test "$locus skbedit priority $prio -> classid $classid"

tc filter del $locus pref 1
}

test_ingress()
{
local prio

for prio in {0..7}; do
test_skbedit_priority_one "dev $swp1 ingress" \
$prio 10:$((8 - prio))
done
}

test_egress()
{
local prio

for prio in {0..7}; do
test_skbedit_priority_one "dev $swp2 egress" \
$prio 10:$((8 - prio))
done
}

trap cleanup EXIT

setup_prepare
setup_wait

tests_run

exit $EXIT_STATUS

0 comments on commit 9096a03

Please sign in to comment.