rhel: Fix build failures because of libraries in /usr/lib.
[sliver-openvswitch.git] / ofproto / ofproto-dpif-upcall.c
index ca39f1f..f0088f0 100644 (file)
 
 #include "connmgr.h"
 #include "coverage.h"
-#include "dynamic-string.h"
 #include "dpif.h"
+#include "dynamic-string.h"
 #include "fail-open.h"
 #include "guarded-list.h"
 #include "latch.h"
-#include "seq.h"
 #include "list.h"
 #include "netlink.h"
 #include "ofpbuf.h"
@@ -34,6 +33,8 @@
 #include "ofproto-dpif-sflow.h"
 #include "packets.h"
 #include "poll-loop.h"
+#include "seq.h"
+#include "unixctl.h"
 #include "vlog.h"
 
 #define MAX_QUEUE_LENGTH 512
@@ -51,6 +52,7 @@ COVERAGE_DEFINE(fmb_queue_revalidated);
 struct handler {
     struct udpif *udpif;               /* Parent udpif. */
     pthread_t thread;                  /* Thread ID. */
+    char *name;                        /* Thread name. */
 
     struct ovs_mutex mutex;            /* Mutex guarding the following. */
 
@@ -72,6 +74,8 @@ struct handler {
  * "handler" threads (see struct handler).  Other upcalls are queued to the
  * main ofproto_dpif. */
 struct udpif {
+    struct list list_node;             /* In all_udpifs list. */
+
     struct dpif *dpif;                 /* Datapath handle. */
     struct dpif_backer *backer;        /* Opaque dpif_backer pointer. */
 
@@ -113,18 +117,28 @@ struct upcall {
 static void upcall_destroy(struct upcall *);
 
 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+static struct list all_udpifs = LIST_INITIALIZER(&all_udpifs);
 
 static void recv_upcalls(struct udpif *);
 static void handle_upcalls(struct udpif *, struct list *upcalls);
 static void miss_destroy(struct flow_miss *);
 static void *udpif_dispatcher(void *);
 static void *udpif_upcall_handler(void *);
+static void upcall_unixctl_show(struct unixctl_conn *conn, int argc,
+                                const char *argv[], void *aux);
 
 struct udpif *
 udpif_create(struct dpif_backer *backer, struct dpif *dpif)
 {
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     struct udpif *udpif = xzalloc(sizeof *udpif);
 
+    if (ovsthread_once_start(&once)) {
+        unixctl_command_register("upcall/show", "", 0, 0, upcall_unixctl_show,
+                                 NULL);
+        ovsthread_once_done(&once);
+    }
+
     udpif->dpif = dpif;
     udpif->backer = backer;
     udpif->secret = random_uint32();
@@ -133,6 +147,7 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif)
     latch_init(&udpif->exit_latch);
     guarded_list_init(&udpif->drop_keys);
     guarded_list_init(&udpif->fmbs);
+    list_push_back(&all_udpifs, &udpif->list_node);
 
     return udpif;
 }
@@ -143,7 +158,8 @@ udpif_destroy(struct udpif *udpif)
     struct flow_miss_batch *fmb;
     struct drop_key *drop_key;
 
-    udpif_recv_set(udpif, 0, false);
+    udpif_set_threads(udpif, 0);
+    list_remove(&udpif->list_node);
 
     while ((drop_key = drop_key_next(udpif))) {
         drop_key_destroy(drop_key);
@@ -161,15 +177,12 @@ udpif_destroy(struct udpif *udpif)
     free(udpif);
 }
 
-/* Tells 'udpif' to begin or stop handling flow misses depending on the value
- * of 'enable'.  'n_handlers' is the number of upcall_handler threads to
- * create.  Passing 'n_handlers' as zero is equivalent to passing 'enable' as
- * false. */
+/* Tells 'udpif' how many threads it should use to handle upcalls.  Disables
+ * all threads if 'n_handlers' is zero.  'udpif''s datapath handle must have
+ * packet reception enabled before starting threads. */
 void
-udpif_recv_set(struct udpif *udpif, size_t n_handlers, bool enable)
+udpif_set_threads(struct udpif *udpif, size_t n_handlers)
 {
-    n_handlers = enable ? n_handlers : 0;
-
     /* Stop the old threads (if any). */
     if (udpif->handlers && udpif->n_handlers != n_handlers) {
         size_t i;
@@ -201,6 +214,7 @@ udpif_recv_set(struct udpif *udpif, size_t n_handlers, bool enable)
             ovs_mutex_destroy(&handler->mutex);
 
             xpthread_cond_destroy(&handler->wake_cond);
+            free(handler->name);
         }
         latch_poll(&udpif->exit_latch);
 
@@ -287,6 +301,7 @@ static void
 upcall_destroy(struct upcall *upcall)
 {
     if (upcall) {
+        ofpbuf_uninit(&upcall->dpif_upcall.packet);
         ofpbuf_uninit(&upcall->upcall_buf);
         free(upcall);
     }
@@ -404,7 +419,9 @@ udpif_upcall_handler(void *arg)
 {
     struct handler *handler = arg;
 
-    set_subprogram_name("upcall_%u", ovsthread_id_self());
+    handler->name = xasprintf("handler_%u", ovsthread_id_self());
+    set_subprogram_name("%s", handler->name);
+
     for (;;) {
         struct list misses = LIST_INITIALIZER(&misses);
         size_t i;
@@ -516,7 +533,10 @@ recv_upcalls(struct udpif *udpif)
         error = dpif_recv(udpif->dpif, &upcall->dpif_upcall,
                           &upcall->upcall_buf);
         if (error) {
-            upcall_destroy(upcall);
+            /* upcall_destroy() can only be called on successfully received
+             * upcalls. */
+            ofpbuf_uninit(&upcall->upcall_buf);
+            free(upcall);
             break;
         }
 
@@ -634,7 +654,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
     n_misses = 0;
     LIST_FOR_EACH_SAFE (upcall, next, list_node, upcalls) {
         struct dpif_upcall *dupcall = &upcall->dpif_upcall;
-        struct ofpbuf *packet = dupcall->packet;
+        struct ofpbuf *packet = &dupcall->packet;
         struct flow_miss *miss = &fmb->miss_buf[n_misses];
         struct flow_miss *existing_miss;
         struct ofproto_dpif *ofproto;
@@ -719,13 +739,13 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
                 memset(&cookie, 0, sizeof cookie);
                 memcpy(&cookie, nl_attr_get(dupcall->userdata),
                        sizeof cookie.sflow);
-                dpif_sflow_received(sflow, dupcall->packet, &flow, odp_in_port,
+                dpif_sflow_received(sflow, packet, &flow, odp_in_port,
                                     &cookie);
             }
             break;
         case IPFIX_UPCALL:
             if (ipfix) {
-                dpif_ipfix_bridge_sample(ipfix, dupcall->packet, &flow);
+                dpif_ipfix_bridge_sample(ipfix, packet, &flow);
             }
             break;
         case FLOW_SAMPLE_UPCALL:
@@ -738,7 +758,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
 
                 /* The flow reflects exactly the contents of the packet.
                  * Sample the packet using it. */
-                dpif_ipfix_flow_sample(ipfix, dupcall->packet, &flow,
+                dpif_ipfix_flow_sample(ipfix, packet, &flow,
                                        cookie.flow_sample.collector_set_id,
                                        cookie.flow_sample.probability,
                                        cookie.flow_sample.obs_domain_id,
@@ -748,7 +768,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
         case BAD_UPCALL:
             break;
         case MISS_UPCALL:
-            NOT_REACHED();
+            OVS_NOT_REACHED();
         }
 
         dpif_ipfix_unref(ipfix);
@@ -792,7 +812,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
     n_ops = 0;
     LIST_FOR_EACH (upcall, list_node, upcalls) {
         struct flow_miss *miss = upcall->flow_miss;
-        struct ofpbuf *packet = upcall->dpif_upcall.packet;
+        struct ofpbuf *packet = &upcall->dpif_upcall.packet;
 
         if (miss->xout.slow) {
             struct xlate_in xin;
@@ -828,23 +848,19 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
         }
     }
 
-    /* Execute batch. */
-    for (i = 0; i < n_ops; i++) {
-        opsp[i] = &ops[i];
-    }
-    dpif_operate(udpif->dpif, opsp, n_ops);
-
     /* Special case for fail-open mode.
      *
      * If we are in fail-open mode, but we are connected to a controller too,
      * then we should send the packet up to the controller in the hope that it
      * will try to set up a flow and thereby allow us to exit fail-open.
      *
-     * See the top-level comment in fail-open.c for more information. */
+     * See the top-level comment in fail-open.c for more information.
+     *
+     * Copy packets before they are modified by execution. */
     if (fail_open) {
         LIST_FOR_EACH (upcall, list_node, upcalls) {
             struct flow_miss *miss = upcall->flow_miss;
-            struct ofpbuf *packet = upcall->dpif_upcall.packet;
+            struct ofpbuf *packet = &upcall->dpif_upcall.packet;
             struct ofproto_packet_in *pin;
 
             pin = xmalloc(sizeof *pin);
@@ -860,6 +876,12 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
         }
     }
 
+    /* Execute batch. */
+    for (i = 0; i < n_ops; i++) {
+        opsp[i] = &ops[i];
+    }
+    dpif_operate(udpif->dpif, opsp, n_ops);
+
     list_move(&fmb->upcalls, upcalls);
 
     if (fmb->reval_seq != seq_read(udpif->reval_seq)) {
@@ -873,3 +895,28 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
         seq_change(udpif->wait_seq);
     }
 }
+\f
+static void
+upcall_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                    const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    struct udpif *udpif;
+
+    LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
+        size_t i;
+
+        ds_put_format(&ds, "%s:\n", dpif_name(udpif->dpif));
+        for (i = 0; i < udpif->n_handlers; i++) {
+            struct handler *handler = &udpif->handlers[i];
+
+            ovs_mutex_lock(&handler->mutex);
+            ds_put_format(&ds, "\t%s: (upcall queue %"PRIuSIZE")\n",
+                          handler->name, handler->n_upcalls);
+            ovs_mutex_unlock(&handler->mutex);
+        }
+    }
+
+    unixctl_command_reply(conn, ds_cstr(&ds));
+    ds_destroy(&ds);
+}