Add ability to restrict flow mods and flow stats requests to cookies.
[sliver-openvswitch.git] / ofproto / ofproto.c
index 1a20097..b6f9207 100644 (file)
@@ -724,10 +724,7 @@ ofproto_bundle_unregister(struct ofproto *ofproto, void *aux)
 \f
 /* Registers a mirror associated with client data pointer 'aux' in 'ofproto'.
  * If 'aux' is already registered then this function updates its configuration
- * to 's'.  Otherwise, this function registers a new mirror.
- *
- * Mirrors affect only the treatment of packets output to the OFPP_NORMAL
- * port.  */
+ * to 's'.  Otherwise, this function registers a new mirror. */
 int
 ofproto_mirror_register(struct ofproto *ofproto, void *aux,
                         const struct ofproto_mirror_settings *s)
@@ -745,6 +742,23 @@ ofproto_mirror_unregister(struct ofproto *ofproto, void *aux)
     return ofproto_mirror_register(ofproto, aux, NULL);
 }
 
+/* Retrieves statistics from mirror associated with client data pointer
+ * 'aux' in 'ofproto'.  Stores packet and byte counts in 'packets' and
+ * 'bytes', respectively.  If a particular counters is not supported,
+ * the appropriate argument is set to UINT64_MAX. */
+int
+ofproto_mirror_get_stats(struct ofproto *ofproto, void *aux,
+                         uint64_t *packets, uint64_t *bytes)
+{
+    if (!ofproto->ofproto_class->mirror_get_stats) {
+        *packets = *bytes = UINT64_MAX;
+        return EOPNOTSUPP;
+    }
+
+    return ofproto->ofproto_class->mirror_get_stats(ofproto, aux,
+                                                    packets, bytes);
+}
+
 /* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs on
  * which all packets are flooded, instead of using MAC learning.  If
  * 'flood_vlans' is NULL, then MAC learning applies to all VLANs.
@@ -894,14 +908,8 @@ ofproto_run(struct ofproto *p)
     int error;
 
     error = p->ofproto_class->run(p);
-    if (error == ENODEV) {
-        /* Someone destroyed the datapath behind our back.  The caller
-         * better destroy us and give up, because we're just going to
-         * spin from here on out. */
-        static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 5);
-        VLOG_ERR_RL(&rl2, "%s: datapath was destroyed externally",
-                    p->name);
-        return ENODEV;
+    if (error && error != EAGAIN) {
+        VLOG_ERR_RL(&rl, "%s: run failed (%s)", p->name, strerror(error));
     }
 
     if (p->ofproto_class->port_poll) {
@@ -937,7 +945,26 @@ ofproto_run(struct ofproto *p)
         NOT_REACHED();
     }
 
-    return 0;
+    return error;
+}
+
+/* Performs periodic activity required by 'ofproto' that needs to be done
+ * with the least possible latency.
+ *
+ * It makes sense to call this function a couple of times per poll loop, to
+ * provide a significant performance boost on some benchmarks with the
+ * ofproto-dpif implementation. */
+int
+ofproto_run_fast(struct ofproto *p)
+{
+    int error;
+
+    error = p->ofproto_class->run_fast ? p->ofproto_class->run_fast(p) : 0;
+    if (error && error != EAGAIN) {
+        VLOG_ERR_RL(&rl, "%s: fastpath run failed (%s)",
+                    p->name, strerror(error));
+    }
+    return error;
 }
 
 void
@@ -1451,6 +1478,21 @@ ofproto_get_port(const struct ofproto *ofproto, uint16_t ofp_port)
     return NULL;
 }
 
+int
+ofproto_port_get_stats(const struct ofport *port, struct netdev_stats *stats)
+{
+    struct ofproto *ofproto = port->ofproto;
+    int error;
+
+    if (ofproto->ofproto_class->port_get_stats) {
+        error = ofproto->ofproto_class->port_get_stats(port, stats);
+    } else {
+        error = EOPNOTSUPP;
+    }
+
+    return error;
+}
+
 static void
 update_port(struct ofproto *ofproto, const char *name)
 {
@@ -1923,7 +1965,7 @@ append_port_stat(struct ofport *port, struct list *replies)
     /* Intentionally ignore return value, since errors will set
      * 'stats' to all-1s, which is correct for OpenFlow, and
      * netdev_get_stats() will log errors. */
-    netdev_get_stats(port->netdev, &stats);
+    ofproto_port_get_stats(port, &stats);
 
     ops = ofputil_append_stats_reply(sizeof *ops, replies);
     ops->port_no = port->opp.port_no;
@@ -2039,8 +2081,9 @@ next_matching_table(struct ofproto *ofproto,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static int
 collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
-                    const struct cls_rule *match, uint16_t out_port,
-                    struct list *rules)
+                    const struct cls_rule *match,
+                    ovs_be64 cookie, ovs_be64 cookie_mask,
+                    uint16_t out_port, struct list *rules)
 {
     struct classifier *cls;
     int error;
@@ -2060,7 +2103,8 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
             if (rule->pending) {
                 return OFPROTO_POSTPONE;
             }
-            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) {
+            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)
+                    && !((rule->flow_cookie ^ cookie) & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
         }
@@ -2081,8 +2125,9 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static int
 collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
-                     const struct cls_rule *match, uint16_t out_port,
-                     struct list *rules)
+                     const struct cls_rule *match,
+                     ovs_be64 cookie, ovs_be64 cookie_mask,
+                     uint16_t out_port, struct list *rules)
 {
     struct classifier *cls;
     int error;
@@ -2101,7 +2146,8 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
             if (rule->pending) {
                 return OFPROTO_POSTPONE;
             }
-            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) {
+            if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)
+                    && !((rule->flow_cookie ^ cookie) & cookie_mask)) {
                 list_push_back(rules, &rule->ofproto_node);
             }
         }
@@ -2126,6 +2172,7 @@ handle_flow_stats_request(struct ofconn *ofconn,
     }
 
     error = collect_rules_loose(ofproto, fsr.table_id, &fsr.match,
+                                fsr.cookie, fsr.cookie_mask,
                                 fsr.out_port, &rules);
     if (error) {
         return error;
@@ -2256,6 +2303,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
     }
 
     error = collect_rules_loose(ofproto, request.table_id, &request.match,
+                                request.cookie, request.cookie_mask,
                                 request.out_port, &rules);
     if (error) {
         return error;
@@ -2551,8 +2599,9 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, OFPP_NONE,
-                                &rules);
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+                                fm->cookie, fm->cookie_mask,
+                                OFPP_NONE, &rules);
     return (error ? error
             : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request)
             : modify_flows__(ofproto, ofconn, fm, request, &rules));
@@ -2571,8 +2620,9 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, OFPP_NONE,
-                                 &rules);
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
+                                 fm->cookie, fm->cookie_mask,
+                                 OFPP_NONE, &rules);
     return (error ? error
             : list_is_empty(&rules) ? add_flow(ofproto, ofconn, fm, request)
             : list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn,
@@ -2614,8 +2664,9 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr, fm->out_port,
-                                &rules);
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+                                fm->cookie, fm->cookie_mask,
+                                fm->out_port, &rules);
     return (error ? error
             : !list_is_empty(&rules) ? delete_flows__(ofproto, ofconn, request,
                                                       &rules)
@@ -2631,8 +2682,9 @@ delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr, fm->out_port,
-                                 &rules);
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
+                                 fm->cookie, fm->cookie_mask,
+                                 fm->out_port, &rules);
     return (error ? error
             : list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn,
                                                          request, &rules)
@@ -3235,8 +3287,8 @@ ofproto_lookup(const char *name)
 }
 
 static void
-ofproto_unixctl_list(struct unixctl_conn *conn, const char *arg OVS_UNUSED,
-                     void *aux OVS_UNUSED)
+ofproto_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                     const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
 {
     struct ofproto *ofproto;
     struct ds results;
@@ -3258,7 +3310,8 @@ ofproto_unixctl_init(void)
     }
     registered = true;
 
-    unixctl_command_register("ofproto/list", "", ofproto_unixctl_list, NULL);
+    unixctl_command_register("ofproto/list", "", 0, 0,
+                             ofproto_unixctl_list, NULL);
 }
 \f
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)