ofproto: Break packet_in encoding out of ofproto into ofp-util.
authorBen Pfaff <blp@nicira.com>
Tue, 22 Mar 2011 16:13:02 +0000 (09:13 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 29 Mar 2011 19:28:10 +0000 (12:28 -0700)
This removes some code from ofproto.c.

lib/ofp-util.c
lib/ofp-util.h
ofproto/ofproto.c

index 3d64fcf..e42abc5 100644 (file)
@@ -1453,6 +1453,49 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     return msg;
 }
 
+/* Converts abstract ofputil_packet_in 'pin' into an OFPT_PACKET_IN message
+ * and returns the message.
+ *
+ * If 'rw_packet' is NULL, the caller takes ownership of the newly allocated
+ * returned ofpbuf.
+ *
+ * If 'rw_packet' is nonnull, then it must contain the same data as
+ * pin->packet.  'rw_packet' is allowed to be the same ofpbuf as pin->packet.
+ * It is modified in-place into an OFPT_PACKET_IN message according to 'pin',
+ * and then ofputil_encode_packet_in() returns 'rw_packet'.  If 'rw_packet' has
+ * enough headroom to insert a "struct ofp_packet_in", this is more efficient
+ * than ofputil_encode_packet_in() because it does not copy the packet
+ * payload. */
+struct ofpbuf *
+ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
+                        struct ofpbuf *rw_packet)
+{
+    int total_len = pin->packet->size;
+    struct ofp_packet_in *opi;
+
+    if (rw_packet) {
+        if (pin->send_len < rw_packet->size) {
+            rw_packet->size = pin->send_len;
+        }
+    } else {
+        rw_packet = ofpbuf_clone_data_with_headroom(
+            pin->packet->data, MIN(pin->send_len, pin->packet->size),
+            offsetof(struct ofp_packet_in, data));
+    }
+
+    /* Add OFPT_PACKET_IN. */
+    opi = ofpbuf_push_zeros(rw_packet, offsetof(struct ofp_packet_in, data));
+    opi->header.version = OFP_VERSION;
+    opi->header.type = OFPT_PACKET_IN;
+    opi->total_len = htons(total_len);
+    opi->in_port = htons(pin->in_port);
+    opi->reason = pin->reason;
+    opi->buffer_id = htonl(pin->buffer_id);
+    update_openflow_length(rw_packet);
+
+    return rw_packet;
+}
+
 /* Returns a string representing the message type of 'type'.  The string is the
  * enumeration constant for the type, e.g. "OFPT_HELLO".  For statistics
  * messages, the constant is followed by "request" or "reply",
index c31165b..b4fe642 100644 (file)
@@ -192,6 +192,19 @@ int ofputil_decode_flow_removed(struct ofputil_flow_removed *,
 struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
                                            enum nx_flow_format);
 
+/* Abstract packet-in message. */
+struct ofputil_packet_in {
+    struct ofpbuf *packet;
+    uint16_t in_port;
+    uint8_t reason;             /* One of OFPR_*. */
+
+    uint32_t buffer_id;
+    int send_len;
+};
+
+struct ofpbuf *ofputil_encode_packet_in(const struct ofputil_packet_in *,
+                                        struct ofpbuf *rw_packet);
+
 /* OpenFlow protocol utility functions. */
 void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **);
 void *make_nxmsg(size_t openflow_len, uint32_t subtype, struct ofpbuf **);
index 6fd8833..699985c 100644 (file)
@@ -4955,59 +4955,42 @@ static void
 schedule_packet_in(struct ofconn *ofconn, struct dpif_upcall *upcall,
                    const struct flow *flow, bool clone)
 {
-    enum { OPI_SIZE = offsetof(struct ofp_packet_in, data) };
     struct ofproto *ofproto = ofconn->ofproto;
-    struct ofp_packet_in *opi;
-    int total_len, send_len;
-    struct ofpbuf *packet;
-    uint32_t buffer_id;
-    int idx;
+    struct ofputil_packet_in pin;
+    struct ofpbuf *msg;
+
+    /* Figure out the easy parts. */
+    pin.packet = upcall->packet;
+    pin.in_port = odp_port_to_ofp_port(flow->in_port);
+    pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION;
 
     /* Get OpenFlow buffer_id. */
     if (upcall->type == DPIF_UC_ACTION) {
-        buffer_id = UINT32_MAX;
+        pin.buffer_id = UINT32_MAX;
     } else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) {
-        buffer_id = pktbuf_get_null();
+        pin.buffer_id = pktbuf_get_null();
     } else if (!ofconn->pktbuf) {
-        buffer_id = UINT32_MAX;
+        pin.buffer_id = UINT32_MAX;
     } else {
-        buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet, flow->in_port);
+        pin.buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet,
+                                    flow->in_port);
     }
 
     /* Figure out how much of the packet to send. */
-    total_len = send_len = upcall->packet->size;
-    if (buffer_id != UINT32_MAX) {
-        send_len = MIN(send_len, ofconn->miss_send_len);
+    pin.send_len = upcall->packet->size;
+    if (pin.buffer_id != UINT32_MAX) {
+        pin.send_len = MIN(pin.send_len, ofconn->miss_send_len);
     }
     if (upcall->type == DPIF_UC_ACTION) {
-        send_len = MIN(send_len, upcall->userdata);
+        pin.send_len = MIN(pin.send_len, upcall->userdata);
     }
 
-    /* Copy or steal buffer for OFPT_PACKET_IN. */
-    if (clone) {
-        packet = ofpbuf_clone_data_with_headroom(upcall->packet->data,
-                                                 send_len, OPI_SIZE);
-    } else {
-        packet = upcall->packet;
-        packet->size = send_len;
-    }
-
-    /* Add OFPT_PACKET_IN. */
-    opi = ofpbuf_push_zeros(packet, OPI_SIZE);
-    opi->header.version = OFP_VERSION;
-    opi->header.type = OFPT_PACKET_IN;
-    opi->total_len = htons(total_len);
-    opi->in_port = htons(odp_port_to_ofp_port(flow->in_port));
-    opi->reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION;
-    opi->buffer_id = htonl(buffer_id);
-    update_openflow_length(packet);
-
-    /* Hand over to packet scheduler.  It might immediately call into
-     * do_send_packet_in() or it might buffer it for a while (until a later
-     * call to pinsched_run()). */
-    idx = upcall->type == DPIF_UC_MISS ? 0 : 1;
-    pinsched_send(ofconn->schedulers[idx], flow->in_port,
-                  packet, do_send_packet_in, ofconn);
+    /* Make OFPT_PACKET_IN and hand over to packet scheduler.  It might
+     * immediately call into do_send_packet_in() or it might buffer it for a
+     * while (until a later call to pinsched_run()). */
+    msg = ofputil_encode_packet_in(&pin, clone ? NULL : upcall->packet);
+    pinsched_send(ofconn->schedulers[upcall->type == DPIF_UC_MISS ? 0 : 1],
+                  flow->in_port, msg, do_send_packet_in, ofconn);
 }
 
 /* Given 'upcall', of type DPIF_UC_ACTION or DPIF_UC_MISS, sends an