ofproto-dpif-upcall: Avoid double-delete of ukeys.
[cascardo/ovs.git] / ofproto / pktbuf.c
index acc0d34..def0c92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include <stdlib.h>
 #include "coverage.h"
 #include "ofp-util.h"
-#include "ofpbuf.h"
+#include "dp-packet.h"
 #include "timeval.h"
 #include "util.h"
-#include "vconn.h"
-#include "vlog.h"
+#include "openvswitch/vconn.h"
+#include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(pktbuf);
 
@@ -48,10 +48,10 @@ COVERAGE_DEFINE(pktbuf_reuse_error);
 #define OVERWRITE_MSECS 5000
 
 struct packet {
-    struct ofpbuf *buffer;
+    struct dp_packet *buffer;
     uint32_t cookie;
     long long int timeout;
-    uint16_t in_port;
+    ofp_port_t in_port;
 };
 
 struct pktbuf {
@@ -79,7 +79,7 @@ pktbuf_destroy(struct pktbuf *pb)
         size_t i;
 
         for (i = 0; i < PKTBUF_CNT; i++) {
-            ofpbuf_delete(pb->packets[i].buffer);
+            dp_packet_delete(pb->packets[i].buffer);
         }
         free(pb);
     }
@@ -104,7 +104,7 @@ make_id(unsigned int buffer_idx, unsigned int cookie)
  * The caller retains ownership of 'buffer'. */
 uint32_t
 pktbuf_save(struct pktbuf *pb, const void *buffer, size_t buffer_size,
-            uint16_t in_port)
+            ofp_port_t in_port)
 {
     struct packet *p = &pb->packets[pb->buffer_idx];
     pb->buffer_idx = (pb->buffer_idx + 1) & PKTBUF_MASK;
@@ -112,16 +112,16 @@ pktbuf_save(struct pktbuf *pb, const void *buffer, size_t buffer_size,
         if (time_msec() < p->timeout) {
             return UINT32_MAX;
         }
-        ofpbuf_delete(p->buffer);
+        dp_packet_delete(p->buffer);
     }
 
     /* Don't use maximum cookie value since all-1-bits ID is special. */
     if (++p->cookie >= COOKIE_MAX) {
         p->cookie = 0;
     }
-    p->buffer = ofpbuf_clone_data_with_headroom(buffer, buffer_size,
-                                                sizeof(struct ofp_packet_in));
 
+    /* Use 2 bytes of headroom to 32-bit align the L3 header. */
+    p->buffer = dp_packet_clone_data_with_headroom(buffer, buffer_size, 2);
 
     p->timeout = time_msec() + OVERWRITE_MSECS;
     p->in_port = in_port;
@@ -158,20 +158,19 @@ pktbuf_get_null(void)
  * 0 if successful, otherwise an OpenFlow error code.
  *
  * On success, ordinarily stores the buffered packet in '*bufferp' and the
- * datapath port number on which the packet was received in '*in_port'.  The
+ * OpenFlow port number on which the packet was received in '*in_port'.  The
  * caller becomes responsible for freeing the buffer.  However, if 'id'
  * identifies a "null" packet buffer (created with pktbuf_get_null()), stores
- * NULL in '*bufferp' and UINT16_max in '*in_port'.
+ * NULL in '*bufferp' and OFPP_NONE in '*in_port'.
  *
  * 'in_port' may be NULL if the input port is not of interest.
  *
- * A returned packet will have at least sizeof(struct ofp_packet_in) bytes of
- * headroom.
+ * The L3 header of a returned packet will be 32-bit aligned.
  *
  * On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
 enum ofperr
-pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
-                uint16_t *in_port)
+pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct dp_packet **bufferp,
+                ofp_port_t *in_port)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 20);
     struct packet *p;
@@ -185,12 +184,13 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
     if (!pb) {
         VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
                      "without buffers");
-        return OFPERR_OFPBRC_BUFFER_UNKNOWN;
+        error = OFPERR_OFPBRC_BUFFER_UNKNOWN;
+        goto error;
     }
 
     p = &pb->packets[id & PKTBUF_MASK];
     if (p->cookie == id >> PKTBUF_BITS) {
-        struct ofpbuf *buffer = p->buffer;
+        struct dp_packet *buffer = p->buffer;
         if (buffer) {
             *bufferp = buffer;
             if (in_port) {
@@ -218,7 +218,7 @@ pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
 error:
     *bufferp = NULL;
     if (in_port) {
-        *in_port = UINT16_MAX;
+        *in_port = OFPP_NONE;
     }
     return error;
 }
@@ -228,7 +228,27 @@ pktbuf_discard(struct pktbuf *pb, uint32_t id)
 {
     struct packet *p = &pb->packets[id & PKTBUF_MASK];
     if (p->cookie == id >> PKTBUF_BITS) {
-        ofpbuf_delete(p->buffer);
+        dp_packet_delete(p->buffer);
         p->buffer = NULL;
     }
 }
+
+/* Returns the number of packets buffered in 'pb'.  Returns 0 if 'pb' is
+ * null. */
+unsigned int
+pktbuf_count_packets(const struct pktbuf *pb)
+{
+    int n = 0;
+
+    if (pb) {
+        int i;
+
+        for (i = 0; i < PKTBUF_CNT; i++) {
+            if (pb->packets[i].buffer) {
+                n++;
+            }
+        }
+    }
+
+    return n;
+}