datapath: Convert odp_flow_key to use Netlink attributes instead.
[sliver-openvswitch.git] / ofproto / ofproto.c
index 5fef092..fe58e7b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
  * Copyright (c) 2010 Jean Tourrilhes - HP-Labs.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +35,7 @@
 #include "hmap.h"
 #include "in-band.h"
 #include "mac-learning.h"
+#include "multipath.h"
 #include "netdev.h"
 #include "netflow.h"
 #include "netlink.h"
@@ -1353,6 +1354,60 @@ ofproto_is_alive(const struct ofproto *p)
     return !hmap_is_empty(&p->controllers);
 }
 
+void
+ofproto_get_ofproto_controller_info(const struct ofproto * ofproto,
+                                    struct shash *info)
+{
+    const struct ofconn *ofconn;
+
+    shash_init(info);
+
+    HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) {
+        const struct rconn *rconn = ofconn->rconn;
+        const int last_error = rconn_get_last_error(rconn);
+        struct ofproto_controller_info *cinfo = xmalloc(sizeof *cinfo);
+
+        shash_add(info, rconn_get_target(rconn), cinfo);
+
+        cinfo->is_connected = rconn_is_connected(rconn);
+        cinfo->role = ofconn->role;
+
+        cinfo->pairs.n = 0;
+
+        if (last_error == EOF) {
+            cinfo->pairs.keys[cinfo->pairs.n] = "last_error";
+            cinfo->pairs.values[cinfo->pairs.n++] = xstrdup("End of file");
+        } else if (last_error > 0) {
+            cinfo->pairs.keys[cinfo->pairs.n] = "last_error";
+            cinfo->pairs.values[cinfo->pairs.n++] =
+                xstrdup(strerror(last_error));
+        }
+
+        cinfo->pairs.keys[cinfo->pairs.n] = "state";
+        cinfo->pairs.values[cinfo->pairs.n++] =
+            xstrdup(rconn_get_state(rconn));
+
+        cinfo->pairs.keys[cinfo->pairs.n] = "time_in_state";
+        cinfo->pairs.values[cinfo->pairs.n++] =
+            xasprintf("%u", rconn_get_state_elapsed(rconn));
+    }
+}
+
+void
+ofproto_free_ofproto_controller_info(struct shash *info)
+{
+    struct shash_node *node;
+
+    SHASH_FOR_EACH (node, info) {
+        struct ofproto_controller_info *cinfo = node->data;
+        while (cinfo->pairs.n) {
+            free((char *) cinfo->pairs.values[--cinfo->pairs.n]);
+        }
+        free(cinfo);
+    }
+    shash_destroy(info);
+}
+
 /* Deletes port number 'odp_port' from the datapath for 'ofproto'.
  *
  * This is almost the same as calling dpif_port_del() directly on the
@@ -1480,7 +1535,8 @@ ofproto_flush_flows(struct ofproto *ofproto)
 static void
 reinit_ports(struct ofproto *p)
 {
-    struct svec devnames;
+    struct shash_node *node;
+    struct shash devnames;
     struct ofport *ofport;
     struct odp_port *odp_ports;
     size_t n_odp_ports;
@@ -1488,21 +1544,20 @@ reinit_ports(struct ofproto *p)
 
     COVERAGE_INC(ofproto_reinit_ports);
 
-    svec_init(&devnames);
+    shash_init(&devnames);
     HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
-        svec_add (&devnames, ofport->opp.name);
+        shash_add_once (&devnames, ofport->opp.name, NULL);
     }
     dpif_port_list(p->dpif, &odp_ports, &n_odp_ports);
     for (i = 0; i < n_odp_ports; i++) {
-        svec_add (&devnames, odp_ports[i].devname);
+        shash_add_once (&devnames, odp_ports[i].devname, NULL);
     }
     free(odp_ports);
 
-    svec_sort_unique(&devnames);
-    for (i = 0; i < devnames.n; i++) {
-        update_port(p, devnames.names[i]);
+    SHASH_FOR_EACH (node, &devnames) {
+        update_port(p, node->name);
     }
-    svec_destroy(&devnames);
+    shash_destroy(&devnames);
 }
 
 static struct ofport *
@@ -2268,8 +2323,16 @@ static int
 facet_put__(struct ofproto *ofproto, struct facet *facet, int flags,
             struct odp_flow_put *put)
 {
+    uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
+    struct ofpbuf key;
+
+    ofpbuf_use_stack(&key, keybuf, sizeof keybuf);
+    odp_flow_key_from_flow(&key, &facet->flow);
+    assert(key.base == keybuf);
+
     memset(&put->flow.stats, 0, sizeof put->flow.stats);
-    odp_flow_key_from_flow(&put->flow.key, &facet->flow);
+    put->flow.key = key.data;
+    put->flow.key_len = key.size;
     put->flow.actions = facet->actions;
     put->flow.actions_len = facet->actions_len;
     put->flow.flags = 0;
@@ -2320,9 +2383,16 @@ static void
 facet_uninstall(struct ofproto *p, struct facet *facet)
 {
     if (facet->installed) {
+        uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
         struct odp_flow odp_flow;
+        struct ofpbuf key;
 
-        odp_flow_key_from_flow(&odp_flow.key, &facet->flow);
+        ofpbuf_use_stack(&key, keybuf, sizeof keybuf);
+        odp_flow_key_from_flow(&key, &facet->flow);
+        assert(key.base == keybuf);
+
+        odp_flow.key = key.data;
+        odp_flow.key_len = key.size;
         odp_flow.actions = NULL;
         odp_flow.actions_len = 0;
         odp_flow.flags = 0;
@@ -2458,10 +2528,16 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet)
      * to talk to the datapath. */
     if (actions_changed || facet->may_install != facet->installed) {
         if (facet->may_install) {
+            uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
             struct odp_flow_put put;
+            struct ofpbuf key;
+
+            ofpbuf_use_stack(&key, keybuf, sizeof keybuf);
+            odp_flow_key_from_flow(&key, &facet->flow);
 
             memset(&put.flow.stats, 0, sizeof put.flow.stats);
-            odp_flow_key_from_flow(&put.flow.key, &facet->flow);
+            put.flow.key = key.data;
+            put.flow.key_len = key.size;
             put.flow.actions = odp_actions->data;
             put.flow.actions_len = odp_actions->size;
             put.flow.flags = 0;
@@ -2514,7 +2590,7 @@ static void
 send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh,
               int error)
 {
-    struct ofpbuf *buf = make_ofp_error_msg(error, oh);
+    struct ofpbuf *buf = ofputil_encode_error_msg(error, oh);
     if (buf) {
         COVERAGE_INC(ofproto_error);
         queue_tx(buf, ofconn, ofconn->reply_counter);
@@ -2622,7 +2698,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
 
 /* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a
  * flow translation. */
-#define MAX_RESUBMIT_RECURSION 8
+#define MAX_RESUBMIT_RECURSION 16
 
 static void do_xlate_actions(const union ofp_action *in, size_t n_in,
                              struct action_xlate_ctx *ctx);
@@ -2680,7 +2756,7 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
             ctx->recurse--;
         }
     } else {
-        struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
+        static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
         VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times",
                     MAX_RESUBMIT_RECURSION);
@@ -2857,17 +2933,29 @@ xlate_set_dl_tci(struct action_xlate_ctx *ctx)
     }
 }
 
+struct xlate_reg_state {
+    ovs_be16 vlan_tci;
+    ovs_be64 tun_id;
+};
+
 static void
-xlate_reg_move_action(struct action_xlate_ctx *ctx,
-                      const struct nx_action_reg_move *narm)
+save_reg_state(const struct action_xlate_ctx *ctx,
+               struct xlate_reg_state *state)
 {
-    ovs_be16 old_tci = ctx->flow.vlan_tci;
-
-    nxm_execute_reg_move(narm, &ctx->flow);
+    state->vlan_tci = ctx->flow.vlan_tci;
+    state->tun_id = ctx->flow.tun_id;
+}
 
-    if (ctx->flow.vlan_tci != old_tci) {
+static void
+update_reg_state(struct action_xlate_ctx *ctx,
+                 const struct xlate_reg_state *state)
+{
+    if (ctx->flow.vlan_tci != state->vlan_tci) {
         xlate_set_dl_tci(ctx);
     }
+    if (ctx->flow.tun_id != state->tun_id) {
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, ctx->flow.tun_id);
+    }
 }
 
 static void
@@ -2877,7 +2965,9 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
     const struct nx_action_set_queue *nasq;
+    const struct nx_action_multipath *nam;
     enum nx_action_subtype subtype = ntohs(nah->subtype);
+    struct xlate_reg_state state;
     ovs_be64 tun_id;
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
@@ -2910,12 +3000,18 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         break;
 
     case NXAST_REG_MOVE:
-        xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah);
+        save_reg_state(ctx, &state);
+        nxm_execute_reg_move((const struct nx_action_reg_move *) nah,
+                             &ctx->flow);
+        update_reg_state(ctx, &state);
         break;
 
     case NXAST_REG_LOAD:
+        save_reg_state(ctx, &state);
         nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
                              &ctx->flow);
+        update_reg_state(ctx, &state);
+        break;
 
     case NXAST_NOTE:
         /* Nothing to do. */
@@ -2927,6 +3023,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         ctx->flow.tun_id = tun_id;
         break;
 
+    case NXAST_MULTIPATH:
+        nam = (const struct nx_action_multipath *) nah;
+        multipath_execute(nam, &ctx->flow);
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow at the same time. */
 
@@ -3390,42 +3491,44 @@ static void
 query_stats(struct ofproto *p, struct rule *rule,
             uint64_t *packet_countp, uint64_t *byte_countp)
 {
+    uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
     uint64_t packet_count, byte_count;
     struct facet *facet;
-    struct odp_flow *odp_flows;
-    size_t n_odp_flows;
+    struct ofpbuf key;
 
     /* Start from historical data for 'rule' itself that are no longer tracked
      * by the datapath.  This counts, for example, facets that have expired. */
     packet_count = rule->packet_count;
     byte_count = rule->byte_count;
 
-    /* Prepare to ask the datapath for statistics on all of the rule's facets.
+    /* Ask the datapath for statistics on all of the rule's facets.  (We could
+     * batch up statistics requests using dpif_flow_get_multiple(), but that is
+     * not yet implemented.)
      *
      * Also, add any statistics that are not tracked by the datapath for each
      * facet.  This includes, for example, statistics for packets that were
      * executed "by hand" by ofproto via dpif_execute() but must be accounted
      * to a rule. */
-    odp_flows = xzalloc(list_size(&rule->facets) * sizeof *odp_flows);
-    n_odp_flows = 0;
+    ofpbuf_use_stack(&key, keybuf, sizeof keybuf);
     LIST_FOR_EACH (facet, list_node, &rule->facets) {
-        struct odp_flow *odp_flow = &odp_flows[n_odp_flows++];
-        odp_flow_key_from_flow(&odp_flow->key, &facet->flow);
-        packet_count += facet->packet_count;
-        byte_count += facet->byte_count;
-    }
+        struct odp_flow odp_flow;
 
-    /* Fetch up-to-date statistics from the datapath and add them in. */
-    if (!dpif_flow_get_multiple(p->dpif, odp_flows, n_odp_flows)) {
-        size_t i;
+        ofpbuf_clear(&key);
+        odp_flow_key_from_flow(&key, &facet->flow);
 
-        for (i = 0; i < n_odp_flows; i++) {
-            struct odp_flow *odp_flow = &odp_flows[i];
-            packet_count += odp_flow->stats.n_packets;
-            byte_count += odp_flow->stats.n_bytes;
+        odp_flow.key = key.data;
+        odp_flow.key_len = key.size;
+        odp_flow.actions = NULL;
+        odp_flow.actions_len = 0;
+        odp_flow.flags = 0;
+        if (!dpif_flow_get(p->dpif, &odp_flow)) {
+            packet_count += odp_flow.stats.n_packets;
+            byte_count += odp_flow.stats.n_bytes;
         }
+
+        packet_count += facet->packet_count;
+        byte_count += facet->byte_count;
     }
-    free(odp_flows);
 
     /* Return the stats to the caller. */
     *packet_countp = packet_count;
@@ -3523,8 +3626,8 @@ put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule,
 
     act_len = sizeof *rule->actions * rule->n_actions;
 
-    start_len = (*replyp)->size;
     append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, ofconn, replyp);
+    start_len = (*replyp)->size;
     reply = *replyp;
 
     nfs = ofpbuf_put_uninit(reply, sizeof *nfs);
@@ -4463,36 +4566,50 @@ ofproto_expire(struct ofproto *ofproto)
 static void
 ofproto_update_used(struct ofproto *p)
 {
-    struct odp_flow *flows;
-    size_t n_flows;
-    size_t i;
-    int error;
-
-    error = dpif_flow_list_all(p->dpif, &flows, &n_flows);
-    if (error) {
-        return;
-    }
+    struct dpif_flow_dump dump;
 
-    for (i = 0; i < n_flows; i++) {
-        struct odp_flow *f = &flows[i];
+    dpif_flow_dump_start(&dump, p->dpif);
+    for (;;) {
+        uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
         struct facet *facet;
+        struct odp_flow f;
         struct flow flow;
 
-        odp_flow_key_to_flow(&f->key, &flow);
+        memset(&f, 0, sizeof f);
+        f.key = (struct nlattr *) keybuf;
+        f.key_len = sizeof keybuf;
+        if (!dpif_flow_dump_next(&dump, &f)) {
+            break;
+        }
+
+        if (f.key_len > sizeof keybuf) {
+            VLOG_WARN_RL(&rl, "ODP flow key overflowed buffer");
+            continue;
+        }
+        if (odp_flow_key_to_flow(f.key, f.key_len, &flow)) {
+            struct ds s;
+
+            ds_init(&s);
+            odp_flow_key_format(f.key, f.key_len, &s);
+            VLOG_WARN_RL(&rl, "failed to convert ODP flow key to flow: %s",
+                         ds_cstr(&s));
+            ds_destroy(&s);
+
+            continue;
+        }
         facet = facet_find(p, &flow);
 
         if (facet && facet->installed) {
-            facet_update_time(p, facet, &f->stats);
-            facet_account(p, facet, f->stats.n_bytes);
+            facet_update_time(p, facet, &f.stats);
+            facet_account(p, facet, f.stats.n_bytes);
         } else {
             /* There's a flow in the datapath that we know nothing about.
              * Delete it. */
             COVERAGE_INC(ofproto_unexpected_rule);
-            dpif_flow_del(p->dpif, f);
+            dpif_flow_del(p->dpif, &f);
         }
-
     }
-    free(flows);
+    dpif_flow_dump_done(&dump);
 }
 
 /* Calculates and returns the number of milliseconds of idle time after which
@@ -4600,7 +4717,14 @@ facet_active_timeout(struct ofproto *ofproto, struct facet *facet)
          * ofproto_update_used() zeroed TCP flags. */
         memset(&odp_flow, 0, sizeof odp_flow);
         if (facet->installed) {
-            odp_flow_key_from_flow(&odp_flow.key, &facet->flow);
+            uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
+            struct ofpbuf key;
+
+            ofpbuf_use_stack(&key, keybuf, sizeof keybuf);
+            odp_flow_key_from_flow(&key, &facet->flow);
+
+            odp_flow.key = key.data;
+            odp_flow.key_len = key.size;
             odp_flow.flags = ODPFF_ZERO_TCP_FLAGS;
             dpif_flow_get(ofproto->dpif, &odp_flow);
 
@@ -4678,7 +4802,7 @@ compose_ofp_flow_removed(struct ofconn *ofconn, const struct rule *rule,
     struct ofp_flow_removed *ofr;
     struct ofpbuf *buf;
 
-    ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf);
+    ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0), &buf);
     ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match,
                               rule->flow_cookie, &ofr->cookie);
     ofr->priority = htons(rule->cr.priority);
@@ -4698,9 +4822,9 @@ compose_nx_flow_removed(const struct rule *rule, uint8_t reason)
     struct ofpbuf *buf;
     int match_len;
 
-    make_nxmsg(sizeof *nfr, NXT_FLOW_REMOVED, &buf);
-
+    make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &buf);
     match_len = nx_put_match(buf, &rule->cr);
+
     nfr = buf->data;
     nfr->cookie = rule->flow_cookie;
     nfr->priority = htons(rule->cr.priority);
@@ -5000,7 +5124,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
     struct ds result;
     struct flow flow;
     uint16_t in_port;
-    ovs_be32 tun_id;
+    ovs_be64 tun_id;
     char *s;
 
     ofpbuf_init(&packet, strlen(args) / 2);
@@ -5022,7 +5146,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
         goto exit;
     }
 
-    tun_id = ntohl(strtoul(tun_id_s, NULL, 10));
+    tun_id = htonll(strtoull(tun_id_s, NULL, 10));
     in_port = ofp_port_to_odp_port(atoi(in_port_s));
 
     packet_s = ofpbuf_put_hex(&packet, packet_s, NULL);