未验证 提交 ab866dc7 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!381 net: hns3: add support handling tx dhcp packets for ROH

Merge Pull Request from: @chenke1978 
 
[Description]
For ROH distributed scenario, EID is allocated by DHCP mode.
Driver needs to convert the origin MAC address to EID format,
and updates the destination MAC, chaddr and client id(if exists)
when transmit DHCP packets. Meantime, the chaddr field should
follow the source mac address, in order to make the dhcp
server reply to the right client. For the payload of
dhcp packet changed, so the checksum of L4 should be
calculated too.

[Testing]
kernel options:
CONFIG_ROH=m
CONFIG_ROH_HNS=m

Test passed with below step:
1. Load the NIC/ROCE/ROH driver normally on the ROH device.
2. Preparing the DHCP Server and DHCP Client applications
3. Enable the DHCP service on the server node.
4. Execute the DHCP client application on the client node.
5. Check the DHCP process and wait until the DHCP IP address
   allocation is complete.
6. The communication is normal based on the new IP address.

    
 
Link:https://gitee.com/openeuler/kernel/pulls/381 

Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
......@@ -1166,6 +1166,142 @@ static void hns3_tx_spare_reclaim_cb(struct hns3_enet_ring *ring,
}
}
static struct hns3_dhcp_packet *hns3_get_dhcp_packet(struct sk_buff *skb,
int *dhcp_len)
{
struct hns3_dhcp_packet *dhcp;
union l4_hdr_info l4;
int l4_payload_len;
l4.hdr = skb_transport_header(skb);
if (l4.udp->dest != htons(HNS3_DHCP_CLIENT_PORT) ||
l4.udp->source != htons(HNS3_DHCP_SERVER_PORT))
return NULL;
dhcp = (struct hns3_dhcp_packet *)(l4.hdr + sizeof(struct udphdr));
l4_payload_len = ntohs(l4.udp->len) - sizeof(struct udphdr);
if (l4_payload_len < offsetof(struct hns3_dhcp_packet, options) ||
dhcp->hlen != ETH_ALEN ||
dhcp->cookie != htonl(HNS3_DHCP_MAGIC))
return NULL;
*dhcp_len = l4_payload_len;
return dhcp;
}
static u8 *hns3_dhcp_option_scan(struct hns3_dhcp_packet *packet,
struct hns3_dhcp_opt_state *opt_state)
{
int opt_len;
u8 *cur_opt;
/* option bytes: [code][len][data0~data[len-1]] */
while (opt_state->rem > 0) {
switch (opt_state->opt_ptr[DHCP_OPT_CODE]) {
/* option padding and end have no len and data byte. */
case DHCP_OPT_PADDING:
opt_state->rem--;
opt_state->opt_ptr++;
break;
case DHCP_OPT_END:
if (DHCP_OVERLOAD_USE_FILE(opt_state->overload_flag)) {
opt_state->overload_flag |=
DHCP_OVERLOAD_FILE_USED;
opt_state->opt_ptr = packet->file;
opt_state->rem = sizeof(packet->file);
break;
}
if (DHCP_OVERLOAD_USE_SNAME(opt_state->overload_flag)) {
opt_state->overload_flag |=
DHCP_OVERLOAD_SNAME_USED;
opt_state->opt_ptr = packet->sname;
opt_state->rem = sizeof(packet->sname);
break;
}
return NULL;
default:
if (opt_state->rem <= DHCP_OPT_LEN)
return NULL;
/* opt_len includes code, len and data bytes */
opt_len = opt_state->opt_ptr[DHCP_OPT_LEN] +
DHCP_OPT_DATA;
cur_opt = opt_state->opt_ptr;
if (opt_state->rem < opt_len)
return NULL;
opt_state->opt_ptr += opt_len;
opt_state->rem -= opt_len;
if (cur_opt[DHCP_OPT_CODE] == DHCP_OPT_OVERLOAD) {
opt_state->overload_flag |=
cur_opt[DHCP_OPT_DATA];
break;
}
return cur_opt;
}
}
return NULL;
}
static void hns3_dhcp_update_option61(struct hns3_nic_priv *priv,
struct hns3_dhcp_packet *packet,
int dhcp_len)
{
struct hns3_dhcp_opt_state opt_state;
u8 *cur_opt;
opt_state.opt_ptr = packet->options;
opt_state.rem = dhcp_len - offsetof(struct hns3_dhcp_packet, options);
opt_state.overload_flag = 0;
cur_opt = hns3_dhcp_option_scan(packet, &opt_state);
while (cur_opt) {
if (cur_opt[DHCP_OPT_CODE] != DHCP_OPT_CLIENT_ID) {
cur_opt = hns3_dhcp_option_scan(packet, &opt_state);
continue;
}
if (cur_opt[DHCP_OPT_LEN] > ETH_ALEN)
ether_addr_copy(&cur_opt[DHCP_CLIENT_ID_MAC_OFT],
priv->roh_perm_mac);
break;
}
}
static void hns3_dhcp_cal_l4_csum(struct sk_buff *skb)
{
union l3_hdr_info l3;
union l4_hdr_info l4;
__wsum csum = 0;
int offset;
if (skb->ip_summed == CHECKSUM_PARTIAL)
return;
l3.hdr = skb_network_header(skb);
l4.hdr = skb_transport_header(skb);
offset = skb_transport_offset(skb);
l4.udp->check = 0;
csum = csum_partial(l4.udp, ntohs(l4.udp->len), 0);
l4.udp->check = csum_tcpudp_magic(l3.v4->saddr, l3.v4->daddr,
skb->len - offset, IPPROTO_UDP, csum);
}
static void hns3_dhcp_packet_convert(struct hns3_nic_priv *priv,
struct sk_buff *skb,
struct hns3_dhcp_packet *dhcp,
int dhcp_len)
{
struct ethhdr *l2hdr = eth_hdr(skb);
if (!dhcp)
return;
ether_addr_copy(dhcp->chaddr, l2hdr->h_source);
hns3_dhcp_update_option61(priv, dhcp, dhcp_len);
/* for l4 payload changed, need to re-calculate the csum */
hns3_dhcp_cal_l4_csum(skb);
}
static int hns3_set_tso(struct sk_buff *skb, u32 *paylen_fdop_ol4cs,
u16 *mss, u32 *type_cs_vlan_tso, u32 *send_bytes)
{
......@@ -1717,7 +1853,20 @@ static int hns3_handle_csum_partial(struct hns3_enet_ring *ring,
return 0;
}
static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
static bool hns3_roh_check_udpv4(struct sk_buff *skb)
{
union l3_hdr_info l3;
l3.hdr = skb_network_header(skb);
if (skb->protocol != htons(ETH_P_IP) ||
l3.v4->version != IP_VERSION_IPV4)
return false;
return l3.v4->protocol == IPPROTO_UDP;
}
static int hns3_fill_skb_desc(struct hns3_nic_priv *priv,
struct hns3_enet_ring *ring,
struct sk_buff *skb, struct hns3_desc *desc,
struct hns3_desc_cb *desc_cb)
{
......@@ -1742,6 +1891,15 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring,
hnae3_set_field(param.paylen_fdop_ol4cs, HNS3_TXD_FD_OP_M,
HNS3_TXD_FD_OP_S, fd_op);
if (hnae3_check_roh_mac_type(priv->ae_handle) &&
hns3_roh_check_udpv4(skb)) {
struct hns3_dhcp_packet *dhcp;
int dhcp_len;
dhcp = hns3_get_dhcp_packet(skb, &dhcp_len);
hns3_dhcp_packet_convert(priv, skb, dhcp, dhcp_len);
}
/* Set txbd */
desc->tx.ol_type_vlan_len_msec =
cpu_to_le32(param.ol_type_vlan_len_msec);
......@@ -2339,15 +2497,16 @@ static int hns3_handle_desc_filling(struct hns3_enet_ring *ring,
return hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB);
}
static int hns3_handle_skb_desc(struct hns3_enet_ring *ring,
static int hns3_handle_skb_desc(struct hns3_nic_priv *priv,
struct hns3_enet_ring *ring,
struct sk_buff *skb,
struct hns3_desc_cb *desc_cb,
int next_to_use_head)
{
int ret;
ret = hns3_fill_skb_desc(ring, skb, &ring->desc[ring->next_to_use],
desc_cb);
ret = hns3_fill_skb_desc(priv, ring, skb,
&ring->desc[ring->next_to_use], desc_cb);
if (unlikely(ret < 0))
goto fill_err;
......@@ -2396,7 +2555,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
goto out_err_tx_ok;
}
ret = hns3_handle_skb_desc(ring, skb, desc_cb, ring->next_to_use);
ret = hns3_handle_skb_desc(priv, ring, skb, desc_cb, ring->next_to_use);
if (unlikely(ret <= 0))
goto out_err_tx_ok;
......@@ -5225,6 +5384,10 @@ static int hns3_init_mac_addr(struct net_device *netdev)
return 0;
}
if (hnae3_check_roh_mac_type(h) &&
is_zero_ether_addr(priv->roh_perm_mac))
ether_addr_copy(priv->roh_perm_mac, netdev->dev_addr);
if (h->ae_algo->ops->set_mac_addr)
ret = h->ae_algo->ops->set_mac_addr(h, netdev->dev_addr, true);
......@@ -5376,6 +5539,7 @@ static int hns3_client_init(struct hnae3_handle *handle)
priv->tx_timeout_count = 0;
priv->max_non_tso_bd_num = ae_dev->dev_specs.max_non_tso_bd_num;
set_bit(HNS3_NIC_STATE_DOWN, &priv->state);
eth_zero_addr(priv->roh_perm_mac);
handle->msg_enable = netif_msg_init(debug, DEFAULT_MSG_LEVEL);
......
......@@ -604,6 +604,56 @@ struct hns3_nic_priv {
struct hns3_enet_coalesce rx_coal;
u32 tx_copybreak;
u32 rx_copybreak;
u8 roh_perm_mac[ETH_ALEN];
};
#define HNS3_DHCP_SERVER_PORT 68
#define HNS3_DHCP_CLIENT_PORT 67
#define HNS3_DHCP_MAGIC 0x63825363
#define DHCP_OPT_CODE 0
#define DHCP_OPT_LEN 1
#define DHCP_OPT_DATA 2
#define DHCP_CLIENT_ID_LEN 7
#define DHCP_CLIENT_ID_MAC_OFT 3
#define DHCP_OVERLOAD_FILE 0x1
#define DHCP_OVERLOAD_SNAME 0x2
#define DHCP_OVERLOAD_FILE_USED 0x101
#define DHCP_OVERLOAD_SNAME_USED 0x202
#define DHCP_OVERLOAD_USE_FILE(x) \
(((x) & DHCP_OVERLOAD_FILE_USED) == DHCP_OVERLOAD_FILE)
#define DHCP_OVERLOAD_USE_SNAME(x) \
(((x) & DHCP_OVERLOAD_SNAME_USED) == DHCP_OVERLOAD_SNAME)
enum DHCP_OPTION_CODES {
DHCP_OPT_PADDING = 0,
DHCP_OPT_OVERLOAD = 52,
DHCP_OPT_CLIENT_ID = 61,
DHCP_OPT_END = 255
};
struct hns3_dhcp_packet {
u8 op;
u8 htype;
u8 hlen;
u8 hops;
u32 xid;
u16 secs;
u16 flags;
u32 ciaddr;
u32 yiaddr;
u32 siaddr_nip;
u32 gateway_nip;
u8 chaddr[16]; /* link-layer client hardware address (MAC) */
u8 sname[64];
u8 file[128];
u32 cookie; /* DHCP magic bytes: 0x63825363 */
u8 options[312];
};
struct hns3_dhcp_opt_state {
u8 *opt_ptr; /* refer to current option item */
int rem; /* remain bytes in options */
u32 overload_flag; /* whether use file and sname field as options */
};
union l3_hdr_info {
......
......@@ -2867,12 +2867,28 @@ static void hclge_get_fec(struct hnae3_handle *handle, u8 *fec_ability,
if (fec_mode)
*fec_mode = mac->fec_mode;
}
static void hclge_roh_convert_mac_addr(struct hclge_dev *hdev)
{
#define HCLGE_ROH_EID_MASK_BYTE 3
struct hclge_vport *vport = &hdev->vport[0];
struct hnae3_handle *handle = &vport->nic;
if (hnae3_check_roh_mac_type(handle)) {
if (!is_valid_ether_addr(hdev->hw.mac.mac_addr))
random_ether_addr(hdev->hw.mac.mac_addr);
memset(hdev->hw.mac.mac_addr, 0, HCLGE_ROH_EID_MASK_BYTE);
}
}
static int hclge_mac_init(struct hclge_dev *hdev)
{
struct hclge_mac *mac = &hdev->hw.mac;
int ret;
hclge_mac_type_init(hdev);
hclge_roh_convert_mac_addr(hdev);
hdev->support_sfp_query = true;
hdev->hw.mac.duplex = HCLGE_MAC_FULL;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册