Loading drivers/net/hyperv/hyperv_net.h +9 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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. */ Loading drivers/net/hyperv/netvsc_drv.c +50 −23 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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)) Loading Loading @@ -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; Loading Loading @@ -1245,23 +1258,25 @@ 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: case TCP_V6_FLOW: info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 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; Loading Loading @@ -1302,23 +1317,35 @@ 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 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 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 Loading
drivers/net/hyperv/hyperv_net.h +9 −2 Original line number Diff line number Diff line Loading @@ -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 */ Loading @@ -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. */ Loading
drivers/net/hyperv/netvsc_drv.c +50 −23 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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)) Loading Loading @@ -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; Loading Loading @@ -1245,23 +1258,25 @@ 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: case TCP_V6_FLOW: info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; 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; Loading Loading @@ -1302,23 +1317,35 @@ 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 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 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