classifier: Add support for conjunctive matches.
[cascardo/ovs.git] / ofproto / ofproto.c
index ab4918f..ba4263e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009-2015 Nicira, Inc.
  * Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -57,7 +57,7 @@
 #include "timeval.h"
 #include "unaligned.h"
 #include "unixctl.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
 #include "bundles.h"
 
 VLOG_DEFINE_THIS_MODULE(ofproto);
@@ -2934,10 +2934,15 @@ query_tables(struct ofproto *ofproto,
         atomic_read_relaxed(&ofproto->tables[i].miss_config, &f->miss_config);
         f->max_entries = 1000000;
 
-        bitmap_set_multiple(f->nonmiss.next, i + 1,
-                            ofproto->n_tables - (i + 1), true);
+        bool more_tables = false;
+        for (int j = i + 1; j < ofproto->n_tables; j++) {
+            if (!(ofproto->tables[j].flags & OFTABLE_HIDDEN)) {
+                bitmap_set1(f->nonmiss.next, j);
+                more_tables = true;
+            }
+        }
         f->nonmiss.instructions = (1u << N_OVS_INSTRUCTIONS) - 1;
-        if (i == ofproto->n_tables - 1) {
+        if (!more_tables) {
             f->nonmiss.instructions &= ~(1u << OVSINST_OFPIT11_GOTO_TABLE);
         }
         f->nonmiss.write.ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
@@ -2958,6 +2963,10 @@ query_tables(struct ofproto *ofproto,
 
             s->table_id = i;
             s->active_count = classifier_count(cls);
+            if (i == 0) {
+                s->active_count -= connmgr_count_hidden_rules(
+                    ofproto->connmgr);
+            }
         }
     } else {
         stats = NULL;
@@ -4138,6 +4147,54 @@ evict_rules_from_table(struct oftable *table, unsigned int extra_space)
     return error;
 }
 
+static bool
+is_conjunction(const struct ofpact *ofpacts, size_t ofpacts_len)
+{
+    return ofpacts_len > 0 && ofpacts->type == OFPACT_CONJUNCTION;
+}
+
+static void
+get_conjunctions(const struct ofputil_flow_mod *fm,
+                 struct cls_conjunction **conjsp, size_t *n_conjsp)
+    OVS_REQUIRES(ofproto_mutex)
+{
+    struct cls_conjunction *conjs = NULL;
+    int n_conjs = 0;
+
+    if (is_conjunction(fm->ofpacts, fm->ofpacts_len)) {
+        const struct ofpact *ofpact;
+        int i;
+
+        n_conjs = 0;
+        OFPACT_FOR_EACH (ofpact, fm->ofpacts, fm->ofpacts_len) {
+            n_conjs++;
+        }
+
+        conjs = xzalloc(n_conjs * sizeof *conjs);
+        i = 0;
+        OFPACT_FOR_EACH (ofpact, fm->ofpacts, fm->ofpacts_len) {
+            struct ofpact_conjunction *oc = ofpact_get_CONJUNCTION(ofpact);
+            conjs[i].clause = oc->clause;
+            conjs[i].n_clauses = oc->n_clauses;
+            conjs[i].id = oc->id;
+            i++;
+        }
+    }
+
+    *conjsp = conjs;
+    *n_conjsp = n_conjs;
+}
+
+static void
+set_conjunctions(struct rule *rule, const struct cls_conjunction *conjs,
+                 size_t n_conjs)
+    OVS_REQUIRES(ofproto_mutex)
+{
+    struct cls_rule *cr = CONST_CAST(struct cls_rule *, &rule->cr);
+
+    cls_rule_set_conjunctions(cr, conjs, n_conjs);
+}
+
 /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT
  * in which no matching flow already exists in the flow table.
  *
@@ -4284,7 +4341,12 @@ add_flow(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
     }
 
     classifier_defer(&table->cls);
-    classifier_insert(&table->cls, &rule->cr);
+
+    struct cls_conjunction *conjs;
+    size_t n_conjs;
+    get_conjunctions(fm, &conjs, &n_conjs);
+    classifier_insert(&table->cls, &rule->cr, conjs, n_conjs);
+    free(conjs);
 
     error = ofproto->ofproto_class->rule_insert(rule);
     if (error) {
@@ -4396,8 +4458,43 @@ modify_flows__(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
         }
 
         if (change_actions) {
+           /* We have to change the actions.  The rule's conjunctive match set
+            * is a function of its actions, so we need to update that too.  The
+            * conjunctive match set is used in the lookup process to figure
+            * which (if any) collection of conjunctive sets the packet matches
+            * with.  However, a rule with conjunction actions is never to be
+            * returned as a classifier lookup result.  To make sure a rule with
+            * conjunction actions is not returned as a lookup result, we update
+            * them in a carefully chosen order:
+            *
+            * - If we're adding a conjunctive match set where there wasn't one
+            *   before, we have to make the conjunctive match set available to
+            *   lookups before the rule's actions are changed, as otherwise
+            *   rule with a conjunction action could be returned as a lookup
+            *   result.
+            *
+            * - To clear some nonempty conjunctive set, we set the rule's
+            *   actions first, so that a lookup can't return a rule with
+            *   conjunction actions.
+            *
+            * - Otherwise, order doesn't matter for changing one nonempty
+            *   conjunctive match set to some other nonempty set, since the
+            *   rule's actions are not seen by the classifier, and hence don't
+            *   matter either before or after the change. */
+            struct cls_conjunction *conjs;
+            size_t n_conjs;
+            get_conjunctions(fm, &conjs, &n_conjs);
+
+            if (n_conjs) {
+                set_conjunctions(rule, conjs, n_conjs);
+            }
             ovsrcu_set(&rule->actions, rule_actions_create(fm->ofpacts,
                                                            fm->ofpacts_len));
+            if (!conjs) {
+                set_conjunctions(rule, conjs, n_conjs);
+            }
+
+            free(conjs);
         }
 
         if (change_actions || reset_counters) {
@@ -6126,6 +6223,11 @@ handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh)
     struct ofpbuf *buf;
     struct ofputil_bundle_ctrl_msg reply;
 
+    error = reject_slave_controller(ofconn);
+    if (error) {
+        return error;
+    }
+
     error = ofputil_decode_bundle_ctrl(oh, &bctrl);
     if (error) {
         return error;
@@ -6173,6 +6275,11 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
     enum ofperr error;
     struct ofputil_bundle_add_msg badd;
 
+    error = reject_slave_controller(ofconn);
+    if (error) {
+        return error;
+    }
+
     error = ofputil_decode_bundle_add(oh, &badd);
     if (error) {
         return error;
@@ -6682,7 +6789,7 @@ static void
 oftable_init(struct oftable *table)
 {
     memset(table, 0, sizeof *table);
-    classifier_init(&table->cls, flow_segment_u32s);
+    classifier_init(&table->cls, flow_segment_u64s);
     table->max_flows = UINT_MAX;
     atomic_init(&table->miss_config, OFPUTIL_TABLE_MISS_DEFAULT);