vlog: Introduce VLOG_DEFINE_THIS_MODULE for declaring vlog module in use.
[sliver-openvswitch.git] / ofproto / ofproto.c
index 031531c..66b957e 100644 (file)
 #include "timeval.h"
 #include "unixctl.h"
 #include "vconn.h"
+#include "vlog.h"
 #include "xtoxll.h"
 
-#define THIS_MODULE VLM_ofproto
-#include "vlog.h"
+VLOG_DEFINE_THIS_MODULE(ofproto)
 
 #include "sflow_api.h"
 
@@ -411,15 +411,11 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
     uint64_t old_dpid = p->datapath_id;
     p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p);
     if (p->datapath_id != old_dpid) {
-        struct ofconn *ofconn;
-
         VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id);
 
         /* Force all active connections to reconnect, since there is no way to
          * notify a controller that the datapath ID has changed. */
-        LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) {
-            rconn_reconnect(ofconn->rconn);
-        }
+        ofproto_reconnect_controllers(p);
     }
 }
 
@@ -664,6 +660,18 @@ ofproto_set_controllers(struct ofproto *p,
     }
 }
 
+/* Drops the connections between 'ofproto' and all of its controllers, forcing
+ * them to reconnect. */
+void
+ofproto_reconnect_controllers(struct ofproto *ofproto)
+{
+    struct ofconn *ofconn;
+
+    LIST_FOR_EACH (ofconn, struct ofconn, node, &ofproto->all_conns) {
+        rconn_reconnect(ofconn->rconn);
+    }
+}
+
 static bool
 any_extras_changed(const struct ofproto *ofproto,
                    const struct sockaddr_in *extras, size_t n)
@@ -1478,7 +1486,7 @@ ofport_remove(struct ofproto *p, struct ofport *ofport)
     uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
 
     netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
-    port_array_set(&p->ports, odp_port, NULL);
+    port_array_delete(&p->ports, odp_port);
     shash_delete(&p->port_by_name,
                  shash_find(&p->port_by_name, (char *) ofport->opp.name));
     if (p->sflow) {
@@ -1798,7 +1806,7 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port)
     }
     for (oa = actions_first(&i, rule->actions, rule->n_actions); oa;
          oa = actions_next(&i)) {
-        if (oa->type == htons(OFPAT_OUTPUT) && oa->output.port == out_port) {
+        if (action_outputs_to_port(oa, out_port)) {
             return true;
         }
     }
@@ -2070,15 +2078,11 @@ is_controller_rule(struct rule *rule)
      * NetFlow expiration messages since it is just part of the control
      * logic for the network and not real traffic. */
 
-    if (rule && rule->super) {
-        struct rule *super = rule->super;
-
-        return super->n_actions == 1 &&
-               super->actions[0].type == htons(OFPAT_OUTPUT) &&
-               super->actions[0].output.port == htons(OFPP_CONTROLLER);
-    }
-
-    return false;
+    return (rule
+            && rule->super
+            && rule->super->n_actions == 1
+            && action_outputs_to_port(&rule->super->actions[0],
+                                      htons(OFPP_CONTROLLER)));
 }
 
 static void
@@ -2195,7 +2199,8 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn,
                          (1u << OFPAT_SET_NW_DST) |
                          (1u << OFPAT_SET_NW_TOS) |
                          (1u << OFPAT_SET_TP_SRC) |
-                         (1u << OFPAT_SET_TP_DST));
+                         (1u << OFPAT_SET_TP_DST) |
+                         (1u << OFPAT_ENQUEUE));
 
     PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
         hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp));
@@ -2272,11 +2277,10 @@ add_output_group_action(struct odp_actions *actions, uint16_t group,
 }
 
 static void
-add_controller_action(struct odp_actions *actions,
-                      const struct ofp_action_output *oao)
+add_controller_action(struct odp_actions *actions, uint16_t max_len)
 {
     union odp_action *a = odp_actions_add(actions, ODPAT_CONTROLLER);
-    a->controller.arg = ntohs(oao->max_len);
+    a->controller.arg = max_len;
 }
 
 struct action_xlate_ctx {
@@ -2368,15 +2372,15 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
 }
 
 static void
-xlate_output_action(struct action_xlate_ctx *ctx,
-                    const struct ofp_action_output *oao)
+xlate_output_action__(struct action_xlate_ctx *ctx,
+                      uint16_t port, uint16_t max_len)
 {
     uint16_t odp_port;
     uint16_t prev_nf_output_iface = ctx->nf_output_iface;
 
     ctx->nf_output_iface = NF_OUT_DROP;
 
-    switch (ntohs(oao->port)) {
+    switch (port) {
     case OFPP_IN_PORT:
         add_output_action(ctx, ctx->flow.in_port);
         break;
@@ -2400,13 +2404,13 @@ xlate_output_action(struct action_xlate_ctx *ctx,
         add_output_group_action(ctx->out, DP_GROUP_ALL, &ctx->nf_output_iface);
         break;
     case OFPP_CONTROLLER:
-        add_controller_action(ctx->out, oao);
+        add_controller_action(ctx->out, max_len);
         break;
     case OFPP_LOCAL:
         add_output_action(ctx, ODPP_LOCAL);
         break;
     default:
-        odp_port = ofp_port_to_odp_port(ntohs(oao->port));
+        odp_port = ofp_port_to_odp_port(port);
         if (odp_port != ctx->flow.in_port) {
             add_output_action(ctx, odp_port);
         }
@@ -2423,6 +2427,65 @@ xlate_output_action(struct action_xlate_ctx *ctx,
     }
 }
 
+static void
+xlate_output_action(struct action_xlate_ctx *ctx,
+                    const struct ofp_action_output *oao)
+{
+    xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len));
+}
+
+/* If the final ODP action in 'ctx' is "pop priority", drop it, as an
+ * optimization, because we're going to add another action that sets the
+ * priority immediately after, or because there are no actions following the
+ * pop.  */
+static void
+remove_pop_action(struct action_xlate_ctx *ctx)
+{
+    size_t n = ctx->out->n_actions;
+    if (n > 0 && ctx->out->actions[n - 1].type == ODPAT_POP_PRIORITY) {
+        ctx->out->n_actions--;
+    }
+}
+
+static void
+xlate_enqueue_action(struct action_xlate_ctx *ctx,
+                     const struct ofp_action_enqueue *oae)
+{
+    uint16_t ofp_port, odp_port;
+    uint32_t priority;
+    int error;
+
+    error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id),
+                                   &priority);
+    if (error) {
+        /* Fall back to ordinary output action. */
+        xlate_output_action__(ctx, ntohs(oae->port), 0);
+        return;
+    }
+
+    /* Figure out ODP output port. */
+    ofp_port = ntohs(oae->port);
+    if (ofp_port != OFPP_IN_PORT) {
+        odp_port = ofp_port_to_odp_port(ofp_port);
+    } else {
+        odp_port = ctx->flow.in_port;
+    }
+
+    /* Add ODP actions. */
+    remove_pop_action(ctx);
+    odp_actions_add(ctx->out, ODPAT_SET_PRIORITY)->priority.priority
+        = priority;
+    add_output_action(ctx, odp_port);
+    odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
+
+    /* Update NetFlow output port. */
+    if (ctx->nf_output_iface == NF_OUT_DROP) {
+        ctx->nf_output_iface = odp_port;
+    } else if (ctx->nf_output_iface != NF_OUT_FLOOD) {
+        ctx->nf_output_iface = NF_OUT_MULTI;
+    }
+}
+
 static void
 xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
@@ -2446,7 +2509,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         break;
 
     /* If you add a new action here that modifies flow data, don't forget to
-     * update the flow key in ctx->flow in the same key. */
+     * update the flow key in ctx->flow at the same time. */
 
     default:
         VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
@@ -2540,6 +2603,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
             break;
 
+        case OFPAT_ENQUEUE:
+            xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
+            break;
+
         default:
             VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
             break;
@@ -2567,6 +2634,7 @@ xlate_actions(const union ofp_action *in, size_t n_in,
     ctx.may_set_up_flow = true;
     ctx.nf_output_iface = NF_OUT_DROP;
     do_xlate_actions(in, n_in, &ctx);
+    remove_pop_action(&ctx);
 
     /* Check with in-band control to see if we're allowed to set up this
      * flow. */
@@ -3144,6 +3212,95 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn,
     return 0;
 }
 
+struct queue_stats_cbdata {
+    struct ofconn *ofconn;
+    struct ofpbuf *msg;
+    uint16_t port_no;
+};
+
+static void
+put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
+                const struct netdev_queue_stats *stats)
+{
+    struct ofp_queue_stats *reply;
+
+    reply = append_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg);
+    reply->port_no = htons(cbdata->port_no);
+    memset(reply->pad, 0, sizeof reply->pad);
+    reply->queue_id = htonl(queue_id);
+    reply->tx_bytes = htonll(stats->tx_bytes);
+    reply->tx_packets = htonll(stats->tx_packets);
+    reply->tx_errors = htonll(stats->tx_errors);
+}
+
+static void
+handle_queue_stats_dump_cb(uint32_t queue_id,
+                           struct netdev_queue_stats *stats,
+                           void *cbdata_)
+{
+    struct queue_stats_cbdata *cbdata = cbdata_;
+
+    put_queue_stats(cbdata, queue_id, stats);
+}
+
+static void
+handle_queue_stats_for_port(struct ofport *port, uint16_t port_no,
+                            uint32_t queue_id,
+                            struct queue_stats_cbdata *cbdata)
+{
+    cbdata->port_no = port_no;
+    if (queue_id == OFPQ_ALL) {
+        netdev_dump_queue_stats(port->netdev,
+                                handle_queue_stats_dump_cb, cbdata);
+    } else {
+        struct netdev_queue_stats stats;
+
+        netdev_get_queue_stats(port->netdev, queue_id, &stats);
+        put_queue_stats(cbdata, queue_id, &stats);
+    }
+}
+
+static int
+handle_queue_stats_request(struct ofproto *ofproto, struct ofconn *ofconn,
+                           const struct ofp_stats_request *osr,
+                           size_t arg_size)
+{
+    struct ofp_queue_stats_request *qsr;
+    struct queue_stats_cbdata cbdata;
+    struct ofport *port;
+    unsigned int port_no;
+    uint32_t queue_id;
+
+    if (arg_size != sizeof *qsr) {
+        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+    }
+    qsr = (struct ofp_queue_stats_request *) osr->body;
+
+    COVERAGE_INC(ofproto_queue_req);
+
+    cbdata.ofconn = ofconn;
+    cbdata.msg = start_stats_reply(osr, 128);
+
+    port_no = ntohs(qsr->port_no);
+    queue_id = ntohl(qsr->queue_id);
+    if (port_no == OFPP_ALL) {
+        PORT_ARRAY_FOR_EACH (port, &ofproto->ports, port_no) {
+            handle_queue_stats_for_port(port, port_no, queue_id, &cbdata);
+        }
+    } else if (port_no < ofproto->max_ports) {
+        port = port_array_get(&ofproto->ports, port_no);
+        if (port) {
+            handle_queue_stats_for_port(port, port_no, queue_id, &cbdata);
+        }
+    } else {
+        ofpbuf_delete(cbdata.msg);
+        return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT);
+    }
+    queue_tx(cbdata.msg, ofconn, ofconn->reply_counter);
+
+    return 0;
+}
+
 static int
 handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
                      struct ofp_header *oh)
@@ -3175,6 +3332,9 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn,
     case OFPST_PORT:
         return handle_port_stats_request(p, ofconn, osr, arg_size);
 
+    case OFPST_QUEUE:
+        return handle_queue_stats_request(p, ofconn, osr, arg_size);
+
     case OFPST_VENDOR:
         return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
 
@@ -3492,6 +3652,7 @@ static int
 handle_flow_mod(struct ofproto *p, struct ofconn *ofconn,
                 struct ofp_flow_mod *ofm)
 {
+    struct ofp_match orig_match;
     size_t n_actions;
     int error;
 
@@ -3513,7 +3674,25 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn,
         return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
     }
 
+    /* Normalize ofp->match.  If normalization actually changes anything, then
+     * log the differences. */
+    ofm->match.pad1[0] = ofm->match.pad2[0] = 0;
+    orig_match = ofm->match;
     normalize_match(&ofm->match);
+    if (memcmp(&ofm->match, &orig_match, sizeof orig_match)) {
+        static struct vlog_rate_limit normal_rl = VLOG_RATE_LIMIT_INIT(1, 1);
+        if (!VLOG_DROP_INFO(&normal_rl)) {
+            char *old = ofp_match_to_literal_string(&orig_match);
+            char *new = ofp_match_to_literal_string(&ofm->match);
+            VLOG_INFO("%s: normalization changed ofp_match, details:",
+                      rconn_get_name(ofconn->rconn));
+            VLOG_INFO(" pre: %s", old);
+            VLOG_INFO("post: %s", new);
+            free(old);
+            free(new);
+        }
+    }
+
     if (!ofm->match.wildcards) {
         ofm->priority = htons(UINT16_MAX);
     }