Skip to content

Commit 7d170f2

Browse files
tlfalcongregkh
authored andcommitted
ibmveth: set correct gso_size and gso_type
commit 7b5967389f5a8dfb9d32843830f5e2717e20995d upstream. 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 <brking@linux.vnet.ibm.com> Reviewed-by: Pradeep Satyanarayana <pradeeps@linux.vnet.ibm.com> Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Reviewed-by: Jonathan Maxwell <jmaxwell37@gmail.com> Reviewed-by: David Dai <zdai@us.ibm.com> Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent ac0cbfb commit 7d170f2

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

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 <santil@linux.vnet.ibm.com>");
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);
@@ -1172,6 +1177,45 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
11721177
goto retry_bounce;
11731178
}
11741179

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

11841229
restart_poll:
11851230
while (frames_processed < budget) {
@@ -1197,9 +1242,21 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
11971242
int length = ibmveth_rxq_frame_length(adapter);
11981243
int offset = ibmveth_rxq_frame_offset(adapter);
11991244
int csum_good = ibmveth_rxq_csum_good(adapter);
1245+
int lrg_pkt = ibmveth_rxq_large_packet(adapter);
12001246

12011247
skb = ibmveth_rxq_get_buffer(adapter);
12021248

1249+
/* if the large packet bit is set in the rx queue
1250+
* descriptor, the mss will be written by PHYP eight
1251+
* bytes from the start of the rx buffer, which is
1252+
* skb->data at this stage
1253+
*/
1254+
if (lrg_pkt) {
1255+
__be64 *rxmss = (__be64 *)(skb->data + 8);
1256+
1257+
mss = (u16)be64_to_cpu(*rxmss);
1258+
}
1259+
12031260
new_skb = NULL;
12041261
if (length < rx_copybreak)
12051262
new_skb = netdev_alloc_skb(netdev, length);
@@ -1233,11 +1290,15 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
12331290
if (iph->check == 0xffff) {
12341291
iph->check = 0;
12351292
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
1236-
adapter->rx_large_packets++;
12371293
}
12381294
}
12391295
}
12401296

1297+
if (length > netdev->mtu + ETH_HLEN) {
1298+
ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
1299+
adapter->rx_large_packets++;
1300+
}
1301+
12411302
napi_gro_receive(napi, skb); /* send it up */
12421303

12431304
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)