diff mbox

[ovs-dev,1/2] ofproto: ofp_packet_out messages in bundles

Message ID 1468705528-31495-1-git-send-email-amantas@lasige.di.fc.ul.pt
State Superseded
Headers show

Commit Message

Andre Mantas July 16, 2016, 9:45 p.m. UTC
From: Andre Mantas <amantas@lasige.di.fc.ul.pt>

This patch allows ofp_packet_out messages to be added to bundles. In a 
multi controller scenario, packet_out messages inside bundles can serve 
as a commit_reply for other controllers - since the original commit_reply 
is only forwarded to the controller that sent the commit_request.

Tested with make check and external controller adding packet_out messages 
to a bundle with different destinations (hosts and controllers). Also tested 
grouping packet_out with port_mod messages in the same bundle. After 
committing the bundle, the destinations received the packet_out.

Signed-off-by: Andre Mantas <amantas@lasige.di.fc.ul.pt>
---
 lib/ofp-util.c             |  2 +-
 ofproto/bundles.h          |  5 ++++
 ofproto/ofproto-provider.h |  7 +++++
 ofproto/ofproto.c          | 70 ++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 81 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index c5353cc..6725220 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -9578,6 +9578,7 @@  ofputil_is_bundlable(enum ofptype type)
         /* Minimum required by OpenFlow 1.4. */
     case OFPTYPE_PORT_MOD:
     case OFPTYPE_FLOW_MOD:
+    case OFPTYPE_PACKET_OUT:
         return true;
 
         /* Nice to have later. */
@@ -9585,7 +9586,6 @@  ofputil_is_bundlable(enum ofptype type)
     case OFPTYPE_GROUP_MOD:
     case OFPTYPE_TABLE_MOD:
     case OFPTYPE_METER_MOD:
-    case OFPTYPE_PACKET_OUT:
     case OFPTYPE_NXT_TLV_TABLE_MOD:
 
         /* Not to be bundlable. */
diff --git a/ofproto/bundles.h b/ofproto/bundles.h
index d045031..61c1b48 100644
--- a/ofproto/bundles.h
+++ b/ofproto/bundles.h
@@ -22,6 +22,7 @@ 
 #include <sys/types.h>
 
 #include "connmgr.h"
+#include "dp-packet.h"
 #include "ofproto-provider.h"
 #include "openvswitch/ofp-msgs.h"
 #include "openvswitch/ofp-util.h"
@@ -37,6 +38,7 @@  struct ofp_bundle_entry {
     union {
         struct ofproto_flow_mod ofm;   /* ofm.fm.ofpacts must be malloced. */
         struct ofproto_port_mod opm;
+        struct ofproto_packet_out opo; /* opo.po.ofpacts must be malloced */
     };
 
     /* OpenFlow header and some of the message contents for error reporting. */
@@ -89,6 +91,9 @@  ofp_bundle_entry_free(struct ofp_bundle_entry *entry)
     if (entry) {
         if (entry->type == OFPTYPE_FLOW_MOD) {
             free(entry->ofm.fm.ofpacts);
+        } else if (entry->type == OFPTYPE_PACKET_OUT) {
+            dp_packet_delete(entry->opo.payload);
+            free(entry->opo.po.ofpacts);
         }
         free(entry);
     }
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index daa0077..c98f110 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1814,6 +1814,13 @@  struct ofproto_port_mod {
     struct ofport *port;                /* Affected port. */
 };
 
+/* packet_out with execution context. */
+struct ofproto_packet_out {
+    struct ofputil_packet_out po;
+    struct dp_packet *payload;
+    struct flow flow;
+};
+
 enum ofperr ofproto_flow_mod(struct ofproto *, struct ofproto_flow_mod *)
     OVS_EXCLUDED(ofproto_mutex);
 void ofproto_add_flow(struct ofproto *, const struct match *, int priority,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index ff6affd..c5a6097 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -6996,6 +6996,8 @@  do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
                  * effect. */
                 be->ofm.version = version;
                 error = ofproto_flow_mod_start(ofproto, &be->ofm);
+            } else if (be->type == OFPTYPE_PACKET_OUT) {
+                prev_is_port_mod = false;
             } else {
                 OVS_NOT_REACHED();
             }
@@ -7016,7 +7018,7 @@  do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
                 if (be->type == OFPTYPE_FLOW_MOD) {
                     ofproto_flow_mod_revert(ofproto, &be->ofm);
                 }
-                /* Nothing needs to be reverted for a port mod. */
+                /* Nothing needs to be reverted for a port mod or packet out. */
             }
         } else {
             /* 4. Finish. */
@@ -7042,6 +7044,18 @@  do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
                      * also from OVSDB changes asynchronously to all upcall
                      * processing. */
                     port_mod_finish(ofconn, &be->opm.pm, be->opm.port);
+                } else if (be->type == OFPTYPE_PACKET_OUT) {
+                    /* Try to send the packet. The bundle is committed
+                     * regardless of errors */
+                    error = ofproto->ofproto_class->packet_out(ofproto,
+                                                        be->opo.payload,
+                                                        &(be->opo.flow),
+                                                        be->opo.po.ofpacts,
+                                                        be->opo.po.ofpacts_len);
+                    if (error) {
+                        VLOG_INFO("Error sending packet out while committing a "
+                                  "bundle: %d", error);
+                    }
                 }
             }
         }
@@ -7150,6 +7164,58 @@  handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
             error = ofproto_check_ofpacts(ofproto, bmsg->ofm.fm.ofpacts,
                                           bmsg->ofm.fm.ofpacts_len);
         }
+    } else if (type == OFPTYPE_PACKET_OUT) {
+        uint64_t ofpacts_stub[1024 / 8];
+        struct ofpbuf ofpacts;
+
+        /* Decode message. */
+        ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+        error = ofputil_decode_packet_out(&(bmsg->opo.po), badd.msg, &ofpacts);
+        /* Same validation steps as in handle_packet_out  */
+        if (error) {
+            goto exit;
+        }
+
+        /* Move actions to heap. */
+        bmsg->opo.po.ofpacts = ofpbuf_steal_data(&ofpacts);
+
+        if (ofp_to_u16(bmsg->opo.po.in_port) >= ofproto->max_ports
+            && ofp_to_u16(bmsg->opo.po.in_port) < ofp_to_u16(OFPP_MAX)) {
+            error = OFPERR_OFPBRC_BAD_PORT;
+            goto exit;
+        }
+
+        /* Get payload. */
+        if (bmsg->opo.po.buffer_id != UINT32_MAX) {
+            error = ofconn_pktbuf_retrieve(ofconn, bmsg->opo.po.buffer_id,
+                                           &(bmsg->opo.payload), NULL);
+            if (error) {
+                goto exit;
+            }
+        } else {
+            /* Ensure that the L3 header is 32-bit aligned. */
+            bmsg->opo.payload = dp_packet_clone_data_with_headroom(
+                                                        bmsg->opo.po.packet,
+                                                        bmsg->opo.po.packet_len,
+                                                        2);
+        }
+
+        /* Verify actions against packet */
+        flow_extract(bmsg->opo.payload, &(bmsg->opo.flow));
+        bmsg->opo.flow.in_port.ofp_port = bmsg->opo.po.in_port;
+        /* Check actions like for flow mods. */
+        error = ofpacts_check_consistency(bmsg->opo.po.ofpacts,
+                                          bmsg->opo.po.ofpacts_len,
+                                          &(bmsg->opo.flow),
+                                          u16_to_ofp(ofproto->max_ports),
+                                          0, ofproto->n_tables,
+                                          ofconn_get_protocol(ofconn));
+        if (error) {
+            goto exit;
+        }
+
+        error = ofproto_check_ofpacts(ofproto, bmsg->opo.po.ofpacts,
+                                      bmsg->opo.po.ofpacts_len);
     } else {
         OVS_NOT_REACHED();
     }
@@ -7158,7 +7224,7 @@  handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
         error = ofp_bundle_add_message(ofconn, badd.bundle_id, badd.flags,
                                        bmsg);
     }
-
+exit:
     if (error) {
         ofp_bundle_entry_free(bmsg);
     }
-- 
2.5.0


From aedda156635261c896826b7751acfff7d99d83cb Mon Sep 17 00:00:00 2001
From: Andre Mantas <andremantas7@gmail.com>
Date: Sat, 16 Jul 2016 22:26:50 +0100
Subject: [PATCH 2/2] ofproto: ofp_packet_out messages in bundles

Added new helper function to refactor duplicated code used in 
handle_packet_out() and bundle_add() functions.

Tested with make check and external controller adding packet_out messages 
to a bundle with different destinations (hosts and controllers).

Signed-off-by: Andre Mantas <amantas@lasige.di.fc.ul.pt>
---
 lib/ofp-util.c    |   1 +
 ofproto/ofproto.c | 166 +++++++++++++++++++++++++-----------------------------
 2 files changed, 77 insertions(+), 90 deletions(-)

diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 5495771..a16239a 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -9863,6 +9863,7 @@  ofputil_is_bundlable(enum ofptype type)
         /* Minimum required by OpenFlow 1.4. */
     case OFPTYPE_PORT_MOD:
     case OFPTYPE_FLOW_MOD:
+        /* Optional */
     case OFPTYPE_PACKET_OUT:
         return true;
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 8fbfa6c..9c4f0cf 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -324,6 +324,14 @@  static void update_mtu(struct ofproto *, struct ofport *);
 static void update_mtu_ofproto(struct ofproto *);
 static void meter_delete(struct ofproto *, uint32_t first, uint32_t last);
 static void meter_insert_rule(struct rule *);
+static enum ofperr ofproto_extract_packet_out(struct ofproto *p,
+                                              struct ofconn *ofconn,
+                                              const struct ofp_header *oh,
+                                              uint64_t *ofpacts_stub,
+                                              struct ofpbuf *ofpacts,
+                                              struct ofputil_packet_out *po,
+                                              struct dp_packet **payload,
+                                              struct flow *flow);
 
 /* unixctl. */
 static void ofproto_unixctl_init(void);
@@ -3388,6 +3396,66 @@  reject_slave_controller(struct ofconn *ofconn)
     }
 }
 
+/**
+ * Extracts, validates and initializes all the required fields to send a
+ * PacketOut to the datapath. The caller must free ofpacts and payload.
+ *
+ * Used by handle_packet_out() and handle_bundle_add()
+ *
+ * Returns 0 if successful, otherwise an OpenFlow error. */
+static enum ofperr
+ofproto_extract_packet_out(struct ofproto *p, struct ofconn *ofconn,
+                           const struct ofp_header *oh,
+                           uint64_t *ofpacts_stub, struct ofpbuf *ofpacts,
+                           struct ofputil_packet_out *po,
+                           struct dp_packet **payload, struct flow *flow)
+{
+    enum ofperr error;
+
+    /* Decode message. */
+    ofpbuf_use_stub(ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+    error = ofputil_decode_packet_out(po, oh, ofpacts);
+    if (error) {
+        return error;
+    }
+    if (ofp_to_u16(po->in_port) >= p->max_ports
+        && ofp_to_u16(po->in_port) < ofp_to_u16(OFPP_MAX)) {
+        error = OFPERR_OFPBRC_BAD_PORT;
+    }
+
+    /* Get payload. */
+    if (po->buffer_id != UINT32_MAX) {
+        error = ofconn_pktbuf_retrieve(ofconn, po->buffer_id, payload, NULL);
+        if (error) {
+            goto exit;
+        }
+    } else {
+        /* Ensure that the L3 header is 32-bit aligned. */
+        *payload = dp_packet_clone_data_with_headroom(po->packet,
+                                                      po->packet_len, 2);
+    }
+
+    /* Verify actions against packet, then send packet if successful. */
+    flow_extract(*payload, flow);
+    flow->in_port.ofp_port = po->in_port;
+
+    /* Check actions like for flow mods.  We pass a 'table_id' of 0 to
+     * ofproto_check_consistency(), which isn't strictly correct because these
+     * actions aren't in any table.  This is OK as 'table_id' is only used to
+     * check instructions (e.g., goto-table), which can't appear on the action
+     * list of a packet-out. */
+    error = ofpacts_check_consistency(po->ofpacts, po->ofpacts_len,
+                                      flow, u16_to_ofp(p->max_ports),
+                                      0, p->n_tables,
+                                      ofconn_get_protocol(ofconn));
+    if (!error) {
+       error = ofproto_check_ofpacts(p, po->ofpacts, po->ofpacts_len);
+    }
+
+exit:
+    return error;
+}
+
 /* Checks that the 'ofpacts_len' bytes of action in 'ofpacts' are appropriate
  * for 'ofproto':
  *
@@ -3436,52 +3504,15 @@  handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
         goto exit;
     }
 
-    /* Decode message. */
-    ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
-    error = ofputil_decode_packet_out(&po, oh, &ofpacts);
-    if (error) {
-        goto exit_free_ofpacts;
-    }
-    if (ofp_to_u16(po.in_port) >= p->max_ports
-        && ofp_to_u16(po.in_port) < ofp_to_u16(OFPP_MAX)) {
-        error = OFPERR_OFPBRC_BAD_PORT;
-        goto exit_free_ofpacts;
-    }
-
-    /* Get payload. */
-    if (po.buffer_id != UINT32_MAX) {
-        error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
-        if (error) {
-            goto exit_free_ofpacts;
-        }
-    } else {
-        /* Ensure that the L3 header is 32-bit aligned. */
-        payload = dp_packet_clone_data_with_headroom(po.packet, po.packet_len, 2);
-    }
+    error = ofproto_extract_packet_out(p, ofconn, oh, ofpacts_stub, &ofpacts,
+                                       &po, &payload, &flow);
 
-    /* Verify actions against packet, then send packet if successful. */
-    flow_extract(payload, &flow);
-    flow.in_port.ofp_port = po.in_port;
-
-    /* Check actions like for flow mods.  We pass a 'table_id' of 0 to
-     * ofproto_check_consistency(), which isn't strictly correct because these
-     * actions aren't in any table.  This is OK as 'table_id' is only used to
-     * check instructions (e.g., goto-table), which can't appear on the action
-     * list of a packet-out. */
-    error = ofpacts_check_consistency(po.ofpacts, po.ofpacts_len,
-                                      &flow, u16_to_ofp(p->max_ports),
-                                      0, p->n_tables,
-                                      ofconn_get_protocol(ofconn));
     if (!error) {
-        error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len);
-        if (!error) {
-            error = p->ofproto_class->packet_out(p, payload, &flow,
-                                                 po.ofpacts, po.ofpacts_len);
-        }
+        error = p->ofproto_class->packet_out(p, payload, &flow,
+                                             po.ofpacts, po.ofpacts_len);
     }
     dp_packet_delete(payload);
 
-exit_free_ofpacts:
     ofpbuf_uninit(&ofpacts);
 exit:
     return error;
@@ -7255,54 +7286,9 @@  handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
         uint64_t ofpacts_stub[1024 / 8];
         struct ofpbuf ofpacts;
 
-        /* Decode message. */
-        ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
-        error = ofputil_decode_packet_out(&(bmsg->opo.po), badd.msg, &ofpacts);
-        /* Same validation steps as in handle_packet_out  */
-        if (error) {
-            goto exit;
-        }
-
-        /* Move actions to heap. */
-        bmsg->opo.po.ofpacts = ofpbuf_steal_data(&ofpacts);
-
-        if (ofp_to_u16(bmsg->opo.po.in_port) >= ofproto->max_ports
-            && ofp_to_u16(bmsg->opo.po.in_port) < ofp_to_u16(OFPP_MAX)) {
-            error = OFPERR_OFPBRC_BAD_PORT;
-            goto exit;
-        }
-
-        /* Get payload. */
-        if (bmsg->opo.po.buffer_id != UINT32_MAX) {
-            error = ofconn_pktbuf_retrieve(ofconn, bmsg->opo.po.buffer_id,
-                                           &(bmsg->opo.payload), NULL);
-            if (error) {
-                goto exit;
-            }
-        } else {
-            /* Ensure that the L3 header is 32-bit aligned. */
-            bmsg->opo.payload = dp_packet_clone_data_with_headroom(
-                                                        bmsg->opo.po.packet,
-                                                        bmsg->opo.po.packet_len,
-                                                        2);
-        }
-
-        /* Verify actions against packet */
-        flow_extract(bmsg->opo.payload, &(bmsg->opo.flow));
-        bmsg->opo.flow.in_port.ofp_port = bmsg->opo.po.in_port;
-        /* Check actions like for flow mods. */
-        error = ofpacts_check_consistency(bmsg->opo.po.ofpacts,
-                                          bmsg->opo.po.ofpacts_len,
-                                          &(bmsg->opo.flow),
-                                          u16_to_ofp(ofproto->max_ports),
-                                          0, ofproto->n_tables,
-                                          ofconn_get_protocol(ofconn));
-        if (error) {
-            goto exit;
-        }
-
-        error = ofproto_check_ofpacts(ofproto, bmsg->opo.po.ofpacts,
-                                      bmsg->opo.po.ofpacts_len);
+        ofproto_extract_packet_out(ofproto, ofconn, badd.msg, ofpacts_stub,
+                                   &ofpacts, &bmsg->opo.po,
+                                   &bmsg->opo.payload, &bmsg->opo.flow);
     } else {
         OVS_NOT_REACHED();
     }
@@ -7311,7 +7297,7 @@  handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
         error = ofp_bundle_add_message(ofconn, badd.bundle_id, badd.flags,
                                        bmsg);
     }
-exit:
+
     if (error) {
         ofp_bundle_entry_free(bmsg);
     }