vswitch: Fix schema version number.
[openvswitch] / ofproto / ofproto.c
index 45b9d460fb53030c467c5e40407bb164a8205718..aae85680ce72c34724586b69f29917575042cd98 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"
@@ -225,7 +226,7 @@ struct facet {
     bool installed;              /* Installed in datapath? */
     bool may_install;            /* True ordinarily; false if actions must
                                   * be reassessed for every packet. */
-    unsigned int actions_len;    /* Number of bytes in actions[]. */
+    size_t actions_len;          /* Number of bytes in actions[]. */
     struct nlattr *actions;      /* Datapath actions. */
     tag_type tags;               /* Tags (set only by hooks). */
     struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
@@ -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 *
@@ -2050,10 +2105,10 @@ rule_has_out_port(const struct rule *rule, ovs_be16 out_port)
  * Takes ownership of 'packet'. */
 static bool
 execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
-                    const struct nlattr *odp_actions, unsigned int actions_len,
+                    const struct nlattr *odp_actions, size_t actions_len,
                     struct ofpbuf *packet)
 {
-    if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint32_t))
+    if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t))
         && odp_actions->nla_type == ODPAT_CONTROLLER) {
         /* As an optimization, avoid a round-trip from userspace to kernel to
          * userspace.  This also avoids possibly filling up kernel packet
@@ -2064,8 +2119,7 @@ execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
         msg->type = _ODPL_ACTION_NR;
         msg->length = sizeof(struct odp_msg) + packet->size;
         msg->port = in_port;
-        msg->reserved = 0;
-        msg->arg = nl_attr_get_u32(odp_actions);
+        msg->arg = nl_attr_get_u64(odp_actions);
 
         send_packet_in(ofproto, packet);
 
@@ -2251,6 +2305,9 @@ facet_make_actions(struct ofproto *p, struct facet *facet,
 
     action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
     odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions);
+    facet->tags = ctx.tags;
+    facet->may_install = ctx.may_set_up_flow;
+    facet->nf_flow.output_iface = ctx.nf_output_iface;
 
     if (facet->actions_len != odp_actions->size
         || memcmp(facet->actions, odp_actions->data, odp_actions->size)) {
@@ -2476,8 +2533,6 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet)
         facet_flush_stats(ofproto, facet);
     }
 
-    ofpbuf_delete(odp_actions);
-
     /* Update 'facet' now that we've taken care of all the old state. */
     facet->tags = ctx.tags;
     facet->nf_flow.output_iface = ctx.nf_output_iface;
@@ -2495,6 +2550,8 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet)
         facet->used = new_rule->created;
     }
 
+    ofpbuf_delete(odp_actions);
+
     return true;
 }
 \f
@@ -2512,7 +2569,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);
@@ -2620,7 +2677,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);
@@ -2678,7 +2735,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);
@@ -2734,7 +2791,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
                       &ctx->nf_output_iface, ctx->odp_actions);
         break;
     case OFPP_CONTROLLER:
-        nl_msg_put_u32(ctx->odp_actions, ODPAT_CONTROLLER, max_len);
+        nl_msg_put_u64(ctx->odp_actions, ODPAT_CONTROLLER, max_len);
         break;
     case OFPP_LOCAL:
         add_output_action(ctx, ODPP_LOCAL);
@@ -2855,17 +2912,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
@@ -2875,7 +2944,10 @@ 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));
     switch (subtype) {
@@ -2886,8 +2958,9 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
 
     case NXAST_SET_TUNNEL:
         nast = (const struct nx_action_set_tunnel *) nah;
-        nl_msg_put_be32(ctx->odp_actions, ODPAT_SET_TUNNEL, nast->tun_id);
-        ctx->flow.tun_id = nast->tun_id;
+        tun_id = htonll(ntohl(nast->tun_id));
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, tun_id);
+        ctx->flow.tun_id = tun_id;
         break;
 
     case NXAST_DROP_SPOOFED_ARP:
@@ -2906,17 +2979,34 @@ 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. */
         break;
 
+    case NXAST_SET_TUNNEL64:
+        tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id;
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, tun_id);
+        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. */
 
@@ -3248,7 +3338,7 @@ make_nxstats_reply(ovs_be32 xid, ovs_be32 subtype, size_t body_len)
     nsm->type = htons(OFPST_VENDOR);
     nsm->flags = htons(0);
     nsm->vendor = htonl(NX_VENDOR_ID);
-    nsm->subtype = htonl(subtype);
+    nsm->subtype = subtype;
     return msg;
 }
 
@@ -3451,9 +3541,9 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule,
     ofs->length = htons(len);
     ofs->table_id = 0;
     ofs->pad = 0;
-    ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match);
+    ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofs->match,
+                              rule->flow_cookie, &ofs->cookie);
     calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec);
-    ofs->cookie = rule->flow_cookie;
     ofs->priority = htons(rule->cr.priority);
     ofs->idle_timeout = htons(rule->idle_timeout);
     ofs->hard_timeout = htons(rule->hard_timeout);
@@ -3513,8 +3603,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);
@@ -4668,9 +4758,9 @@ 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);
-    ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match);
-    ofr->cookie = rule->flow_cookie;
+    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);
     ofr->reason = reason;
     calc_flow_duration(rule->created, &ofr->duration_sec, &ofr->duration_nsec);
@@ -4688,10 +4778,10 @@ compose_nx_flow_removed(const struct rule *rule, uint8_t reason)
     struct ofpbuf *buf;
     int match_len;
 
-    nfr = 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);
     nfr->reason = reason;
@@ -4990,7 +5080,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);
@@ -5012,7 +5102,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);