Merge branch 'macsec-inherit-lower-device-s-features-and-tso-limits-when-offloading'

Sabrina Dubroca says:

====================
macsec: inherit lower device's features and TSO limits when offloading

When macsec is offloaded to a NIC, we can take advantage of some of
its features, mainly TSO and checksumming. This increases performance
significantly. Some features cannot be inherited, because they require
additional ops that aren't provided by the macsec netdevice.

We also need to inherit TSO limits from the lower device, like
VLAN/macvlan devices do.

This series also moves the existing macsec offload selftest to the
netdevsim selftests before adding tests for the new features. To allow
this new selftest to work, netdevsim's hw_features are expanded.
====================

Link: https://patch.msgid.link/cover.1730929545.git.sd@queasysnail.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-11-11 14:12:23 -08:00
commit f95a392ed4
7 changed files with 200 additions and 89 deletions

View File

@ -2621,6 +2621,17 @@ static void macsec_set_head_tail_room(struct net_device *dev)
dev->needed_tailroom = real_dev->needed_tailroom + needed_tailroom;
}
static void macsec_inherit_tso_max(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
/* if macsec is offloaded, we need to follow the lower
* device's capabilities. otherwise, we can ignore them.
*/
if (macsec_is_offloaded(macsec))
netif_inherit_tso_max(dev, macsec->real_dev);
}
static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
{
enum macsec_offload prev_offload;
@ -2666,6 +2677,10 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
macsec_set_head_tail_room(dev);
macsec->insert_tx_tag = macsec_needs_tx_tag(macsec, ops);
macsec_inherit_tso_max(dev);
netdev_update_features(dev);
return ret;
}
@ -3521,6 +3536,10 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
#define MACSEC_FEATURES \
(NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
#define MACSEC_OFFLOAD_FEATURES \
(MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \
NETIF_F_LRO | NETIF_F_RXHASH | NETIF_F_CSUM_MASK | NETIF_F_RXCSUM)
static int macsec_dev_init(struct net_device *dev)
{
struct macsec_dev *macsec = macsec_priv(dev);
@ -3531,7 +3550,12 @@ static int macsec_dev_init(struct net_device *dev)
if (err)
return err;
dev->features = real_dev->features & MACSEC_FEATURES;
macsec_inherit_tso_max(dev);
dev->hw_features = real_dev->hw_features & MACSEC_OFFLOAD_FEATURES;
dev->hw_features |= NETIF_F_GSO_SOFTWARE;
dev->features = real_dev->features & MACSEC_OFFLOAD_FEATURES;
dev->features |= NETIF_F_GSO_SOFTWARE;
dev->lltx = true;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
@ -3561,8 +3585,12 @@ static netdev_features_t macsec_fix_features(struct net_device *dev,
{
struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->real_dev;
netdev_features_t mask;
features &= (real_dev->features & MACSEC_FEATURES) |
mask = macsec_is_offloaded(macsec) ? MACSEC_OFFLOAD_FEATURES
: MACSEC_FEATURES;
features &= (real_dev->features & mask) |
NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES;
return features;
@ -4428,31 +4456,26 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct net_device *real_dev = netdev_notifier_info_to_dev(ptr);
struct macsec_rxh_data *rxd;
struct macsec_dev *m, *n;
LIST_HEAD(head);
if (!is_macsec_master(real_dev))
return NOTIFY_DONE;
rxd = macsec_data_rtnl(real_dev);
switch (event) {
case NETDEV_DOWN:
case NETDEV_UP:
case NETDEV_CHANGE: {
struct macsec_dev *m, *n;
struct macsec_rxh_data *rxd;
rxd = macsec_data_rtnl(real_dev);
case NETDEV_CHANGE:
list_for_each_entry_safe(m, n, &rxd->secys, secys) {
struct net_device *dev = m->secy.netdev;
netif_stacked_transfer_operstate(real_dev, dev);
}
break;
}
case NETDEV_UNREGISTER: {
struct macsec_dev *m, *n;
struct macsec_rxh_data *rxd;
rxd = macsec_data_rtnl(real_dev);
case NETDEV_UNREGISTER:
list_for_each_entry_safe(m, n, &rxd->secys, secys) {
macsec_common_dellink(m->secy.netdev, &head);
}
@ -4462,12 +4485,7 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
unregister_netdevice_many(&head);
break;
}
case NETDEV_CHANGEMTU: {
struct macsec_dev *m;
struct macsec_rxh_data *rxd;
rxd = macsec_data_rtnl(real_dev);
case NETDEV_CHANGEMTU:
list_for_each_entry(m, &rxd->secys, secys) {
struct net_device *dev = m->secy.netdev;
unsigned int mtu = real_dev->mtu - (m->secy.icv_len +
@ -4476,7 +4494,13 @@ static int macsec_notify(struct notifier_block *this, unsigned long event,
if (dev->mtu > mtu)
dev_set_mtu(dev, mtu);
}
}
break;
case NETDEV_FEAT_CHANGE:
list_for_each_entry(m, &rxd->secys, secys) {
macsec_inherit_tso_max(m->secy.netdev);
netdev_update_features(m->secy.netdev);
}
break;
}
return NOTIFY_OK;

View File

@ -663,7 +663,11 @@ static void nsim_setup(struct net_device *dev)
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_TSO;
dev->hw_features |= NETIF_F_HW_TC;
dev->hw_features |= NETIF_F_HW_TC |
NETIF_F_SG |
NETIF_F_FRAGLIST |
NETIF_F_HW_CSUM |
NETIF_F_TSO;
dev->max_mtu = ETH_MAX_MTU;
dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD;
}

View File

@ -4,12 +4,14 @@ TEST_PROGS = devlink.sh \
devlink_in_netns.sh \
devlink_trap.sh \
ethtool-coalesce.sh \
ethtool-features.sh \
ethtool-fec.sh \
ethtool-pause.sh \
ethtool-ring.sh \
fib.sh \
fib_notifications.sh \
hw_stats_l3.sh \
macsec-offload.sh \
nexthop.sh \
peer.sh \
psample.sh \

View File

@ -1,6 +1,7 @@
CONFIG_DUMMY=y
CONFIG_GENEVE=m
CONFIG_IPV6=y
CONFIG_MACSEC=m
CONFIG_NETDEVSIM=m
CONFIG_NET_SCH_MQPRIO=y
CONFIG_NET_SCH_MULTIQ=y

View File

@ -0,0 +1,31 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
source ethtool-common.sh
NSIM_NETDEV=$(make_netdev)
set -o pipefail
FEATS="
tx-checksum-ip-generic
tx-scatter-gather
tx-tcp-segmentation
generic-segmentation-offload
generic-receive-offload"
for feat in $FEATS ; do
s=$(ethtool --json -k $NSIM_NETDEV | jq ".[].\"$feat\".active" 2>/dev/null)
check $? "$s" true
s=$(ethtool --json -k $NSIM_NETDEV | jq ".[].\"$feat\".fixed" 2>/dev/null)
check $? "$s" false
done
if [ $num_errors -eq 0 ]; then
echo "PASSED all $((num_passes)) checks"
exit 0
else
echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
exit 1
fi

View File

@ -0,0 +1,117 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
source ethtool-common.sh
NSIM_NETDEV=$(make_netdev)
MACSEC_NETDEV=macsec_nsim
set -o pipefail
if ! ethtool -k $NSIM_NETDEV | grep -q 'macsec-hw-offload: on'; then
echo "SKIP: netdevsim doesn't support MACsec offload"
exit 4
fi
if ! ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac 2>/dev/null; then
echo "SKIP: couldn't create macsec device"
exit 4
fi
ip link del $MACSEC_NETDEV
#
# test macsec offload API
#
ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}" type macsec port 4 offload mac
check $?
ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}2" type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
check $?
ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}3" type macsec sci abbacdde01020304 offload mac
check $?
ip link add link $NSIM_NETDEV "${MACSEC_NETDEV}4" type macsec port 8 offload mac 2> /dev/null
check $? '' '' 1
ip macsec add "${MACSEC_NETDEV}" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
check $?
ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef"
check $?
ip macsec add "${MACSEC_NETDEV}" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
check $?
ip macsec add "${MACSEC_NETDEV}" rx port 1235 address "1c:ed:de:ad:be:ef" 2> /dev/null
check $? '' '' 1
# can't disable macsec offload when SAs are configured
ip link set "${MACSEC_NETDEV}" type macsec offload off 2> /dev/null
check $? '' '' 1
ip macsec offload "${MACSEC_NETDEV}" off 2> /dev/null
check $? '' '' 1
# toggle macsec offload via rtnetlink
ip link set "${MACSEC_NETDEV}2" type macsec offload off
check $?
ip link set "${MACSEC_NETDEV}2" type macsec offload mac
check $?
# toggle macsec offload via genetlink
ip macsec offload "${MACSEC_NETDEV}2" off
check $?
ip macsec offload "${MACSEC_NETDEV}2" mac
check $?
for dev in ${MACSEC_NETDEV}{,2,3} ; do
ip link del $dev
check $?
done
#
# test ethtool features when toggling offload
#
ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec offload mac
TMP_FEATS_ON_1="$(ethtool -k $MACSEC_NETDEV)"
ip link set $MACSEC_NETDEV type macsec offload off
TMP_FEATS_OFF_1="$(ethtool -k $MACSEC_NETDEV)"
ip link set $MACSEC_NETDEV type macsec offload mac
TMP_FEATS_ON_2="$(ethtool -k $MACSEC_NETDEV)"
[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_2" ]
check $?
ip link del $MACSEC_NETDEV
ip link add link $NSIM_NETDEV $MACSEC_NETDEV type macsec
check $?
TMP_FEATS_OFF_2="$(ethtool -k $MACSEC_NETDEV)"
[ "$TMP_FEATS_OFF_1" = "$TMP_FEATS_OFF_2" ]
check $?
ip link set $MACSEC_NETDEV type macsec offload mac
check $?
TMP_FEATS_ON_3="$(ethtool -k $MACSEC_NETDEV)"
[ "$TMP_FEATS_ON_1" = "$TMP_FEATS_ON_3" ]
check $?
if [ $num_errors -eq 0 ]; then
echo "PASSED all $((num_passes)) checks"
exit 0
else
echo "FAILED $num_errors/$((num_errors+num_passes)) checks"
exit 1
fi

View File

@ -21,7 +21,6 @@ ALL_TESTS="
kci_test_vrf
kci_test_encap
kci_test_macsec
kci_test_macsec_offload
kci_test_ipsec
kci_test_ipsec_offload
kci_test_fdb_get
@ -560,73 +559,6 @@ kci_test_macsec()
end_test "PASS: macsec"
}
kci_test_macsec_offload()
{
sysfsd=/sys/kernel/debug/netdevsim/netdevsim0/ports/0/
sysfsnet=/sys/bus/netdevsim/devices/netdevsim0/net/
probed=false
local ret=0
run_cmd_grep "^Usage: ip macsec" ip macsec help
if [ $? -ne 0 ]; then
end_test "SKIP: macsec: iproute2 too old"
return $ksft_skip
fi
if ! mount | grep -q debugfs; then
mount -t debugfs none /sys/kernel/debug/ &> /dev/null
fi
# setup netdevsim since dummydev doesn't have offload support
if [ ! -w /sys/bus/netdevsim/new_device ] ; then
run_cmd modprobe -q netdevsim
if [ $ret -ne 0 ]; then
end_test "SKIP: macsec_offload can't load netdevsim"
return $ksft_skip
fi
probed=true
fi
echo "0" > /sys/bus/netdevsim/new_device
while [ ! -d $sysfsnet ] ; do :; done
udevadm settle
dev=`ls $sysfsnet`
ip link set $dev up
if [ ! -d $sysfsd ] ; then
end_test "FAIL: macsec_offload can't create device $dev"
return 1
fi
run_cmd_grep 'macsec-hw-offload: on' ethtool -k $dev
if [ $? -eq 1 ] ; then
end_test "FAIL: macsec_offload netdevsim doesn't support MACsec offload"
return 1
fi
run_cmd ip link add link $dev kci_macsec1 type macsec port 4 offload mac
run_cmd ip link add link $dev kci_macsec2 type macsec address "aa:bb:cc:dd:ee:ff" port 5 offload mac
run_cmd ip link add link $dev kci_macsec3 type macsec sci abbacdde01020304 offload mac
run_cmd_fail ip link add link $dev kci_macsec4 type macsec port 8 offload mac
msname=kci_macsec1
run_cmd ip macsec add "$msname" tx sa 0 pn 1024 on key 01 12345678901234567890123456789012
run_cmd ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef"
run_cmd ip macsec add "$msname" rx port 1234 address "1c:ed:de:ad:be:ef" sa 0 pn 1 on \
key 00 0123456789abcdef0123456789abcdef
run_cmd_fail ip macsec add "$msname" rx port 1235 address "1c:ed:de:ad:be:ef"
# clean up any leftovers
for msdev in kci_macsec{1,2,3,4} ; do
ip link del $msdev 2> /dev/null
done
echo 0 > /sys/bus/netdevsim/del_device
$probed && rmmod netdevsim
if [ $ret -ne 0 ]; then
end_test "FAIL: macsec_offload"
return 1
fi
end_test "PASS: macsec_offload"
}
#-------------------------------------------------------------------
# Example commands
# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \