From 875244c7a9048bfe2075f0d6bbb4fa13edaae242 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 6 Jan 2011 10:26:42 +0900 Subject: [PATCH] datapath: Treat GSO skbs as if they were fragments In dp_output_control() UDP GSO skbs are split into fragments which are passed to userspace. So the resulting flow set-up by the controller (I am using ovs-vswitchd) is created based on a fragment. This means that the UDP source and destination port of the flow is zero. In order for the datapath to match the resulting flow flow_extract() needs to treat UDP GSO skbs as if they are fragments. That is, set the UDP source and destination port to 0. A flow established for a UDP GSO skb with this change won't match any subsequent non-GSO skbs, they will need to be passed to the controller and a new flow established. But without this change no UDP GSO skbs will ever match any flow. I noticed this while using KVM using virtio with VhostNet and netperf's UDP_STREAM test. The result was that the test sent ~5Gbit/s but only a small fraction of that was received by the other side. Much less than the 1Gbit/s available on the physical link between the host (and guest) and the machine running netserver. 100% of one of the host's CPUs was consumed, 50% for the host and 50% for the guest. The host consumption was contributed to largely by ovs-vswitchd. With this change I get a much nicer result of a fraction under 1Gbit/s sent and almost all packets ending up at the other end. Signed-off-by: Simon Horman Signed-off-by: Jesse Gross --- datapath/flow.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/datapath/flow.c b/datapath/flow.c index b33b31559..fb339e73e 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -333,7 +333,8 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key, key->nw_proto = nh->protocol; /* Transport layer. */ - if (!(nh->frag_off & htons(IP_MF | IP_OFFSET))) { + if (!(nh->frag_off & htons(IP_MF | IP_OFFSET)) && + !(skb_shinfo(skb)->gso_type & SKB_GSO_UDP)) { if (key->nw_proto == IPPROTO_TCP) { if (tcphdr_ok(skb)) { struct tcphdr *tcp = tcp_hdr(skb); -- 2.43.0