ofproto-dpif: Hide struct rule_dpif internally.
[cascardo/ovs.git] / ofproto / ofproto-dpif.c
index c7e32ef..cab7bc3 100644 (file)
@@ -83,7 +83,29 @@ BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);
 struct flow_miss;
 struct facet;
 
+struct rule_dpif {
+    struct rule up;
+
+    /* These statistics:
+     *
+     *   - Do include packets and bytes from facets that have been deleted or
+     *     whose own statistics have been folded into the rule.
+     *
+     *   - Do include packets and bytes sent "by hand" that were accounted to
+     *     the rule without any facet being involved (this is a rare corner
+     *     case in rule_execute()).
+     *
+     *   - Do not include packet or bytes that can be obtained from any facet's
+     *     packet_count or byte_count member or that can be obtained from the
+     *     datapath by, e.g., dpif_flow_get() for any subfacet.
+     */
+    struct ovs_mutex stats_mutex;
+    uint64_t packet_count OVS_GUARDED;  /* Number of packets received. */
+    uint64_t byte_count OVS_GUARDED;    /* Number of bytes received. */
+};
+
 static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes);
+static struct rule_dpif *rule_dpif_cast(const struct rule *);
 
 struct ofbundle {
     struct hmap_node hmap_node; /* In struct ofproto's "bundles" hmap. */
@@ -822,7 +844,7 @@ type_run(const char *type)
             HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
                 int stp_port = ofport->stp_port
                     ? stp_port_no(ofport->stp_port)
-                    : 0;
+                    : -1;
                 xlate_ofport_set(ofproto, ofport->bundle, ofport,
                                  ofport->up.ofp_port, ofport->odp_port,
                                  ofport->up.netdev, ofport->cfm,
@@ -1248,7 +1270,7 @@ construct(struct ofproto *ofproto_)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct shash_node *node, *next;
-    odp_port_t max_ports;
+    uint32_t max_ports;
     int error;
 
     error = open_dpif_backer(ofproto->up.type, &ofproto->backer);
@@ -1257,8 +1279,7 @@ construct(struct ofproto *ofproto_)
     }
 
     max_ports = dpif_get_max_ports(ofproto->backer->dpif);
-    ofproto_init_max_ports(ofproto_, u16_to_ofp(MIN(odp_to_u32(max_ports),
-                                                    ofp_to_u16(OFPP_MAX))));
+    ofproto_init_max_ports(ofproto_, MIN(max_ports, ofp_to_u16(OFPP_MAX)));
 
     ofproto->netflow = NULL;
     ofproto->sflow = NULL;
@@ -1360,7 +1381,7 @@ add_internal_flow(struct ofproto_dpif *ofproto, int id,
 
     if (rule_dpif_lookup_in_table(ofproto, &fm.match.flow, NULL, TBL_INTERNAL,
                                   rulep)) {
-        ovs_rwlock_unlock(&(*rulep)->up.evict);
+        rule_dpif_release(*rulep);
     } else {
         NOT_REACHED();
     }
@@ -1422,13 +1443,24 @@ destruct(struct ofproto *ofproto_)
     struct rule_dpif *rule, *next_rule;
     struct ofputil_packet_in *pin, *next_pin;
     struct ofputil_flow_mod *fm, *next_fm;
+    struct facet *facet, *next_facet;
+    struct cls_cursor cursor;
     struct oftable *table;
 
+    ovs_rwlock_rdlock(&ofproto->facets.rwlock);
+    cls_cursor_init(&cursor, &ofproto->facets, NULL);
+    ovs_rwlock_unlock(&ofproto->facets.rwlock);
+    CLS_CURSOR_FOR_EACH_SAFE (facet, next_facet, cr, &cursor) {
+        facet_remove(facet);
+    }
+
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
     ovs_rwlock_wrlock(&xlate_rwlock);
     xlate_remove_ofproto(ofproto);
     ovs_rwlock_unlock(&xlate_rwlock);
 
+    flow_miss_batch_ofproto_destroyed(ofproto->backer->udpif, ofproto);
+
     hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node);
     complete_operations(ofproto);
 
@@ -1438,10 +1470,11 @@ destruct(struct ofproto *ofproto_)
         ovs_rwlock_wrlock(&table->cls.rwlock);
         cls_cursor_init(&cursor, &table->cls, NULL);
         CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) {
-            ofproto_rule_destroy(&ofproto->up, &table->cls, &rule->up);
+            ofproto_rule_delete(&ofproto->up, &table->cls, &rule->up);
         }
         ovs_rwlock_unlock(&table->cls.rwlock);
     }
+    complete_operations(ofproto);
 
     ovs_mutex_lock(&ofproto->flow_mod_mutex);
     LIST_FOR_EACH_SAFE (fm, next_fm, list_node, &ofproto->flow_mods) {
@@ -3109,7 +3142,7 @@ port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
-    if (!ofport->is_tunnel) {
+    if (!ofport->is_tunnel && !netdev_vport_is_patch(ofport->up.netdev)) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
             /* The caller is going to close ofport->up.netdev.  If this is a
@@ -3976,12 +4009,8 @@ rule_expire(struct rule_dpif *rule)
         return;
     }
 
-    if (!ovs_rwlock_trywrlock(&rule->up.evict)) {
-        COVERAGE_INC(ofproto_dpif_expired);
-
-        /* Get rid of the rule. */
-        ofproto_rule_expire(&rule->up, reason);
-    }
+    COVERAGE_INC(ofproto_dpif_expired);
+    ofproto_rule_expire(&rule->up, reason);
 }
 \f
 /* Facets. */
@@ -4183,7 +4212,7 @@ facet_is_controller_flow(struct facet *facet)
         is_controller = ofpacts_len > 0
             && ofpacts->type == OFPACT_CONTROLLER
             && ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len);
-        rule_release(rule);
+        rule_dpif_release(rule);
         return is_controller;
     }
     return false;
@@ -4277,7 +4306,7 @@ facet_check_consistency(struct facet *facet)
     rule_dpif_lookup(facet->ofproto, &facet->flow, NULL, &rule);
     xlate_in_init(&xin, facet->ofproto, &facet->flow, rule, 0, NULL);
     xlate_actions(&xin, &xout);
-    rule_release(rule);
+    rule_dpif_release(rule);
 
     ok = ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions)
         && facet->xout.slow == xout.slow;
@@ -4375,7 +4404,7 @@ facet_revalidate(struct facet *facet)
         || memcmp(&facet->xout.wc, &xout.wc, sizeof xout.wc)) {
         facet_remove(facet);
         xlate_out_uninit(&xout);
-        rule_release(new_rule);
+        rule_dpif_release(new_rule);
         return false;
     }
 
@@ -4407,7 +4436,7 @@ facet_revalidate(struct facet *facet)
     facet->used = MAX(facet->used, new_rule->up.created);
 
     xlate_out_uninit(&xout);
-    rule_release(new_rule);
+    rule_dpif_release(new_rule);
     return true;
 }
 
@@ -4435,12 +4464,12 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow,
     }
 
     rule_dpif_lookup(ofproto, flow, NULL, &rule);
-    rule_credit_stats(rule, stats);
+    rule_dpif_credit_stats(rule, stats);
     xlate_in_init(&xin, ofproto, flow, rule, stats->tcp_flags, NULL);
     xin.resubmit_stats = stats;
     xin.may_learn = may_learn;
     xlate_actions_for_side_effects(&xin);
-    rule_release(rule);
+    rule_dpif_release(rule);
 }
 
 static void
@@ -4506,7 +4535,8 @@ push_all_stats(void)
 }
 
 void
-rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
+rule_dpif_credit_stats(struct rule_dpif *rule,
+                       const struct dpif_flow_stats *stats)
 {
     ovs_mutex_lock(&rule->stats_mutex);
     rule->packet_count += stats->n_packets;
@@ -4514,6 +4544,33 @@ rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
     ofproto_rule_update_used(&rule->up, stats->used);
     ovs_mutex_unlock(&rule->stats_mutex);
 }
+
+bool
+rule_dpif_fail_open(const struct rule_dpif *rule)
+{
+    return rule->up.cr.priority == FAIL_OPEN_PRIORITY;
+}
+
+ovs_be64
+rule_dpif_get_flow_cookie(const struct rule_dpif *rule)
+{
+    return rule->up.flow_cookie;
+}
+
+void
+rule_dpif_reduce_timeouts(struct rule_dpif *rule, uint16_t idle_timeout,
+                     uint16_t hard_timeout)
+{
+    ofproto_rule_reduce_timeouts(&rule->up, idle_timeout, hard_timeout);
+}
+
+void
+rule_dpif_get_actions(const struct rule_dpif *rule,
+                      const struct ofpact **ofpacts, size_t *ofpacts_len)
+{
+    *ofpacts = rule->up.ofpacts;
+    *ofpacts_len = rule->up.ofpacts_len;
+}
 \f
 /* Subfacets. */
 
@@ -4782,16 +4839,15 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
                      flow->in_port.ofp_port);
     }
 
-    *rule = choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
-                             ofproto->no_packet_in_rule);
-    ovs_rwlock_rdlock(&(*rule)->up.evict);
+    choose_miss_rule(port ? port->up.pp.config : 0, ofproto->miss_rule,
+                     ofproto->no_packet_in_rule, rule);
 }
 
 bool
 rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
                           const struct flow *flow, struct flow_wildcards *wc,
                           uint8_t table_id, struct rule_dpif **rule)
-    OVS_ACQ_RDLOCK((*rule)->up.evict)
+    OVS_TRY_RDLOCK(true, (*rule)->up.evict)
 {
     struct cls_rule *cls_rule;
     struct classifier *cls;
@@ -4839,15 +4895,17 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto,
 /* Given a port configuration (specified as zero if there's no port), chooses
  * which of 'miss_rule' and 'no_packet_in_rule' should be used in case of a
  * flow table miss. */
-struct rule_dpif *
+void
 choose_miss_rule(enum ofputil_port_config config, struct rule_dpif *miss_rule,
-                 struct rule_dpif *no_packet_in_rule)
+                 struct rule_dpif *no_packet_in_rule, struct rule_dpif **rule)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
 {
-    return config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+    *rule = config & OFPUTIL_PC_NO_PACKET_IN ? no_packet_in_rule : miss_rule;
+    ovs_rwlock_rdlock(&(*rule)->up.evict);
 }
 
 void
-rule_release(struct rule_dpif *rule)
+rule_dpif_release(struct rule_dpif *rule)
     OVS_NO_THREAD_SAFETY_ANALYSIS
 {
     if (rule) {
@@ -4870,6 +4928,11 @@ complete_operation(struct rule_dpif *rule)
     }
 }
 
+static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
+{
+    return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL;
+}
+
 static struct rule *
 rule_alloc(void)
 {
@@ -4893,15 +4956,27 @@ rule_construct(struct rule *rule_)
     rule->packet_count = 0;
     rule->byte_count = 0;
     ovs_mutex_unlock(&rule->stats_mutex);
-    complete_operation(rule);
     return 0;
 }
 
 static void
-rule_destruct(struct rule *rule_)
+rule_insert(struct rule *rule_)
 {
     struct rule_dpif *rule = rule_dpif_cast(rule_);
     complete_operation(rule);
+}
+
+static void
+rule_delete(struct rule *rule_)
+{
+    struct rule_dpif *rule = rule_dpif_cast(rule_);
+    complete_operation(rule);
+}
+
+static void
+rule_destruct(struct rule *rule_)
+{
+    struct rule_dpif *rule = rule_dpif_cast(rule_);
     ovs_mutex_destroy(&rule->stats_mutex);
 }
 
@@ -4934,7 +5009,7 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
     struct xlate_in xin;
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
-    rule_credit_stats(rule, &stats);
+    rule_dpif_credit_stats(rule, &stats);
 
     xlate_in_init(&xin, ofproto, flow, rule, stats.tcp_flags, packet);
     xin.resubmit_stats = &stats;
@@ -4956,10 +5031,17 @@ rule_execute(struct rule *rule, const struct flow *flow,
 }
 
 static void
-rule_modify_actions(struct rule *rule_)
+rule_modify_actions(struct rule *rule_, bool reset_counters)
 {
     struct rule_dpif *rule = rule_dpif_cast(rule_);
 
+    if (reset_counters) {
+        ovs_mutex_lock(&rule->stats_mutex);
+        rule->packet_count = 0;
+        rule->byte_count = 0;
+        ovs_mutex_unlock(&rule->stats_mutex);
+    }
+
     complete_operation(rule);
 }
 \f
@@ -5548,7 +5630,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         xlate_out_uninit(&trace.xout);
     }
 
-    rule_release(rule);
+    rule_dpif_release(rule);
 }
 
 static void
@@ -6344,6 +6426,8 @@ const struct ofproto_class ofproto_dpif_class = {
     NULL,                       /* rule_choose_table */
     rule_alloc,
     rule_construct,
+    rule_insert,
+    rule_delete,
     rule_destruct,
     rule_dealloc,
     rule_get_stats,