For some time, it's been a goal to set up a kernel flow in all of
the cases where we can.  One place where OVS currently falls short
is in flows that miss in the OpenFlow table.  All of these packets
currently go to userspace.

This commit takes one step toward setting up kernel flows for these
cases by making it possible to distinguish them from packets sent
to userspace by "output to OFPP_CONTROLLER" actions.

Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 lib/odp-util.c         |   20 ++++++++++++--
 lib/odp-util.h         |    1 +
 ofproto/ofproto-dpif.c |   66 +++++++++++++++++++----------------------------
 3 files changed, 45 insertions(+), 42 deletions(-)

diff --git a/lib/odp-util.c b/lib/odp-util.c
index 6fafe79..b840c50 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -190,7 +190,12 @@ format_odp_userspace_action(struct ds *ds, const struct 
nlattr *attr)
         memcpy(&cookie, &userdata, sizeof cookie);
 
         if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) {
-            ds_put_format(ds, ",controller,length=%"PRIu16,
+            enum ofp_packet_in_reason reason = cookie.controller.reason;
+
+            ds_put_format(ds, ",controller,%s,length=%"PRIu16,
+                          (reason == OFPR_NO_MATCH ? "no_match"
+                           : reason == OFPR_ACTION ? "action"
+                           : "<unknown>"),
                           cookie.controller.max_len);
         } else if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
             ds_put_format(ds, ",sFlow,n_output=%"PRIu8","
@@ -334,6 +339,7 @@ parse_odp_action(const char *s, const struct shash 
*port_names,
         unsigned long long int length;
         unsigned long long int ifindex;
         char userdata_s[32];
+        char reason_s[9];
         int n_output;
         int vid, pcp;
         int n = -1;
@@ -341,12 +347,20 @@ parse_odp_action(const char *s, const struct shash 
*port_names,
         if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
             odp_put_userspace_action(pid, NULL, actions);
             return n;
-        } else if (sscanf(s, "userspace(pid=%lli,controller,length=%lli)%n",
-                          &pid, &length, &n) > 0 && n > 0) {
+        } else if (sscanf(s, "userspace(pid=%lli,controller,%8[a-z_],"
+                          "length=%lli)%n",
+                          &pid, reason_s, &length, &n) > 0 && n > 0) {
             union user_action_cookie cookie;
 
             memset(&cookie, 0, sizeof cookie);
             cookie.controller.type = USER_ACTION_COOKIE_CONTROLLER;
+            if (!strcmp(reason_s, "no_match")) {
+                cookie.controller.reason = OFPR_NO_MATCH;
+            } else if (!strcmp(reason_s, "action")) {
+                cookie.controller.reason = OFPR_ACTION;
+            } else {
+                return -EINVAL;
+            }
             cookie.controller.max_len = length;
             odp_put_userspace_action(pid, &cookie, actions);
             return n;
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 245e292..168c233 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -135,6 +135,7 @@ union user_action_cookie {
 
     struct {
         uint8_t type;           /* USER_ACTION_COOKIE_CONTROLLER. */
+        uint8_t reason;         /* OFPR_NO_MATCH or OFPR_ACTION. */
         uint16_t max_len;       /* Maximum number of bytes to send. */
     } controller;
 };
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 2bd76a6..e725f28 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -2362,50 +2362,35 @@ struct flow_miss_op {
     struct subfacet *subfacet;
 };
 
-/* Sends an OFPT_PACKET_IN message for 'packet' of type OFPR_NO_MATCH to each
- * OpenFlow controller as necessary according to their individual
- * configurations.
+/* Sends an OFPT_PACKET_IN message for 'packet' to each OpenFlow controller as
+ * necessary according to their individual configurations.
+ *
+ * If 'cookie' is nonnull, then the OFPT_PACKET_IN 'reason' code is taken from
+ * cookie->reason.  If cookie->reason is OFPR_ACTION, then the maximum number
+ * of bytes to send is taken from cookie->max_len.  If cookie is NULL, the
+ * 'reason' is assumed to be OFPR_NO_MATCH.
  *
  * If 'clone' is true, the caller retains ownership of 'packet'.  Otherwise,
  * ownership is transferred to this function. */
 static void
-send_packet_in_miss(struct ofproto_dpif *ofproto, struct ofpbuf *packet,
-                    const struct flow *flow, bool clone)
-{
-    struct ofputil_packet_in pin;
-
-    pin.packet = packet;
-    pin.in_port = flow->in_port;
-    pin.reason = OFPR_NO_MATCH;
-    pin.buffer_id = 0;          /* not yet known */
-    pin.send_len = 0;           /* not used for flow table misses */
-    connmgr_send_packet_in(ofproto->up.connmgr, &pin, flow,
-                           clone ? NULL : packet);
-}
-
-/* Sends an OFPT_PACKET_IN message for 'packet' of type OFPR_ACTION to each
- * OpenFlow controller as necessary according to their individual
- * configurations.
- *
- * 'send_len' should be the number of bytes of 'packet' to send to the
- * controller, as specified in the action that caused the packet to be sent.
- *
- * If 'clone' is true, the caller retains ownership of 'upcall->packet'.
- * Otherwise, ownership is transferred to this function. */
-static void
-send_packet_in_action(struct ofproto_dpif *ofproto, struct ofpbuf *packet,
-                      uint64_t userdata, const struct flow *flow, bool clone)
+send_packet_in(struct ofproto_dpif *ofproto, struct ofpbuf *packet,
+               const union user_action_cookie *cookie,
+               const struct flow *flow, bool clone)
 {
     struct ofputil_packet_in pin;
-    union user_action_cookie cookie;
-
-    memcpy(&cookie, &userdata, sizeof(cookie));
 
     pin.packet = packet;
     pin.in_port = flow->in_port;
-    pin.reason = OFPR_ACTION;
+    pin.reason = (cookie && cookie->controller.reason == OFPR_ACTION
+                  ? OFPR_ACTION : OFPR_NO_MATCH);
     pin.buffer_id = 0;          /* not yet known */
-    pin.send_len = cookie.controller.max_len;
+    if (cookie && cookie->controller.reason == OFPR_ACTION) {
+        pin.reason = OFPR_ACTION;
+        pin.send_len = cookie->controller.max_len;
+    } else {
+        pin.reason = OFPR_NO_MATCH;
+        pin.send_len = 0;       /* not used for flow table misses */
+    }
     connmgr_send_packet_in(ofproto->up.connmgr, &pin, flow,
                            clone ? NULL : packet);
 }
@@ -2527,7 +2512,7 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct 
flow_miss *miss,
              *
              * See the top-level comment in fail-open.c for more information.
              */
-            send_packet_in_miss(ofproto, packet, flow, true);
+            send_packet_in(ofproto, packet, NULL, flow, true);
         }
 
         if (!facet->may_install || !subfacet->actions) {
@@ -2729,8 +2714,7 @@ handle_userspace_upcall(struct ofproto_dpif *ofproto,
         ofpbuf_delete(upcall->packet);
     } else if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) {
         COVERAGE_INC(ofproto_dpif_ctlr_action);
-        send_packet_in_action(ofproto, upcall->packet, upcall->userdata,
-                              &flow, false);
+        send_packet_in(ofproto, upcall->packet, &cookie, &flow, false);
     } else {
         VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata);
         ofpbuf_delete(upcall->packet);
@@ -3089,11 +3073,14 @@ execute_controller_action(struct ofproto_dpif *ofproto,
          * This optimization will not accidentally catch sFlow
          * OVS_ACTION_ATTR_USERSPACE actions, since those are encapsulated
          * inside OVS_ACTION_ATTR_SAMPLE. */
+        union user_action_cookie cookie;
+        uint64_t cookie_u64;
         const struct nlattr *nla;
 
         nla = nl_attr_find_nested(odp_actions, OVS_USERSPACE_ATTR_USERDATA);
-        send_packet_in_action(ofproto, packet, nl_attr_get_u64(nla), flow,
-                              clone);
+        cookie_u64 = nl_attr_get_u64(nla);
+        memcpy(&cookie, &cookie_u64, sizeof cookie);
+        send_packet_in(ofproto, packet, &cookie, flow, clone);
         return true;
     } else {
         return false;
@@ -4252,6 +4239,7 @@ compose_controller_action(struct action_xlate_ctx *ctx, 
int len)
 
     memset(&cookie, 0, sizeof cookie);
     cookie.controller.type = USER_ACTION_COOKIE_CONTROLLER;
+    cookie.controller.reason = OFPR_ACTION;
     cookie.controller.max_len = len;
     put_userspace_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, &cookie);
 }
-- 
1.7.2.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to