unixctl: Make dpif/dump-flows fetch kernel flows.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index d6afc80..2544534 100644 (file)
@@ -450,9 +450,6 @@ struct dpif_backer {
      * performance in new situations.  */
     unsigned max_n_subfacet;         /* Maximum number of flows */
     unsigned avg_n_subfacet;         /* Average number of flows. */
-
-    /* Number of upcall handling threads. */
-    unsigned int n_handler_threads;
 };
 
 /* All existing ofproto_backer instances, indexed by ofproto->up.type. */
@@ -690,22 +687,15 @@ type_run(const char *type)
 
         error = dpif_recv_set(backer->dpif, backer->recv_set_enable);
         if (error) {
-            udpif_recv_set(backer->udpif, 0, false);
             VLOG_ERR("Failed to enable receiving packets in dpif.");
             return error;
         }
-        udpif_recv_set(backer->udpif, n_handler_threads,
-                       backer->recv_set_enable);
         dpif_flow_flush(backer->dpif);
         backer->need_revalidate = REV_RECONFIGURE;
     }
 
-    /* If the n_handler_threads is reconfigured, call udpif_recv_set()
-     * to reset the handler threads. */
-    if (backer->n_handler_threads != n_handler_threads) {
-        udpif_recv_set(backer->udpif, n_handler_threads,
-                       backer->recv_set_enable);
-        backer->n_handler_threads = n_handler_threads;
+    if (backer->recv_set_enable) {
+        udpif_set_threads(backer->udpif, n_handlers);
     }
 
     if (backer->need_revalidate) {
@@ -1171,9 +1161,10 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
         close_dpif_backer(backer);
         return error;
     }
-    udpif_recv_set(backer->udpif, n_handler_threads,
-                   backer->recv_set_enable);
-    backer->n_handler_threads = n_handler_threads;
+
+    if (backer->recv_set_enable) {
+        udpif_set_threads(backer->udpif, n_handlers);
+    }
 
     backer->max_n_subfacet = 0;
     backer->avg_n_subfacet = 0;
@@ -1286,7 +1277,7 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
                                   rulep)) {
         rule_dpif_unref(*rulep);
     } else {
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     return 0;
@@ -2505,7 +2496,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         break;
 
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
     if (!vlan_bitmap_equal(trunks, bundle->trunks)) {
         free(bundle->trunks);
@@ -5121,14 +5112,15 @@ trace_report(struct xlate_in *xin, const char *s, int recurse)
  *     - bridge br_flow [-generate | packet]
  *
  * On success, initializes '*ofprotop' and 'flow' and returns NULL.  On failure
- * returns a nonnull error message. */
-static const char *
+ * returns a nonnull malloced error message. */
+static char * WARN_UNUSED_RESULT
 parse_flow_and_packet(int argc, const char *argv[],
                       struct ofproto_dpif **ofprotop, struct flow *flow,
                       struct ofpbuf **packetp)
 {
     const struct dpif_backer *backer = NULL;
     const char *error = NULL;
+    char *m_err = NULL;
     struct simap port_names = SIMAP_INITIALIZER(&port_names);
     struct ofpbuf *packet;
     struct ofpbuf odp_key;
@@ -5149,6 +5141,7 @@ parse_flow_and_packet(int argc, const char *argv[],
             /* The 3-argument form must end in "-generate' or a hex string. */
             goto exit;
         }
+        error = NULL;
     }
 
     /* odp_flow can have its in_port specified as a name instead of port no.
@@ -5185,7 +5178,7 @@ parse_flow_and_packet(int argc, const char *argv[],
     /* Parse the flow and determine whether a datapath or
      * bridge is specified. If function odp_flow_key_from_string()
      * returns 0, the flow is a odp_flow. If function
-     * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
+     * parse_ofp_exact_flow() returns NULL, the flow is a br_flow. */
     if (!odp_flow_from_string(argv[argc - 1], &port_names,
                               &odp_key, &odp_mask)) {
         if (!backer) {
@@ -5198,20 +5191,25 @@ parse_flow_and_packet(int argc, const char *argv[],
             error = "Invalid datapath flow";
             goto exit;
         }
-    } else if (!parse_ofp_exact_flow(flow, NULL, argv[argc - 1], NULL)) {
-        if (argc != 3) {
-            error = "Must specify bridge name";
-            goto exit;
-        }
+    } else {
+        char *err = parse_ofp_exact_flow(flow, NULL, argv[argc - 1], NULL);
 
-        *ofprotop = ofproto_dpif_lookup(argv[1]);
-        if (!*ofprotop) {
-            error = "Unknown bridge name";
+        if (err) {
+            m_err = xasprintf("Bad flow syntax: %s", err);
+            free(err);
             goto exit;
+        } else {
+            if (argc != 3) {
+                error = "Must specify bridge name";
+                goto exit;
+            }
+
+            *ofprotop = ofproto_dpif_lookup(argv[1]);
+            if (!*ofprotop) {
+                error = "Unknown bridge name";
+                goto exit;
+            }
         }
-    } else {
-        error = "Bad flow syntax";
-        goto exit;
     }
 
     /* Generate a packet, if requested. */
@@ -5228,10 +5226,11 @@ parse_flow_and_packet(int argc, const char *argv[],
         }
     }
 
-    error = NULL;
-
 exit:
-    if (error) {
+    if (error && !m_err) {
+        m_err = xstrdup(error);
+    }
+    if (m_err) {
         ofpbuf_delete(packet);
         packet = NULL;
     }
@@ -5239,7 +5238,7 @@ exit:
     ofpbuf_uninit(&odp_key);
     ofpbuf_uninit(&odp_mask);
     simap_destroy(&port_names);
-    return error;
+    return m_err;
 }
 
 static void
@@ -5248,7 +5247,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
 {
     struct ofproto_dpif *ofproto;
     struct ofpbuf *packet;
-    const char *error;
+    char *error;
     struct flow flow;
 
     error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
@@ -5262,6 +5261,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
         ofpbuf_delete(packet);
     } else {
         unixctl_command_reply_error(conn, error);
+        free(error);
     }
 }
 
@@ -5280,18 +5280,17 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
 
     /* Three kinds of error return values! */
     enum ofperr retval;
-    const char *error;
-    char *rw_error;
+    char *error;
 
     packet = NULL;
     ds_init(&result);
     ofpbuf_init(&ofpacts, 0);
 
     /* Parse actions. */
-    rw_error = parse_ofpacts(argv[--argc], &ofpacts, &usable_protocols);
-    if (rw_error) {
-        unixctl_command_reply_error(conn, rw_error);
-        free(rw_error);
+    error = parse_ofpacts(argv[--argc], &ofpacts, &usable_protocols);
+    if (error) {
+        unixctl_command_reply_error(conn, error);
+        free(error);
         goto exit;
     }
 
@@ -5309,6 +5308,7 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
     error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
     if (error) {
         unixctl_command_reply_error(conn, error);
+        free(error);
         goto exit;
     }
 
@@ -5744,14 +5744,34 @@ ofproto_unixctl_dpif_enable_megaflows(struct unixctl_conn *conn,
     unixctl_command_reply(conn, "megaflows enabled");
 }
 
+static bool
+ofproto_dpif_contains_flow(const struct ofproto_dpif *ofproto,
+                           const struct nlattr *key, size_t key_len)
+{
+    enum odp_key_fitness fitness;
+    struct ofproto_dpif *ofp;
+    struct flow flow;
+
+    xlate_receive(ofproto->backer, NULL, key, key_len, &flow, &fitness, &ofp,
+                  NULL, NULL, NULL, NULL);
+    return ofp == ofproto;
+}
+
 static void
 ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
                                 int argc OVS_UNUSED, const char *argv[],
                                 void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
+    const struct dpif_flow_stats *stats;
     const struct ofproto_dpif *ofproto;
-    struct subfacet *subfacet;
+    struct dpif_flow_dump flow_dump;
+    const struct nlattr *actions;
+    const struct nlattr *mask;
+    const struct nlattr *key;
+    size_t actions_len;
+    size_t mask_len;
+    size_t key_len;
 
     ofproto = ofproto_dpif_lookup(argv[1]);
     if (!ofproto) {
@@ -5759,57 +5779,29 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
         return;
     }
 
-    update_stats(ofproto->backer);
-
-    HMAP_FOR_EACH (subfacet, hmap_node, &ofproto->backer->subfacets) {
-        struct facet *facet = subfacet->facet;
-        struct odputil_keybuf maskbuf;
-        struct ofpbuf mask;
-
-        if (facet->ofproto != ofproto) {
+    ds_init(&ds);
+    dpif_flow_dump_start(&flow_dump, ofproto->backer->dpif);
+    while (dpif_flow_dump_next(&flow_dump, &key, &key_len, &mask, &mask_len,
+                               &actions, &actions_len, &stats)) {
+        if (!ofproto_dpif_contains_flow(ofproto, key, key_len)) {
             continue;
         }
 
-        ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf);
-        if (enable_megaflows) {
-            odp_flow_key_from_mask(&mask, &facet->xout.wc.masks,
-                                   &facet->flow, UINT32_MAX);
-        }
-
-        odp_flow_format(subfacet->key, subfacet->key_len,
-                        mask.data, mask.size, NULL, &ds, false);
-
-        ds_put_format(&ds, ", packets:%"PRIu64", bytes:%"PRIu64", used:",
-                      subfacet->dp_packet_count, subfacet->dp_byte_count);
-        if (subfacet->used) {
-            ds_put_format(&ds, "%.3fs",
-                          (time_msec() - subfacet->used) / 1000.0);
-        } else {
-            ds_put_format(&ds, "never");
-        }
-        if (subfacet->facet->tcp_flags) {
-            ds_put_cstr(&ds, ", flags:");
-            packet_format_tcp_flags(&ds, subfacet->facet->tcp_flags);
-        }
-
+        odp_flow_format(key, key_len, mask, mask_len, NULL, &ds, false);
+        ds_put_cstr(&ds, ", ");
+        dpif_flow_stats_format(stats, &ds);
         ds_put_cstr(&ds, ", actions:");
-        if (facet->xout.slow) {
-            uint64_t slow_path_stub[128 / 8];
-            const struct nlattr *actions;
-            size_t actions_len;
-
-            compose_slow_path(ofproto, &facet->flow, facet->xout.slow,
-                              slow_path_stub, sizeof slow_path_stub,
-                              &actions, &actions_len);
-            format_odp_actions(&ds, actions, actions_len);
-        } else {
-            format_odp_actions(&ds, facet->xout.odp_actions.data,
-                               facet->xout.odp_actions.size);
-        }
+        format_odp_actions(&ds, actions, actions_len);
         ds_put_char(&ds, '\n');
     }
 
-    unixctl_command_reply(conn, ds_cstr(&ds));
+    if (dpif_flow_dump_done(&flow_dump)) {
+        ds_clear(&ds);
+        ds_put_format(&ds, "dpif/dump_flows failed: %s", ovs_strerror(errno));
+        unixctl_command_reply_error(conn, ds_cstr(&ds));
+    } else {
+        unixctl_command_reply(conn, ds_cstr(&ds));
+    }
     ds_destroy(&ds);
 }