Merge branch 'hv_netvsc-TCP-hash-level'
Haiyang Zhang says: ==================== hv_netvsc: support changing TCP hash level The patch set simplifies the existing hash level switching code for UDP. It also adds the support for changing TCP hash level. So users can switch between L3 an L4 hash levels for TCP and UDP. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
28f50eb209
@ -19,12 +19,12 @@ Features
|
||||
|
||||
Receive Side Scaling
|
||||
--------------------
|
||||
Hyper-V supports receive side scaling. For TCP, packets are
|
||||
distributed among available queues based on IP address and port
|
||||
Hyper-V supports receive side scaling. For TCP & UDP, packets can
|
||||
be distributed among available queues based on IP address and port
|
||||
number.
|
||||
|
||||
For UDP, we can switch UDP hash level between L3 and L4 by ethtool
|
||||
command. UDP over IPv4 and v6 can be set differently. The default
|
||||
For TCP & UDP, we can switch hash level between L3 and L4 by ethtool
|
||||
command. TCP/UDP over IPv4 and v6 can be set differently. The default
|
||||
hash level is L4. We currently only allow switching TX hash level
|
||||
from within the guests.
|
||||
|
||||
|
@ -704,6 +704,14 @@ struct netvsc_reconfig {
|
||||
u32 event;
|
||||
};
|
||||
|
||||
/* L4 hash bits for different protocols */
|
||||
#define HV_TCP4_L4HASH 1
|
||||
#define HV_TCP6_L4HASH 2
|
||||
#define HV_UDP4_L4HASH 4
|
||||
#define HV_UDP6_L4HASH 8
|
||||
#define HV_DEFAULT_L4HASH (HV_TCP4_L4HASH | HV_TCP6_L4HASH | HV_UDP4_L4HASH | \
|
||||
HV_UDP6_L4HASH)
|
||||
|
||||
/* The context of the netvsc device */
|
||||
struct net_device_context {
|
||||
/* point back to our device context */
|
||||
@ -726,10 +734,9 @@ struct net_device_context {
|
||||
u32 tx_send_table[VRSS_SEND_TAB_SIZE];
|
||||
|
||||
/* Ethtool settings */
|
||||
bool udp4_l4_hash;
|
||||
bool udp6_l4_hash;
|
||||
u8 duplex;
|
||||
u32 speed;
|
||||
u32 l4_hash; /* L4 hash settings */
|
||||
struct netvsc_ethtool_stats eth_stats;
|
||||
|
||||
/* State to manage the associated VF interface. */
|
||||
|
@ -203,7 +203,7 @@ static inline u32 netvsc_get_hash(
|
||||
const struct net_device_context *ndc)
|
||||
{
|
||||
struct flow_keys flow;
|
||||
u32 hash;
|
||||
u32 hash, pkt_proto = 0;
|
||||
static u32 hashrnd __read_mostly;
|
||||
|
||||
net_get_random_once(&hashrnd, sizeof(hashrnd));
|
||||
@ -211,11 +211,25 @@ static inline u32 netvsc_get_hash(
|
||||
if (!skb_flow_dissect_flow_keys(skb, &flow, 0))
|
||||
return 0;
|
||||
|
||||
if (flow.basic.ip_proto == IPPROTO_TCP ||
|
||||
(flow.basic.ip_proto == IPPROTO_UDP &&
|
||||
((flow.basic.n_proto == htons(ETH_P_IP) && ndc->udp4_l4_hash) ||
|
||||
(flow.basic.n_proto == htons(ETH_P_IPV6) &&
|
||||
ndc->udp6_l4_hash)))) {
|
||||
switch (flow.basic.ip_proto) {
|
||||
case IPPROTO_TCP:
|
||||
if (flow.basic.n_proto == htons(ETH_P_IP))
|
||||
pkt_proto = HV_TCP4_L4HASH;
|
||||
else if (flow.basic.n_proto == htons(ETH_P_IPV6))
|
||||
pkt_proto = HV_TCP6_L4HASH;
|
||||
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
if (flow.basic.n_proto == htons(ETH_P_IP))
|
||||
pkt_proto = HV_UDP4_L4HASH;
|
||||
else if (flow.basic.n_proto == htons(ETH_P_IPV6))
|
||||
pkt_proto = HV_UDP6_L4HASH;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (pkt_proto & ndc->l4_hash) {
|
||||
return skb_get_hash(skb);
|
||||
} else {
|
||||
if (flow.basic.n_proto == htons(ETH_P_IP))
|
||||
@ -898,8 +912,7 @@ static void netvsc_init_settings(struct net_device *dev)
|
||||
{
|
||||
struct net_device_context *ndc = netdev_priv(dev);
|
||||
|
||||
ndc->udp4_l4_hash = true;
|
||||
ndc->udp6_l4_hash = true;
|
||||
ndc->l4_hash = HV_DEFAULT_L4HASH;
|
||||
|
||||
ndc->speed = SPEED_UNKNOWN;
|
||||
ndc->duplex = DUPLEX_FULL;
|
||||
@ -1245,23 +1258,32 @@ static int
|
||||
netvsc_get_rss_hash_opts(struct net_device_context *ndc,
|
||||
struct ethtool_rxnfc *info)
|
||||
{
|
||||
const u32 l4_flag = RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
|
||||
info->data = RXH_IP_SRC | RXH_IP_DST;
|
||||
|
||||
switch (info->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
if (ndc->l4_hash & HV_TCP4_L4HASH)
|
||||
info->data |= l4_flag;
|
||||
|
||||
break;
|
||||
|
||||
case TCP_V6_FLOW:
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
if (ndc->l4_hash & HV_TCP6_L4HASH)
|
||||
info->data |= l4_flag;
|
||||
|
||||
break;
|
||||
|
||||
case UDP_V4_FLOW:
|
||||
if (ndc->udp4_l4_hash)
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
if (ndc->l4_hash & HV_UDP4_L4HASH)
|
||||
info->data |= l4_flag;
|
||||
|
||||
break;
|
||||
|
||||
case UDP_V6_FLOW:
|
||||
if (ndc->udp6_l4_hash)
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
if (ndc->l4_hash & HV_UDP6_L4HASH)
|
||||
info->data |= l4_flag;
|
||||
|
||||
break;
|
||||
|
||||
@ -1302,23 +1324,51 @@ static int netvsc_set_rss_hash_opts(struct net_device_context *ndc,
|
||||
{
|
||||
if (info->data == (RXH_IP_SRC | RXH_IP_DST |
|
||||
RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
||||
if (info->flow_type == UDP_V4_FLOW)
|
||||
ndc->udp4_l4_hash = true;
|
||||
else if (info->flow_type == UDP_V6_FLOW)
|
||||
ndc->udp6_l4_hash = true;
|
||||
else
|
||||
switch (info->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
ndc->l4_hash |= HV_TCP4_L4HASH;
|
||||
break;
|
||||
|
||||
case TCP_V6_FLOW:
|
||||
ndc->l4_hash |= HV_TCP6_L4HASH;
|
||||
break;
|
||||
|
||||
case UDP_V4_FLOW:
|
||||
ndc->l4_hash |= HV_UDP4_L4HASH;
|
||||
break;
|
||||
|
||||
case UDP_V6_FLOW:
|
||||
ndc->l4_hash |= HV_UDP6_L4HASH;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info->data == (RXH_IP_SRC | RXH_IP_DST)) {
|
||||
if (info->flow_type == UDP_V4_FLOW)
|
||||
ndc->udp4_l4_hash = false;
|
||||
else if (info->flow_type == UDP_V6_FLOW)
|
||||
ndc->udp6_l4_hash = false;
|
||||
else
|
||||
switch (info->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
ndc->l4_hash &= ~HV_TCP4_L4HASH;
|
||||
break;
|
||||
|
||||
case TCP_V6_FLOW:
|
||||
ndc->l4_hash &= ~HV_TCP6_L4HASH;
|
||||
break;
|
||||
|
||||
case UDP_V4_FLOW:
|
||||
ndc->l4_hash &= ~HV_UDP4_L4HASH;
|
||||
break;
|
||||
|
||||
case UDP_V6_FLOW:
|
||||
ndc->l4_hash &= ~HV_UDP6_L4HASH;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user