ofproto/trace: Use final flow to compute "Relevant fields".
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index 52759b5..03f7840 100644 (file)
@@ -251,6 +251,11 @@ struct dpif_backer {
     enum revalidate_reason need_revalidate; /* Revalidate all flows. */
 
     bool recv_set_enable; /* Enables or disables receiving packets. */
+
+    /* True if the datapath supports variable-length
+     * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
+     * False if the datapath supports only 8-byte (or shorter) userdata. */
+    bool variable_length_userdata;
 };
 
 /* All existing ofproto_backer instances, indexed by ofproto->up.type. */
@@ -552,7 +557,8 @@ type_run(const char *type)
                               ofproto->sflow, ofproto->ipfix,
                               ofproto->netflow, ofproto->up.frag_handling,
                               ofproto->up.forward_bpdu,
-                              connmgr_has_in_band(ofproto->up.connmgr));
+                              connmgr_has_in_band(ofproto->up.connmgr),
+                              ofproto->backer->variable_length_userdata);
 
             HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) {
                 xlate_bundle_set(ofproto, bundle, bundle->name,
@@ -774,6 +780,8 @@ struct odp_garbage {
     odp_port_t odp_port;
 };
 
+static bool check_variable_length_userdata(struct dpif_backer *backer);
+
 static int
 open_dpif_backer(const char *type, struct dpif_backer **backerp)
 {
@@ -872,6 +880,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
         close_dpif_backer(backer);
         return error;
     }
+    backer->variable_length_userdata = check_variable_length_userdata(backer);
 
     if (backer->recv_set_enable) {
         udpif_set_threads(backer->udpif, n_handlers, n_revalidators);
@@ -880,6 +889,82 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     return error;
 }
 
+/* Tests whether 'backer''s datapath supports variable-length
+ * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.  We need
+ * to disable some features on older datapaths that don't support this
+ * feature.
+ *
+ * Returns false if 'backer' definitely does not support variable-length
+ * userdata, true if it seems to support them or if at least the error we get
+ * is ambiguous. */
+static bool
+check_variable_length_userdata(struct dpif_backer *backer)
+{
+    struct eth_header *eth;
+    struct ofpbuf actions;
+    struct dpif_execute execute;
+    struct ofpbuf packet;
+    size_t start;
+    int error;
+
+    /* Compose a userspace action that will cause an ERANGE error on older
+     * datapaths that don't support variable-length userdata.
+     *
+     * We really test for using userdata longer than 8 bytes, but older
+     * datapaths accepted these, silently truncating the userdata to 8 bytes.
+     * The same older datapaths rejected userdata shorter than 8 bytes, so we
+     * test for that instead as a proxy for longer userdata support. */
+    ofpbuf_init(&actions, 64);
+    start = nl_msg_start_nested(&actions, OVS_ACTION_ATTR_USERSPACE);
+    nl_msg_put_u32(&actions, OVS_USERSPACE_ATTR_PID,
+                   dpif_port_get_pid(backer->dpif, ODPP_NONE));
+    nl_msg_put_unspec_zero(&actions, OVS_USERSPACE_ATTR_USERDATA, 4);
+    nl_msg_end_nested(&actions, start);
+
+    /* Compose a dummy ethernet packet. */
+    ofpbuf_init(&packet, ETH_HEADER_LEN);
+    eth = ofpbuf_put_zeros(&packet, ETH_HEADER_LEN);
+    eth->eth_type = htons(0x1234);
+
+    /* Execute the actions.  On older datapaths this fails with ERANGE, on
+     * newer datapaths it succeeds. */
+    execute.actions = actions.data;
+    execute.actions_len = actions.size;
+    execute.packet = &packet;
+    execute.md = PKT_METADATA_INITIALIZER(0);
+    execute.needs_help = false;
+
+    error = dpif_execute(backer->dpif, &execute);
+
+    ofpbuf_uninit(&packet);
+    ofpbuf_uninit(&actions);
+
+    switch (error) {
+    case 0:
+        /* Variable-length userdata is supported.
+         *
+         * Purge received packets to avoid processing the nonsense packet we
+         * sent to userspace, then report success. */
+        dpif_recv_purge(backer->dpif);
+        return true;
+
+    case ERANGE:
+        /* Variable-length userdata is not supported. */
+        VLOG_WARN("%s: datapath does not support variable-length userdata "
+                  "feature (needs Linux 3.10+ or kernel module from OVS "
+                  "1..11+).  The NXAST_SAMPLE action will be ignored.",
+                  dpif_name(backer->dpif));
+        return false;
+
+    default:
+        /* Something odd happened.  We're not sure whether variable-length
+         * userdata is supported.  Default to "yes". */
+        VLOG_WARN("%s: variable-length userdata feature probe failed (%s)",
+                  dpif_name(backer->dpif), ovs_strerror(error));
+        return true;
+    }
+}
+
 static int
 construct(struct ofproto *ofproto_)
 {
@@ -2800,12 +2885,11 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
                              const struct ofpact *ofpacts, size_t ofpacts_len,
                              struct ofpbuf *packet)
 {
-    struct odputil_keybuf keybuf;
     struct dpif_flow_stats stats;
     struct xlate_out xout;
     struct xlate_in xin;
     ofp_port_t in_port;
-    struct ofpbuf key;
+    struct dpif_execute execute;
     int error;
 
     ovs_assert((rule != NULL) != (ofpacts != NULL));
@@ -2821,16 +2905,21 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
     xin.resubmit_stats = &stats;
     xlate_actions(&xin, &xout);
 
-    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
     in_port = flow->in_port.ofp_port;
     if (in_port == OFPP_NONE) {
         in_port = OFPP_LOCAL;
     }
-    odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(ofproto, in_port));
+    execute.actions = xout.odp_actions.data;
+    execute.actions_len = xout.odp_actions.size;
+    execute.packet = packet;
+    execute.md.tunnel = flow->tunnel;
+    execute.md.skb_priority = flow->skb_priority;
+    execute.md.pkt_mark = flow->pkt_mark;
+    execute.md.in_port = ofp_port_to_odp_port(ofproto, in_port);
+    execute.needs_help = (xout.slow & SLOW_ACTION) != 0;
+
+    error = dpif_execute(ofproto->backer->dpif, &execute);
 
-    error = dpif_execute(ofproto->backer->dpif, key.data, key.size,
-                         xout.odp_actions.data, xout.odp_actions.size, packet,
-                         (xout.slow & SLOW_ACTION) != 0);
     xlate_out_uninit(&xout);
 
     return error;
@@ -3781,7 +3870,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         ds_put_char(ds, '\n');
         trace_format_flow(ds, 0, "Final flow", &trace);
 
-        match_init(&match, flow, &trace.xout.wc);
+        match_init(&match, &trace.flow, &trace.xout.wc);
         ds_put_cstr(ds, "Relevant fields: ");
         match_format(&match, ds, OFP_DEFAULT_PRIORITY);
         ds_put_char(ds, '\n');