datapath-windows: set the nlBuf tail properly
[cascardo/ovs.git] / ofproto / ofproto.c
index c35bc3a..6d78fe4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 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);
@@ -89,8 +89,6 @@ static void oftable_enable_eviction(struct oftable *,
                                     size_t n_fields);
 
 static void oftable_remove_rule(struct rule *rule) OVS_REQUIRES(ofproto_mutex);
-static void oftable_remove_rule__(struct ofproto *, struct rule *)
-    OVS_REQUIRES(ofproto_mutex);
 
 /* A set of rules within a single OpenFlow table (oftable) that have the same
  * values for the oftable's eviction_fields.  A rule to be evicted, when one is
@@ -169,7 +167,7 @@ static enum ofperr collect_rules_loose(struct ofproto *,
  * (We can't do this immediately from ofopgroup_complete() because that holds
  * ofproto_mutex, which rule_execute() needs released.) */
 struct rule_execute {
-    struct list list_node;      /* In struct ofproto's "rule_executes" list. */
+    struct ovs_list list_node;  /* In struct ofproto's "rule_executes" list. */
     struct rule *rule;          /* Owns a reference to the rule. */
     ofp_port_t in_port;
     struct ofpbuf *packet;      /* Owns the packet. */
@@ -184,7 +182,7 @@ struct learned_cookie {
         struct hmap_node hmap_node OVS_GUARDED_BY(ofproto_mutex);
 
         /* In 'dead_cookies' list when removed from hmap. */
-        struct list list_node;
+        struct ovs_list list_node;
     } u;
 
     /* Key. */
@@ -204,9 +202,9 @@ static const struct ofpact_learn *next_learn_with_delete(
 static void learned_cookies_inc(struct ofproto *, const struct rule_actions *)
     OVS_REQUIRES(ofproto_mutex);
 static void learned_cookies_dec(struct ofproto *, const struct rule_actions *,
-                                struct list *dead_cookies)
+                                struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex);
-static void learned_cookies_flush(struct ofproto *, struct list *dead_cookies)
+static void learned_cookies_flush(struct ofproto *, struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex);
 
 /* ofport. */
@@ -237,6 +235,8 @@ struct ofport_usage {
 /* rule. */
 static void ofproto_rule_send_removed(struct rule *, uint8_t reason);
 static bool rule_is_readonly(const struct rule *);
+static void ofproto_rule_remove__(struct ofproto *, struct rule *)
+    OVS_REQUIRES(ofproto_mutex);
 
 /* The source of a flow_mod request, in the code that processes flow_mods.
  *
@@ -1332,18 +1332,6 @@ ofproto_get_snoops(const struct ofproto *ofproto, struct sset *snoops)
     connmgr_get_snoops(ofproto->connmgr, snoops);
 }
 
-static void
-ofproto_rule_delete__(struct rule *rule, uint8_t reason)
-    OVS_REQUIRES(ofproto_mutex)
-{
-    struct rule_collection rules;
-
-    rules.rules = rules.stub;
-    rules.n = 1;
-    rules.stub[0] = rule;
-    delete_flows__(&rules, reason, NULL);
-}
-
 /* Deletes 'rule' from 'ofproto'.
  *
  * Within an ofproto implementation, this function allows an ofproto
@@ -1361,7 +1349,7 @@ ofproto_rule_delete(struct ofproto *ofproto, struct rule *rule)
      * switch is being deleted and any OpenFlow channels have been or soon will
      * be killed. */
     ovs_mutex_lock(&ofproto_mutex);
-    oftable_remove_rule__(ofproto, rule);
+    oftable_remove_rule(rule);
     ofproto->ofproto_class->rule_delete(rule);
     ovs_mutex_unlock(&ofproto_mutex);
 }
@@ -1385,15 +1373,20 @@ ofproto_flush__(struct ofproto *ofproto)
 
     ovs_mutex_lock(&ofproto_mutex);
     OFPROTO_FOR_EACH_TABLE (table, ofproto) {
+        struct rule_collection rules;
         struct rule *rule;
 
         if (table->flags & OFTABLE_HIDDEN) {
             continue;
         }
 
+        rule_collection_init(&rules);
+
         CLS_FOR_EACH (rule, cr, &table->cls) {
-            ofproto_rule_delete__(rule, OFPRR_DELETE);
+            rule_collection_add(&rules, rule);
         }
+        delete_flows__(&rules, OFPRR_DELETE, NULL);
+        rule_collection_destroy(&rules);
     }
     /* XXX: Concurrent handler threads may insert new learned flows based on
      * learn actions of the now deleted flows right after we release
@@ -2758,7 +2751,7 @@ run_rule_executes(struct ofproto *ofproto)
     OVS_EXCLUDED(ofproto_mutex)
 {
     struct rule_execute *e, *next;
-    struct list executes;
+    struct ovs_list executes;
 
     guarded_list_pop_all(&ofproto->rule_executes, &executes);
     LIST_FOR_EACH_SAFE (e, next, list_node, &executes) {
@@ -2778,7 +2771,7 @@ static void
 destroy_rule_executes(struct ofproto *ofproto)
 {
     struct rule_execute *e, *next;
-    struct list executes;
+    struct ovs_list executes;
 
     guarded_list_pop_all(&ofproto->rule_executes, &executes);
     LIST_FOR_EACH_SAFE (e, next, list_node, &executes) {
@@ -2804,7 +2797,7 @@ hash_learned_cookie(ovs_be64 cookie_, uint8_t table_id)
 static void
 learned_cookies_update_one__(struct ofproto *ofproto,
                              const struct ofpact_learn *learn,
-                             int delta, struct list *dead_cookies)
+                             int delta, struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex)
 {
     uint32_t hash = hash_learned_cookie(learn->cookie, learn->table_id);
@@ -2855,7 +2848,7 @@ next_learn_with_delete(const struct rule_actions *actions,
 static void
 learned_cookies_update__(struct ofproto *ofproto,
                          const struct rule_actions *actions,
-                         int delta, struct list *dead_cookies)
+                         int delta, struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex)
 {
     if (actions->has_learn_with_delete) {
@@ -2879,14 +2872,14 @@ learned_cookies_inc(struct ofproto *ofproto,
 static void
 learned_cookies_dec(struct ofproto *ofproto,
                     const struct rule_actions *actions,
-                    struct list *dead_cookies)
+                    struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex)
 {
     learned_cookies_update__(ofproto, actions, -1, dead_cookies);
 }
 
 static void
-learned_cookies_flush(struct ofproto *ofproto, struct list *dead_cookies)
+learned_cookies_flush(struct ofproto *ofproto, struct ovs_list *dead_cookies)
     OVS_REQUIRES(ofproto_mutex)
 {
     struct learned_cookie *c, *next;
@@ -2941,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;
@@ -3322,7 +3320,7 @@ handle_table_features_request(struct ofconn *ofconn,
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofputil_table_features *features;
-    struct list replies;
+    struct ovs_list replies;
     struct ofpbuf msg;
     size_t i;
 
@@ -3348,7 +3346,7 @@ handle_table_features_request(struct ofconn *ofconn,
 }
 
 static void
-append_port_stat(struct ofport *port, struct list *replies)
+append_port_stat(struct ofport *port, struct ovs_list *replies)
 {
     struct ofputil_port_stats ops = { .port_no = port->pp.port_no };
 
@@ -3366,11 +3364,11 @@ append_port_stat(struct ofport *port, struct list *replies)
 static void
 handle_port_request(struct ofconn *ofconn,
                     const struct ofp_header *request, ofp_port_t port_no,
-                    void (*cb)(struct ofport *, struct list *replies))
+                    void (*cb)(struct ofport *, struct ovs_list *replies))
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofport *port;
-    struct list replies;
+    struct ovs_list replies;
 
     ofpmp_init(&replies, request);
     if (port_no != OFPP_ANY) {
@@ -3402,7 +3400,7 @@ handle_port_stats_request(struct ofconn *ofconn,
 }
 
 static void
-append_port_desc(struct ofport *port, struct list *replies)
+append_port_desc(struct ofport *port, struct ovs_list *replies)
 {
     ofputil_append_port_desc_stats_reply(&port->pp, replies);
 }
@@ -3790,7 +3788,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
     struct ofputil_flow_stats_request fsr;
     struct rule_criteria criteria;
     struct rule_collection rules;
-    struct list replies;
+    struct ovs_list replies;
     enum ofperr error;
     size_t i;
 
@@ -4021,7 +4019,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
 
 struct queue_stats_cbdata {
     struct ofport *ofport;
-    struct list replies;
+    struct ovs_list replies;
     long long int now;
 };
 
@@ -4117,29 +4115,32 @@ handle_queue_stats_request(struct ofconn *ofconn,
     return error;
 }
 
-static bool
-should_evict_a_rule(struct oftable *table, unsigned int extra_space)
-    OVS_REQUIRES(ofproto_mutex)
-    OVS_NO_THREAD_SAFETY_ANALYSIS
-{
-    return classifier_count(&table->cls) + extra_space > table->max_flows;
-}
-
 static enum ofperr
 evict_rules_from_table(struct oftable *table, unsigned int extra_space)
     OVS_REQUIRES(ofproto_mutex)
 {
-    while (should_evict_a_rule(table, extra_space)) {
+    enum ofperr error = 0;
+    struct rule_collection rules;
+    unsigned int count = classifier_count(&table->cls) + extra_space;
+    unsigned int max_flows = table->max_flows;
+
+    rule_collection_init(&rules);
+
+    while (count-- > max_flows) {
         struct rule *rule;
 
         if (!choose_rule_to_evict(table, &rule)) {
-            return OFPERR_OFPFMFC_TABLE_FULL;
+            error = OFPERR_OFPFMFC_TABLE_FULL;
+            break;
         } else {
-            ofproto_rule_delete__(rule, OFPRR_EVICTION);
+            eviction_group_remove_rule(rule);
+            rule_collection_add(&rules, rule);
         }
     }
+    delete_flows__(&rules, OFPRR_EVICTION, NULL);
+    rule_collection_destroy(&rules);
 
-    return 0;
+    return error;
 }
 
 /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT
@@ -4287,7 +4288,8 @@ add_flow(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
         meter_insert_rule(rule);
     }
 
-    classifier_insert(&table->cls, CONST_CAST(struct cls_rule *, &rule->cr));
+    classifier_defer(&table->cls);
+    classifier_insert(&table->cls, &rule->cr);
 
     error = ofproto->ofproto_class->rule_insert(rule);
     if (error) {
@@ -4295,6 +4297,8 @@ add_flow(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
         ofproto_rule_unref(rule);
         return error;
     }
+    classifier_publish(&table->cls);
+
     learned_cookies_inc(ofproto, actions);
 
     if (minimask_get_vid_mask(&rule->cr.match.mask) == VLAN_VID_MASK) {
@@ -4330,7 +4334,7 @@ modify_flows__(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
                const struct flow_mod_requester *req)
     OVS_REQUIRES(ofproto_mutex)
 {
-    struct list dead_cookies = LIST_INITIALIZER(&dead_cookies);
+    struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
     enum nx_flow_update_event event;
     size_t i;
 
@@ -4511,23 +4515,36 @@ delete_flows__(const struct rule_collection *rules,
     OVS_REQUIRES(ofproto_mutex)
 {
     if (rules->n) {
-        struct list dead_cookies = LIST_INITIALIZER(&dead_cookies);
+        struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
         struct ofproto *ofproto = rules->rules[0]->ofproto;
+        struct rule *rule, *next;
         size_t i;
 
-        for (i = 0; i < rules->n; i++) {
-            struct rule *rule = rules->rules[i];
-            const struct rule_actions *actions = rule_get_actions(rule);
+        for (i = 0, next = rules->rules[0];
+             rule = next, next = (++i < rules->n) ? rules->rules[i] : NULL,
+                 rule; ) {
+            struct classifier *cls = &ofproto->tables[rule->table_id].cls;
+            uint8_t next_table = next ? next->table_id : UINT8_MAX;
 
             ofproto_rule_send_removed(rule, reason);
 
             ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
                              req ? req->ofconn : NULL, req ? req->xid : 0,
                              NULL);
-            oftable_remove_rule(rule);
+
+            if (next_table == rule->table_id) {
+                classifier_defer(cls);
+            }
+            classifier_remove(cls, &rule->cr);
+            if (next_table != rule->table_id) {
+                classifier_publish(cls);
+            }
+            ofproto_rule_remove__(ofproto, rule);
+
             ofproto->ofproto_class->rule_delete(rule);
 
-            learned_cookies_dec(ofproto, actions, &dead_cookies);
+            learned_cookies_dec(ofproto, rule_get_actions(rule),
+                                &dead_cookies);
         }
         learned_cookies_flush(ofproto, &dead_cookies);
         ofmonitor_flush(ofproto->connmgr);
@@ -4553,7 +4570,7 @@ delete_flows_loose(struct ofproto *ofproto,
     error = collect_rules_loose(ofproto, &criteria, &rules);
     rule_criteria_destroy(&criteria);
 
-    if (!error && rules.n > 0) {
+    if (!error) {
         delete_flows__(&rules, fm->delete_reason, req);
     }
     rule_collection_destroy(&rules);
@@ -4579,7 +4596,7 @@ delete_flow_strict(struct ofproto *ofproto, const struct ofputil_flow_mod *fm,
     error = collect_rules_strict(ofproto, &criteria, &rules);
     rule_criteria_destroy(&criteria);
 
-    if (!error && rules.n > 0) {
+    if (!error) {
         delete_flows__(&rules, fm->delete_reason, req);
     }
     rule_collection_destroy(&rules);
@@ -4626,7 +4643,12 @@ void
 ofproto_rule_expire(struct rule *rule, uint8_t reason)
     OVS_REQUIRES(ofproto_mutex)
 {
-    ofproto_rule_delete__(rule, reason);
+    struct rule_collection rules;
+
+    rules.rules = rules.stub;
+    rules.n = 1;
+    rules.stub[0] = rule;
+    delete_flows__(&rules, reason, NULL);
 }
 
 /* Reduces '*timeout' to no more than 'max'.  A value of zero in either case
@@ -4910,7 +4932,7 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
 static void
 ofproto_compose_flow_refresh_update(const struct rule *rule,
                                     enum nx_flow_monitor_flags flags,
-                                    struct list *msgs)
+                                    struct ovs_list *msgs)
     OVS_REQUIRES(ofproto_mutex)
 {
     const struct rule_actions *actions;
@@ -4942,7 +4964,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
 
 void
 ofmonitor_compose_refresh_updates(struct rule_collection *rules,
-                                  struct list *msgs)
+                                  struct ovs_list *msgs)
     OVS_REQUIRES(ofproto_mutex)
 {
     size_t i;
@@ -5059,7 +5081,7 @@ handle_flow_monitor_request(struct ofconn *ofconn, const struct ofp_header *oh)
     struct ofmonitor **monitors;
     size_t n_monitors, allocated_monitors;
     struct rule_collection rules;
-    struct list replies;
+    struct ovs_list replies;
     enum ofperr error;
     struct ofpbuf b;
     size_t i;
@@ -5152,7 +5174,7 @@ handle_flow_monitor_cancel(struct ofconn *ofconn, const struct ofp_header *oh)
  */
 struct meter {
     long long int created;      /* Time created. */
-    struct list rules;          /* List of "struct rule_dpif"s. */
+    struct ovs_list rules;      /* List of "struct rule_dpif"s. */
     ofproto_meter_id provider_meter_id;
     uint16_t flags;             /* Meter flags. */
     uint16_t n_bands;           /* Number of meter bands. */
@@ -5308,9 +5330,7 @@ handle_delete_meter(struct ofconn *ofconn, struct ofputil_meter_mod *mm)
             }
         }
     }
-    if (rules.n > 0) {
-        delete_flows__(&rules, OFPRR_METER_DELETE, NULL);
-    }
+    delete_flows__(&rules, OFPRR_METER_DELETE, NULL);
 
     /* Delete the meters. */
     meter_delete(ofproto, first, last);
@@ -5407,7 +5427,7 @@ handle_meter_request(struct ofconn *ofconn, const struct ofp_header *request,
                      enum ofptype type)
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
-    struct list replies;
+    struct ovs_list replies;
     uint64_t bands_stub[256 / 8];
     struct ofpbuf bands;
     uint32_t meter_id, first, last;
@@ -5557,7 +5577,7 @@ group_get_ref_count(struct ofgroup *group)
 }
 
 static void
-append_group_stats(struct ofgroup *group, struct list *replies)
+append_group_stats(struct ofgroup *group, struct ovs_list *replies)
 {
     struct ofputil_group_stats ogs;
     const struct ofproto *ofproto = group->ofproto;
@@ -5591,11 +5611,11 @@ append_group_stats(struct ofgroup *group, struct list *replies)
 static void
 handle_group_request(struct ofconn *ofconn,
                      const struct ofp_header *request, uint32_t group_id,
-                     void (*cb)(struct ofgroup *, struct list *replies))
+                     void (*cb)(struct ofgroup *, struct ovs_list *replies))
 {
     struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofgroup *group;
-    struct list replies;
+    struct ovs_list replies;
 
     ofpmp_init(&replies, request);
     if (group_id == OFPG_ALL) {
@@ -5630,7 +5650,7 @@ handle_group_stats_request(struct ofconn *ofconn,
 }
 
 static void
-append_group_desc(struct ofgroup *group, struct list *replies)
+append_group_desc(struct ofgroup *group, struct ovs_list *replies)
 {
     struct ofputil_group_desc gds;
 
@@ -6111,6 +6131,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;
@@ -6158,6 +6183,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;
@@ -6770,15 +6800,12 @@ oftable_enable_eviction(struct oftable *table,
     }
 }
 
-/* Removes 'rule' from the oftable that contains it. */
+/* Removes 'rule' from the ofproto data structures AFTER caller has removed
+ * it from the classifier. */
 static void
-oftable_remove_rule__(struct ofproto *ofproto, struct rule *rule)
+ofproto_rule_remove__(struct ofproto *ofproto, struct rule *rule)
     OVS_REQUIRES(ofproto_mutex)
 {
-    struct classifier *cls = &ofproto->tables[rule->table_id].cls;
-
-    classifier_remove(cls, CONST_CAST(struct cls_rule *, &rule->cr));
-
     cookies_remove(ofproto, rule);
 
     eviction_group_remove_rule(rule);
@@ -6795,7 +6822,11 @@ static void
 oftable_remove_rule(struct rule *rule)
     OVS_REQUIRES(ofproto_mutex)
 {
-    oftable_remove_rule__(rule->ofproto, rule);
+    struct classifier *cls = &rule->ofproto->tables[rule->table_id].cls;
+
+    if (classifier_remove(cls, &rule->cr)) {
+        ofproto_rule_remove__(rule->ofproto, rule);
+    }
 }
 \f
 /* unixctl commands. */