[ovs-dev] [PATCH 9/9] tunneling: Add UDP checksum support for userspace tunnels.

Jesse Gross jesse at nicira.com
Mon Mar 30 22:14:52 UTC 2015


Kernel based OVS recently added the ability to support checksums
for UDP based tunnels (Geneve and VXLAN). This adds similar support
for the userspace datapath to bring feature parity.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 lib/netdev-vport.c       | 37 ++++++++++++++++++++++++++++++++++---
 lib/odp-util.c           | 15 +++++++--------
 tests/odp.at             |  5 +++--
 tests/tunnel-push-pop.at | 10 +++++-----
 4 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index ef96862..d39d449 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -891,6 +891,18 @@ udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
         return NULL;
     }
 
+    if (udp->udp_csum) {
+        uint32_t csum = packet_csum_pseudoheader(dp_packet_l3(packet));
+
+        csum = csum_continue(csum, udp, dp_packet_size(packet) -
+                             ((const unsigned char *)udp -
+                              (const unsigned char *)dp_packet_l2(packet)));
+        if (csum_finish(csum)) {
+            return NULL;
+        }
+        tnl->flags |= FLOW_TNL_F_CSUM;
+    }
+
     tnl->tp_src = udp->udp_src;
     tnl->tp_dst = udp->udp_dst;
 
@@ -919,13 +931,25 @@ push_udp_header(struct dp_packet *packet, const void *header, int size)
     /* set udp src port */
     udp->udp_src = get_src_port(packet);
     udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
-    /* udp_csum is zero */
+
+    if (udp->udp_csum) {
+        uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
+
+        csum = csum_continue(csum, udp,
+                             ip_tot_size - sizeof (struct ip_header));
+        udp->udp_csum = csum_finish(csum);
+
+        if (!udp->udp_csum) {
+            udp->udp_csum = htons(0xffff);
+        }
+    }
 
     return udp + 1;
 }
 
 static void *
 udp_build_header(struct netdev_tunnel_config *tnl_cfg,
+                 const struct flow *tnl_flow,
                  struct ovs_action_push_tnl *data)
 {
     struct ip_header *ip;
@@ -937,6 +961,13 @@ udp_build_header(struct netdev_tunnel_config *tnl_cfg,
     udp = (struct udp_header *) (ip + 1);
     udp->udp_dst = tnl_cfg->dst_port;
 
+    if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+        /* Write a value in now to mark that we should compute the checksum
+         * later. 0xffff is handy because it is transparent to the
+         * calculation. */
+        udp->udp_csum = htons(0xffff);
+    }
+
     return udp + 1;
 }
 
@@ -1182,7 +1213,7 @@ netdev_vxlan_build_header(const struct netdev *netdev,
     ovs_mutex_lock(&dev->mutex);
     tnl_cfg = &dev->tnl_cfg;
 
-    vxh = udp_build_header(tnl_cfg, data);
+    vxh = udp_build_header(tnl_cfg, tnl_flow, data);
 
     put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
     put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
@@ -1286,7 +1317,7 @@ netdev_geneve_build_header(const struct netdev *netdev,
     ovs_mutex_lock(&dev->mutex);
     tnl_cfg = &dev->tnl_cfg;
 
-    gnh = udp_build_header(tnl_cfg, data);
+    gnh = udp_build_header(tnl_cfg, tnl_flow, data);
 
     gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
     gnh->proto_type = htons(ETH_TYPE_TEB);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 47dfc92..3e6a7bd 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -516,8 +516,9 @@ format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip)
     const struct udp_header *udp;
 
     udp = (const struct udp_header *) (ip + 1);
-    ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),",
-                  ntohs(udp->udp_src), ntohs(udp->udp_dst));
+    ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),",
+                  ntohs(udp->udp_src), ntohs(udp->udp_dst),
+                  ntohs(udp->udp_csum));
 
     return udp + 1;
 }
@@ -854,7 +855,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
     struct ip_header *ip;
     struct udp_header *udp;
     struct gre_base_hdr *greh;
-    uint16_t gre_proto, dl_type, udp_src, udp_dst;
+    uint16_t gre_proto, dl_type, udp_src, udp_dst, csum;
     ovs_be32 sip, dip;
     uint32_t tnl_type = 0, header_len = 0;
     void *l3, *l4;
@@ -899,14 +900,14 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
     /* Tunnel header */
     udp = (struct udp_header *) l4;
     greh = (struct gre_base_hdr *) l4;
-    if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),",
-                         &udp_src, &udp_dst)) {
+    if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
+                         &udp_src, &udp_dst, &csum)) {
         uint32_t vx_flags, vni;
 
         udp->udp_src = htons(udp_src);
         udp->udp_dst = htons(udp_dst);
         udp->udp_len = 0;
-        udp->udp_csum = 0;
+        udp->udp_csum = htons(csum);
 
         if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
                             &vx_flags, &vni)) {
@@ -942,8 +943,6 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
         ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1);
 
         if (greh->flags & htons(GRE_CSUM)) {
-            uint16_t csum;
-
             if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx16, &csum)) {
                 return -EINVAL;
             }
diff --git a/tests/odp.at b/tests/odp.at
index 7fda449..d615891 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -281,8 +281,9 @@ set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src
 tnl_pop(4)
 tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1))
 tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1))
-tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1))
-tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081),geneve(oam,vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1))
 ])
 AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],
   [`cat actions.txt`
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index effe543..1e530ba 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -9,7 +9,7 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
                     -- add-port int-br t1 -- set Interface t1 type=gre \
                        options:remote_ip=1.1.2.92 options:key=456 ofport_request=3\
                     -- add-port int-br t3 -- set Interface t3 type=vxlan \
-                       options:remote_ip=1.1.2.93 options:out_key=flow ofport_request=4\
+                       options:remote_ip=1.1.2.93 options:out_key=flow options:csum=true ofport_request=4\
                     -- add-port int-br t4 -- set Interface t4 type=geneve \
                        options:remote_ip=1.1.2.92 options:key=123 ofport_request=5\
                        ], [0])
@@ -23,7 +23,7 @@ dummy at ovs-dummy: hit:0 missed:0
 		int-br 65534/2: (dummy)
 		t1 3/3: (gre: key=456, remote_ip=1.1.2.92)
 		t2 2/4789: (vxlan: key=123, remote_ip=1.1.2.92)
-		t3 4/4789: (vxlan: out_key=flow, remote_ip=1.1.2.93)
+		t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=1.1.2.93)
 		t4 5/6081: (geneve: key=123, remote_ip=1.1.2.92)
 ])
 
@@ -67,14 +67,14 @@ dnl Check VXLAN tunnel push
 AT_CHECK([ovs-ofctl add-flow int-br action=2])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
+  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
 ])
 
-dnl Check VXLAN tunnel push set tunnel id by flow
+dnl Check VXLAN tunnel push set tunnel id by flow and checksum
 AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
+  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
 ])
 
 dnl Check GRE tunnel push
-- 
1.9.1




More information about the dev mailing list