[ovs-dev] [PATCH 1/2] tunneling: Convert tunnel push/pop functions to act on single packets.

Jesse Gross jesse at nicira.com
Wed Apr 8 20:19:26 UTC 2015


The userspace tunneling API for pushing and popping tunnel headers
is currently based on processing batches of packets. However, there
is no obvious way to take advantage of batching for these operations
and so each tunnel operation has a pair of loops to process the
batch. This changes the API to operate on single packets to enable
better code reuse.

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 lib/netdev-provider.h |   9 ++--
 lib/netdev-vport.c    | 140 +++++++++++---------------------------------------
 lib/netdev.c          |  34 +++++++++---
 3 files changed, 62 insertions(+), 121 deletions(-)

diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index fabeb2d..a81f8f8 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -264,14 +264,13 @@ struct netdev_class {
      * flow.  Push header is called for packet to build header specific to
      * a packet on actual transmit.  It uses partial header build by
      * build_header() which is passed as data. */
-    int (*push_header)(const struct netdev *netdev,
-                       struct dp_packet **buffers, int cnt,
-                       const struct ovs_action_push_tnl *data);
+    void (*push_header)(const struct netdev *netdev,
+                        struct dp_packet *packet,
+                        const struct ovs_action_push_tnl *data);
 
     /* Pop tunnel header from packet, build tunnel metadata and resize packet
      * for further processing. */
-    int  (*pop_header)(struct netdev *netdev,
-                       struct dp_packet **buffers, int cnt);
+    int (*pop_header)(struct netdev *netdev, struct dp_packet *packet);
 
     /* Returns the id of the numa node the 'netdev' is on.  If there is no
      * such info, returns NETDEV_NUMA_UNSPEC. */
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 23483e3..8a2cc7b 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -920,13 +920,15 @@ get_src_port(struct dp_packet *packet)
                  tnl_udp_port_min);
 }
 
-static void *
-push_udp_header(struct dp_packet *packet, const void *header, int size)
+static void
+push_udp_header(const struct netdev *netdev OVS_UNUSED,
+                struct dp_packet *packet,
+                const struct ovs_action_push_tnl *data)
 {
     struct udp_header *udp;
     int ip_tot_size;
 
-    udp = push_ip_header(packet, header, size, &ip_tot_size);
+    udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
 
     /* set udp src port */
     udp->udp_src = get_src_port(packet);
@@ -943,8 +945,6 @@ push_udp_header(struct dp_packet *packet, const void *header, int size)
             udp->udp_csum = htons(0xffff);
         }
     }
-
-    return udp + 1;
 }
 
 static void *
@@ -1042,14 +1042,9 @@ parse_gre_header(struct dp_packet *packet,
     return hlen;
 }
 
-static void
-reset_tnl_md(struct pkt_metadata *md)
-{
-    memset(&md->tunnel, 0, sizeof(md->tunnel));
-}
-
-static void
-gre_extract_md(struct dp_packet *packet)
+static int
+netdev_gre_pop_header(struct netdev *netdev_ OVS_UNUSED,
+                      struct dp_packet *packet)
 {
     struct pkt_metadata *md = &packet->md;
     struct flow_tnl *tnl = &md->tunnel;
@@ -1058,37 +1053,28 @@ gre_extract_md(struct dp_packet *packet)
 
     memset(md, 0, sizeof *md);
     if (hlen > dp_packet_size(packet)) {
-        return;
+        return EINVAL;
     }
 
     hlen = parse_gre_header(packet, tnl);
     if (hlen < 0) {
-        reset_tnl_md(md);
+        return -hlen;
     }
 
     dp_packet_reset_packet(packet, hlen);
-}
-
-static int
-netdev_gre_pop_header(struct netdev *netdev_ OVS_UNUSED,
-                      struct dp_packet **pkt, int cnt)
-{
-    int i;
 
-    for (i = 0; i < cnt; i++) {
-        gre_extract_md(pkt[i]);
-    }
     return 0;
 }
 
 static void
-netdev_gre_push_header__(struct dp_packet *packet,
-                         const void *header, int size)
+netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED,
+                       struct dp_packet *packet,
+                       const struct ovs_action_push_tnl *data)
 {
     struct gre_base_hdr *greh;
     int ip_tot_size;
 
-    greh = push_ip_header(packet, header, size,  &ip_tot_size);
+    greh = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
 
     if (greh->flags & htons(GRE_CSUM)) {
         ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
@@ -1097,21 +1083,6 @@ netdev_gre_push_header__(struct dp_packet *packet,
 }
 
 static int
-netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED,
-                       struct dp_packet **packets, int cnt,
-                       const struct ovs_action_push_tnl *data)
-{
-    int i;
-
-    for (i = 0; i < cnt; i++) {
-        netdev_gre_push_header__(packets[i], data->header, data->header_len);
-        packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
-    }
-    return 0;
-}
-
-
-static int
 netdev_gre_build_header(const struct netdev *netdev,
                         struct ovs_action_push_tnl *data,
                         const struct flow *tnl_flow)
@@ -1158,8 +1129,9 @@ netdev_gre_build_header(const struct netdev *netdev,
     return 0;
 }
 
-static void
-vxlan_extract_md(struct dp_packet *packet)
+static int
+netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED,
+                        struct dp_packet *packet)
 {
     struct pkt_metadata *md = &packet->md;
     struct flow_tnl *tnl = &md->tunnel;
@@ -1167,12 +1139,12 @@ vxlan_extract_md(struct dp_packet *packet)
 
     memset(md, 0, sizeof *md);
     if (VXLAN_HLEN > dp_packet_size(packet)) {
-        return;
+        return EINVAL;
     }
 
     vxh = udp_extract_tnl_md(packet, tnl);
     if (!vxh) {
-        return;
+        return EINVAL;
     }
 
     if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
@@ -1180,24 +1152,13 @@ vxlan_extract_md(struct dp_packet *packet)
         VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
                      ntohl(get_16aligned_be32(&vxh->vx_flags)),
                      ntohl(get_16aligned_be32(&vxh->vx_vni)));
-        reset_tnl_md(md);
-        return;
+        return EINVAL;
     }
     tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
     tnl->flags |= FLOW_TNL_F_KEY;
 
     dp_packet_reset_packet(packet, VXLAN_HLEN);
-}
-
-static int
-netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED,
-                        struct dp_packet **pkt, int cnt)
-{
-    int i;
 
-    for (i = 0; i < cnt; i++) {
-        vxlan_extract_md(pkt[i]);
-    }
     return 0;
 }
 
@@ -1226,21 +1187,8 @@ netdev_vxlan_build_header(const struct netdev *netdev,
 }
 
 static int
-netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
-                         struct dp_packet **packets, int cnt,
-                         const struct ovs_action_push_tnl *data)
-{
-    int i;
-
-    for (i = 0; i < cnt; i++) {
-        push_udp_header(packets[i], data->header, VXLAN_HLEN);
-        packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
-    }
-    return 0;
-}
-
-static void
-geneve_extract_md(struct dp_packet *packet)
+netdev_geneve_pop_header(struct netdev *netdev_ OVS_UNUSED,
+                         struct dp_packet *packet)
 {
     struct pkt_metadata *md = &packet->md;
     struct flow_tnl *tnl = &md->tunnel;
@@ -1251,40 +1199,36 @@ geneve_extract_md(struct dp_packet *packet)
     if (GENEVE_BASE_HLEN > dp_packet_size(packet)) {
         VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n",
                      (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet));
-        return;
+        return EINVAL;
     }
 
     gnh = udp_extract_tnl_md(packet, tnl);
     if (!gnh) {
-        return;
+        return EINVAL;
     }
 
     hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4;
     if (hlen > dp_packet_size(packet)) {
         VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
                      hlen, dp_packet_size(packet));
-        reset_tnl_md(md);
-        return;
+        return EINVAL;
     }
 
     if (gnh->ver != 0) {
         VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
-        reset_tnl_md(md);
-        return;
+        return EINVAL;
     }
 
     if (gnh->opt_len && gnh->critical) {
         VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n",
                      gnh->opt_len * 4);
-        reset_tnl_md(md);
-        return;
+        return EINVAL;
     }
 
     if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
         VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
                      ntohs(gnh->proto_type));
-        reset_tnl_md(md);
-        return;
+        return EINVAL;
     }
 
     tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
@@ -1292,17 +1236,7 @@ geneve_extract_md(struct dp_packet *packet)
     tnl->flags |= FLOW_TNL_F_KEY;
 
     dp_packet_reset_packet(packet, hlen);
-}
 
-static int
-netdev_geneve_pop_header(struct netdev *netdev_ OVS_UNUSED,
-                         struct dp_packet **pkt, int cnt)
-{
-    int i;
-
-    for (i = 0; i < cnt; i++) {
-        geneve_extract_md(pkt[i]);
-    }
     return 0;
 }
 
@@ -1331,20 +1265,6 @@ netdev_geneve_build_header(const struct netdev *netdev,
     return 0;
 }
 
-static int
-netdev_geneve_push_header(const struct netdev *netdev OVS_UNUSED,
-                          struct dp_packet **packets, int cnt,
-                          const struct ovs_action_push_tnl *data)
-{
-    int i;
-
-    for (i = 0; i < cnt; i++) {
-        push_udp_header(packets[i], data->header, data->header_len);
-        packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
-    }
-    return 0;
-}
-
 static void
 netdev_vport_range(struct unixctl_conn *conn, int argc,
                    const char *argv[], void *aux OVS_UNUSED)
@@ -1475,7 +1395,7 @@ netdev_vport_tunnel_register(void)
      * a port number to the end if one is necessary. */
     static const struct vport_class vport_classes[] = {
         TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header,
-                                            netdev_geneve_push_header,
+                                            push_udp_header,
                                             netdev_geneve_pop_header),
         TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header,
                                        netdev_gre_push_header,
@@ -1484,7 +1404,7 @@ netdev_vport_tunnel_register(void)
         TUNNEL_CLASS("gre64", "gre64_sys", NULL,  NULL, NULL),
         TUNNEL_CLASS("ipsec_gre64", "gre64_sys", NULL, NULL, NULL),
         TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
-                                           netdev_vxlan_push_header,
+                                           push_udp_header,
                                            netdev_vxlan_pop_header),
         TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL)
     };
diff --git a/lib/netdev.c b/lib/netdev.c
index c1d9b8f..aed5289 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -34,6 +34,7 @@
 #include "netdev-dpdk.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
+#include "odp-netlink.h"
 #include "openflow/openflow.h"
 #include "packets.h"
 #include "poll-loop.h"
@@ -735,9 +736,23 @@ netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers,
 int
 netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt)
 {
-    return (netdev->netdev_class->pop_header
-             ? netdev->netdev_class->pop_header(netdev, buffers, cnt)
-             : EOPNOTSUPP);
+    int i;
+
+    if (!netdev->netdev_class->pop_header) {
+        return EOPNOTSUPP;
+    }
+
+    for (i = 0; i < cnt; i++) {
+        int err;
+
+        err = netdev->netdev_class->pop_header(netdev, buffers[i]);
+        if (err) {
+            struct flow_tnl *tunnel_md = &buffers[i]->md.tunnel;
+            memset(tunnel_md, 0, sizeof *tunnel_md);
+        }
+    }
+
+    return 0;
 }
 
 int
@@ -755,11 +770,18 @@ netdev_push_header(const struct netdev *netdev,
                    struct dp_packet **buffers, int cnt,
                    const struct ovs_action_push_tnl *data)
 {
-    if (netdev->netdev_class->push_header) {
-        return netdev->netdev_class->push_header(netdev, buffers, cnt, data);
-    } else {
+    int i;
+
+    if (!netdev->netdev_class->push_header) {
         return -EINVAL;
     }
+
+    for (i = 0; i < cnt; i++) {
+        netdev->netdev_class->push_header(netdev, buffers[i], data);
+        buffers[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
+    }
+
+    return 0;
 }
 
 /* Registers with the poll loop to wake up from the next call to poll_block()
-- 
1.9.1




More information about the dev mailing list