Add an ethtool self-test to verify the hardware ARP offload
functionality. The test validates that the MAC correctly responds
to ARP requests without CPU intervention.
Test procedure:
1. Check for aoe (ARP Offload Engine) hardware capability
2. Create an ARP request packet with test IP addresses
3. Enable ARP offload with the target IP address
4. Transmit the ARP request in PHY loopback mode
5. Verify that an ARP reply is received from the hardware
6. Clean up and restore configuration
The test requires the device to be in PHY loopback mode and runs as part
of offline ethtool self-test suite.
Usage:
$ ethtool -t <interface>
Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com>
---
drivers/net/ethernet/amd/xgbe/xgbe-selftest.c | 117 ++++++++++++++++++
1 file changed, 117 insertions(+)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-selftest.c b/drivers/net/ethernet/amd/xgbe/xgbe-selftest.c
index 55e5e467facd..ae4825578c59 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-selftest.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-selftest.c
@@ -9,8 +9,10 @@
#include <linux/crc32.h>
#include <linux/ip.h>
#include <linux/udp.h>
+#include <linux/if_arp.h>
#include <net/tcp.h>
#include <net/udp.h>
+#include <net/arp.h>
#include <net/checksum.h>
#include <net/selftests.h>
@@ -152,6 +154,117 @@ static int __xgbe_test_loopback(struct xgbe_prv_data *pdata,
return ret;
}
+static int xgbe_test_arp_validate(struct sk_buff *skb,
+ struct net_device *ndev,
+ struct packet_type *pt,
+ struct net_device *orig_ndev)
+{
+ struct net_test_priv *tdata = pt->af_packet_priv;
+ struct ethhdr *eth_hdr;
+ struct arphdr *ah;
+
+ skb = skb_unshare(skb, GFP_ATOMIC);
+ if (!skb)
+ goto out;
+ if (skb_linearize(skb))
+ goto out;
+
+ eth_hdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* Verify the reply is destined to our test source MAC */
+ if (!ether_addr_equal_unaligned(eth_hdr->h_dest, tdata->packet->src))
+ goto out;
+
+ /* Verify this is an ARP packet */
+ if (eth_hdr->h_proto != htons(ETH_P_ARP))
+ goto out;
+
+ ah = arp_hdr(skb);
+
+ /* Verify this is an ARP reply */
+ if (ah->ar_op != htons(ARPOP_REPLY))
+ goto out;
+
+ tdata->ok = true;
+ complete(&tdata->comp);
+out:
+ kfree_skb(skb);
+ return 0;
+}
+
+static int xgbe_test_arpoffload(struct xgbe_prv_data *pdata)
+{
+ unsigned char src[ETH_ALEN] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ unsigned char bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct net_packet_attrs attr = {};
+ struct net_test_priv *tdata;
+ struct sk_buff *skb = NULL;
+ u32 dst_ip = 0xabcdefab;
+ u32 src_ip = 0xefdcbaef;
+ int ret;
+
+ /* Check if ARP offload is supported */
+ if (!pdata->hw_feat.aoe)
+ return -EOPNOTSUPP;
+
+ tdata = kzalloc(sizeof(*tdata), GFP_KERNEL);
+ if (!tdata)
+ return -ENOMEM;
+
+ tdata->ok = false;
+ init_completion(&tdata->comp);
+
+ tdata->pt.type = htons(ETH_P_ARP);
+ tdata->pt.func = xgbe_test_arp_validate;
+ tdata->pt.dev = pdata->netdev;
+ tdata->pt.af_packet_priv = tdata;
+ tdata->packet = &attr;
+ dev_add_pack(&tdata->pt);
+
+ attr.src = src;
+ attr.ip_src = src_ip;
+ attr.dst = bcast;
+ attr.ip_dst = dst_ip;
+
+ /* Create ARP request packet */
+ skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, htonl(dst_ip),
+ pdata->netdev, htonl(src_ip), NULL, src, bcast);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto free;
+ }
+
+ skb->pkt_type = PACKET_HOST;
+ skb->dev = pdata->netdev;
+ skb->protocol = htons(ETH_P_ARP);
+
+ /* Enable ARP offload */
+ xgbe_enable_arp_offload(pdata, dst_ip);
+
+ ret = dev_set_promiscuity(pdata->netdev, 1);
+ if (ret) {
+ kfree_skb(skb);
+ goto cleanup;
+ }
+
+ ret = dev_direct_xmit(skb, 0);
+ if (ret)
+ goto cleanup_promisc;
+
+ /* Wait for ARP reply */
+ wait_for_completion_timeout(&tdata->comp, NET_LB_TIMEOUT);
+ ret = tdata->ok ? 0 : -ETIMEDOUT;
+
+cleanup_promisc:
+ dev_set_promiscuity(pdata->netdev, -1);
+cleanup:
+ xgbe_disable_arp_offload(pdata);
+ dev_remove_pack(&tdata->pt);
+free:
+ kfree(tdata);
+ return ret;
+}
+
static int xgbe_test_mac_loopback(struct xgbe_prv_data *pdata)
{
struct net_packet_attrs attr = {};
@@ -251,6 +364,10 @@ static const struct xgbe_test xgbe_selftests[] = {
.name = "Jumbo Frame ",
.lb = XGBE_LOOPBACK_PHY,
.fn = xgbe_test_jumbo,
+ }, {
+ .name = "ARP Offload ",
+ .lb = XGBE_LOOPBACK_PHY,
+ .fn = xgbe_test_arpoffload,
},
};
--
2.34.1
Hi Raju,
kernel test robot noticed the following build errors:
[auto build test ERROR on net/main]
[also build test ERROR on net-next/main linus/master v6.19-rc8 next-20260202]
[cannot apply to horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Raju-Rangoju/net-amd-xgbe-add-hardware-ARP-offload-support/20260202-235023
base: net/main
patch link: https://lore.kernel.org/r/20260202153542.1727429-3-Raju.Rangoju%40amd.com
patch subject: [PATCH 2/3] net: amd-xgbe: add ARP offload ethtool self-test
config: powerpc-randconfig-002-20260203 (https://download.01.org/0day-ci/archive/20260203/202602030920.SWN7cwzT-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 10.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260203/202602030920.SWN7cwzT-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602030920.SWN7cwzT-lkp@intel.com/
All errors (new ones prefixed by >>):
powerpc-linux-ld: drivers/net/ethernet/amd/xgbe/xgbe-selftest.o: in function `xgbe_test_arpoffload':
>> drivers/net/ethernet/amd/xgbe/xgbe-selftest.c:230: undefined reference to `arp_create'
powerpc-linux-ld: net/core/selftests.o: in function `net_test_get_skb':
net/core/selftests.c:104: undefined reference to `ip_send_check'
powerpc-linux-ld: net/core/selftests.c:148: undefined reference to `udp4_hwcsum'
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for HOTPLUG_CPU
Depends on [n]: SMP [=y] && (PPC_PSERIES [=n] || PPC_PMAC [=n] || PPC_POWERNV [=n] || FSL_SOC_BOOKE [=n])
Selected by [y]:
- PM_SLEEP_SMP [=y] && SMP [=y] && (ARCH_SUSPEND_POSSIBLE [=n] || ARCH_HIBERNATION_POSSIBLE [=y]) && PM_SLEEP [=y]
WARNING: unmet direct dependencies detected for NET_SELFTESTS
Depends on [n]: NET [=y] && PHYLIB [=y] && INET [=n]
Selected by [y]:
- AMD_XGBE [=y] && NETDEVICES [=y] && ETHERNET [=y] && NET_VENDOR_AMD [=y] && (OF_ADDRESS [=y] || ACPI || PCI [=n]) && HAS_IOMEM [=y] && (X86 || ARM64 || COMPILE_TEST [=y]) && PTP_1588_CLOCK_OPTIONAL [=y]
vim +230 drivers/net/ethernet/amd/xgbe/xgbe-selftest.c
194
195 static int xgbe_test_arpoffload(struct xgbe_prv_data *pdata)
196 {
197 unsigned char src[ETH_ALEN] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
198 unsigned char bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
199 struct net_packet_attrs attr = {};
200 struct net_test_priv *tdata;
201 struct sk_buff *skb = NULL;
202 u32 dst_ip = 0xabcdefab;
203 u32 src_ip = 0xefdcbaef;
204 int ret;
205
206 /* Check if ARP offload is supported */
207 if (!pdata->hw_feat.aoe)
208 return -EOPNOTSUPP;
209
210 tdata = kzalloc(sizeof(*tdata), GFP_KERNEL);
211 if (!tdata)
212 return -ENOMEM;
213
214 tdata->ok = false;
215 init_completion(&tdata->comp);
216
217 tdata->pt.type = htons(ETH_P_ARP);
218 tdata->pt.func = xgbe_test_arp_validate;
219 tdata->pt.dev = pdata->netdev;
220 tdata->pt.af_packet_priv = tdata;
221 tdata->packet = &attr;
222 dev_add_pack(&tdata->pt);
223
224 attr.src = src;
225 attr.ip_src = src_ip;
226 attr.dst = bcast;
227 attr.ip_dst = dst_ip;
228
229 /* Create ARP request packet */
> 230 skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, htonl(dst_ip),
231 pdata->netdev, htonl(src_ip), NULL, src, bcast);
232 if (!skb) {
233 ret = -ENOMEM;
234 goto free;
235 }
236
237 skb->pkt_type = PACKET_HOST;
238 skb->dev = pdata->netdev;
239 skb->protocol = htons(ETH_P_ARP);
240
241 /* Enable ARP offload */
242 xgbe_enable_arp_offload(pdata, dst_ip);
243
244 ret = dev_set_promiscuity(pdata->netdev, 1);
245 if (ret) {
246 kfree_skb(skb);
247 goto cleanup;
248 }
249
250 ret = dev_direct_xmit(skb, 0);
251 if (ret)
252 goto cleanup_promisc;
253
254 /* Wait for ARP reply */
255 wait_for_completion_timeout(&tdata->comp, NET_LB_TIMEOUT);
256 ret = tdata->ok ? 0 : -ETIMEDOUT;
257
258 cleanup_promisc:
259 dev_set_promiscuity(pdata->netdev, -1);
260 cleanup:
261 xgbe_disable_arp_offload(pdata);
262 dev_remove_pack(&tdata->pt);
263 free:
264 kfree(tdata);
265 return ret;
266 }
267
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.