[ovs-dev] [PATCH] dpif-netdev: Remove an extra memcpy of packet data from datapath-upcall interface for bridges with datapath_type=netdev.

Ryan Wilson wryan at nicira.com
Mon Jun 2 22:54:52 UTC 2014


When a bridge of datatype type netdev receives a packet, it copies the
packet from the NIC to a buffer in userspace. Currently, when making
an upcall, the packet is again copied to the upcall's buffer. However,
this extra copy is not necessary when the datapath exists in userspace
as the upcall can directly access the packet data.

This patch eliminates this extra copy of the packet data in most cases.
In cases where the packet may still be used later by callers of
dp_netdev_execute_actions, making a copy of the packet data is still
necessary.
---
 lib/dpif-netdev.c |   15 +++++----------
 lib/ofpbuf.c      |   18 ++++++++++++++++++
 lib/ofpbuf.h      |    2 ++
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 91c83d6..7cb0478 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -2024,7 +2024,6 @@ dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
                                    miniflow_hash_5tuple(&key.flow, 0)
                                    % dp->n_handlers,
                                    DPIF_UC_MISS, &key.flow, NULL);
-        ofpbuf_delete(packet);
     }
 }
 
@@ -2063,7 +2062,6 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
         if (userdata) {
             buf_size += NLA_ALIGN(userdata->nla_len);
         }
-        buf_size += ofpbuf_size(packet);
         ofpbuf_init(buf, buf_size);
 
         /* Put ODP flow. */
@@ -2078,15 +2076,14 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                                           NLA_ALIGN(userdata->nla_len));
         }
 
-        ofpbuf_set_data(&upcall->packet,
-                        ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet)));
-        ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
+        ofpbuf_set(&upcall->packet, packet);
 
         seq_change(q->seq);
 
         error = 0;
     } else {
         dp_netdev_count_packet(dp, DP_STAT_LOST);
+        ofpbuf_delete(packet);
         error = ENOBUFS;
     }
     ovs_mutex_unlock(&q->mutex);
@@ -2120,19 +2117,17 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
         break;
 
     case OVS_ACTION_ATTR_USERSPACE: {
+        struct ofpbuf *userspace_packet;
         const struct nlattr *userdata;
 
         userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+        userspace_packet = may_steal ? packet : ofpbuf_clone(packet);
 
-        dp_netdev_output_userspace(aux->dp, packet,
+        dp_netdev_output_userspace(aux->dp, userspace_packet,
                                    miniflow_hash_5tuple(aux->key, 0)
                                        % aux->dp->n_handlers,
                                    DPIF_UC_ACTION, aux->key,
                                    userdata);
-
-        if (may_steal) {
-            ofpbuf_delete(packet);
-        }
         break;
     }
 
diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c
index 1f4b61d..ade940b 100644
--- a/lib/ofpbuf.c
+++ b/lib/ofpbuf.c
@@ -555,3 +555,21 @@ ofpbuf_resize_l2(struct ofpbuf *b, int increment)
     ofpbuf_adjust_layer_offset(&b->l2_5_ofs, increment);
     return b->frame;
 }
+
+/* Sets ofpbuf 'dst' equal to 'src'. Note that 'dst' and 'src' share the
+ * same buffer, so calling ofpbuf_delete('dst') will also delete 'src'. */
+void
+ofpbuf_set(struct ofpbuf *dst, struct ofpbuf *src)
+{
+    ofpbuf_set_base(dst, ofpbuf_base(src));
+    ofpbuf_set_data(dst, ofpbuf_data(src));
+    ofpbuf_set_size(dst, ofpbuf_size(src));
+
+    dst->allocated = src->allocated;
+    dst->frame = src->frame;
+    dst->l2_5_ofs = src->l2_5_ofs;
+    dst->l3_ofs = src->l3_ofs;
+    dst->l4_ofs = src->l4_ofs;
+    dst->source = src->source;
+    dst->list_node = src->list_node;
+}
diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h
index 85be899..ec08c27 100644
--- a/lib/ofpbuf.h
+++ b/lib/ofpbuf.h
@@ -101,6 +101,8 @@ static inline const void *ofpbuf_get_udp_payload(const struct ofpbuf *);
 static inline const void *ofpbuf_get_sctp_payload(const struct ofpbuf *);
 static inline const void *ofpbuf_get_icmp_payload(const struct ofpbuf *);
 
+void ofpbuf_set(struct ofpbuf *, struct ofpbuf *);
+
 void ofpbuf_use(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_stack(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_stub(struct ofpbuf *, void *, size_t);
-- 
1.7.9.5




More information about the dev mailing list