|
@@ -42,14 +42,6 @@
|
|
|
|
|
|
#define RING_SIZE_MIN 64
|
|
#define RING_SIZE_MIN 64
|
|
#define LINKCHANGE_INT (2 * HZ)
|
|
#define LINKCHANGE_INT (2 * HZ)
|
|
-#define NETVSC_HW_FEATURES (NETIF_F_RXCSUM | \
|
|
|
|
- NETIF_F_SG | \
|
|
|
|
- NETIF_F_TSO | \
|
|
|
|
- NETIF_F_TSO6 | \
|
|
|
|
- NETIF_F_HW_CSUM)
|
|
|
|
-
|
|
|
|
-/* Restrict GSO size to account for NVGRE */
|
|
|
|
-#define NETVSC_GSO_MAX_SIZE 62768
|
|
|
|
|
|
|
|
static int ring_size = 128;
|
|
static int ring_size = 128;
|
|
module_param(ring_size, int, S_IRUGO);
|
|
module_param(ring_size, int, S_IRUGO);
|
|
@@ -323,33 +315,25 @@ static int netvsc_get_slots(struct sk_buff *skb)
|
|
return slots + frag_slots;
|
|
return slots + frag_slots;
|
|
}
|
|
}
|
|
|
|
|
|
-static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
|
|
|
|
|
|
+static u32 net_checksum_info(struct sk_buff *skb)
|
|
{
|
|
{
|
|
- u32 ret_val = TRANSPORT_INFO_NOT_IP;
|
|
|
|
-
|
|
|
|
- if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
|
|
|
|
- (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
|
|
|
|
- goto not_ip;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- *trans_off = skb_transport_offset(skb);
|
|
|
|
|
|
+ if (skb->protocol == htons(ETH_P_IP)) {
|
|
|
|
+ struct iphdr *ip = ip_hdr(skb);
|
|
|
|
|
|
- if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
|
|
|
|
- struct iphdr *iphdr = ip_hdr(skb);
|
|
|
|
-
|
|
|
|
- if (iphdr->protocol == IPPROTO_TCP)
|
|
|
|
- ret_val = TRANSPORT_INFO_IPV4_TCP;
|
|
|
|
- else if (iphdr->protocol == IPPROTO_UDP)
|
|
|
|
- ret_val = TRANSPORT_INFO_IPV4_UDP;
|
|
|
|
|
|
+ if (ip->protocol == IPPROTO_TCP)
|
|
|
|
+ return TRANSPORT_INFO_IPV4_TCP;
|
|
|
|
+ else if (ip->protocol == IPPROTO_UDP)
|
|
|
|
+ return TRANSPORT_INFO_IPV4_UDP;
|
|
} else {
|
|
} else {
|
|
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
|
|
|
|
- ret_val = TRANSPORT_INFO_IPV6_TCP;
|
|
|
|
|
|
+ struct ipv6hdr *ip6 = ipv6_hdr(skb);
|
|
|
|
+
|
|
|
|
+ if (ip6->nexthdr == IPPROTO_TCP)
|
|
|
|
+ return TRANSPORT_INFO_IPV6_TCP;
|
|
else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
|
|
else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
|
|
- ret_val = TRANSPORT_INFO_IPV6_UDP;
|
|
|
|
|
|
+ return TRANSPORT_INFO_IPV6_UDP;
|
|
}
|
|
}
|
|
|
|
|
|
-not_ip:
|
|
|
|
- return ret_val;
|
|
|
|
|
|
+ return TRANSPORT_INFO_NOT_IP;
|
|
}
|
|
}
|
|
|
|
|
|
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
@@ -362,9 +346,6 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
struct rndis_packet *rndis_pkt;
|
|
struct rndis_packet *rndis_pkt;
|
|
u32 rndis_msg_size;
|
|
u32 rndis_msg_size;
|
|
struct rndis_per_packet_info *ppi;
|
|
struct rndis_per_packet_info *ppi;
|
|
- struct ndis_tcp_ip_checksum_info *csum_info;
|
|
|
|
- int hdr_offset;
|
|
|
|
- u32 net_trans_info;
|
|
|
|
u32 hash;
|
|
u32 hash;
|
|
u32 skb_length;
|
|
u32 skb_length;
|
|
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
|
|
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
|
|
@@ -445,13 +426,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
VLAN_PRIO_SHIFT;
|
|
VLAN_PRIO_SHIFT;
|
|
}
|
|
}
|
|
|
|
|
|
- net_trans_info = get_net_transport_info(skb, &hdr_offset);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Setup the sendside checksum offload only if this is not a
|
|
|
|
- * GSO packet.
|
|
|
|
- */
|
|
|
|
- if ((net_trans_info & (INFO_TCP | INFO_UDP)) && skb_is_gso(skb)) {
|
|
|
|
|
|
+ if (skb_is_gso(skb)) {
|
|
struct ndis_tcp_lso_info *lso_info;
|
|
struct ndis_tcp_lso_info *lso_info;
|
|
|
|
|
|
rndis_msg_size += NDIS_LSO_PPI_SIZE;
|
|
rndis_msg_size += NDIS_LSO_PPI_SIZE;
|
|
@@ -462,7 +437,7 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
ppi->ppi_offset);
|
|
ppi->ppi_offset);
|
|
|
|
|
|
lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
|
|
lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
|
|
- if (net_trans_info & (INFO_IPV4 << 16)) {
|
|
|
|
|
|
+ if (skb->protocol == htons(ETH_P_IP)) {
|
|
lso_info->lso_v2_transmit.ip_version =
|
|
lso_info->lso_v2_transmit.ip_version =
|
|
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
|
|
NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
|
|
ip_hdr(skb)->tot_len = 0;
|
|
ip_hdr(skb)->tot_len = 0;
|
|
@@ -478,10 +453,12 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
|
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
|
&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
|
|
&ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
|
|
}
|
|
}
|
|
- lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
|
|
|
|
|
|
+ lso_info->lso_v2_transmit.tcp_header_offset = skb_transport_offset(skb);
|
|
lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
|
|
lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
|
|
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
|
- if (net_trans_info & INFO_TCP) {
|
|
|
|
|
|
+ if (net_checksum_info(skb) & net_device_ctx->tx_checksum_mask) {
|
|
|
|
+ struct ndis_tcp_ip_checksum_info *csum_info;
|
|
|
|
+
|
|
rndis_msg_size += NDIS_CSUM_PPI_SIZE;
|
|
rndis_msg_size += NDIS_CSUM_PPI_SIZE;
|
|
ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
|
|
ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
|
|
TCPIP_CHKSUM_PKTINFO);
|
|
TCPIP_CHKSUM_PKTINFO);
|
|
@@ -489,15 +466,25 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
|
csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
|
|
csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
|
|
ppi->ppi_offset);
|
|
ppi->ppi_offset);
|
|
|
|
|
|
- if (net_trans_info & (INFO_IPV4 << 16))
|
|
|
|
|
|
+ csum_info->transmit.tcp_header_offset = skb_transport_offset(skb);
|
|
|
|
+
|
|
|
|
+ if (skb->protocol == htons(ETH_P_IP)) {
|
|
csum_info->transmit.is_ipv4 = 1;
|
|
csum_info->transmit.is_ipv4 = 1;
|
|
- else
|
|
|
|
|
|
+
|
|
|
|
+ if (ip_hdr(skb)->protocol == IPPROTO_TCP)
|
|
|
|
+ csum_info->transmit.tcp_checksum = 1;
|
|
|
|
+ else
|
|
|
|
+ csum_info->transmit.udp_checksum = 1;
|
|
|
|
+ } else {
|
|
csum_info->transmit.is_ipv6 = 1;
|
|
csum_info->transmit.is_ipv6 = 1;
|
|
|
|
|
|
- csum_info->transmit.tcp_checksum = 1;
|
|
|
|
- csum_info->transmit.tcp_header_offset = hdr_offset;
|
|
|
|
|
|
+ if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
|
|
|
|
+ csum_info->transmit.tcp_checksum = 1;
|
|
|
|
+ else
|
|
|
|
+ csum_info->transmit.udp_checksum = 1;
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- /* UDP checksum (and other) offload is not supported. */
|
|
|
|
|
|
+ /* Can't do offload of this type of checksum */
|
|
if (skb_checksum_help(skb))
|
|
if (skb_checksum_help(skb))
|
|
goto drop;
|
|
goto drop;
|
|
}
|
|
}
|
|
@@ -1372,10 +1359,6 @@ static int netvsc_probe(struct hv_device *dev,
|
|
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
|
|
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
|
|
|
|
|
|
net->netdev_ops = &device_ops;
|
|
net->netdev_ops = &device_ops;
|
|
-
|
|
|
|
- net->hw_features = NETVSC_HW_FEATURES;
|
|
|
|
- net->features = NETVSC_HW_FEATURES | NETIF_F_HW_VLAN_CTAG_TX;
|
|
|
|
-
|
|
|
|
net->ethtool_ops = ðtool_ops;
|
|
net->ethtool_ops = ðtool_ops;
|
|
SET_NETDEV_DEV(net, &dev->device);
|
|
SET_NETDEV_DEV(net, &dev->device);
|
|
|
|
|
|
@@ -1395,10 +1378,15 @@ static int netvsc_probe(struct hv_device *dev,
|
|
}
|
|
}
|
|
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
|
|
memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
|
|
|
|
|
|
|
|
+ /* hw_features computed in rndis_filter_device_add */
|
|
|
|
+ net->features = net->hw_features |
|
|
|
|
+ NETIF_F_HIGHDMA | NETIF_F_SG |
|
|
|
|
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
|
|
|
|
+ net->vlan_features = net->features;
|
|
|
|
+
|
|
nvdev = net_device_ctx->nvdev;
|
|
nvdev = net_device_ctx->nvdev;
|
|
netif_set_real_num_tx_queues(net, nvdev->num_chn);
|
|
netif_set_real_num_tx_queues(net, nvdev->num_chn);
|
|
netif_set_real_num_rx_queues(net, nvdev->num_chn);
|
|
netif_set_real_num_rx_queues(net, nvdev->num_chn);
|
|
- netif_set_gso_max_size(net, NETVSC_GSO_MAX_SIZE);
|
|
|
|
|
|
|
|
/* MTU range: 68 - 1500 or 65521 */
|
|
/* MTU range: 68 - 1500 or 65521 */
|
|
net->min_mtu = NETVSC_MTU_MIN;
|
|
net->min_mtu = NETVSC_MTU_MIN;
|