Skip to content

Commit 7b59673

Browse files
tlfalcondavem330
authored andcommitted
ibmveth: set correct gso_size and gso_type
This patch is based on an earlier one submitted by Jon Maxwell with the following commit message: "We recently encountered a bug where a few customers using ibmveth on the same LPAR hit an issue where a TCP session hung when large receive was enabled. Closer analysis revealed that the session was stuck because the one side was advertising a zero window repeatedly. We narrowed this down to the fact the ibmveth driver did not set gso_size which is translated by TCP into the MSS later up the stack. The MSS is used to calculate the TCP window size and as that was abnormally large, it was calculating a zero window, even although the sockets receive buffer was completely empty." We rely on the Virtual I/O Server partition in a pseries environment to provide the MSS through the TCP header checksum field. The stipulation is that users should not disable checksum offloading if rx packet aggregation is enabled through VIOS. Some firmware offerings provide the MSS in the RX buffer. This is signalled by a bit in the RX queue descriptor. Reviewed-by: Brian King <[email protected]> Reviewed-by: Pradeep Satyanarayana <[email protected]> Reviewed-by: Marcelo Ricardo Leitner <[email protected]> Reviewed-by: Jonathan Maxwell <[email protected]> Reviewed-by: David Dai <[email protected]> Signed-off-by: Thomas Falcon <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1472d59 commit 7b59673

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

drivers/net/ethernet/ibm/ibmveth.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool;
5858

5959
static const char ibmveth_driver_name[] = "ibmveth";
6060
static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver";
61-
#define ibmveth_driver_version "1.05"
61+
#define ibmveth_driver_version "1.06"
6262

6363
MODULE_AUTHOR("Santiago Leon <[email protected]>");
6464
MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver");
@@ -137,6 +137,11 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
137137
return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;
138138
}
139139

140+
static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter)
141+
{
142+
return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT;
143+
}
144+
140145
static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
141146
{
142147
return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
@@ -1174,6 +1179,45 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
11741179
goto retry_bounce;
11751180
}
11761181

1182+
static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt)
1183+
{
1184+
int offset = 0;
1185+
1186+
/* only TCP packets will be aggregated */
1187+
if (skb->protocol == htons(ETH_P_IP)) {
1188+
struct iphdr *iph = (struct iphdr *)skb->data;
1189+
1190+
if (iph->protocol == IPPROTO_TCP) {
1191+
offset = iph->ihl * 4;
1192+
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
1193+
} else {
1194+
return;
1195+
}
1196+
} else if (skb->protocol == htons(ETH_P_IPV6)) {
1197+
struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data;
1198+
1199+
if (iph6->nexthdr == IPPROTO_TCP) {
1200+
offset = sizeof(struct ipv6hdr);
1201+
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
1202+
} else {
1203+
return;
1204+
}
1205+
} else {
1206+
return;
1207+
}
1208+
/* if mss is not set through Large Packet bit/mss in rx buffer,
1209+
* expect that the mss will be written to the tcp header checksum.
1210+
*/
1211+
if (lrg_pkt) {
1212+
skb_shinfo(skb)->gso_size = mss;
1213+
} else if (offset) {
1214+
struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset);
1215+
1216+
skb_shinfo(skb)->gso_size = ntohs(tcph->check);
1217+
tcph->check = 0;
1218+
}
1219+
}
1220+
11771221
static int ibmveth_poll(struct napi_struct *napi, int budget)
11781222
{
11791223
struct ibmveth_adapter *adapter =
@@ -1182,6 +1226,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
11821226
int frames_processed = 0;
11831227
unsigned long lpar_rc;
11841228
struct iphdr *iph;
1229+
u16 mss = 0;
11851230

11861231
restart_poll:
11871232
while (frames_processed < budget) {
@@ -1199,9 +1244,21 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
11991244
int length = ibmveth_rxq_frame_length(adapter);
12001245
int offset = ibmveth_rxq_frame_offset(adapter);
12011246
int csum_good = ibmveth_rxq_csum_good(adapter);
1247+
int lrg_pkt = ibmveth_rxq_large_packet(adapter);
12021248

12031249
skb = ibmveth_rxq_get_buffer(adapter);
12041250

1251+
/* if the large packet bit is set in the rx queue
1252+
* descriptor, the mss will be written by PHYP eight
1253+
* bytes from the start of the rx buffer, which is
1254+
* skb->data at this stage
1255+
*/
1256+
if (lrg_pkt) {
1257+
__be64 *rxmss = (__be64 *)(skb->data + 8);
1258+
1259+
mss = (u16)be64_to_cpu(*rxmss);
1260+
}
1261+
12051262
new_skb = NULL;
12061263
if (length < rx_copybreak)
12071264
new_skb = netdev_alloc_skb(netdev, length);
@@ -1235,11 +1292,15 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
12351292
if (iph->check == 0xffff) {
12361293
iph->check = 0;
12371294
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
1238-
adapter->rx_large_packets++;
12391295
}
12401296
}
12411297
}
12421298

1299+
if (length > netdev->mtu + ETH_HLEN) {
1300+
ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
1301+
adapter->rx_large_packets++;
1302+
}
1303+
12431304
napi_gro_receive(napi, skb); /* send it up */
12441305

12451306
netdev->stats.rx_packets++;

drivers/net/ethernet/ibm/ibmveth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ struct ibmveth_rx_q_entry {
209209
#define IBMVETH_RXQ_TOGGLE 0x80000000
210210
#define IBMVETH_RXQ_TOGGLE_SHIFT 31
211211
#define IBMVETH_RXQ_VALID 0x40000000
212+
#define IBMVETH_RXQ_LRG_PKT 0x04000000
212213
#define IBMVETH_RXQ_NO_CSUM 0x02000000
213214
#define IBMVETH_RXQ_CSUM_GOOD 0x01000000
214215
#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF

0 commit comments

Comments
 (0)