296 lines
9.0 KiB
C
296 lines
9.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2021, Intel Corporation. */
|
|
|
|
/* advanced RSS configuration ethtool support for iavf */
|
|
|
|
#include "iavf.h"
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_ip4_hdr - fill the IPv4 RSS protocol header
|
|
* @hdr: the virtchnl message protocol header data structure
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
*/
|
|
static void
|
|
iavf_fill_adv_rss_ip4_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
|
|
{
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV4);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_SA)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, SRC);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV4_DA)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_ip6_hdr - fill the IPv6 RSS protocol header
|
|
* @hdr: the virtchnl message protocol header data structure
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
*/
|
|
static void
|
|
iavf_fill_adv_rss_ip6_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
|
|
{
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, IPV6);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_SA)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, SRC);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_IPV6_DA)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_tcp_hdr - fill the TCP RSS protocol header
|
|
* @hdr: the virtchnl message protocol header data structure
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
*/
|
|
static void
|
|
iavf_fill_adv_rss_tcp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
|
|
{
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, TCP);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, SRC_PORT);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, TCP, DST_PORT);
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_udp_hdr - fill the UDP RSS protocol header
|
|
* @hdr: the virtchnl message protocol header data structure
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
*/
|
|
static void
|
|
iavf_fill_adv_rss_udp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
|
|
{
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, UDP);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, SRC_PORT);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, UDP, DST_PORT);
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_sctp_hdr - fill the SCTP RSS protocol header
|
|
* @hdr: the virtchnl message protocol header data structure
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
*/
|
|
static void
|
|
iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
|
|
{
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, SCTP);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, SRC_PORT);
|
|
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT)
|
|
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, SCTP, DST_PORT);
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_gtp_hdr - Fill GTP-related RSS protocol headers
|
|
* @proto_hdrs: pointer to the virtchnl protocol headers structure to populate
|
|
* @packet_hdrs: bitmask of packet header types to configure
|
|
* @hash_flds: RSS hash field configuration
|
|
*
|
|
* This function populates the virtchnl protocol header structure with
|
|
* appropriate GTP-related header types based on the specified packet_hdrs.
|
|
* It supports GTPC, GTPU with extension headers, and uplink/downlink PDU
|
|
* types. For certain GTPU types, it also appends an IPv4 header to enable
|
|
* hashing on the destination IP address.
|
|
*
|
|
* Return: 0 on success or -EOPNOTSUPP if the packet_hdrs value is unsupported.
|
|
*/
|
|
static int
|
|
iavf_fill_adv_rss_gtp_hdr(struct virtchnl_proto_hdrs *proto_hdrs,
|
|
u32 packet_hdrs, u64 hash_flds)
|
|
{
|
|
struct virtchnl_proto_hdr *hdr;
|
|
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count - 1];
|
|
|
|
switch (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC_TEID:
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPC:
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPC);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_EH:
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_UP:
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_UP);
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
|
|
iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_DWN:
|
|
VIRTCHNL_SET_PROTO_HDR_TYPE(hdr, GTPU_EH_PDU_DWN);
|
|
fallthrough;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_GTPU_IP:
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
|
|
iavf_fill_adv_rss_ip4_hdr(hdr, IAVF_ADV_RSS_HASH_FLD_IPV4_DA);
|
|
break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* iavf_fill_adv_rss_cfg_msg - fill the RSS configuration into virtchnl message
|
|
* @rss_cfg: the virtchnl message to be filled with RSS configuration setting
|
|
* @packet_hdrs: the RSS configuration protocol header types
|
|
* @hash_flds: the RSS configuration protocol hash fields
|
|
* @symm: if true, symmetric hash is required
|
|
*
|
|
* Returns 0 if the RSS configuration virtchnl message is filled successfully
|
|
*/
|
|
int
|
|
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
|
|
u32 packet_hdrs, u64 hash_flds, bool symm)
|
|
{
|
|
const u32 packet_l3_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L3;
|
|
const u32 packet_l4_hdrs = packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_L4;
|
|
struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs;
|
|
struct virtchnl_proto_hdr *hdr;
|
|
|
|
if (symm)
|
|
rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
|
|
else
|
|
rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
|
|
|
|
proto_hdrs->tunnel_level = 0; /* always outer layer */
|
|
|
|
if (packet_l3_hdrs) {
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
|
|
switch (packet_l3_hdrs) {
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4:
|
|
iavf_fill_adv_rss_ip4_hdr(hdr, hash_flds);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_IPV6:
|
|
iavf_fill_adv_rss_ip6_hdr(hdr, hash_flds);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (packet_l4_hdrs) {
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
|
|
switch (packet_l4_hdrs) {
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_TCP:
|
|
iavf_fill_adv_rss_tcp_hdr(hdr, hash_flds);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_UDP:
|
|
iavf_fill_adv_rss_udp_hdr(hdr, hash_flds);
|
|
break;
|
|
case IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP:
|
|
iavf_fill_adv_rss_sctp_hdr(hdr, hash_flds);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP) {
|
|
hdr = &proto_hdrs->proto_hdr[proto_hdrs->count++];
|
|
if (iavf_fill_adv_rss_gtp_hdr(proto_hdrs, packet_hdrs, hash_flds))
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* iavf_find_adv_rss_cfg_by_hdrs - find RSS configuration with header type
|
|
* @adapter: pointer to the VF adapter structure
|
|
* @packet_hdrs: protocol header type to find.
|
|
*
|
|
* Returns pointer to advance RSS configuration if found or null
|
|
*/
|
|
struct iavf_adv_rss *
|
|
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs)
|
|
{
|
|
struct iavf_adv_rss *rss;
|
|
|
|
list_for_each_entry(rss, &adapter->adv_rss_list_head, list)
|
|
if (rss->packet_hdrs == packet_hdrs)
|
|
return rss;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* iavf_print_adv_rss_cfg
|
|
* @adapter: pointer to the VF adapter structure
|
|
* @rss: pointer to the advance RSS configuration to print
|
|
* @action: the string description about how to handle the RSS
|
|
* @result: the string description about the virtchnl result
|
|
*
|
|
* Print the advance RSS configuration
|
|
**/
|
|
void
|
|
iavf_print_adv_rss_cfg(struct iavf_adapter *adapter, struct iavf_adv_rss *rss,
|
|
const char *action, const char *result)
|
|
{
|
|
u32 packet_hdrs = rss->packet_hdrs;
|
|
u64 hash_flds = rss->hash_flds;
|
|
static char hash_opt[300];
|
|
const char *proto;
|
|
|
|
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_TCP)
|
|
proto = "TCP";
|
|
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_UDP)
|
|
proto = "UDP";
|
|
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_SCTP)
|
|
proto = "SCTP";
|
|
else if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_GTP)
|
|
proto = "GTP";
|
|
else
|
|
return;
|
|
|
|
memset(hash_opt, 0, sizeof(hash_opt));
|
|
|
|
strcat(hash_opt, proto);
|
|
if (packet_hdrs & IAVF_ADV_RSS_FLOW_SEG_HDR_IPV4)
|
|
strcat(hash_opt, "v4 ");
|
|
else
|
|
strcat(hash_opt, "v6 ");
|
|
|
|
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_SA |
|
|
IAVF_ADV_RSS_HASH_FLD_IPV6_SA))
|
|
strcat(hash_opt, "IP SA,");
|
|
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_IPV4_DA |
|
|
IAVF_ADV_RSS_HASH_FLD_IPV6_DA))
|
|
strcat(hash_opt, "IP DA,");
|
|
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_SRC_PORT |
|
|
IAVF_ADV_RSS_HASH_FLD_UDP_SRC_PORT |
|
|
IAVF_ADV_RSS_HASH_FLD_SCTP_SRC_PORT))
|
|
strcat(hash_opt, "src port,");
|
|
if (hash_flds & (IAVF_ADV_RSS_HASH_FLD_TCP_DST_PORT |
|
|
IAVF_ADV_RSS_HASH_FLD_UDP_DST_PORT |
|
|
IAVF_ADV_RSS_HASH_FLD_SCTP_DST_PORT))
|
|
strcat(hash_opt, "dst port,");
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPC_TEID)
|
|
strcat(hash_opt, "gtp-c,");
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_IP_TEID)
|
|
strcat(hash_opt, "gtp-u ip,");
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_EH_TEID)
|
|
strcat(hash_opt, "gtp-u ext,");
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_UP_TEID)
|
|
strcat(hash_opt, "gtp-u ul,");
|
|
if (hash_flds & IAVF_ADV_RSS_HASH_FLD_GTPU_DWN_TEID)
|
|
strcat(hash_opt, "gtp-u dl,");
|
|
|
|
if (!action)
|
|
action = "";
|
|
|
|
if (!result)
|
|
result = "";
|
|
|
|
dev_info(&adapter->pdev->dev, "%s %s %s\n", action, hash_opt, result);
|
|
}
|