ofproto-dpif: Hide struct rule_dpif internally.
[cascardo/ovs.git] / ofproto / ofproto-dpif-upcall.c
index 54d3c21..54f441b 100644 (file)
@@ -55,6 +55,8 @@ struct handler {
     struct list upcalls OVS_GUARDED;
     size_t n_upcalls OVS_GUARDED;
 
+    size_t n_new_upcalls;              /* Only changed by the dispatcher. */
+
     pthread_cond_t wake_cond;          /* Wakes 'thread' while holding
                                           'mutex'. */
 };
@@ -123,6 +125,9 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif)
     list_init(&udpif->upcalls);
     list_init(&udpif->fmbs);
     atomic_init(&udpif->reval_seq, 0);
+    ovs_mutex_init(&udpif->drop_key_mutex);
+    ovs_mutex_init(&udpif->upcall_mutex);
+    ovs_mutex_init(&udpif->fmb_mutex);
 
     return udpif;
 }
@@ -216,7 +221,7 @@ udpif_recv_set(struct udpif *udpif, size_t n_handlers, bool enable)
             handler->udpif = udpif;
             list_init(&handler->upcalls);
             xpthread_cond_init(&handler->wake_cond, NULL);
-            ovs_mutex_init(&handler->mutex, PTHREAD_MUTEX_NORMAL);
+            ovs_mutex_init(&handler->mutex);
             xpthread_create(&handler->thread, NULL, udpif_miss_handler, handler);
         }
         xpthread_create(&udpif->dispatcher, NULL, udpif_dispatcher, udpif);
@@ -342,6 +347,37 @@ flow_miss_batch_destroy(struct flow_miss_batch *fmb)
     free(fmb);
 }
 
+/* Discards any flow miss batches queued up in 'udpif' for 'ofproto' (because
+ * 'ofproto' is being destroyed).
+ *
+ * 'ofproto''s xports must already have been removed, otherwise new flow miss
+ * batches could still end up getting queued. */
+void
+flow_miss_batch_ofproto_destroyed(struct udpif *udpif,
+                                  const struct ofproto_dpif *ofproto)
+{
+    struct flow_miss_batch *fmb, *next_fmb;
+
+    ovs_mutex_lock(&udpif->fmb_mutex);
+    LIST_FOR_EACH_SAFE (fmb, next_fmb, list_node, &udpif->fmbs) {
+        struct flow_miss *miss, *next_miss;
+
+        HMAP_FOR_EACH_SAFE (miss, next_miss, hmap_node, &fmb->misses) {
+            if (miss->ofproto == ofproto) {
+                hmap_remove(&fmb->misses, &miss->hmap_node);
+                miss_destroy(miss);
+            }
+        }
+
+        if (hmap_is_empty(&fmb->misses)) {
+            list_remove(&fmb->list_node);
+            flow_miss_batch_destroy(fmb);
+            udpif->n_fmbs--;
+        }
+    }
+    ovs_mutex_unlock(&udpif->fmb_mutex);
+}
+
 /* Retreives the next drop key which ofproto-dpif needs to process.  The caller
  * is responsible for destroying it with drop_key_destroy(). */
 struct drop_key *
@@ -512,6 +548,10 @@ static void
 recv_upcalls(struct udpif *udpif)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
+    size_t n_udpif_new_upcalls = 0;
+    struct handler *handler;
+    int n;
+
     for (;;) {
         struct upcall *upcall;
         int error;
@@ -532,7 +572,6 @@ recv_upcalls(struct udpif *udpif)
         } else if (upcall->type == MISS_UPCALL) {
             struct dpif_upcall *dupcall = &upcall->dpif_upcall;
             uint32_t hash = udpif->secret;
-            struct handler *handler;
             struct nlattr *nla;
             size_t n_bytes, left;
 
@@ -544,44 +583,50 @@ recv_upcalls(struct udpif *udpif)
                     || type == OVS_KEY_ATTR_UDP) {
                     if (nl_attr_get_size(nla) == 4) {
                         ovs_be32 attr = nl_attr_get_be32(nla);
-                        hash = mhash_add(hash, (uint32_t) attr);
+                        hash = mhash_add(hash, (OVS_FORCE uint32_t) attr);
                         n_bytes += 4;
                     } else {
                         VLOG_WARN("Netlink attribute with incorrect size.");
                     }
                 }
             }
-           hash =  mhash_finish(hash, n_bytes);
-
-           handler = &udpif->handlers[hash % udpif->n_handlers];
-
-           ovs_mutex_lock(&handler->mutex);
-           if (handler->n_upcalls < MAX_QUEUE_LENGTH) {
-               list_push_back(&handler->upcalls, &upcall->list_node);
-               handler->n_upcalls++;
-               xpthread_cond_signal(&handler->wake_cond);
-               ovs_mutex_unlock(&handler->mutex);
-               if (!VLOG_DROP_DBG(&rl)) {
-                   struct ds ds = DS_EMPTY_INITIALIZER;
-
-                   odp_flow_key_format(upcall->dpif_upcall.key,
-                                       upcall->dpif_upcall.key_len,
-                                       &ds);
-                   VLOG_DBG("dispatcher: miss enqueue (%s)", ds_cstr(&ds));
-                   ds_destroy(&ds);
-               }
-           } else {
-               ovs_mutex_unlock(&handler->mutex);
-               COVERAGE_INC(miss_queue_overflow);
-               upcall_destroy(upcall);
-           }
+            hash =  mhash_finish(hash, n_bytes);
+
+            handler = &udpif->handlers[hash % udpif->n_handlers];
+
+            ovs_mutex_lock(&handler->mutex);
+            if (handler->n_upcalls < MAX_QUEUE_LENGTH) {
+                list_push_back(&handler->upcalls, &upcall->list_node);
+                handler->n_new_upcalls = ++handler->n_upcalls;
+
+                if (handler->n_new_upcalls >= FLOW_MISS_MAX_BATCH) {
+                    xpthread_cond_signal(&handler->wake_cond);
+                }
+                ovs_mutex_unlock(&handler->mutex);
+                if (!VLOG_DROP_DBG(&rl)) {
+                    struct ds ds = DS_EMPTY_INITIALIZER;
+
+                    odp_flow_key_format(upcall->dpif_upcall.key,
+                                        upcall->dpif_upcall.key_len,
+                                        &ds);
+                    VLOG_DBG("dispatcher: miss enqueue (%s)", ds_cstr(&ds));
+                    ds_destroy(&ds);
+                }
+            } else {
+                ovs_mutex_unlock(&handler->mutex);
+                COVERAGE_INC(miss_queue_overflow);
+                upcall_destroy(upcall);
+            }
         } else {
             ovs_mutex_lock(&udpif->upcall_mutex);
             if (udpif->n_upcalls < MAX_QUEUE_LENGTH) {
-                udpif->n_upcalls++;
+                n_udpif_new_upcalls = ++udpif->n_upcalls;
                 list_push_back(&udpif->upcalls, &upcall->list_node);
                 ovs_mutex_unlock(&udpif->upcall_mutex);
-                seq_change(udpif->wait_seq);
+
+                if (n_udpif_new_upcalls >= FLOW_MISS_MAX_BATCH) {
+                    seq_change(udpif->wait_seq);
+                }
             } else {
                 ovs_mutex_unlock(&udpif->upcall_mutex);
                 COVERAGE_INC(upcall_queue_overflow);
@@ -589,6 +634,18 @@ recv_upcalls(struct udpif *udpif)
             }
         }
     }
+    for (n = 0; n < udpif->n_handlers; ++n) {
+        handler = &udpif->handlers[n];
+        if (handler->n_new_upcalls) {
+            handler->n_new_upcalls = 0;
+            ovs_mutex_lock(&handler->mutex);
+            xpthread_cond_signal(&handler->wake_cond);
+            ovs_mutex_unlock(&handler->mutex);
+        }
+    }
+    if (n_udpif_new_upcalls) {
+        seq_change(udpif->wait_seq);
+    }
 }
 
 static struct flow_miss *
@@ -627,7 +684,7 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
 
     flow_wildcards_init_catchall(&wc);
     rule_dpif_lookup(ofproto, &miss->flow, &wc, &rule);
-    rule_credit_stats(rule, &miss->stats);
+    rule_dpif_credit_stats(rule, &miss->stats);
     xlate_in_init(&xin, ofproto, &miss->flow, rule, miss->stats.tcp_flags,
                   NULL);
     xin.may_learn = true;
@@ -635,26 +692,29 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
     xlate_actions(&xin, &miss->xout);
     flow_wildcards_or(&miss->xout.wc, &miss->xout.wc, &wc);
 
-    if (rule->up.cr.priority == FAIL_OPEN_PRIORITY) {
-        struct ofputil_packet_in pin;
-
-        /* Extra-special case for fail-open mode.
-         *
-         * We are in fail-open mode and the packet matched the fail-open
-         * rule, but we are connected to a controller too.  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. */
-        pin.packet = packet->data;
-        pin.packet_len = packet->size;
-        pin.reason = OFPR_NO_MATCH;
-        pin.controller_id = 0;
-        pin.table_id = 0;
-        pin.cookie = 0;
-        pin.send_len = 0; /* Not used for flow table misses. */
-        flow_get_metadata(&miss->flow, &pin.fmd);
-        ofproto_dpif_send_packet_in(ofproto, &pin);
+    if (rule_dpif_fail_open(rule)) {
+        LIST_FOR_EACH (packet, list_node, &miss->packets) {
+            struct ofputil_packet_in *pin;
+
+            /* Extra-special case for fail-open mode.
+             *
+             * We are in fail-open mode and the packet matched the fail-open
+             * rule, but we are connected to a controller too.  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. */
+            pin = xmalloc(sizeof(*pin));
+            pin->packet = xmemdup(packet->data, packet->size);
+            pin->packet_len = packet->size;
+            pin->reason = OFPR_NO_MATCH;
+            pin->controller_id = 0;
+            pin->table_id = 0;
+            pin->cookie = 0;
+            pin->send_len = 0; /* Not used for flow table misses. */
+            flow_get_metadata(&miss->flow, &pin->fmd);
+            ofproto_dpif_send_packet_in(ofproto, pin);
+        }
     }
 
     if (miss->xout.slow) {
@@ -665,7 +725,7 @@ execute_flow_miss(struct flow_miss *miss, struct dpif_op *ops, size_t *n_ops)
             xlate_actions_for_side_effects(&xin);
         }
     }
-    rule_release(rule);
+    rule_dpif_release(rule);
 
     if (miss->xout.odp_actions.size) {
         LIST_FOR_EACH (packet, list_node, &miss->packets) {
@@ -764,7 +824,7 @@ handle_miss_upcalls(struct udpif *udpif, struct list *upcalls)
             continue;
         }
 
-        flow_extract(dupcall->packet, flow.skb_priority, flow.skb_mark,
+        flow_extract(dupcall->packet, flow.skb_priority, flow.pkt_mark,
                      &flow.tunnel, &flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */