Merge pull request #1 from spil-jasper/master
authorBen Pfaff <blp@nicira.com>
Thu, 1 May 2014 14:40:35 +0000 (07:40 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 1 May 2014 14:40:35 +0000 (07:40 -0700)
Add BuildRequires to RHEL specfile

21 files changed:
FAQ
NEWS
datapath/flow_table.c
lib/bfd.c
lib/cfm.c
lib/classifier.c
lib/ofp-print.c
lib/ofp-util.h
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto-dpif-xlate.h
ofproto/ofproto-dpif.c
tests/bfd.at
tests/cfm.at
tests/classifier.at
tests/ofp-print.at
tests/ofp-util.at
tests/ofproto-macros.at
tests/test-vconn.c
utilities/ovs-ofctl.c
vswitchd/bridge.c
vswitchd/vswitch.xml

diff --git a/FAQ b/FAQ
index c43b0c8..128abe8 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -1119,19 +1119,28 @@ A: The following table lists the versions of OpenFlow supported by
        2.0                yes    [*]    [*]    [*]    ---
        2.1                yes    [*]    [*]    [*]    ---
        2.2                yes    [*]    [*]    [*]    [%]
+       2.3                yes    yes    yes    yes    [%]
 
        [*] Supported, with one or more missing features.
        [%] Support is unsafe: ovs-vswitchd will abort when certain
            unimplemented features are tested.
 
-   Because of missing features, OpenFlow 1.1, 1.2, and 1.3 must be
-   enabled manually.  The following command enables OpenFlow 1.0, 1.1,
-   1.2, and 1.3 on bridge br0:
+   Open vSwitch 2.3 enables OpenFlow 1.0, 1.1, 1.2, and 1.3 by default
+   in ovs-vswitchd.  In Open vSwitch 1.10 through 2.2, OpenFlow 1.1,
+   1.2, and 1.3 must be enabled manually in ovs-vswitchd.  Either way,
+   the user may override the default:
 
-       ovs-vsctl set bridge br0 protocols=OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13
+       - To enable OpenFlow 1.0, 1.1, 1.2, and 1.3 on bridge br0:
 
-   Use the -O option to enable support for later versions of OpenFlow
-   in ovs-ofctl.  For example:
+         ovs-vsctl set bridge br0 protocols=OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13
+
+       - To enable only OpenFlow 1.0 on bridge br0:
+
+         ovs-vsctl set bridge br0 protocols=OpenFlow10
+
+   All current versions of ovs-ofctl enable only OpenFlow 1.0 by
+   default.  Use the -O option to enable support for later versions of
+   OpenFlow in ovs-ofctl.  For example:
 
        ovs-ofctl -O OpenFlow13 dump-flows br0
 
@@ -1143,9 +1152,9 @@ A: The following table lists the versions of OpenFlow supported by
    invoked with a special --enable-of14 command line option.
 
    OPENFLOW-1.1+ in the Open vSwitch source tree tracks support for
-   OpenFlow 1.1 and later features.  When support for a given OpenFlow
-   version is solidly implemented, Open vSwitch will enable that
-   version by default.
+   OpenFlow 1.1 and later features.  When support for OpenFlow 1.4 is
+   solidly implemented, Open vSwitch will enable that version by
+   default.
 
 Q: Does Open vSwitch support MPLS?
 
diff --git a/NEWS b/NEWS
index 74b57ff..59e69af 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,16 @@
 Post-v2.2.0
 ---------------------
-
+   - OpenFlow 1.1, 1.2, and 1.3 are now enabled by default in
+     ovs-vswitchd.
+   - Linux kernel datapath now has an exact match cache optimizing the
+     flow matching process.
+   - Datapath flows now have partially wildcarded tranport port field
+     matches.  This reduces userspace upcalls, but increases the
+     number of different masks in the datapath.  The kernel datapath
+     exact match cache removes the overhead of matching the incoming
+     packets with the larger number of masks, but when paired with an
+     older kernel module, some workloads may perform worse with the
+     new userspace.
 
 v2.2.0 - xx xxx xxx
 ---------------------
index c8bd9d1..58a25c7 100644 (file)
@@ -577,7 +577,6 @@ struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
 
                if (ce->skb_hash == skb_hash) {
                        struct sw_flow_mask *mask;
-                       struct sw_flow *flow;
 
                        mask = rcu_dereference_ovsl(ma->masks[ce->mask_index]);
                        if (mask) {
index e3e3ae5..2d53bd2 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -203,6 +203,12 @@ struct bfd {
     bool forwarding_if_rx;
     long long int forwarding_if_rx_detect_time;
 
+    /* When 'bfd->forwarding_if_rx' is set, at least one bfd control packet
+     * is required to be received every 100 * bfd->cfg_min_rx.  If bfd
+     * control packet is not received within this interval, even if data
+     * packets are received, the bfd->forwarding will still be false. */
+    long long int demand_rx_bfd_time;
+
     /* BFD decay related variables. */
     bool in_decay;                /* True when bfd is in decay. */
     int decay_min_rx;             /* min_rx is set to decay_min_rx when */
@@ -841,6 +847,10 @@ bfd_process_packet(struct bfd *bfd, const struct flow *flow,
     }
     /* XXX: RFC 5880 Section 6.8.6 Demand mode related calculations here. */
 
+    if (bfd->forwarding_if_rx) {
+        bfd->demand_rx_bfd_time = time_msec() + 100 * bfd->cfg_min_rx;
+    }
+
 out:
     bfd_forwarding__(bfd);
     ovs_mutex_unlock(&mutex);
@@ -876,19 +886,22 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev)
 static bool
 bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
-    long long int time;
+    long long int now = time_msec();
+    bool forwarding_if_rx;
     bool last_forwarding = bfd->last_forwarding;
 
     if (bfd->forwarding_override != -1) {
         return bfd->forwarding_override == 1;
     }
 
-    time = bfd->forwarding_if_rx_detect_time;
-    bfd->last_forwarding = (bfd->state == STATE_UP
-                            || (bfd->forwarding_if_rx && time > time_msec()))
-                            && bfd->rmt_diag != DIAG_PATH_DOWN
-                            && bfd->rmt_diag != DIAG_CPATH_DOWN
-                            && bfd->rmt_diag != DIAG_RCPATH_DOWN;
+    forwarding_if_rx = bfd->forwarding_if_rx
+                       && bfd->forwarding_if_rx_detect_time > now
+                       && bfd->demand_rx_bfd_time > now;
+
+    bfd->last_forwarding = (bfd->state == STATE_UP || forwarding_if_rx)
+                           && bfd->rmt_diag != DIAG_PATH_DOWN
+                           && bfd->rmt_diag != DIAG_CPATH_DOWN
+                           && bfd->rmt_diag != DIAG_RCPATH_DOWN;
     if (bfd->last_forwarding != last_forwarding) {
         bfd->flap_count++;
         bfd_status_changed(bfd);
index 6a173a7..1b32625 100644 (file)
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -137,6 +137,11 @@ struct cfm {
     /* True when the variables returned by cfm_get_*() are changed
      * since last check. */
     bool status_changed;
+
+    /* When 'cfm->demand' is set, at least one ccm is required to be received
+     * every 100 * cfm_interval.  If ccm is not received within this interval,
+     * even if data packets are received, the cfm fault will be set. */
+    struct timer demand_rx_ccm_t;
 };
 
 /* Remote MPs represent foreign network entities that are configured to have
@@ -459,7 +464,8 @@ cfm_run(struct cfm *cfm) OVS_EXCLUDED(mutex)
         if (cfm->demand) {
             uint64_t rx_packets = cfm_rx_packets(cfm);
             demand_override = hmap_count(&cfm->remote_mps) == 1
-                && rx_packets > cfm->rx_packets;
+                && rx_packets > cfm->rx_packets
+                && !timer_expired(&cfm->demand_rx_ccm_t);
             cfm->rx_packets = rx_packets;
         }
 
@@ -836,6 +842,10 @@ cfm_process_heartbeat(struct cfm *cfm, const struct ofpbuf *p)
             rmp->mpid = ccm_mpid;
             if (!cfm_fault) {
                 rmp->num_health_ccm++;
+                if (cfm->demand) {
+                    timer_set_duration(&cfm->demand_rx_ccm_t,
+                                       100 * cfm->ccm_interval_ms);
+                }
             }
             rmp->recv = true;
             cfm->recv_fault |= cfm_fault;
index f90443b..2646996 100644 (file)
 VLOG_DEFINE_THIS_MODULE(classifier);
 
 struct trie_node;
+struct trie_ctx;
+
+/* Ports trie depends on both ports sharing the same ovs_be32. */
+#define TP_PORTS_OFS32 (offsetof(struct flow, tp_src) / 4)
+BUILD_ASSERT_DECL(TP_PORTS_OFS32 == offsetof(struct flow, tp_dst) / 4);
 
 /* Prefix trie for a 'field' */
 struct cls_trie {
@@ -79,6 +84,8 @@ struct cls_subtable {
     uint8_t index_ofs[CLS_MAX_INDICES]; /* u32 flow segment boundaries. */
     struct hindex indices[CLS_MAX_INDICES]; /* Staged lookup indices. */
     unsigned int trie_plen[CLS_MAX_TRIES];  /* Trie prefix length in 'mask'. */
+    int ports_mask_len;
+    struct trie_node *ports_trie; /* NULL if none. */
     struct minimask mask;       /* Wildcards for fields. */
     /* 'mask' must be the last field. */
 };
@@ -124,7 +131,6 @@ cls_match_alloc(struct cls_rule *rule)
     return cls_match;
 }
 
-struct trie_ctx;
 static struct cls_subtable *find_subtable(const struct cls_classifier *,
                                           const struct minimask *);
 static struct cls_subtable *insert_subtable(struct cls_classifier *,
@@ -165,10 +171,16 @@ static void trie_init(struct cls_classifier *, int trie_idx,
                       const struct mf_field *);
 static unsigned int trie_lookup(const struct cls_trie *, const struct flow *,
                                 unsigned int *checkbits);
-
+static unsigned int trie_lookup_value(const struct trie_node *,
+                                      const ovs_be32 value[],
+                                      unsigned int *checkbits);
 static void trie_destroy(struct trie_node *);
 static void trie_insert(struct cls_trie *, const struct cls_rule *, int mlen);
+static void trie_insert_prefix(struct trie_node **, const ovs_be32 *prefix,
+                               int mlen);
 static void trie_remove(struct cls_trie *, const struct cls_rule *, int mlen);
+static void trie_remove_prefix(struct trie_node **, const ovs_be32 *prefix,
+                               int mlen);
 static void mask_set_prefix_bits(struct flow_wildcards *, uint8_t be32ofs,
                                  unsigned int nbits);
 static bool mask_prefix_bits_set(const struct flow_wildcards *,
@@ -721,6 +733,13 @@ create_partition(struct cls_classifier *cls, struct cls_subtable *subtable,
     return partition;
 }
 
+static inline ovs_be32 minimatch_get_ports(const struct minimatch *match)
+{
+    /* Could optimize to use the same map if needed for fast path. */
+    return MINIFLOW_GET_BE32(&match->flow, tp_src)
+        & MINIFLOW_GET_BE32(&match->mask.masks, tp_src);
+}
+
 /* Inserts 'rule' into 'cls'.  Until 'rule' is removed from 'cls', the caller
  * must not modify or free it.
  *
@@ -765,6 +784,19 @@ classifier_replace(struct classifier *cls_, struct cls_rule *rule)
                 trie_insert(&cls->tries[i], rule, subtable->trie_plen[i]);
             }
         }
+
+        /* Ports trie. */
+        if (subtable->ports_mask_len) {
+            /* We mask the value to be inserted to always have the wildcarded
+             * bits in known (zero) state, so we can include them in comparison
+             * and they will always match (== their original value does not
+             * matter). */
+            ovs_be32 masked_ports = minimatch_get_ports(&rule->match);
+
+            trie_insert_prefix(&subtable->ports_trie, &masked_ports,
+                               subtable->ports_mask_len);
+        }
+
         return NULL;
     } else {
         struct cls_rule *old_cls_rule = old_rule->cls_rule;
@@ -805,9 +837,14 @@ classifier_remove(struct classifier *cls_, struct cls_rule *rule)
     ovs_assert(cls_match);
 
     subtable = find_subtable(cls, &rule->match.mask);
-
     ovs_assert(subtable);
 
+    if (subtable->ports_mask_len) {
+        ovs_be32 masked_ports = minimatch_get_ports(&rule->match);
+
+        trie_remove_prefix(&subtable->ports_trie,
+                           &masked_ports, subtable->ports_mask_len);
+    }
     for (i = 0; i < cls->n_tries; i++) {
         if (subtable->trie_plen[i]) {
             trie_remove(&cls->tries[i], rule, subtable->trie_plen[i]);
@@ -1336,6 +1373,11 @@ insert_subtable(struct cls_classifier *cls, const struct minimask *mask)
                                                          cls->tries[i].field);
     }
 
+    /* Ports trie. */
+    subtable->ports_trie = NULL;
+    subtable->ports_mask_len
+        = 32 - ctz32(ntohl(MINIFLOW_GET_BE32(&mask->masks, tp_src)));
+
     hmap_insert(&cls->subtables, &subtable->hmap_node, hash);
     elem.subtable = subtable;
     elem.tag = subtable->tag;
@@ -1359,6 +1401,8 @@ destroy_subtable(struct cls_classifier *cls, struct cls_subtable *subtable)
         }
     }
 
+    trie_destroy(subtable->ports_trie);
+
     for (i = 0; i < subtable->n_indices; i++) {
         hindex_destroy(&subtable->indices[i]);
     }
@@ -1644,6 +1688,23 @@ find_match_wc(const struct cls_subtable *subtable, const struct flow *flow,
          * but it didn't match. */
         rule = NULL;
     }
+    if (!rule && subtable->ports_mask_len) {
+        /* Ports are always part of the final range, if any.
+         * No match was found for the ports.  Use the ports trie to figure out
+         * which ports bits to unwildcard. */
+        unsigned int mbits;
+        ovs_be32 value, mask;
+
+        mask = MINIFLOW_GET_BE32(&subtable->mask.masks, tp_src);
+        value = ((OVS_FORCE ovs_be32 *)flow)[TP_PORTS_OFS32] & mask;
+        trie_lookup_value(subtable->ports_trie, &value, &mbits);
+
+        ((OVS_FORCE ovs_be32 *)&wc->masks)[TP_PORTS_OFS32] |=
+            mask & htonl(~0 << (32 - mbits));
+
+        ofs.start = TP_PORTS_OFS32;
+        goto range_out;
+    }
  out:
     /* Must unwildcard all the fields, as they were looked at. */
     flow_wildcards_fold_minimask(wc, &subtable->mask);
@@ -2037,14 +2098,18 @@ minimatch_get_prefix(const struct minimatch *match, const struct mf_field *mf)
 static void
 trie_insert(struct cls_trie *trie, const struct cls_rule *rule, int mlen)
 {
-    const ovs_be32 *prefix = minimatch_get_prefix(&rule->match, trie->field);
+    trie_insert_prefix(&trie->root,
+                       minimatch_get_prefix(&rule->match, trie->field), mlen);
+}
+
+static void
+trie_insert_prefix(struct trie_node **edge, const ovs_be32 *prefix, int mlen)
+{
     struct trie_node *node;
-    struct trie_node **edge;
     int ofs = 0;
 
     /* Walk the tree. */
-    for (edge = &trie->root;
-         (node = *edge) != NULL;
+    for (; (node = *edge) != NULL;
          edge = trie_next_edge(node, prefix, ofs)) {
         unsigned int eqbits = trie_prefix_equal_bits(node, prefix, ofs, mlen);
         ofs += eqbits;
@@ -2085,16 +2150,25 @@ trie_insert(struct cls_trie *trie, const struct cls_rule *rule, int mlen)
 static void
 trie_remove(struct cls_trie *trie, const struct cls_rule *rule, int mlen)
 {
-    const ovs_be32 *prefix = minimatch_get_prefix(&rule->match, trie->field);
+    trie_remove_prefix(&trie->root,
+                       minimatch_get_prefix(&rule->match, trie->field), mlen);
+}
+
+/* 'mlen' must be the (non-zero) CIDR prefix length of the 'trie->field' mask
+ * in 'rule'. */
+static void
+trie_remove_prefix(struct trie_node **root, const ovs_be32 *prefix, int mlen)
+{
     struct trie_node *node;
     struct trie_node **edges[sizeof(union mf_value) * 8];
     int depth = 0, ofs = 0;
 
     /* Walk the tree. */
-    for (edges[depth] = &trie->root;
+    for (edges[0] = root;
          (node = *edges[depth]) != NULL;
          edges[++depth] = trie_next_edge(node, prefix, ofs)) {
         unsigned int eqbits = trie_prefix_equal_bits(node, prefix, ofs, mlen);
+
         if (eqbits < node->nbits) {
             /* Mismatch, nothing to be removed.  This should never happen, as
              * only rules in the classifier are ever removed. */
index 9091b1b..38e228c 100644 (file)
@@ -2295,6 +2295,9 @@ ofp_print_version(const struct ofp_header *oh,
     case OFP13_VERSION:
         ds_put_cstr(string, " (OF1.3)");
         break;
+    case OFP14_VERSION:
+        ds_put_cstr(string, " (OF1.4)");
+        break;
     default:
         ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
         break;
index fe2c7c2..7c28034 100644 (file)
@@ -170,13 +170,15 @@ void ofputil_format_version_bitmap_names(struct ds *msg, uint32_t bitmap);
 uint32_t ofputil_protocols_to_version_bitmap(enum ofputil_protocol);
 enum ofputil_protocol ofputil_protocols_from_version_bitmap(uint32_t bitmap);
 
-/* Bitmap of OpenFlow versions that Open vSwitch supports. */
-#define OFPUTIL_SUPPORTED_VERSIONS \
-    ((1u << OFP10_VERSION) | (1u << OFP12_VERSION) | (1u << OFP13_VERSION))
-
-/* Bitmap of OpenFlow versions to enable by default (a subset of
- * OFPUTIL_SUPPORTED_VERSIONS). */
-#define OFPUTIL_DEFAULT_VERSIONS (1u << OFP10_VERSION)
+/* Bitmaps of OpenFlow versions that Open vSwitch supports, and that it enables
+ * by default.  When Open vSwitch has experimental or incomplete support for
+ * newer versions of OpenFlow, those versions should not be supported by
+ * default and thus should be omitted from the latter bitmap. */
+#define OFPUTIL_SUPPORTED_VERSIONS ((1u << OFP10_VERSION) | \
+                                    (1u << OFP11_VERSION) | \
+                                    (1u << OFP12_VERSION) | \
+                                    (1u << OFP13_VERSION))
+#define OFPUTIL_DEFAULT_VERSIONS OFPUTIL_SUPPORTED_VERSIONS
 
 enum ofputil_protocol ofputil_protocols_from_string(const char *s);
 
index e2ac9ad..57e84a7 100644 (file)
@@ -192,6 +192,10 @@ struct xlate_ctx {
     uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
     bool exit;                  /* No further actions should be processed. */
 
+    bool use_recirc;            /* Should generate recirc? */
+    struct xlate_recirc recirc; /* Information used for generating
+                                 * recirculation actions */
+
     /* OpenFlow 1.1+ action set.
      *
      * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS.
@@ -971,9 +975,10 @@ lookup_input_bundle(const struct xbridge *xbridge, ofp_port_t in_port,
         return xport->xbundle;
     }
 
-    /* Special-case OFPP_NONE, which a controller may use as the ingress
-     * port for traffic that it is sourcing. */
-    if (in_port == OFPP_NONE) {
+    /* Special-case OFPP_NONE (OF1.0) and OFPP_CONTROLLER (OF1.1+),
+     * which a controller may use as the ingress port for traffic that
+     * it is sourcing. */
+    if (in_port == OFPP_CONTROLLER || in_port == OFPP_NONE) {
         return &ofpp_none_bundle;
     }
 
@@ -1208,19 +1213,19 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
         /* Partially configured bundle with no slaves.  Drop the packet. */
         return;
     } else if (!out_xbundle->bond) {
-        ctx->xout->use_recirc = false;
+        ctx->use_recirc = false;
         xport = CONTAINER_OF(list_front(&out_xbundle->xports), struct xport,
                              bundle_node);
     } else {
         struct ofport_dpif *ofport;
-        struct xlate_recirc *xr = &ctx->xout->recirc;
+        struct xlate_recirc *xr = &ctx->recirc;
         struct flow_wildcards *wc = &ctx->xout->wc;
 
         if (ctx->xbridge->enable_recirc) {
-            ctx->xout->use_recirc = bond_may_recirc(
+            ctx->use_recirc = bond_may_recirc(
                 out_xbundle->bond, &xr->recirc_id, &xr->hash_basis);
 
-            if (ctx->xout->use_recirc) {
+            if (ctx->use_recirc) {
                 /* Only TCP mode uses recirculation. */
                 xr->hash_alg = OVS_HASH_ALG_L4;
                 bond_update_post_recirc_rules(out_xbundle->bond, false);
@@ -1241,7 +1246,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
 
         /* If ctx->xout->use_recirc is set, the main thread will handle stats
          * accounting for this bond. */
-        if (!ctx->xout->use_recirc) {
+        if (!ctx->use_recirc) {
             if (ctx->xin->resubmit_stats) {
                 bond_account(out_xbundle->bond, &ctx->xin->flow, vid,
                              ctx->xin->resubmit_stats->n_bytes);
@@ -1951,9 +1956,9 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
                                               &ctx->xout->odp_actions,
                                               &ctx->xout->wc);
 
-        if (ctx->xout->use_recirc) {
+        if (ctx->use_recirc) {
             struct ovs_action_hash *act_hash;
-            struct xlate_recirc *xr = &ctx->xout->recirc;
+            struct xlate_recirc *xr = &ctx->recirc;
 
             /* Hash action. */
             act_hash = nl_msg_put_unspec_uninit(&ctx->xout->odp_actions,
@@ -3267,6 +3272,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
     ctx.orig_skb_priority = flow->skb_priority;
     ctx.table_id = 0;
     ctx.exit = false;
+    ctx.use_recirc = false;
 
     if (!xin->ofpacts && !ctx.rule) {
         ctx.table_id = rule_dpif_lookup(ctx.xbridge->ofproto, flow,
@@ -3284,7 +3290,6 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout)
         ctx.rule = rule;
     }
     xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule);
-    xout->use_recirc = false;
 
     if (xin->ofpacts) {
         ofpacts = xin->ofpacts;
index 18137d5..760736a 100644 (file)
@@ -57,9 +57,6 @@ struct xlate_out {
     ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */
     mirror_mask_t mirrors;      /* Bitmap of associated mirrors. */
 
-    bool use_recirc;            /* Should generate recirc? */
-    struct xlate_recirc recirc; /* Information used for generating
-                                 * recirculation actions */
     uint64_t odp_actions_stub[256 / 8];
     struct ofpbuf odp_actions;
 };
index 4cebd77..7d082bc 100644 (file)
@@ -948,9 +948,9 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     return error;
 }
 
-/* Tests whether 'backer''s datapath supports recirculation Only newer datapath
- * supports OVS_KEY_ATTR in OVS_ACTION_ATTR_USERSPACE actions.  We need to
- * disable some features on older datapaths that don't support this feature.
+/* Tests whether 'backer''s datapath supports recirculation.  Only newer
+ * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys.  We need to disable some
+ * features on older datapaths that don't support this feature.
  *
  * Returns false if 'backer' definitely does not support recirculation, true if
  * it seems to support recirculation or if at least the error we get is
@@ -1357,6 +1357,12 @@ run(struct ofproto *ofproto_)
         ovs_rwlock_unlock(&ofproto->ml->rwlock);
     }
 
+    /* Always updates the ofproto->pins_seqno to avoid frequent wakeup during
+     * flow restore.  Even though nothing is processed during flow restore,
+     * all queued 'pins' will be handled immediately when flow restore
+     * completes. */
+    ofproto->pins_seqno = seq_read(ofproto->pins_seq);
+
     /* Do not perform any periodic activity required by 'ofproto' while
      * waiting for flow restore to complete. */
     if (!ofproto_get_flow_restore_wait()) {
@@ -1372,12 +1378,6 @@ run(struct ofproto *ofproto_)
         }
     }
 
-    /* Always updates the ofproto->pins_seqno to avoid frequent wakeup during
-     * flow restore.  Even though nothing is processed during flow restore,
-     * all queued 'pins' will be handled immediately when flow restore
-     * completes. */
-    ofproto->pins_seqno = seq_read(ofproto->pins_seq);
-
     if (ofproto->netflow) {
         netflow_run(ofproto->netflow);
     }
index 3723d60..f6f5592 100644 (file)
@@ -401,10 +401,9 @@ AT_CLEANUP
 
 # forwarding_if_rx Test1
 # Test1 tests the case when bfd is only enabled on one end of the link.
-# Under this situation, the bfd state should be DOWN and the forwarding
-# flag should be FALSE by default.  However, if forwarding_if_rx is
-# enabled, as long as there is packet received, the bfd forwarding flag
-# should be TRUE.
+# Under this situation, the forwarding flag should always be false, even
+# though there is data packet received, since there is no bfd control
+# packet received during the demand_rx_bfd interval.
 AT_SETUP([bfd - bfd forwarding_if_rx - bfd on one side])
 OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
                     add-port br1 p1 -- set Interface p1 type=patch \
@@ -438,15 +437,8 @@ do
     AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
              [0], [stdout], [])
 done
-# the forwarding flag should be true, since there is data received.
-BFD_CHECK([p0], [true], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-
-# reset bfd forwarding_if_rx.
-AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=false], [0])
-# forwarding flag should turn to false since the STATE is DOWN.
+# the forwarding flag should be false, due to the demand_rx_bfd.
 BFD_CHECK([p0], [false], [false], [none], [down], [No Diagnostic], [none], [down], [No Diagnostic])
-BFD_CHECK_TX([p0], [1000ms], [1000ms], [0ms])
-BFD_CHECK_RX([p0], [500ms], [500ms], [1ms])
 
 AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
 AT_CLEANUP
@@ -605,6 +597,74 @@ BFD_CHECK_RX([p0], [1000ms], [1000ms], [300ms])
 AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
 AT_CLEANUP
 
+# forwarding_if_rx Test4
+# Test4 is for testing the demand_rx_bfd feature.
+# bfd is enabled on both ends of the link.
+AT_SETUP([bfd - bfd forwarding_if_rx - demand_rx_bfd])
+OVS_VSWITCHD_START([add-br br1 -- set bridge br1 datapath-type=dummy -- \
+                    add-port br1 p1 -- set Interface p1 type=patch \
+                    options:peer=p0 ofport_request=2 -- \
+                    add-port br0 p0 -- set Interface p0 type=patch \
+                    options:peer=p1 ofport_request=1 -- \
+                    set Interface p0 bfd:enable=true bfd:min_tx=300 bfd:min_rx=300 bfd:forwarding_if_rx=true -- \
+                    set Interface p1 bfd:enable=true bfd:min_tx=500 bfd:min_rx=500])
+
+ovs-appctl time/stop
+# advance the clock, to stablize the states.
+for i in `seq 0 19`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
+BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
+BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
+
+# disable the bfd on p1.
+AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
+
+# advance clock by 4000ms, while receiving packets.
+# the STATE should go DOWN, due to Control Detection Time Expired.
+# but forwarding flag should be still true.
+for i in `seq 0 7`
+do
+    ovs-appctl time/warp 500
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+
+# advance clock long enough to trigger the demand_bfd_rx interval
+# (100 * bfd->cfm_min_rx), forwarding flag should go down since there
+# is no bfd control packet received during the demand_rx_bfd.
+for i in `seq 0 120`
+do
+    ovs-appctl time/warp 300
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+
+# now enable the bfd on p1 again.
+AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=true], [0])
+# advance clock by 5000ms.  and p1 and p0 should be all up.
+for i in `seq 0 9`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [true], [false], [none], [up], [Control Detection Time Expired], [none], [up], [No Diagnostic])
+BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], [up], [Control Detection Time Expired])
+BFD_CHECK_TX([p0], [500ms], [300ms], [500ms])
+
+# disable the bfd on p1 again.
+AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
+# advance clock long enough to trigger the demand_rx_bfd,
+# forwarding flag should go down since there is no bfd control packet
+# received during the demand_rx_bfd.
+for i in `seq 0 120`
+do
+    ovs-appctl time/warp 300
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+
+AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
+AT_CLEANUP
+
 # test bfd:flap_count.
 # This test contains three part:
 # part 1. tests the flap_count on normal bfd monitored link.
@@ -683,6 +743,7 @@ BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"]
 
 # Part-3 now turn on forwarding_if_rx.
 AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=true], [0])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
 # disable the bfd on p1.
 AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
 
@@ -699,9 +760,9 @@ BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired
 # flap_count should remain unchanged.
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["5"])
 
-# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
+# stop the traffic for more than 100 * bfd->cfm_min_rx ms, the forwarding flag of p0 should turn false.
 # and there should be the increment of flap_count.
-for i in `seq 0 7`; do ovs-appctl time/warp 500; done
+for i in `seq 0 120`; do ovs-appctl time/warp 100; done
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
 BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["6"])
 
@@ -712,21 +773,15 @@ do
     AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
              [0], [stdout], [])
 done
-BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-# flap_count should be incremented again.
-BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["7"])
-
-# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
-# and there should be the increment of flap_count.
-for i in `seq 0 7`; do ovs-appctl time/warp 500; done
+# forwarding should be false, since there is still no bfd control packet received.
 BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
-BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["8"])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["6"])
 
 # turn on the bfd on p1.
 AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
 for i in `seq 0 49`; do ovs-appctl time/warp 100; done
 # even though there is no data traffic, since p1 bfd is on again, should increment the flap_count.
-BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["9"])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["7"])
 BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
 
 OVS_VSWITCHD_STOP
index a3c44a1..fdca4ac 100644 (file)
@@ -14,6 +14,19 @@ Remote MPID $7
 ])
 ])
 
+m4_define([CFM_CHECK_EXTENDED_FAULT], [
+AT_CHECK([ovs-appctl cfm/show $1 | sed -e '/next CCM tx:/d' | sed -e '/next fault check:/d' | sed -e  '/recv since check:/d'],[0],
+[dnl
+---- $1 ----
+MPID $2: extended
+       fault: $3
+       average health: $4
+       opstate: $5
+       remote_opstate: $6
+       interval: $7
+])
+])
+
 m4_define([CFM_VSCTL_LIST_IFACE], [
 AT_CHECK([ovs-vsctl list interface $1 | sed -n '/$2/p'],[0],
 [dnl
@@ -101,6 +114,68 @@ done
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+# test demand_rx_ccm under demand mode.
+AT_SETUP([cfm - demand_rx_ccm])
+#Create 2 bridges connected by patch ports and enable cfm
+OVS_VSWITCHD_START([add-br br1 -- \
+                    set bridge br1 datapath-type=dummy \
+                    other-config:hwaddr=aa:55:aa:56:00:00 -- \
+                    add-port br1 p1 -- set Interface p1 type=patch \
+                    options:peer=p0 ofport_request=2 -- \
+                    add-port br0 p0 -- set Interface p0 type=patch \
+                    options:peer=p1 ofport_request=1 -- \
+                    set Interface p0 cfm_mpid=1 other_config:cfm_interval=300 other_config:cfm_extended=true other_config:cfm_demand=true -- \
+                    set Interface p1 cfm_mpid=2 other_config:cfm_interval=300 other_config:cfm_extended=true other_config:cfm_demand=true])
+
+ovs-appctl time/stop
+# wait for a while to stablize cfm. (need a longer time, since in demand mode
+# the fault interval is (MAX(ccm_interval_ms, 500) * 3.5) ms)
+for i in `seq 0 200`; do ovs-appctl time/warp 100; done
+CFM_CHECK_EXTENDED([p0], [1], [100], [up], [up], [300ms], [2], [up])
+CFM_CHECK_EXTENDED([p1], [2], [100], [up], [up], [300ms], [1], [up])
+
+# turn off the cfm on p1.
+AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
+# cfm should never go down while receiving data packets.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED([p0], [1], [0], [up], [up], [300ms], [2], [up])
+
+# wait longer, since the demand_rx_ccm interval is 100 * 300 ms.
+# since there is no ccm received, the [recv] fault should be raised.
+for i in `seq 0 200`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
+
+# now turn on the cfm on p1 again,
+AT_CHECK([ovs-vsctl set Interface p1 cfm_mpid=2])
+# cfm should be up for both p0 and p1
+for i in `seq 0 200`; do ovs-appctl time/warp 100; done
+CFM_CHECK_EXTENDED([p0], [1], [100], [up], [up], [300ms], [2], [up])
+CFM_CHECK_EXTENDED([p1], [2], [100], [up], [up], [300ms], [1], [up])
+
+# now turn off the cfm on p1 again
+AT_CHECK([ovs-vsctl clear Interface p1 cfm_mpid])
+# since there is no ccm received, the [recv] fault should be raised.
+for i in `seq 0 400`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2  "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+CFM_CHECK_EXTENDED_FAULT([p0], [1], [recv], [0], [up], [up], [300ms])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 # test cfm_flap_count.
 AT_SETUP([cfm - flap_count])
 #Create 2 bridges connected by patch ports and enable cfm
index b6c9352..5338a11 100644 (file)
@@ -55,7 +55,7 @@ Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=79
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=0x40/0xfff0
 Datapath actions: 2
 ])
 OVS_VSWITCHD_STOP
@@ -78,6 +78,8 @@ AT_DATA([flows.txt], [dnl
 table=0 in_port=1 priority=16,tcp,nw_dst=10.1.0.0/255.255.0.0,action=output(3)
 table=0 in_port=1 priority=32,tcp,nw_dst=10.1.2.0/255.255.255.0,tp_src=79,action=output(2)
 table=0 in_port=1 priority=33,tcp,nw_dst=10.1.2.15,tp_dst=80,action=drop
+table=0 in_port=1 priority=33,tcp,nw_dst=10.1.2.15,tp_dst=8080,action=output(2)
+table=0 in_port=1 priority=33,tcp,nw_dst=10.1.2.15,tp_dst=192,action=output(2)
 table=0 in_port=1 priority=0,ip,action=drop
 table=0 in_port=2 priority=16,tcp,nw_dst=192.168.0.0/255.255.0.0,action=output(1)
 table=0 in_port=2 priority=0,ip,action=drop
@@ -102,7 +104,7 @@ Datapath actions: drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
-  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=8,tp_dst=79
+  [Megaflow: recirc_id=0,skb_priority=0,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_src=0x0/0xffc0,tp_dst=0x40/0xfff0
 Datapath actions: 3
 ])
 OVS_VSWITCHD_STOP(["/'prefixes' with incompatible field: ipv6_label/d"])
index ef3102f..b74b681 100644 (file)
@@ -2375,7 +2375,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 05 1e 00 18 00 00 00 0a \
 00 00 00 02 02 00 00 00 ff ff ff ff ff ff ff ff \
 "], [0], [dnl
-OFPT_ROLE_STATUS (OF 0x05) (xid=0xa): role=master reason=experimenter_data_changed
+OFPT_ROLE_STATUS (OF1.4) (xid=0xa): role=master reason=experimenter_data_changed
 ])
 AT_CLEANUP
 
@@ -2385,7 +2385,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 05 1e 00 18 00 00 00 0a \
 00 00 00 02 01 00 00 00 ff ff ff ff ff ff ff ff \
 "], [0], [dnl
-OFPT_ROLE_STATUS (OF 0x05) (xid=0xa): role=master reason=configuration_changed
+OFPT_ROLE_STATUS (OF1.4) (xid=0xa): role=master reason=configuration_changed
 ])
 AT_CLEANUP
 
@@ -2395,7 +2395,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 05 1e 00 18 00 00 00 0a \
 00 00 00 02 01 00 00 00 00 00 00 00 00 00 00 10 \
 "], [0], [dnl
-OFPT_ROLE_STATUS (OF 0x05) (xid=0xa): role=master generation_id=16 reason=configuration_changed
+OFPT_ROLE_STATUS (OF1.4) (xid=0xa): role=master generation_id=16 reason=configuration_changed
 ])
 AT_CLEANUP
 
index fbb6848..248faf4 100644 (file)
@@ -24,7 +24,7 @@ OFPT_HELLO (OF1.3) (xid=0x1):
 ])
 AT_CHECK([ovs-ofctl encode-hello 0x3e], [0], [dnl
 00000000  05 00 00 08 00 00 00 01-
-OFPT_HELLO (OF 0x05) (xid=0x1):
+OFPT_HELLO (OF1.4) (xid=0x1):
  version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05
 ])
 
index 52f5af2..fe765ee 100644 (file)
@@ -83,7 +83,7 @@ m4_define([OVS_VSWITCHD_START],
 /ofproto|INFO|datapath ID changed to fedcba9876543210/d']])
 
    dnl Add bridges, ports, etc.
-   AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 protocols=[[OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13]] fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2])
+   AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2])
 ])
 
 m4_divert_push([PREPARE_TESTS])
index 8b24bd8..ec66f86 100644 (file)
@@ -231,7 +231,7 @@ test_read_hello(int argc OVS_UNUSED, char *argv[])
        if (retval == sizeof hello) {
            enum ofpraw raw;
 
-           CHECK(hello.version, OFP10_VERSION);
+           CHECK(hello.version, OFP13_VERSION);
            CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
            CHECK(raw, OFPRAW_OFPT_HELLO);
            CHECK(ntohs(hello.length), sizeof hello);
@@ -304,7 +304,7 @@ test_send_hello(const char *type, const void *out, size_t out_size,
            if (retval == sizeof hello) {
                enum ofpraw raw;
 
-               CHECK(hello.version, OFP10_VERSION);
+               CHECK(hello.version, OFP13_VERSION);
                CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
                CHECK(raw, OFPRAW_OFPT_HELLO);
                CHECK(ntohs(hello.length), sizeof hello);
@@ -355,7 +355,7 @@ test_send_plain_hello(int argc OVS_UNUSED, char *argv[])
     const char *type = argv[1];
     struct ofpbuf *hello;
 
-    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION,
                              htonl(0x12345678), 0);
     test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), 0);
     ofpbuf_delete(hello);
@@ -371,7 +371,7 @@ test_send_long_hello(int argc OVS_UNUSED, char *argv[])
     struct ofpbuf *hello;
     enum { EXTRA_BYTES = 8 };
 
-    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION,
                              htonl(0x12345678), EXTRA_BYTES);
     ofpbuf_put_zeros(hello, EXTRA_BYTES);
     ofpmsg_update_length(hello);
@@ -387,7 +387,7 @@ test_send_echo_hello(int argc OVS_UNUSED, char *argv[])
     const char *type = argv[1];
     struct ofpbuf *echo;
 
-    echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP10_VERSION,
+    echo = ofpraw_alloc_xid(OFPRAW_OFPT_ECHO_REQUEST, OFP13_VERSION,
                              htonl(0x12345678), 0);
     test_send_hello(type, ofpbuf_data(echo), ofpbuf_size(echo), EPROTO);
     ofpbuf_delete(echo);
@@ -413,7 +413,7 @@ test_send_invalid_version_hello(int argc OVS_UNUSED, char *argv[])
     const char *type = argv[1];
     struct ofpbuf *hello;
 
-    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP10_VERSION,
+    hello = ofpraw_alloc_xid(OFPRAW_OFPT_HELLO, OFP13_VERSION,
                              htonl(0x12345678), 0);
     ((struct ofp_header *) ofpbuf_data(hello))->version = 0;
     test_send_hello(type, ofpbuf_data(hello), ofpbuf_size(hello), EPROTO);
index 91c7f28..deba9dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -174,6 +174,23 @@ parse_options(int argc, char *argv[])
     uint32_t versions;
     enum ofputil_protocol version_protocols;
 
+    /* For now, ovs-ofctl only enables OpenFlow 1.0 by default.  This is
+     * because ovs-ofctl implements command such as "add-flow" as raw OpenFlow
+     * requests, but those requests have subtly different semantics in
+     * different OpenFlow versions.  For example:
+     *
+     *     - In OpenFlow 1.0, a "mod-flow" operation that does not find any
+     *       existing flow to modify adds a new flow.
+     *
+     *     - In OpenFlow 1.1, a "mod-flow" operation that does not find any
+     *       existing flow to modify adds a new flow, but only if the mod-flow
+     *       did not match on the flow cookie.
+     *
+     *     - In OpenFlow 1.2 and a later, a "mod-flow" operation never adds a
+     *       new flow.
+     */
+    set_allowed_ofp_versions("OpenFlow10");
+
     for (;;) {
         unsigned long int timeout;
         int c;
index 84e9ab8..12852b4 100644 (file)
@@ -626,13 +626,6 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
         bridge_configure_stp(br);
         bridge_configure_tables(br);
         bridge_configure_dp_desc(br);
-
-        if (smap_get(&br->cfg->other_config, "flow-eviction-threshold")) {
-            /* XXX: Remove this warning message eventually. */
-            VLOG_WARN_ONCE("As of June 2013, flow-eviction-threshold has been"
-                           " moved to the Open_vSwitch table.  Ignoring its"
-                           " setting in the bridge table.");
-        }
     }
     free(managers);
 
index 78594e7..7f2fd58 100644 (file)
 
       <column name="protocols">
        <p>
-         List of OpenFlow protocols that may be used when negotiating a
-         connection with a controller.  A default value of
-         <code>OpenFlow10</code> will be used if this column is empty.
+         List of OpenFlow protocols that may be used when negotiating
+         a connection with a controller.  OpenFlow 1.0, 1.1, 1.2, and
+         1.3 are enabled by default if this column is empty.
        </p>
 
        <p>
        </column>
 
        <column name="bfd" key="forwarding_if_rx" type='{"type": "boolean"}'>
-          True to consider the interface capable of packet I/O as long as it
-          continues to receive any packets (not just BFD packets).  This
-          prevents link congestion that causes consecutive BFD control packets
-          to be lost from marking the interface down.
+          When <code>true</code>, traffic received on the
+          <ref table="Interface"/> is used to indicate the capability of packet
+          I/O.  BFD control packets are still transmitted and received.  At
+          least one BFD control packet must be received every 100 * <ref
+          column="bfd" key="min_rx"/> amount of time.  Otherwise, even if
+          traffic are received, the <ref column="bfd" key="forwarding"/>
+          will be <code>false</code>.
        </column>
 
        <column name="bfd" key="cpath_down" type='{"type": "boolean"}'>
           <ref column="other_config" key="cfm_extended"/> is true, the CFM
           module operates in demand mode.  When in demand mode, traffic
           received on the <ref table="Interface"/> is used to indicate
-          liveness.  CCMs are still transmitted and received, but if the
-          <ref table="Interface"/> is receiving traffic, their absence does not
-          cause a connectivity fault.
+          liveness.  CCMs are still transmitted and received.  At least one
+          CCM must be received every 100 * <ref column="other_config"
+          key="cfm_interval"/> amount of time.  Otherwise, even if traffic
+          are received, the CFM module will raise the connectivity fault.
         </p>
 
         <p>