Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 24 Sep 2012 13:26:21 +0000 (15:26 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 24 Sep 2012 13:26:21 +0000 (15:26 +0200)
37 files changed:
AUTHORS
FAQ
NEWS
datapath/datapath.c
datapath/vport.c
include/openflow/openflow-1.0.h
include/openflow/openflow-1.1.h
include/openflow/openflow-1.2.h
lib/autopath.c
lib/bundle.c
lib/flow.c
lib/meta-flow.c
lib/nx-match.c
lib/nx-match.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-parse.c
lib/ofp-util.c
lib/ofp-util.h
lib/stream-unix.c
lib/unixctl.c
ofproto/connmgr.c
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ovsdb/ovsdb-client.c
ovsdb/ovsdb-tool.1.in
python/ovs/jsonrpc.py
tests/autopath.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ofproto.at
tests/test-netflow.c
utilities/ovs-lib.in
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
vswitchd/bridge.c

diff --git a/AUTHORS b/AUTHORS
index 70257e5..1ed8676 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,7 @@ Alexey I. Froloff       raorn@altlinux.org
 Andrew Evans            aevans@nicira.com
 Andrew Lambeth          wal@nicira.com
 Andy Southgate          andy.southgate@citrix.com
+Anupam Chanda           achanda@nicira.com
 Arun Sharma             arun.sharma@calsoftinc.com
 Ben Pfaff               blp@nicira.com
 Brian Kruger            bkruger+ovsdev@gmail.com
diff --git a/FAQ b/FAQ
index ae904f1..a98739c 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -740,6 +740,13 @@ A: The OFPT_FEATURES_REQUEST message requests an OpenFlow switch to
    normally an intermittent condition (unless ovs-vswitchd is not
    running).
 
+Q: I added some flows with my controller or with ovs-ofctl, but when I
+   run "ovs-dpctl dump-flows" I don't see them.
+
+A: ovs-dpctl queries a kernel datapath, not an OpenFlow switch.  It
+   won't display the information that you want.  You want to use
+   "ovs-ofctl dump-flows" instead.
+
 Contact 
 -------
 
diff --git a/NEWS b/NEWS
index cbc5c58..38e5129 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,14 @@ post-v1.8.0
     - OpenFlow:
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
+    - ovs-ofctl:
+      - Commands and actions that accept port numbers now also accept keywords
+        that represent those ports (such as LOCAL, NONE, and ALL).  This is
+        also the recommended way to specify these ports, for compatibility
+        with OpenFlow 1.1 and later (which use the OpenFlow 1.0 numbers
+        for these ports for different purposes).
+      - Commands and actions that accept port numbers no longer accept port 0,
+        which is not a valid port number in OpenFlow 1.0 and later.
     - ovs-dpctl:
       - Support requesting the port number with the "port_no" option in
         the "add-if" command.
index c83ce16..a6915fb 100644 (file)
@@ -2257,3 +2257,4 @@ module_exit(dp_cleanup);
 
 MODULE_DESCRIPTION("Open vSwitch switching datapath");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
index 172261a..dc7adfa 100644 (file)
@@ -522,7 +522,7 @@ void ovs_vport_record_error(struct vport *vport, enum vport_err_type err_type)
        case VPORT_E_TX_ERROR:
                vport->err_stats.tx_errors++;
                break;
-       };
+       }
 
        spin_unlock(&vport->stats_lock);
 }
index 56af4c5..9af7740 100644 (file)
 
 #include "openflow/openflow-common.h"
 
-/* Port numbering.  Physical ports are numbered starting from 1. */
+/* Port number(s)   meaning
+ * ---------------  --------------------------------------
+ * 0x0000           not assigned a meaning by OpenFlow 1.0
+ * 0x0001...0xfeff  "physical" ports
+ * 0xff00...0xfff7  "reserved" but not assigned a meaning by OpenFlow 1.0
+ * 0xfff8...0xffff  "reserved" OFPP_* ports with assigned meanings
+ */
 enum ofp_port {
-    /* Maximum number of physical switch ports. */
-    OFPP_MAX = 0xff00,
+    /* Ranges. */
+    OFPP_MAX        = 0xff00,   /* Maximum number of physical switch ports. */
+    OFPP_FIRST_RESV = 0xfff8,   /* First assigned reserved port number. */
+    OFPP_LAST_RESV  = 0xffff,   /* Last assigned reserved port number. */
 
-    /* Fake output "ports". */
+    /* Reserved output "ports". */
     OFPP_IN_PORT    = 0xfff8,  /* Send the packet out the input port.  This
                                   virtual port must be explicitly used
                                   in order to send back out of the input
index 696c3ec..9785db4 100644 (file)
@@ -281,6 +281,10 @@ enum ofp11_instruction_type {
     OFPIT11_EXPERIMENTER = 0xFFFF  /* Experimenter instruction */
 };
 
+#define OFPIT11_ALL (OFPIT11_GOTO_TABLE | OFPIT11_WRITE_METADATA |      \
+                     OFPIT11_WRITE_ACTIONS | OFPIT11_APPLY_ACTIONS |    \
+                     OFPIT11_CLEAR_ACTIONS)
+
 #define OFP11_INSTRUCTION_ALIGN 8
 
 /* Generic ofp_instruction structure. */
@@ -588,6 +592,26 @@ OFP_ASSERT(sizeof(struct ofp11_flow_stats) == 48);
 /* Body for ofp_stats_request of type OFPST_AGGREGATE. */
 /* Identical to ofp11_flow_stats_request */
 
+/* Flow match fields. */
+enum ofp11_flow_match_fields {
+    OFPFMF11_IN_PORT     = 1 << 0,  /* Switch input port. */
+    OFPFMF11_DL_VLAN     = 1 << 1,  /* VLAN id. */
+    OFPFMF11_DL_VLAN_PCP = 1 << 2,  /* VLAN priority. */
+    OFPFMF11_DL_TYPE     = 1 << 3,  /* Ethernet frame type. */
+    OFPFMF11_NW_TOS      = 1 << 4,  /* IP ToS (DSCP field, 6 bits). */
+    OFPFMF11_NW_PROTO    = 1 << 5,  /* IP protocol. */
+    OFPFMF11_TP_SRC      = 1 << 6,  /* TCP/UDP/SCTP source port. */
+    OFPFMF11_TP_DST      = 1 << 7,  /* TCP/UDP/SCTP destination port. */
+    OFPFMF11_MPLS_LABEL  = 1 << 8,  /* MPLS label. */
+    OFPFMF11_MPLS_TC     = 1 << 9,  /* MPLS TC. */
+    OFPFMF11_TYPE        = 1 << 10, /* Match type. */
+    OFPFMF11_DL_SRC      = 1 << 11, /* Ethernet source address. */
+    OFPFMF11_DL_DST      = 1 << 12, /* Ethernet destination address. */
+    OFPFMF11_NW_SRC      = 1 << 13, /* IP source address. */
+    OFPFMF11_NW_DST      = 1 << 14, /* IP destination address. */
+    OFPFMF11_METADATA    = 1 << 15, /* Metadata passed between tables. */
+};
+
 /* Body of reply to OFPST_TABLE request. */
 struct ofp11_table_stats {
     uint8_t table_id;        /* Identifier of table. Lower numbered tables
index 0a73ed1..f6befdb 100644 (file)
@@ -106,8 +106,13 @@ enum oxm12_ofb_match_fields {
     OFPXMT12_OFB_IPV6_ND_TLL,    /* Target link-layer for ND. */
     OFPXMT12_OFB_MPLS_LABEL,     /* MPLS label. */
     OFPXMT12_OFB_MPLS_TC,        /* MPLS TC. */
+
+    /* End Marker */
+    OFPXMT12_OFB_MAX,
 };
 
+#define OFPXMT12_MASK ((1ULL << OFPXMT12_OFB_MAX) - 1)
+
 /* OXM implementation makes use of NXM as they are the same format
  * with different field definitions
  */
@@ -216,12 +221,11 @@ enum ofp12_controller_max_len {
 struct ofp12_action_set_field {
     ovs_be16 type;                  /* OFPAT12_SET_FIELD. */
     ovs_be16 len;                   /* Length is padded to 64 bits. */
+    ovs_be32 dst;                   /* OXM TLV header */
     /* Followed by:
-     * - Exactly oxm_len bytes containing a single OXM TLV, then
      * - Exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4) (between 0 and 7)
      *   bytes of all-zero bytes
      */
-    uint8_t field[4];               /* OXM TLV - Make compiler happy */
 };
 OFP_ASSERT(sizeof(struct ofp12_action_set_field) == 8);
 
index ae8007d..b204e84 100644 (file)
@@ -36,7 +36,6 @@ void
 autopath_parse(struct ofpact_autopath *ap, const char *s_)
 {
     char *s;
-    int id_int;
     char *id_str, *dst, *save_ptr;
 
     ofpact_init_AUTOPATH(ap);
@@ -50,12 +49,10 @@ autopath_parse(struct ofpact_autopath *ap, const char *s_)
         ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
     }
 
-    id_int = atoi(id_str);
-    if (id_int < 1 || id_int > UINT32_MAX) {
-        ovs_fatal(0, "%s: autopath id %d is not in valid range "
-                  "1 to %"PRIu32, s_, id_int, UINT32_MAX);
+    ap->port = ofputil_port_from_string(id_str);
+    if (!ap->port) {
+        ovs_fatal(0, "%s: bad port number", s_);
     }
-    ap->port = id_int;
 
     mf_parse_subfield(&ap->dst, dst);
     if (ap->dst.n_bits < 16) {
index e0f8e6b..b68ebab 100644 (file)
@@ -267,12 +267,15 @@ bundle_parse__(const char *s, char **save_ptr,
         uint16_t slave_port;
         char *slave;
 
-        slave = strtok_r(NULL, ", [", save_ptr);
+        slave = strtok_r(NULL, ", []", save_ptr);
         if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
             break;
         }
 
-        slave_port = atoi(slave);
+        slave_port = ofputil_port_from_string(slave);
+        if (!slave_port) {
+            ovs_fatal(0, "%s: bad port number", slave);
+        }
         ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);
 
         bundle = ofpacts->l2;
@@ -387,7 +390,7 @@ bundle_format(const struct ofpact_bundle *bundle, struct ds *s)
             ds_put_cstr(s, ",");
         }
 
-        ds_put_format(s, "%"PRIu16, bundle->slaves[i]);
+        ofputil_format_port(bundle->slaves[i], s);
     }
 
     ds_put_cstr(s, ")");
index a2172a9..e517a03 100644 (file)
@@ -509,7 +509,8 @@ flow_format(struct ds *ds, const struct flow *flow)
         ds_put_cstr(ds, "->");
         print_ipv6_addr(ds, &flow->ipv6_dst);
         ds_put_char(ds, ')');
-    } else {
+    } else if (flow->dl_type == htons(ETH_TYPE_IP) ||
+               flow->dl_type == htons(ETH_TYPE_ARP)) {
         ds_put_format(ds, " proto:%"PRIu8" tos:%#"PRIx8" ttl:%"PRIu8
                           " ip("IP_FMT"->"IP_FMT")",
                           flow->nw_proto, flow->nw_tos, flow->nw_ttl,
index aa44ce8..38c9a27 100644 (file)
@@ -1941,7 +1941,8 @@ mf_from_ofp_port_string(const struct mf_field *mf, const char *s,
     uint16_t port;
 
     assert(mf->n_bytes == sizeof(ovs_be16));
-    if (ofputil_port_from_string(s, &port)) {
+    port = ofputil_port_from_string(s);
+    if (port) {
         *valuep = htons(port);
         *maskp = htons(UINT16_MAX);
         return NULL;
index 17ef160..6ea0642 100644 (file)
@@ -1019,14 +1019,39 @@ nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s)
     mf_format_subfield(&move->dst, s);
 }
 
-void
-nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s)
+static void
+set_field_format(const struct ofpact_reg_load *load, struct ds *s)
+{
+    const struct mf_field *mf = load->dst.field;
+    union mf_value value;
+
+    assert(load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD);
+    ds_put_format(s, "set_field:");
+    memset(&value, 0, sizeof value);
+    bitwise_copy(&load->subvalue, sizeof load->subvalue, 0,
+                 &value, mf->n_bytes, 0, load->dst.n_bits);
+    mf_format(mf, &value, NULL, s);
+    ds_put_format(s, "->%s", mf->name);
+}
+
+static void
+load_format(const struct ofpact_reg_load *load, struct ds *s)
 {
     ds_put_cstr(s, "load:");
     mf_format_subvalue(&load->subvalue, s);
     ds_put_cstr(s, "->");
     mf_format_subfield(&load->dst, s);
 }
+
+void
+nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s)
+{
+    if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) {
+        set_field_format(load, s);
+    } else {
+        load_format(load, s);
+    }
+}
 \f
 enum ofperr
 nxm_reg_move_from_openflow(const struct nx_action_reg_move *narm,
@@ -1066,6 +1091,43 @@ nxm_reg_load_from_openflow(const struct nx_action_reg_load *narl,
 
     return nxm_reg_load_check(load, NULL);
 }
+
+enum ofperr
+nxm_reg_load_from_openflow12_set_field(
+    const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts)
+{
+    uint16_t oasf_len = ntohs(oasf->len);
+    uint32_t oxm_header = ntohl(oasf->dst);
+    uint8_t oxm_length = NXM_LENGTH(oxm_header);
+    struct ofpact_reg_load *load;
+    const struct mf_field *mf;
+
+    /* ofp12_action_set_field is padded to 64 bits by zero */
+    if (oasf_len != ROUND_UP(sizeof(*oasf) + oxm_length, 8)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    if (!is_all_zeros((const uint8_t *)(oasf) + sizeof *oasf + oxm_length,
+                      oasf_len - oxm_length - sizeof *oasf)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+
+    if (NXM_HASMASK(oxm_header)) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    mf = mf_from_nxm_header(oxm_header);
+    if (!mf) {
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+    load = ofpact_put_REG_LOAD(ofpacts);
+    load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD;
+    load->dst.field = mf;
+    load->dst.ofs = 0;
+    load->dst.n_bits = mf->n_bits;
+    bitwise_copy(oasf + 1, mf->n_bytes, load->dst.ofs,
+                 &load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
+
+    return nxm_reg_load_check(load, NULL);
+}
 \f
 enum ofperr
 nxm_reg_move_check(const struct ofpact_reg_move *move, const struct flow *flow)
@@ -1100,9 +1162,8 @@ nxm_reg_move_to_nxast(const struct ofpact_reg_move *move,
     narm->dst = htonl(move->dst.field->nxm_header);
 }
 
-void
-nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
-                      struct ofpbuf *openflow)
+static void
+reg_load_to_nxast(const struct ofpact_reg_load *load, struct ofpbuf *openflow)
 {
     struct nx_action_reg_load *narl;
 
@@ -1111,6 +1172,73 @@ nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
     narl->dst = htonl(load->dst.field->nxm_header);
     narl->value = load->subvalue.be64[1];
 }
+
+static void
+set_field_to_ofast(const struct ofpact_reg_load *load,
+                      struct ofpbuf *openflow)
+{
+    const struct mf_field *mf = load->dst.field;
+    struct ofp12_action_set_field *oasf;
+    uint16_t padded_value_len;
+
+    oasf = ofputil_put_OFPAT12_SET_FIELD(openflow);
+    oasf->dst = htonl(mf->oxm_header);
+
+    /* Set field is the only action of variable length (so far),
+     * so handling the variable length portion is open-coded here */
+    padded_value_len = ROUND_UP(mf->n_bytes, 8);
+    ofpbuf_put_uninit(openflow, padded_value_len);
+    oasf->len = htons(ntohs(oasf->len) + padded_value_len);
+    memset(oasf + 1, 0, padded_value_len);
+
+    bitwise_copy(&load->subvalue, sizeof load->subvalue, load->dst.ofs,
+                 oasf + 1, mf->n_bytes, load->dst.ofs, load->dst.n_bits);
+    return;
+}
+
+void
+nxm_reg_load_to_nxast(const struct ofpact_reg_load *load,
+                      struct ofpbuf *openflow)
+{
+
+    if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) {
+        struct ofp_header *oh = (struct ofp_header *)openflow->l2;
+
+        switch(oh->version) {
+        case OFP12_VERSION:
+            set_field_to_ofast(load, openflow);
+            break;
+
+        case OFP11_VERSION:
+        case OFP10_VERSION:
+            if (load->dst.n_bits < 64) {
+                reg_load_to_nxast(load, openflow);
+            } else {
+                /* Split into 64bit chunks */
+                int chunk, ofs;
+                for (ofs = 0; ofs < load->dst.n_bits; ofs += chunk) {
+                    struct ofpact_reg_load subload = *load;
+
+                    chunk = MIN(load->dst.n_bits - ofs, 64);
+
+                    subload.dst.field =  load->dst.field;
+                    subload.dst.ofs = load->dst.ofs + ofs;
+                    subload.dst.n_bits = chunk;
+                    bitwise_copy(&load->subvalue, sizeof load->subvalue, ofs,
+                                 &subload.subvalue, sizeof subload.subvalue, 0,
+                                 chunk);
+                    reg_load_to_nxast(&subload, openflow);
+                }
+            }
+            break;
+
+        default:
+            NOT_REACHED();
+        }
+    } else {
+        reg_load_to_nxast(load, openflow);
+    }
+}
 \f
 /* nxm_execute_reg_move(), nxm_execute_reg_load(). */
 
index f504ad0..6a57297 100644 (file)
@@ -65,6 +65,8 @@ enum ofperr nxm_reg_move_from_openflow(const struct nx_action_reg_move *,
                                        struct ofpbuf *ofpacts);
 enum ofperr nxm_reg_load_from_openflow(const struct nx_action_reg_load *,
                                        struct ofpbuf *ofpacts);
+enum ofperr nxm_reg_load_from_openflow12_set_field(
+    const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts);
 
 enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *,
                                const struct flow *);
index 210f4ce..19ed7a0 100644 (file)
@@ -1770,7 +1770,8 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     case OFPACT_RESUBMIT:
         resubmit = ofpact_get_RESUBMIT(a);
         if (resubmit->in_port != OFPP_IN_PORT && resubmit->table_id == 255) {
-            ds_put_format(s, "resubmit:%"PRIu16, resubmit->in_port);
+            ds_put_cstr(s, "resubmit:");
+            ofputil_format_port(resubmit->in_port, s);
         } else {
             ds_put_format(s, "resubmit(");
             if (resubmit->in_port != OFPP_IN_PORT) {
@@ -1794,7 +1795,9 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 
     case OFPACT_AUTOPATH:
         autopath = ofpact_get_AUTOPATH(a);
-        ds_put_format(s, "autopath(%u,", autopath->port);
+        ds_put_cstr(s, "autopath(");
+        ofputil_format_port(autopath->port, s);
+        ds_put_char(s, ',');
         mf_format_subfield(&autopath->dst, s);
         ds_put_char(s, ')');
         break;
index 75ccc26..46e2d79 100644 (file)
@@ -108,7 +108,31 @@ enum {
  *
  * Each action is a structure "struct ofpact_*" that begins with "struct
  * ofpact", usually followed by other data that describes the action.  Actions
- * are padded out to a multiple of OFPACT_ALIGNTO bytes in length. */
+ * are padded out to a multiple of OFPACT_ALIGNTO bytes in length.
+ *
+ * The 'compat' member is special:
+ *
+ *     - Most "struct ofpact"s correspond to one particular kind of OpenFlow
+ *       action, at least in a given OpenFlow version.  For example,
+ *       OFPACT_SET_VLAN_VID corresponds to OFPAT10_SET_VLAN_VID in OpenFlow
+ *       1.0.
+ *
+ *       For such actions, the 'compat' member is not meaningful and generally
+ *       should be zero.
+ *
+ *     - A few "struct ofpact"s correspond to multiple OpenFlow actions.  For
+ *       example, OFPACT_SET_TUNNEL can be NXAST_SET_TUNNEL or
+ *       NXAST_SET_TUNNEL64.  In these cases, if the "struct ofpact" originated
+ *       from OpenFlow, then we want to make sure that, if it gets translated
+ *       back to OpenFlow later, it is translated back to the same action type.
+ *       (Otherwise, we'd violate the promise made in DESIGN, in the "Action
+ *       Reproduction" section.)
+ *
+ *       For such actions, the 'compat' member should be the original action
+ *       type.  (If the action didn't originate from OpenFlow, then setting
+ *       'compat' to zero should be fine: code to translate the ofpact to
+ *       OpenFlow must tolerate this case.)
+ */
 struct ofpact {
     enum ofpact_type type;      /* OFPACT_*. */
     enum ofputil_action_code compat; /* Original type when added, if any. */
index 165a36e..e3b7dc1 100644 (file)
@@ -168,8 +168,9 @@ parse_resubmit(char *arg, struct ofpbuf *ofpacts)
 
     in_port_s = strsep(&arg, ",");
     if (in_port_s && in_port_s[0]) {
-        if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) {
-            resubmit->in_port = str_to_u32(in_port_s);
+        resubmit->in_port = ofputil_port_from_string(in_port_s);
+        if (!resubmit->in_port) {
+            ovs_fatal(0, "%s: resubmit to unknown port", in_port_s);
         }
     } else {
         resubmit->in_port = OFPP_IN_PORT;
@@ -488,10 +489,7 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
     pos = str;
     n_actions = 0;
     while (ofputil_parse_key_value(&pos, &act, &arg)) {
-        uint16_t port;
-        int code;
-
-        code = ofputil_action_code_from_name(act);
+        int code = ofputil_action_code_from_name(act);
         if (code >= 0) {
             parse_named_action(code, flow, arg, ofpacts);
         } else if (!strcasecmp(act, "drop")) {
@@ -503,10 +501,13 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
                           "actions");
             }
             break;
-        } else if (ofputil_port_from_string(act, &port)) {
-            ofpact_put_OUTPUT(ofpacts)->port = port;
         } else {
-            ovs_fatal(0, "Unknown action: %s", act);
+            uint16_t port = ofputil_port_from_string(act);
+            if (port) {
+                ofpact_put_OUTPUT(ofpacts)->port = port;
+            } else {
+                ovs_fatal(0, "Unknown action: %s", act);
+            }
         }
         n_actions++;
     }
@@ -681,7 +682,11 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
             if (!strcmp(name, "table")) {
                 fm->table_id = str_to_table_id(value);
             } else if (!strcmp(name, "out_port")) {
-                fm->out_port = atoi(value);
+                fm->out_port = ofputil_port_from_string(name);
+                if (!fm->out_port) {
+                    ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port",
+                              name);
+                }
             } else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
                 fm->priority = str_to_u16(value, name);
             } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
index 1976b94..fc98894 100644 (file)
@@ -2933,6 +2933,143 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     return b;
 }
 \f
+/* Table stats. */
+
+static void
+ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
+                              struct ofpbuf *buf)
+{
+    struct wc_map {
+        enum ofp_flow_wildcards wc10;
+        enum oxm12_ofb_match_fields mf12;
+    };
+
+    static const struct wc_map wc_map[] = {
+        { OFPFW10_IN_PORT,     OFPXMT12_OFB_IN_PORT },
+        { OFPFW10_DL_VLAN,     OFPXMT12_OFB_VLAN_VID },
+        { OFPFW10_DL_SRC,      OFPXMT12_OFB_ETH_SRC },
+        { OFPFW10_DL_DST,      OFPXMT12_OFB_ETH_DST},
+        { OFPFW10_DL_TYPE,     OFPXMT12_OFB_ETH_TYPE },
+        { OFPFW10_NW_PROTO,    OFPXMT12_OFB_IP_PROTO },
+        { OFPFW10_TP_SRC,      OFPXMT12_OFB_TCP_SRC },
+        { OFPFW10_TP_DST,      OFPXMT12_OFB_TCP_DST },
+        { OFPFW10_NW_SRC_MASK, OFPXMT12_OFB_IPV4_SRC },
+        { OFPFW10_NW_DST_MASK, OFPXMT12_OFB_IPV4_DST },
+        { OFPFW10_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
+        { OFPFW10_NW_TOS,      OFPXMT12_OFB_IP_DSCP },
+    };
+
+    struct ofp10_table_stats *out;
+    const struct wc_map *p;
+
+    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out->table_id = in->table_id;
+    strcpy(out->name, in->name);
+    out->wildcards = 0;
+    for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
+        if (in->wildcards & htonll(1ULL << p->mf12)) {
+            out->wildcards |= htonl(p->wc10);
+        }
+    }
+    out->max_entries = in->max_entries;
+    out->active_count = in->active_count;
+    put_32aligned_be64(&out->lookup_count, in->lookup_count);
+    put_32aligned_be64(&out->matched_count, in->matched_count);
+}
+
+static ovs_be32
+oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12)
+{
+    struct map {
+        enum ofp11_flow_match_fields fmf11;
+        enum oxm12_ofb_match_fields mf12;
+    };
+
+    static const struct map map[] = {
+        { OFPFMF11_IN_PORT,     OFPXMT12_OFB_IN_PORT },
+        { OFPFMF11_DL_VLAN,     OFPXMT12_OFB_VLAN_VID },
+        { OFPFMF11_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
+        { OFPFMF11_DL_TYPE,     OFPXMT12_OFB_ETH_TYPE },
+        { OFPFMF11_NW_TOS,      OFPXMT12_OFB_IP_DSCP },
+        { OFPFMF11_NW_PROTO,    OFPXMT12_OFB_IP_PROTO },
+        { OFPFMF11_TP_SRC,      OFPXMT12_OFB_TCP_SRC },
+        { OFPFMF11_TP_DST,      OFPXMT12_OFB_TCP_DST },
+        { OFPFMF11_MPLS_LABEL,  OFPXMT12_OFB_MPLS_LABEL },
+        { OFPFMF11_MPLS_TC,     OFPXMT12_OFB_MPLS_TC },
+        /* I don't know what OFPFMF11_TYPE means. */
+        { OFPFMF11_DL_SRC,      OFPXMT12_OFB_ETH_SRC },
+        { OFPFMF11_DL_DST,      OFPXMT12_OFB_ETH_DST },
+        { OFPFMF11_NW_SRC,      OFPXMT12_OFB_IPV4_SRC },
+        { OFPFMF11_NW_DST,      OFPXMT12_OFB_IPV4_DST },
+        { OFPFMF11_METADATA,    OFPXMT12_OFB_METADATA },
+    };
+
+    const struct map *p;
+    uint32_t fmf11;
+
+    fmf11 = 0;
+    for (p = map; p < &map[ARRAY_SIZE(map)]; p++) {
+        if (oxm12 & htonll(1ULL << p->mf12)) {
+            fmf11 |= p->fmf11;
+        }
+    }
+    return htonl(fmf11);
+}
+
+static void
+ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
+                              struct ofpbuf *buf)
+{
+    struct ofp11_table_stats *out;
+
+    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out->table_id = in->table_id;
+    strcpy(out->name, in->name);
+    out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
+    out->match = oxm12_to_ofp11_flow_match_fields(in->match);
+    out->instructions = in->instructions;
+    out->write_actions = in->write_actions;
+    out->apply_actions = in->apply_actions;
+    out->config = in->config;
+    out->max_entries = in->max_entries;
+    out->active_count = in->active_count;
+    out->lookup_count = in->lookup_count;
+    out->matched_count = in->matched_count;
+}
+
+struct ofpbuf *
+ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
+                                 const struct ofp_header *request)
+{
+    struct ofpbuf *reply;
+    int i;
+
+    reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats);
+
+    switch ((enum ofp_version) request->version) {
+    case OFP10_VERSION:
+        for (i = 0; i < n; i++) {
+            ofputil_put_ofp10_table_stats(&stats[i], reply);
+        }
+        break;
+
+    case OFP11_VERSION:
+        for (i = 0; i < n; i++) {
+            ofputil_put_ofp11_table_stats(&stats[i], reply);
+        }
+        break;
+
+    case OFP12_VERSION:
+        ofpbuf_put(reply, stats, n * sizeof *stats);
+        break;
+
+    default:
+        NOT_REACHED();
+    }
+
+    return reply;
+}
+\f
 /* ofputil_flow_monitor_request */
 
 /* Converts an NXST_FLOW_MONITOR request in 'msg' into an abstract
@@ -3399,36 +3536,72 @@ ofputil_check_output_port(uint16_t port, int max_ports)
         OFPUTIL_NAMED_PORT(LOCAL)               \
         OFPUTIL_NAMED_PORT(NONE)
 
-/* Checks whether 's' is the string representation of an OpenFlow port number,
- * either as an integer or a string name (e.g. "LOCAL").  If it is, stores the
- * number in '*port' and returns true.  Otherwise, returns false. */
-bool
-ofputil_port_from_string(const char *name, uint16_t *port)
+/* Returns the port number represented by 's', which may be an integer or, for
+ * reserved ports, the standard OpenFlow name for the port (e.g. "LOCAL").
+ *
+ * Returns 0 if 's' is not a valid OpenFlow port number or name.  The caller
+ * should issue an error message in this case, because this function usually
+ * does not.  (This gives the caller an opportunity to look up the port name
+ * another way, e.g. by contacting the switch and listing the names of all its
+ * ports).
+ *
+ * This function accepts OpenFlow 1.0 port numbers.  It also accepts a subset
+ * of OpenFlow 1.1+ port numbers, mapping those port numbers into the 16-bit
+ * range as described in include/openflow/openflow-1.1.h. */
+uint16_t
+ofputil_port_from_string(const char *s)
 {
-    struct pair {
-        const char *name;
-        uint16_t value;
-    };
-    static const struct pair pairs[] = {
+    unsigned int port32;
+
+    if (str_to_uint(s, 10, &port32)) {
+        if (port32 == 0) {
+            VLOG_WARN("port 0 is not a valid OpenFlow port number");
+            return 0;
+        } else if (port32 < OFPP_MAX) {
+            return port32;
+        } else if (port32 < OFPP_FIRST_RESV) {
+            VLOG_WARN("port %u is a reserved OF1.0 port number that will "
+                      "be translated to %u when talking to an OF1.1 or "
+                      "later controller", port32, port32 + OFPP11_OFFSET);
+            return port32;
+        } else if (port32 <= OFPP_LAST_RESV) {
+            struct ds s;
+
+            ds_init(&s);
+            ofputil_format_port(port32, &s);
+            VLOG_WARN("port %u is better referred to as %s, for compatibility "
+                      "with future versions of OpenFlow",
+                      port32, ds_cstr(&s));
+            ds_destroy(&s);
+
+            return port32;
+        } else if (port32 < OFPP11_MAX) {
+            VLOG_WARN("port %u is outside the supported range 0 through "
+                      "%"PRIx16"or 0x%x through 0x%"PRIx32, port32,
+                      UINT16_MAX, (unsigned int) OFPP11_MAX, UINT32_MAX);
+            return 0;
+        } else {
+            return port32 - OFPP11_OFFSET;
+        }
+    } else {
+        struct pair {
+            const char *name;
+            uint16_t value;
+        };
+        static const struct pair pairs[] = {
 #define OFPUTIL_NAMED_PORT(NAME) {#NAME, OFPP_##NAME},
-        OFPUTIL_NAMED_PORTS
+            OFPUTIL_NAMED_PORTS
 #undef OFPUTIL_NAMED_PORT
-    };
-    static const int n_pairs = ARRAY_SIZE(pairs);
-    int i;
-
-    if (str_to_int(name, 0, &i) && i >= 0 && i < UINT16_MAX) {
-        *port = i;
-        return true;
-    }
+        };
+        const struct pair *p;
 
-    for (i = 0; i < n_pairs; i++) {
-        if (!strcasecmp(name, pairs[i].name)) {
-            *port = pairs[i].value;
-            return true;
+        for (p = pairs; p < &pairs[ARRAY_SIZE(pairs)]; p++) {
+            if (!strcasecmp(s, p->name)) {
+                return p->value;
+            }
         }
+        return 0;
     }
-    return false;
 }
 
 /* Appends to 's' a string representation of the OpenFlow port number 'port'.
index e3a93c9..4e9f946 100644 (file)
@@ -36,7 +36,7 @@ enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port, uint16_t *ofp10_port);
 ovs_be32 ofputil_port_to_ofp11(uint16_t ofp10_port);
 
 enum ofperr ofputil_check_output_port(uint16_t ofp_port, int max_ports);
-bool ofputil_port_from_string(const char *, uint16_t *port);
+uint16_t ofputil_port_from_string(const char *);
 void ofputil_format_port(uint16_t port, struct ds *);
 
 /* Converting OFPFW10_NW_SRC_MASK and OFPFW10_NW_DST_MASK wildcard bit counts
@@ -450,6 +450,15 @@ enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
 struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
                                        enum ofputil_protocol);
 
+/* Abstract table stats.
+ *
+ * For now we use ofp12_table_stats as a superset of the other protocol
+ * versions' table stats. */
+
+struct ofpbuf *ofputil_encode_table_stats_reply(
+    const struct ofp12_table_stats[], int n,
+    const struct ofp_header *request);
+
 /* Abstract nx_flow_monitor_request. */
 struct ofputil_flow_monitor_request {
     uint32_t id;
index 689dcf1..dde5996 100644 (file)
@@ -48,7 +48,7 @@ unix_open(const char *name, char *suffix, struct stream **streamp,
 
     fd = make_unix_socket(SOCK_STREAM, true, NULL, connect_path);
     if (fd < 0) {
-        VLOG_ERR("%s: connection failed (%s)", connect_path, strerror(-fd));
+        VLOG_WARN("%s: connection failed (%s)", connect_path, strerror(-fd));
         return -fd;
     }
 
index 4ab493d..8686de3 100644 (file)
@@ -95,13 +95,13 @@ unixctl_version(struct unixctl_conn *conn, int argc OVS_UNUSED,
  * arguments to the command; it is used only for presentation to the user in
  * "help" output.
  *
- * 'cb' is called when the command is received.  It is passed the actual set of
- * arguments, as a text string, plus a copy of 'aux'.  Normally 'cb' should
- * reply by calling unixctl_command_reply() or unixctl_command_reply_error()
- * before it returns, but if the command cannot be handled immediately then it
- * can defer the reply until later.  A given connection can only process a
- * single request at a time, so a reply must be made eventually to avoid
- * blocking that connection. */
+ * 'cb' is called when the command is received.  It is passed an array
+ * containing the command name and arguments, plus a copy of 'aux'.  Normally
+ * 'cb' should reply by calling unixctl_command_reply() or
+ * unixctl_command_reply_error() before it returns, but if the command cannot
+ * be handled immediately then it can defer the reply until later.  A given
+ * connection can only process a single request at a time, so a reply must be
+ * made eventually to avoid blocking that connection. */
 void
 unixctl_command_register(const char *name, const char *usage,
                          int min_args, int max_args,
index 391995e..05e69c7 100644 (file)
@@ -1815,6 +1815,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule,
                 fu.cookie = rule->flow_cookie;
                 minimatch_expand(&rule->cr.match, &match);
                 fu.match = &match;
+                fu.priority = rule->cr.priority;
                 if (flags & NXFMF_ACTIONS) {
                     fu.ofpacts = rule->ofpacts;
                     fu.ofpacts_len = rule->ofpacts_len;
index 1289025..9f7acd1 100644 (file)
@@ -1158,7 +1158,7 @@ get_features(struct ofproto *ofproto_ OVS_UNUSED,
 }
 
 static void
-get_tables(struct ofproto *ofproto_, struct ofp10_table_stats *ots)
+get_tables(struct ofproto *ofproto_, struct ofp12_table_stats *ots)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
     struct dpif_dp_stats s;
@@ -1166,9 +1166,8 @@ get_tables(struct ofproto *ofproto_, struct ofp10_table_stats *ots)
     strcpy(ots->name, "classifier");
 
     dpif_get_dp_stats(ofproto->dpif, &s);
-    put_32aligned_be64(&ots->lookup_count, htonll(s.n_hit + s.n_missed));
-    put_32aligned_be64(&ots->matched_count,
-                       htonll(s.n_hit + ofproto->n_matches));
+    ots->lookup_count = htonll(s.n_hit + s.n_missed);
+    ots->matched_count = htonll(s.n_hit + ofproto->n_matches);
 }
 
 static struct ofport *
index fb7db23..0ade586 100644 (file)
@@ -464,7 +464,17 @@ struct ofproto_class {
      *
      *   - 'name' to "table#" where # is the table ID.
      *
-     *   - 'wildcards' to OFPFW10_ALL.
+     *   - 'match' and 'wildcards' to OFPXMT12_MASK.
+     *
+     *   - 'write_actions' and 'apply_actions' to OFPAT12_OUTPUT.
+     *
+     *   - 'write_setfields' and 'apply_setfields' to OFPXMT12_MASK.
+     *
+     *   - 'metadata_match' and 'metadata_write' to UINT64_MAX.
+     *
+     *   - 'instructions' to OFPIT11_ALL.
+     *
+     *   - 'config' to OFPTC11_TABLE_MISS_MASK.
      *
      *   - 'max_entries' to 1,000,000.
      *
@@ -480,6 +490,21 @@ struct ofproto_class {
      *   - 'wildcards' to the set of wildcards actually supported by the table
      *     (if it doesn't support all OpenFlow wildcards).
      *
+     *   - 'instructions' to set the instructions actually supported by
+     *     the table.
+     *
+     *   - 'write_actions' to set the write actions actually supported by
+     *     the table (if it doesn't support all OpenFlow actions).
+     *
+     *   - 'apply_actions' to set the apply actions actually supported by
+     *     the table (if it doesn't support all OpenFlow actions).
+     *
+     *   - 'write_setfields' to set the write setfields actually supported by
+     *     the table.
+     *
+     *   - 'apply_setfields' to set the apply setfields actually supported by
+     *     the table.
+     *
      *   - 'max_entries' to the maximum number of flows actually supported by
      *     the hardware.
      *
@@ -489,10 +514,10 @@ struct ofproto_class {
      *   - 'matched_count' to the number of packets looked up in this flow
      *     table so far that matched one of the flow entries.
      *
-     * Keep in mind that all of the members of struct ofp10_table_stats are in
-     * network byte order.
+     * All of the members of struct ofp12_table_stats are in network byte
+     * order.
      */
-    void (*get_tables)(struct ofproto *ofproto, struct ofp10_table_stats *ots);
+    void (*get_tables)(struct ofproto *ofproto, struct ofp12_table_stats *ots);
 
 /* ## ---------------- ## */
 /* ## ofport Functions ## */
index 9b235e9..e3b24c1 100644 (file)
@@ -2242,16 +2242,30 @@ handle_table_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    struct ofp10_table_stats *ots;
+    struct ofp12_table_stats *ots;
     struct ofpbuf *msg;
     size_t i;
 
-    msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables);
-    ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables);
+    /* Set up default values.
+     *
+     * ofp12_table_stats is used as a generic structure as
+     * it is able to hold all the fields for ofp10_table_stats
+     * and ofp11_table_stats (and of course itself).
+     */
+    ots = xcalloc(p->n_tables, sizeof *ots);
     for (i = 0; i < p->n_tables; i++) {
         ots[i].table_id = i;
         sprintf(ots[i].name, "table%zu", i);
-        ots[i].wildcards = htonl(OFPFW10_ALL);
+        ots[i].match = htonll(OFPXMT12_MASK);
+        ots[i].wildcards = htonll(OFPXMT12_MASK);
+        ots[i].write_actions = htonl(OFPAT12_OUTPUT);
+        ots[i].apply_actions = htonl(OFPAT12_OUTPUT);
+        ots[i].write_setfields = htonll(OFPXMT12_MASK);
+        ots[i].apply_setfields = htonll(OFPXMT12_MASK);
+        ots[i].metadata_match = htonll(UINT64_MAX);
+        ots[i].metadata_write = htonll(UINT64_MAX);
+        ots[i].instructions = htonl(OFPIT11_ALL);
+        ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
         ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
         ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
     }
@@ -2270,7 +2284,11 @@ handle_table_stats_request(struct ofconn *ofconn,
         }
     }
 
+    msg = ofputil_encode_table_stats_reply(ots, p->n_tables, request);
     ofconn_send_reply(ofconn, msg);
+
+    free(ots);
+
     return 0;
 }
 
@@ -3532,6 +3550,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     fu.cookie = rule->flow_cookie;
     minimatch_expand(&rule->cr.match, &match);
     fu.match = &match;
+    fu.priority = rule->cr.priority;
     if (!(flags & NXFMF_ACTIONS)) {
         fu.ofpacts = NULL;
         fu.ofpacts_len = 0;
index a94d7cb..d5d2189 100644 (file)
@@ -39,7 +39,7 @@
 #include "ovsdb-data.h"
 #include "ovsdb-error.h"
 #include "sort.h"
-#include "sset.h"
+#include "svec.h"
 #include "stream.h"
 #include "stream-ssl.h"
 #include "table.h"
@@ -75,7 +75,7 @@ static const struct ovsdb_client_command all_commands[];
 static void usage(void) NO_RETURN;
 static void parse_options(int argc, char *argv[]);
 static struct jsonrpc *open_jsonrpc(const char *server);
-static void fetch_dbs(struct jsonrpc *, struct sset *dbs);
+static void fetch_dbs(struct jsonrpc *, struct svec *dbs);
 
 int
 main(int argc, char *argv[])
@@ -118,22 +118,22 @@ main(int argc, char *argv[])
     }
 
     if (command->need == NEED_DATABASE) {
-        struct sset dbs;
+        struct svec dbs;
 
-        sset_init(&dbs);
+        svec_init(&dbs);
         fetch_dbs(rpc, &dbs);
         if (argc - optind > command->min_args
-            && sset_contains(&dbs, argv[optind])) {
+            && svec_contains(&dbs, argv[optind])) {
             database = argv[optind++];
-        } else if (sset_count(&dbs) == 1) {
-            database = xstrdup(SSET_FIRST(&dbs));
-        } else if (sset_contains(&dbs, "Open_vSwitch")) {
+        } else if (dbs.n == 1) {
+            database = xstrdup(dbs.names[0]);
+        } else if (svec_contains(&dbs, "Open_vSwitch")) {
             database = "Open_vSwitch";
         } else {
             ovs_fatal(0, "no default database for `%s' command, please "
                       "specify a database name", command->name);
         }
-        sset_destroy(&dbs);
+        svec_destroy(&dbs);
     } else {
         database = NULL;
     }
@@ -371,7 +371,7 @@ fetch_schema(struct jsonrpc *rpc, const char *database)
 }
 
 static void
-fetch_dbs(struct jsonrpc *rpc, struct sset *dbs)
+fetch_dbs(struct jsonrpc *rpc, struct svec *dbs)
 {
     struct jsonrpc_msg *request, *reply;
     size_t i;
@@ -390,7 +390,7 @@ fetch_dbs(struct jsonrpc *rpc, struct sset *dbs)
         if (name->type != JSON_STRING) {
             ovs_fatal(0, "list_dbs response %zu is not string", i);
         }
-        sset_add(dbs, name->u.string);
+        svec_add(dbs, name->u.string);
     }
     jsonrpc_msg_destroy(reply);
 }
@@ -400,14 +400,16 @@ do_list_dbs(struct jsonrpc *rpc, const char *database OVS_UNUSED,
             int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     const char *db_name;
-    struct sset dbs;
+    struct svec dbs;
+    size_t i;
 
-    sset_init(&dbs);
+    svec_init(&dbs);
     fetch_dbs(rpc, &dbs);
-    SSET_FOR_EACH (db_name, &dbs) {
+    svec_sort(&dbs);
+    SVEC_FOR_EACH (i, db_name, &dbs) {
         puts(db_name);
     }
-    sset_destroy(&dbs);
+    svec_destroy(&dbs);
 }
 
 static void
index 9d32844..f9a3661 100644 (file)
@@ -134,7 +134,7 @@ instead, to write to a database that is served by
 Prints a summary of the records in \fIdb\fR's log, including the time
 and date at which each database change occurred and any associated
 comment.  This may be useful for debugging.
-.PP
+.IP
 To increase the verbosity of output, add \fB\-m\fR (or \fB\-\-more\fR)
 one or more times to the command line.  With one \fB\-m\fR,
 \fBshow\-log\fR prints a summary of the records added, deleted, or
index fa66aab..c1540eb 100644 (file)
@@ -449,14 +449,16 @@ class Session(object):
                 self.pstream = None
 
         if self.rpc:
-            received_bytes = self.rpc.get_received_bytes()
+            backlog = self.rpc.get_backlog()
             self.rpc.run()
-            if received_bytes != self.rpc.get_received_bytes():
-                # Data was successfully received.
+            if self.rpc.get_backlog() < backlog:
+                # Data previously caught in a queue was successfully sent (or
+                # there's an error, which we'll catch below).
                 #
-                # Previously we only counted receiving a full message as
-                # activity, but with large messages or a slow connection that
-                # policy could time out the session mid-message.
+                # We don't count data that is successfully sent immediately as
+                # activity, because there's a lot of queuing downstream from
+                # us, which means that we can push a lot of data into a
+                # connection that has stalled and won't ever recover.
                 self.reconnect.activity(ovs.timeval.msec())
 
             error = self.rpc.get_status()
@@ -516,16 +518,14 @@ class Session(object):
 
     def recv(self):
         if self.rpc is not None:
-            backlog = self.rpc.get_backlog()
+            received_bytes = self.rpc.get_received_bytes()
             error, msg = self.rpc.recv()
-            if self.rpc.get_backlog() < backlog:
-                # Data previously caught in a queue was successfully sent (or
-                # there's an error, which we'll catch below).
+            if received_bytes != self.rpc.get_received_bytes():
+                # Data was successfully received.
                 #
-                # We don't count data that is successfully sent immediately as
-                # activity, because there's a lot of queuing downstream from
-                # us, which means that we can push a lot of data into a
-                # connection that has stalled and won't ever recover.
+                # Previously we only counted receiving a full message as
+                # activity, but with large messages or a slow connection that
+                # policy could time out the session mid-message.
                 self.reconnect.activity(ovs.timeval.msec())
 
             if not error:
index 634d46f..557c92c 100644 (file)
@@ -24,7 +24,7 @@ AT_CLEANUP
 
 AT_SETUP([autopath action bad port])
 AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(bad, NXM_NX_REG0[[]])'], [1], [],
-  [ovs-ofctl: bad, NXM_NX_REG0[[]]: autopath id 0 is not in valid range 1 to 4294967295
+  [ovs-ofctl: bad, NXM_NX_REG0[[]]: bad port number
 ])
 AT_CLEANUP
 
index 9844592..42b355b 100644 (file)
@@ -351,7 +351,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 00 00 00 23 20 83 c1 5f 00 00 00 00 \
 "], [0], [dnl
 OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:23:20:83:c1:5f->ff:ff:ff:ff:ff:ff) type:8035 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:23:20:83:c1:5f->ff:ff:ff:ff:ff:ff) type:8035
 ])
 AT_CLEANUP
 
@@ -794,13 +794,27 @@ OFPST_AGGREGATE reply (OF1.2) (xid=0x2): packet_count=121 byte_count=19279 flow_
 ])
 AT_CLEANUP
 
-AT_SETUP([OFPST_TABLE request])
+AT_SETUP([OFPST_TABLE request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100030000"], [0], [dnl
 OFPST_TABLE request (xid=0x1):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_TABLE request - OF1.1])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "02120010000000020003000000000000"], [0], [dnl
+OFPST_TABLE request (OF1.1) (xid=0x2):
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_TABLE request - OF1.2])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "03120010000000020003000000000000"], [0], [dnl
+OFPST_TABLE request (OF1.2) (xid=0x2):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_TABLE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
index cc5d770..de56ef8 100644 (file)
@@ -968,13 +968,13 @@ AT_CHECK([[sed -e 's/, uptime [0-9]*//
 s/, now [0-9.]*//
 s/time \([0-9]*\)\.\.\.\1$/time <moment>/
 s/time [0-9]*\.\.\.[0-9]*/time <range>/
-' netflow.log]], [0],
-  [header: v5, seq 0, engine 2,1
-rec: 192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
-
+' netflow.log | sort]], [0],
+  [
+header: v5, seq 0, engine 2,1
 header: v5, seq 1, engine 2,1
-rec: 192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0, time <range>
-rec: 192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
+seq 0: 192.168.0.1 > 192.168.0.2, if 1 > 65535, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
+seq 1: 192.168.0.1 > 192.168.0.2, if 1 > 2, 1 pkts, 60 bytes, ICMP 8:0, time <moment>
+seq 1: 192.168.0.2 > 192.168.0.1, if 2 > 1, 2 pkts, 120 bytes, ICMP 0:0, time <range>
 ])
 AT_CLEANUP
 
@@ -1032,13 +1032,13 @@ while read line; do
     esac
 
     case $line in
-        "rec: 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+        "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 65535, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
             counter=n_learn
            ;;
-       "rec: 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
+       "seq "*": 192.168.0.1 > 192.168.0.2, if 1 > 2, "*" pkts, "*" bytes, TCP 1234 > 80, time "*)
            counter=n_in
            ;;
-       "rec: 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
+       "seq "*": 192.168.0.2 > 192.168.0.1, if 2 > 1, "*" pkts, "*" bytes, TCP 80 > 1234, time "*)
            counter=n_out
            ;;
        *)
index a055851..af7b7ca 100644 (file)
@@ -108,13 +108,13 @@ AT_SETUP([ofproto - basic flow_mod commands (NXM)])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
 ])
-AT_CHECK([echo 'in_port=1,actions=0' | ovs-ofctl add-flows br0 -])
-AT_CHECK([ovs-ofctl add-flow br0 in_port=0,actions=1])
-AT_CHECK([ovs-ofctl -F nxm add-flow br0 table=1,in_port=3,actions=2])
+AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl add-flows br0 -])
+AT_CHECK([ovs-ofctl add-flow br0 in_port=1,actions=2])
+AT_CHECK([ovs-ofctl -F nxm add-flow br0 table=1,in_port=4,actions=3])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- in_port=0 actions=output:1
- in_port=1 actions=output:0
- table=1, in_port=3 actions=output:2
+ in_port=1 actions=output:2
+ in_port=2 actions=output:1
+ table=1, in_port=4 actions=output:3
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
@@ -130,13 +130,13 @@ AT_SETUP([ofproto - basic flow_mod commands (OpenFlow 1.0)])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip], [0], [OFPST_FLOW reply:
 ])
-AT_CHECK([echo 'in_port=1,actions=0' | ovs-ofctl -F openflow10 add-flows br0 -])
-AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 in_port=0,actions=1])
-AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 table=1,in_port=3,actions=2])
+AT_CHECK([echo 'in_port=2,actions=1' | ovs-ofctl -F openflow10 add-flows br0 -])
+AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 in_port=1,actions=2])
+AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 table=1,in_port=4,actions=3])
 AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
- in_port=0 actions=output:1
- in_port=1 actions=output:0
- table=1, in_port=3 actions=output:2
+ in_port=1 actions=output:2
+ in_port=2 actions=output:1
+ table=1, in_port=4 actions=output:3
 OFPST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl -F openflow10 dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
@@ -150,20 +150,20 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - dump flows with cookie])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
 NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=3
 ])
 AT_CHECK([ovs-ofctl dump-flows br0 cookie=0x3/-1 | ofctl_strip | sort], [0], [dnl
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl dump-aggregate br0 cookie=0x3/-1 | STRIP_XIDS], [0], [dnl
@@ -174,21 +174,21 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - dump flows with cookie mask])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl dump-aggregate br0 table=0 | STRIP_XIDS], [0], [dnl
 NXST_AGGREGATE reply: packet_count=0 byte_count=0 flow_count=3
 ])
 AT_CHECK([ovs-ofctl dump-flows br0 cookie=0x3/0x1 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl dump-aggregate br0 cookie=0x3/0x1 | STRIP_XIDS], [0], [dnl
@@ -199,15 +199,15 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flow with cookie change (OpenFlow 1.0)])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F openflow10 add-flow br0 cookie=0x1,in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
 OFPST_FLOW reply:
 ])
 
-AT_CHECK([ovs-ofctl -F openflow10 mod-flows br0 cookie=0x2,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F openflow10 mod-flows br0 cookie=0x2,in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F openflow10 dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x2, in_port=1 actions=output:0
+ cookie=0x2, in_port=1 actions=output:1
 OFPST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -215,15 +215,15 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flow with cookie change (NXM)])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl -F nxm add-flow br0 cookie=0x1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F nxm add-flow br0 cookie=0x1,in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
 NXST_FLOW reply:
 ])
 
-AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=0x2,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=0x2,in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x2, in_port=1 actions=output:0
+ cookie=0x2, in_port=1 actions=output:1
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -231,13 +231,13 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flows based on cookie mask])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x1, in_port=2 actions=output:0
- cookie=0x2, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x1, in_port=2 actions=output:1
+ cookie=0x2, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 
@@ -245,7 +245,7 @@ AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=0x1/0xff,actions=4])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
  cookie=0x1, in_port=1 actions=output:4
  cookie=0x1, in_port=2 actions=output:4
- cookie=0x2, in_port=3 actions=output:0
+ cookie=0x2, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -253,19 +253,19 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flows based on cookie mask with cookie change])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x1, in_port=2 actions=output:0
- cookie=0x2, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x1, in_port=2 actions=output:1
+ cookie=0x2, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 
 AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=1/-1,cookie=4,actions=4])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x2, in_port=3 actions=output:0
+ cookie=0x2, in_port=3 actions=output:1
  cookie=0x4, in_port=1 actions=output:4
  cookie=0x4, in_port=2 actions=output:4
 NXST_FLOW reply:
@@ -275,9 +275,9 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flow with cookie miss (mask==0)])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl -F nxm mod-flows br0 in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F nxm mod-flows br0 in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
- in_port=1 actions=output:0
+ in_port=1 actions=output:1
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -285,7 +285,7 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - mod flow with cookie miss (mask!=0)])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=1/1,in_port=1,actions=0])
+AT_CHECK([ovs-ofctl -F nxm mod-flows br0 cookie=1/1,in_port=1,actions=1])
 AT_CHECK([ovs-ofctl -F nxm dump-flows br0 | ofctl_strip | sort], [0], [dnl
 NXST_FLOW reply:
 ])
@@ -294,13 +294,13 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - del flows with cookies])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 
@@ -313,20 +313,20 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - del flows based on cookie])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 
 AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3/-1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -334,18 +334,18 @@ AT_CLEANUP
 
 AT_SETUP([ofproto - del flows based on cookie mask])
 OVS_VSWITCHD_START
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=0])
-AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=0])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x1,in_port=1,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x2,in_port=2,actions=1])
+AT_CHECK([ovs-ofctl add-flow br0 cookie=0x3,in_port=3,actions=1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x1, in_port=1 actions=output:0
- cookie=0x2, in_port=2 actions=output:0
- cookie=0x3, in_port=3 actions=output:0
+ cookie=0x1, in_port=1 actions=output:1
+ cookie=0x2, in_port=2 actions=output:1
+ cookie=0x3, in_port=3 actions=output:1
 NXST_FLOW reply:
 ])
 AT_CHECK([ovs-ofctl del-flows br0 cookie=0x3/0x1])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
- cookie=0x2, in_port=2 actions=output:0
+ cookie=0x2, in_port=2 actions=output:1
 NXST_FLOW reply:
 ])
 OVS_VSWITCHD_STOP
@@ -588,14 +588,14 @@ check_async () {
     ovs-ofctl -v packet-out br0 none controller '0001020304050010203040501234'
     if test X"$1" = X"OFPR_ACTION"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)"
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234"
     fi
 
     # OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
     ovs-ofctl -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
     if test X"$1" = X"OFPR_NO_MATCH"; then shift;
         echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=NONE (via no_match) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)"
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234"
     fi
 
     # OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
@@ -692,7 +692,7 @@ AT_CAPTURE_FILE([monitor.log])
 
 # Send some packet-outs with OFPP_NONE and OFPP_CONTROLLER (65533) as in_port.
 AT_CHECK([ovs-ofctl packet-out br0 none controller '0001020304050010203040501234'])
-AT_CHECK([ovs-ofctl packet-out br0 65533 controller '0001020304050010203040505678'])
+AT_CHECK([ovs-ofctl packet-out br0 controller controller '0001020304050010203040505678'])
 
 # Stop the monitor and check its output.
 ovs-appctl -t ovs-ofctl ofctl/barrier
@@ -700,9 +700,9 @@ ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 OFPT_PACKET_IN: total_len=14 in_port=NONE (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234
 OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:5678 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:5678
 OFPT_BARRIER_REPLY:
 ])
 
@@ -730,7 +730,7 @@ ovs-appctl -t ovs-ofctl exit
 
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 NXT_PACKET_IN: total_len=14 in_port=NONE metadata=0xfafafafa5a5a5a5a (via action) data_len=14 (unbuffered)
-priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 ip(0.0.0.0->0.0.0.0)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234
 OFPT_BARRIER_REPLY:
 ])
 
index 85ab5e7..c37eeaf 100644 (file)
@@ -74,7 +74,7 @@ print_netflow(struct ofpbuf *buf)
             return;
         }
 
-        printf("rec: "IP_FMT" > "IP_FMT,
+        printf("seq %"PRIu32": "IP_FMT" > "IP_FMT, ntohl(hdr->flow_seq),
                IP_ARGS(&rec->src_addr), IP_ARGS(&rec->dst_addr));
 
         printf(", if %"PRIu16" > %"PRIu16,
index 3c63ddd..01f4ded 100644 (file)
@@ -39,6 +39,8 @@ fi
 
 VERSION='@VERSION@'
 
+DAEMON_CWD=/
+
 LC_ALL=C; export LC_ALL
 
 ## ------------- ##
@@ -159,7 +161,6 @@ start_daemon () {
     fi
 }
 
-DAEMON_CWD=/
 stop_daemon () {
     if test -e "$rundir/$1.pid"; then
         if pid=`cat "$rundir/$1.pid"`; then
index aad9325..be71f18 100644 (file)
@@ -71,12 +71,11 @@ Prints to the console detailed information about network devices
 associated with \fIswitch\fR (version 1.7 or later).  This is a subset
 of the information provided by the \fBshow\fR command.
 .
-.TP
-\fBmod\-port \fIswitch\fR \fInetdev\fR \fIaction\fR
-Modify characteristics of an interface monitored by \fIswitch\fR.  
-\fInetdev\fR can be referred to by its OpenFlow assigned port number or 
-the device name, e.g. \fBeth0\fR.  The \fIaction\fR may be any one of the
-following:
+.IP "\fBmod\-port \fIswitch\fR \fIport\fR \fIaction\fR"
+Modify characteristics of port \fBport\fR in \fIswitch\fR.  \fIport\fR
+may be an OpenFlow port number or name or the keyword \fBLOCAL\fR (the
+preferred way to refer to the OpenFlow local port).  The \fIaction\fR
+may be any one of the following:
 .
 .RS
 .IQ \fBup\fR
@@ -180,12 +179,15 @@ The output format is described in \fBTable Entry Output\fR.
 .
 .IP "\fBqueue\-stats \fIswitch \fR[\fIport \fR[\fIqueue\fR]]"
 Prints to the console statistics for the specified \fIqueue\fR on
-\fIport\fR within \fIswitch\fR.  Either of \fIport\fR or \fIqueue\fR
-or both may be omitted (or equivalently specified as \fBALL\fR).  If
-both are omitted, statistics are printed for all queues on all ports.
-If only \fIqueue\fR is omitted, then statistics are printed for all
-queues on \fIport\fR; if only \fIport\fR is omitted, then statistics
-are printed for \fIqueue\fR on every port where it exists.
+\fIport\fR within \fIswitch\fR.  \fIport\fR can be an OpenFlow port
+number or name, the keyword \fBLOCAL\fR (the preferred way to refer to
+the OpenFlow local port), or the keyword \fBALL\fR.  Either of
+\fIport\fR or \fIqueue\fR or both may be omitted (or equivalently the
+keyword \fBALL\fR).  If both are omitted, statistics are printed for
+all queues on all ports.  If only \fIqueue\fR is omitted, then
+statistics are printed for all queues on \fIport\fR; if only
+\fIport\fR is omitted, then statistics are printed for \fIqueue\fR on
+every port where it exists.
 .
 .SS "OpenFlow Switch Flow Table Commands"
 .
@@ -250,10 +252,10 @@ differences were found.
 Connects to \fIswitch\fR and instructs it to execute the OpenFlow
 \fIactions\fR on each \fIpacket\fR.  For the purpose of executing the
 actions, the packets are considered to have arrived on \fIin_port\fR,
-which may be an OpenFlow assigned port number, an OpenFlow port name
-(e.g. \fBeth0\fR), the keyword \fBlocal\fR for the OpenFlow ``local''
-port \fBOFPP_LOCAL\fR, or the keyword \fBnone\fR to indicate that the
-packet was generated by the switch itself.
+which may be an OpenFlow port number or name (e.g. \fBeth0\fR), the
+keyword \fBLOCAL\fR (the preferred way to refer to the OpenFlow
+``local'' port), or the keyword \fBNONE\fR to indicate that the packet
+was generated by the switch itself.
 .
 .SS "OpenFlow Switch Monitoring Commands"
 .
@@ -325,7 +327,9 @@ Do not report actions as part of flow updates.
 Limits the monitoring to the table with the given \fInumber\fR between
 0 and 254.  By default, all tables are monitored.
 .IP "\fBout_port=\fIport\fR"
-If set, only flows that output to \fIport\fR are monitored.
+If set, only flows that output to \fIport\fR are monitored.  The
+\fIport\fR may be an OpenFlow port number or keyword
+(e.g. \fBLOCAL\fR).
 .IP "\fIfield\fB=\fIvalue\fR"
 Monitors only flows that have \fIfield\fR specified as the given
 \fIvalue\fR.  Any syntax valid for matching on \fBdump\-flows\fR may
@@ -392,9 +396,10 @@ resulting flow matches all packets.  The string \fB*\fR or \fBANY\fR
 may be specified to explicitly mark any of these fields as a wildcard.  
 (\fB*\fR should be quoted to protect it from shell expansion.)
 .
-.IP \fBin_port=\fIport_no\fR
-Matches OpenFlow port \fIport_no\fR.  Ports are numbered as
-displayed by \fBovs\-ofctl show\fR.
+.IP \fBin_port=\fIport\fR
+Matches OpenFlow port \fIport\fR, which may be an OpenFlow port number
+or keyword (e.g. \fBLOCAL\fR).
+\fBovs\-ofctl show\fR.
 .IP
 (The \fBresubmit\fR action can search OpenFlow flow tables with
 arbitrary \fBin_port\fR values, so flows that match port numbers that
@@ -799,25 +804,28 @@ require an additional field, which must be the final field specified:
 .IP \fBactions=\fR[\fItarget\fR][\fB,\fItarget\fR...]\fR
 Specifies a comma-separated list of actions to take on a packet when the 
 flow entry matches.  If no \fItarget\fR is specified, then packets
-matching the flow are dropped.  The \fItarget\fR may be a decimal port 
+matching the flow are dropped.  The \fItarget\fR may be an OpenFlow port 
 number designating the physical port on which to output the packet, or one 
 of the following keywords:
 .
 .RS
-.IP \fBoutput\fR:\fIport\fR
-.IQ \fBoutput\fR:\fIsrc\fB[\fIstart\fB..\fIend\fB]
-Outputs the packet. If \fIport\fR is an OpenFlow port number, outputs directly
-to it.  Otherwise, outputs to the OpenFlow port number read from \fIsrc\fR
-which must be an NXM field as described above.  Outputting to an NXM field is
-an OpenFlow extension which is not supported by standard OpenFlow switches.
-.IP
-Example: \fBoutput:NXM_NX_REG0[16..31]\fR outputs to the OpenFlow port number
-written in the upper half of register 0.
-.
-.IP \fBenqueue\fR:\fIport\fB:\fIqueue\fR
+.IP \fBoutput:\fIport\fR
+Outputs the packet to \fIport\fR, which must be an OpenFlow port
+number or keyword (e.g. \fBLOCAL\fR).
+.
+.IP \fBoutput:\fIsrc\fB[\fIstart\fB..\fIend\fB]
+Outputs the packet to the OpenFlow port number read from \fIsrc\fR,
+which must be an NXM field as described above.  For example,
+\fBoutput:NXM_NX_REG0[16..31]\fR outputs to the OpenFlow port number
+written in the upper half of register 0.  This form of \fBoutput\fR
+uses an OpenFlow extension that is not supported by standard OpenFlow
+switches.
+.
+.IP \fBenqueue:\fIport\fB:\fIqueue\fR
 Enqueues the packet on the specified \fIqueue\fR within port
-\fIport\fR.  The number of supported queues depends on the switch;
-some OpenFlow implementations do not support queuing at all.
+\fIport\fR, which must be an OpenFlow port number or keyword
+(e.g. \fBLOCAL\fR)..  The number of supported queues depends on the
+switch; some OpenFlow implementations do not support queuing at all.
 .
 .IP \fBnormal\fR
 Subjects the packet to the device's normal L2/L3 processing.  (This
@@ -1122,7 +1130,6 @@ For best performance, segregate learned flows into a table (using
 possibly for a lowest-priority ``catch-all'' flow, that is, a flow
 with no match criteria.  (This is why the default \fBtable\fR is 1, to
 keep the learned flows separate from the primary flow table 0.)
-.RE
 .
 .IP "\fBfin_timeout(\fIargument\fR[\fB,\fIargument\fR]\fB)"
 This action changes the idle timeout or hard timeout, or both, of this
@@ -1150,6 +1157,7 @@ This action causes Open vSwitch to immediately halt execution of further
 actions.  Those actions which have already been executed are unaffected.  Any
 further actions, including those which may be in other tables, or different
 levels of the \fBresubmit\fR call stack, are ignored.
+.RE
 .
 .PP
 An opaque identifier called a cookie can be used as a handle to identify
@@ -1245,7 +1253,8 @@ and \fBdel\-flows\fR commands support one additional optional field:
 .
 .TP
 \fBout_port=\fIport\fR
-If set, a matching flow must include an output action to \fIport\fR.
+If set, a matching flow must include an output action to \fIport\fR,
+which must an OpenFlow port number or name (e.g. \fBlocal\fR).
 .
 .SS "Table Entry Output"
 .
index 5f61fd6..dea8878 100644 (file)
@@ -741,9 +741,8 @@ fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
 static uint16_t
 str_to_port_no(const char *vconn_name, const char *port_name)
 {
-    unsigned int port_no;
-
-    if (str_to_uint(port_name, 10, &port_no)) {
+    uint16_t port_no = ofputil_port_from_string(port_name);
+    if (port_no) {
         return port_no;
     } else {
         struct ofputil_phy_port pp;
@@ -1466,9 +1465,7 @@ ofctl_packet_out(int argc, char *argv[])
     parse_ofpacts(argv[3], &ofpacts);
 
     po.buffer_id = UINT32_MAX;
-    po.in_port = (!strcasecmp(argv[2], "none") ? OFPP_NONE
-                  : !strcasecmp(argv[2], "local") ? OFPP_LOCAL
-                  : str_to_port_no(argv[1], argv[2]));
+    po.in_port = str_to_port_no(argv[1], argv[2]);
     po.ofpacts = ofpacts.data;
     po.ofpacts_len = ofpacts.size;
 
index 53bb7b9..940e5e7 100644 (file)
@@ -305,6 +305,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_fault_status);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_mpids);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_health);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_cfm_remote_opstate);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_lacp_current);
     ovsdb_idl_omit(idl, &ovsrec_interface_col_external_ids);