Commit 17bd48f8 authored by Haibin Lu's avatar Haibin Lu Committed by Fengyan
Browse files

UNIC: PF supports MAC loopback

driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I850RQ


CVE: NA

-----------------------------------------------------

Loopback can be used to test the connectivity of the
system hardware.

This patch supports loopback by using standard tools with
packets sent in UB packet format.

Signed-off-by: default avatarHaibin Lu <luhaibin10@hisilicon.com>
Signed-off-by: default avatarJunxin Chen <chenjunxin1@huawei.com>
parent 193e5e1d
Loading
Loading
Loading
Loading
+37 −6
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include "hns3_enet.h"
#include "hns3_ethtool.h"
#include "hns3_unic.h"

/* tqp related stats */
#define HNS3_TQP_STAT(_string, _member)	{			\
@@ -178,6 +179,32 @@ static void hns3_lp_setup_skb(struct sk_buff *skb)
		packet[i] = (unsigned char)(i & 0xff);
}

static struct sk_buff *hns3_lp_skb_prepare(struct net_device *ndev)
{
	unsigned int size = hns3_ubl_supported(hns3_get_handle(ndev)) ?
		HNS3_NIC_LB_TEST_PACKET_SIZE + 1 + NET_IP_ALIGN :
		HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN;
	struct sk_buff *skb;

	skb = alloc_skb(size, GFP_KERNEL);
	if (!skb)
		return NULL;

	skb->dev = ndev;
#ifdef CONFIG_HNS3_UBL
	if (hns3_ubl_supported(hns3_get_handle(ndev))) {
		skb->protocol = htons(ETH_P_UB);
		hns3_unic_lp_setup_skb(skb);
	} else {
		hns3_lp_setup_skb(skb);
	}
#else
	hns3_lp_setup_skb(skb);
#endif
	skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID;
	return skb;
}

static void hns3_lb_check_skb_data(struct hns3_enet_ring *ring,
				   struct sk_buff *skb)
{
@@ -218,7 +245,16 @@ static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget)
		pre_rx_pkt = rx_group->total_packets;

		preempt_disable();
#ifdef CONFIG_HNS3_UBL
		if (hns3_ubl_supported(hns3_get_handle(priv->netdev)))
			hns3_clean_rx_ring(ring, budget,
					   hns3_unic_lb_check_skb_data);
		else
			hns3_clean_rx_ring(ring, budget,
					   hns3_lb_check_skb_data);
#else
		hns3_clean_rx_ring(ring, budget, hns3_lb_check_skb_data);
#endif
		preempt_enable();

		rcv_good_pkt_total += (rx_group->total_packets - pre_rx_pkt);
@@ -253,15 +289,10 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
	u32 i, good_cnt;
	int ret_val = 0;

	skb = alloc_skb(HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN,
			GFP_KERNEL);
	skb = hns3_lp_skb_prepare(ndev);
	if (!skb)
		return HNS3_NIC_LB_TEST_NO_MEM_ERR;

	skb->dev = ndev;
	hns3_lp_setup_skb(skb);
	skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID;

	good_cnt = 0;
	for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) {
		netdev_tx_t tx_ret;
+68 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include "hns3_enet.h"
#include "hns3_unic.h"

#define HNS3_UNIC_LB_TEST_PACKET_SIZE	128

void hns3_unic_set_default_cc(struct sk_buff *skb)
{
	struct ublhdr *ubl = (struct ublhdr *)skb->data;
@@ -80,3 +82,69 @@ u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info)

	return UB_UNKNOWN_CFG_TYPE;
}

#define UNIC_DHCPV4_PROTO 0x0100
void hns3_unic_lp_setup_skb(struct sk_buff *skb)
{
	unsigned int nip_ctrl_len = sizeof(struct ub_nip_ctrl_fld);
	struct net_device *ndev = skb->dev;
	struct ub_nip_ctrl_fld *ctrl_fld;
	unsigned char *sw_ptype;
	unsigned char *packet;
	unsigned int i;

	skb_reserve(skb, NET_IP_ALIGN);

	sw_ptype = (unsigned char *)skb_put(skb, sizeof(unsigned char));
	*sw_ptype = UB_NOIP_CFG_TYPE;
	ctrl_fld = (struct ub_nip_ctrl_fld *)skb_put(skb, nip_ctrl_len);
	packet = (unsigned char *)skb_put(skb, HNS3_UNIC_LB_TEST_PACKET_SIZE -
					  nip_ctrl_len);
	ctrl_fld->proto = htons(UNIC_DHCPV4_PROTO);
	memcpy(ctrl_fld->d_guid, ndev->dev_addr, UBL_ALEN);
	memcpy(ctrl_fld->s_guid, ndev->dev_addr, UBL_ALEN);

	skb_reset_mac_header(skb);
	skb_reset_network_header(skb);

	for (i = 0; i < HNS3_UNIC_LB_TEST_PACKET_SIZE - nip_ctrl_len; i++)
		packet[i] = (unsigned char)(i & 0xff);
}

void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring,
				 struct sk_buff *skb)
{
	unsigned int nip_ctrl_len = sizeof(struct ub_nip_ctrl_fld);
	struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector;
	struct net_device *ndev = skb->dev;
	struct ub_nip_ctrl_fld *ctrl_fld;
	u32 len = skb_headlen(skb);
	bool is_success = false;
	unsigned char *packet;
	u32 i;

	if (len != HNS3_UNIC_LB_TEST_PACKET_SIZE + 1)
		goto out;

	ctrl_fld = (struct ub_nip_ctrl_fld *)(skb->data + 1);
	if (memcmp(ctrl_fld->d_guid, ndev->dev_addr, UBL_ALEN) ||
	    memcmp(ctrl_fld->s_guid, ndev->dev_addr, UBL_ALEN) ||
	    ctrl_fld->proto != htons(UNIC_DHCPV4_PROTO))
		goto out;

	packet = (unsigned char *)ctrl_fld + nip_ctrl_len;
	for (i = 0; i < HNS3_UNIC_LB_TEST_PACKET_SIZE - nip_ctrl_len; i++)
		if (packet[i] != (unsigned char)(i & 0xff))
			goto out;

	is_success = true;

out:
	if (is_success)
		tqp_vector->rx_group.total_packets++;
	else
		print_hex_dump(KERN_ERR, "ubn selftest:", DUMP_PREFIX_OFFSET,
			       16, 1, skb->data, len, true);

	dev_kfree_skb_any(skb);
}
+9 −0
Original line number Diff line number Diff line
@@ -20,9 +20,18 @@

#define UNIC_CC_DEFAULT_FECN_MODE 0x4000

struct ub_nip_ctrl_fld {
	__be16 proto;
	unsigned char d_guid[UBL_ALEN];
	unsigned char s_guid[UBL_ALEN];
};

void hns3_unic_set_default_cc(struct sk_buff *skb);
void hns3_unic_init(struct net_device *netdev);
void hns3_unic_set_l3_type(struct sk_buff *skb, u32 *type_cs_vlan_tso);
u8 hns3_unic_get_l3_type(struct net_device *netdev, u32 ol_info, u32 l234info);
void hns3_unic_lp_setup_skb(struct sk_buff *skb);
void hns3_unic_lb_check_skb_data(struct hns3_enet_ring *ring,
				 struct sk_buff *skb);

#endif