From: Steven Smith Date: Wed, 20 May 2009 12:40:07 +0000 (+0100) Subject: Fix up checksum offload for the newer interfaces. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;p=people%2Fssmith%2Fnetchannel2-pvops.git Fix up checksum offload for the newer interfaces. --- diff --git a/drivers/net/xen-netchannel2/chan.c b/drivers/net/xen-netchannel2/chan.c index c4a222701e5..8cce1778a44 100644 --- a/drivers/net/xen-netchannel2/chan.c +++ b/drivers/net/xen-netchannel2/chan.c @@ -860,7 +860,7 @@ void nc2_detach_rings(struct netchannel2 *nc) /* XXX De-pend the interfaces */ /* Disable all offloads */ - nc->net_device->features &= ~NETIF_F_IP_CSUM; + nc->net_device->features &= ~NETIF_F_HW_CSUM; nc->allow_tx_csum_offload = 0; } diff --git a/drivers/net/xen-netchannel2/offload.c b/drivers/net/xen-netchannel2/offload.c index 6c86fa4712b..3a86087d6dd 100644 --- a/drivers/net/xen-netchannel2/offload.c +++ b/drivers/net/xen-netchannel2/offload.c @@ -26,6 +26,10 @@ void nc2_handle_set_offload(struct netchannel2 *nc, nc2_copy_from_ring(&nc->rings.cons_ring, &msg, hdr->size); if (msg.csum != nc->allow_tx_csum_offload) { nc->allow_tx_csum_offload = msg.csum; + if (msg.csum) + nc->net_device->features |= NETIF_F_HW_CSUM; + else + nc->net_device->features &= ~NETIF_F_HW_CSUM; nc2_set_tx_csum(nc->net_device, msg.csum); /* Linux doesn't support scatter-gather mode without TX csum offload. We therefore need to disable SG diff --git a/drivers/net/xen-netchannel2/posted_buffers.c b/drivers/net/xen-netchannel2/posted_buffers.c index 035181da000..47a6fdf155d 100644 --- a/drivers/net/xen-netchannel2/posted_buffers.c +++ b/drivers/net/xen-netchannel2/posted_buffers.c @@ -171,6 +171,8 @@ struct sk_buff *handle_pre_posted_packet(struct netchannel2 *nc, is_bad = 0; if (msg->prefix_size < SKB_MIN_PAYLOAD_SIZE) prefix_len = SKB_MIN_PAYLOAD_SIZE; + else if (msg->prefix_size < msg->csum_offset + 2) + prefix_len = msg->csum_offset + 2; else prefix_len = msg->prefix_size; /* We don't enforce the MAX_PACKET_BYTES limit here. That's @@ -247,9 +249,9 @@ struct sk_buff *handle_pre_posted_packet(struct netchannel2 *nc, head_skb->len = cur_skb->len + acc_len; head_skb->data_len = cur_skb->data_len + acc_len; head_skb->truesize = cur_skb->truesize + acc_len; - if (skb_headlen(head_skb) < SKB_MIN_PAYLOAD_SIZE) + if (skb_headlen(head_skb) < prefix_len) pull_through(head_skb, - SKB_MIN_PAYLOAD_SIZE - skb_headlen(head_skb)); + prefix_len - skb_headlen(head_skb)); } return head_skb; diff --git a/drivers/net/xen-netchannel2/receiver_map.c b/drivers/net/xen-netchannel2/receiver_map.c index eab13b71eab..4d0637710b8 100644 --- a/drivers/net/xen-netchannel2/receiver_map.c +++ b/drivers/net/xen-netchannel2/receiver_map.c @@ -655,6 +655,8 @@ struct sk_buff *handle_receiver_map_packet(struct netchannel2 *nc, if (msg->prefix_size < SKB_MIN_PAYLOAD_SIZE) prefix_size = SKB_MIN_PAYLOAD_SIZE; + else if (msg->prefix_size < msg->csum_offset + 2) + prefix_size = msg->csum_offset + 2; else prefix_size = msg->prefix_size; /* As in posted_buffers.c, we don't limit the total size of @@ -736,9 +738,8 @@ struct sk_buff *handle_receiver_map_packet(struct netchannel2 *nc, } spin_unlock(&receive_mapper->rm_lock); - if (skb_headlen(head_skb) < SKB_MIN_PAYLOAD_SIZE) - pull_through(head_skb, - SKB_MIN_PAYLOAD_SIZE - skb_headlen(head_skb)); + if (skb_headlen(head_skb) < prefix_size) + pull_through(head_skb, prefix_size - skb_headlen(head_skb)); return head_skb; diff --git a/drivers/net/xen-netchannel2/recv_packet.c b/drivers/net/xen-netchannel2/recv_packet.c index 430ed6ff816..0504d038162 100644 --- a/drivers/net/xen-netchannel2/recv_packet.c +++ b/drivers/net/xen-netchannel2/recv_packet.c @@ -198,6 +198,20 @@ void nc2_handle_packet_msg(struct netchannel2 *nc, break; default: skb->ip_summed = CHECKSUM_PARTIAL; + if (msg.csum_offset + 2 > skb_headlen(skb)) { + /* Whoops. Assuming no bugs in our + receive methods, the other end just + requested checksum calculation + beyond the end of the packet. */ + if (net_ratelimit()) + dev_warn(&nc->net_device->dev, + "csum field too far through packet (%d, skb len %d, headlen %d)\n", + msg.csum_offset, skb->len, + skb_headlen(skb)); + goto err; + } + skb->csum_start = msg.csum_start + skb_headroom(skb); + skb->csum_offset = msg.csum_offset - msg.csum_start; break; } #endif diff --git a/drivers/net/xen-netchannel2/rscb.c b/drivers/net/xen-netchannel2/rscb.c index 52ae3b47556..3be2a6e082f 100644 --- a/drivers/net/xen-netchannel2/rscb.c +++ b/drivers/net/xen-netchannel2/rscb.c @@ -207,7 +207,10 @@ struct sk_buff *handle_receiver_copy_packet(struct netchannel2 *nc, skb_headsize = nr_bytes + NET_IP_ALIGN; if (skb_headsize > ((PAGE_SIZE - sizeof(struct skb_shared_info) - NET_SKB_PAD) & ~(SMP_CACHE_BYTES))) { - skb_headsize = msg->prefix_size + NET_IP_ALIGN; + if (msg->prefix_size < msg->csum_offset + 2) + skb_headsize = msg->csum_offset + 2; + else + skb_headsize = msg->prefix_size + NET_IP_ALIGN; } skb = dev_alloc_skb(skb_headsize); diff --git a/drivers/net/xen-netchannel2/xmit_packet.c b/drivers/net/xen-netchannel2/xmit_packet.c index 7da3bf05fe2..48c6c5e93de 100644 --- a/drivers/net/xen-netchannel2/xmit_packet.c +++ b/drivers/net/xen-netchannel2/xmit_packet.c @@ -108,10 +108,14 @@ static void set_offload_flags(struct sk_buff *skb, volatile struct netchannel2_msg_packet *msg) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,20) - if (skb->ip_summed == CHECKSUM_PARTIAL) - msg->flags |= - NC2_PACKET_FLAG_csum_blank | - NC2_PACKET_FLAG_data_validated; + if (skb->ip_summed == CHECKSUM_PARTIAL) { + msg->flags |= NC2_PACKET_FLAG_data_validated | + NC2_PACKET_FLAG_csum_blank; + msg->csum_start = skb->csum_start - skb_headroom(skb); + msg->csum_offset = skb->csum_offset + msg->csum_start; + } + if (skb->ip_summed == CHECKSUM_UNNECESSARY) + msg->flags |= NC2_PACKET_FLAG_data_validated; #else if (skb->ip_summed == CHECKSUM_HW) msg->flags |= diff --git a/include/xen/interface/io/netchannel2.h b/include/xen/interface/io/netchannel2.h index f746b29dd56..1b181b8b497 100644 --- a/include/xen/interface/io/netchannel2.h +++ b/include/xen/interface/io/netchannel2.h @@ -61,13 +61,33 @@ struct netchannel2_msg_packet { uint8_t pad; uint16_t prefix_size; uint16_t mss; + uint16_t csum_start; + uint16_t csum_offset; /* Variable-size array. The number of elements is determined by the size of the message. */ struct netchannel2_fragment frags[0]; }; + +/* TX csum offload. The transmitting domain has skipped a checksum + * calculation. Before forwarding the packet on, the receiving domain + * must first perform a 16 bit IP checksum on everything from + * csum_start to the end of the packet, and then write the result to + * an offset csum_offset in the packet. + */ #define NC2_PACKET_FLAG_csum_blank 1 +/* RX csum offload. The transmitting domain has already validated the + * protocol-level checksum on this packet (i.e. TCP or UDP), so the + * receiving domain shouldn't bother. This does not tell you anything + * about the IP-level checksum. */ #define NC2_PACKET_FLAG_data_validated 2 +/* If set, this flag indicates that this packet could have used a + * bypass if one had been available, and so it should be sent to the + * autobypass state machine. + */ #define NC2_PACKET_FLAG_bypass_candidate 4 +/* If set, the transmitting domain requires an event urgently when + * this packet's finish message is sent. Otherwise, the event can be + * delayed. */ #define NC2_PACKET_FLAG_need_event 8 /* The mechanism which should be used to receive the data part of