mirror of https://gitee.com/openkylin/linux.git
Merge branch 'mlxsw-Offload-TC-action-skbedit-priority'
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>
This commit is contained in:
commit
9096a03f3c
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue