Open vSwitch CI 5acaff
diff --git a/Documentation/ref/ovs-actions.7.rst b/Documentation/ref/ovs-actions.7.rst
Open vSwitch CI 5acaff
index b59b7634f..d13895655 100644
Open vSwitch CI 5acaff
--- a/Documentation/ref/ovs-actions.7.rst
Open vSwitch CI 5acaff
+++ b/Documentation/ref/ovs-actions.7.rst
Open vSwitch CI 5acaff
@@ -1380,7 +1380,7 @@ The ``delete_field`` action
Open vSwitch CI 5acaff
   | ``delete_field:``\ *field*
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 The ``delete_field`` action deletes a *field* in the syntax described under
Open vSwitch CI 5acaff
-`Field Specifications`_ above.  Currently, only the ``tun_metadta`` fields are
Open vSwitch CI 5acaff
+`Field Specifications`_ above.  Currently, only the ``tun_metadata`` fields are
Open vSwitch CI 5acaff
 supported.
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 This action was added in Open vSwitch 2.14.
Open vSwitch CI 5acaff
diff --git a/NEWS b/NEWS
Open vSwitch CI 38c5a5
index 37a01dea5..e59f9530b 100644
Open vSwitch CI 5acaff
--- a/NEWS
Open vSwitch CI 5acaff
+++ b/NEWS
Open vSwitch CI 38c5a5
@@ -1,3 +1,12 @@
Open vSwitch CI 38c5a5
+v3.1.2 - xx xxx xxxx
Open vSwitch CI 5acaff
+--------------------
Open vSwitch CI 5acaff
+
Open vSwitch CI 38c5a5
+v3.1.1 - 06 Apr 2023
Open vSwitch CI 38c5a5
+--------------------
Open vSwitch CI 38c5a5
+   - Bug fixes
Open vSwitch CI 38c5a5
+   - Security:
Open vSwitch CI 38c5a5
+     * Fixed vulnerability CVE-2023-1668.
Open vSwitch CI 38c5a5
+
Open vSwitch CI 5acaff
 v3.1.0 - 16 Feb 2023
Open vSwitch CI 5acaff
 --------------------
Open vSwitch CI 5acaff
    - ovs-vswitchd now detects changes in CPU affinity and adjusts the number
Open vSwitch CI 5acaff
diff --git a/configure.ac b/configure.ac
Open vSwitch CI 38c5a5
index 9bf896c01..78a7ae31a 100644
Open vSwitch CI 5acaff
--- a/configure.ac
Open vSwitch CI 5acaff
+++ b/configure.ac
Open vSwitch CI 5acaff
@@ -13,7 +13,7 @@
Open vSwitch CI 5acaff
 # limitations under the License.
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 AC_PREREQ(2.63)
Open vSwitch CI 5acaff
-AC_INIT(openvswitch, 3.1.0, bugs@openvswitch.org)
Open vSwitch CI 38c5a5
+AC_INIT(openvswitch, 3.1.2, bugs@openvswitch.org)
Open vSwitch CI 5acaff
 AC_CONFIG_SRCDIR([vswitchd/ovs-vswitchd.c])
Open vSwitch CI 5acaff
 AC_CONFIG_MACRO_DIR([m4])
Open vSwitch CI 5acaff
 AC_CONFIG_AUX_DIR([build-aux])
Open vSwitch CI 5acaff
diff --git a/debian/changelog b/debian/changelog
Open vSwitch CI 38c5a5
index a5ad222c4..4663a2c29 100644
Open vSwitch CI 5acaff
--- a/debian/changelog
Open vSwitch CI 5acaff
+++ b/debian/changelog
Open vSwitch CI 38c5a5
@@ -1,3 +1,15 @@
Open vSwitch CI 38c5a5
+openvswitch (3.1.2-1) unstable; urgency=low
Open vSwitch CI 38c5a5
+   [ Open vSwitch team ]
Open vSwitch CI 38c5a5
+   * New upstream version
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+ -- Open vSwitch team <dev@openvswitch.org>  Thu, 06 Apr 2023 15:10:30 +0200
Open vSwitch CI 38c5a5
+
Open vSwitch CI 5acaff
+openvswitch (3.1.1-1) unstable; urgency=low
Open vSwitch CI 5acaff
+   [ Open vSwitch team ]
Open vSwitch CI 5acaff
+   * New upstream version
Open vSwitch CI 5acaff
+
Open vSwitch CI 38c5a5
+ -- Open vSwitch team <dev@openvswitch.org>  Thu, 06 Apr 2023 15:10:30 +0200
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 openvswitch (3.1.0-1) unstable; urgency=low
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
    * New upstream version
Open vSwitch CI 5acaff
diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
Open vSwitch CI 5acaff
index 045dce8f5..3b0220aaa 100644
Open vSwitch CI 5acaff
--- a/include/openvswitch/meta-flow.h
Open vSwitch CI 5acaff
+++ b/include/openvswitch/meta-flow.h
Open vSwitch CI 5acaff
@@ -2366,6 +2366,10 @@ void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s);
Open vSwitch CI 5acaff
 void field_array_set(enum mf_field_id id, const union mf_value *,
Open vSwitch CI 5acaff
                      struct field_array *);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+/* Mask the required l3 prerequisites if a 'set' action occurs. */
Open vSwitch CI 5acaff
+void mf_set_mask_l3_prereqs(const struct mf_field *, const struct flow *,
Open vSwitch CI 5acaff
+                            struct flow_wildcards *);
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 #ifdef __cplusplus
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 #endif
Open vSwitch CI 5acaff
diff --git a/lib/classifier.c b/lib/classifier.c
Open vSwitch CI 5acaff
index 0a89626cc..18dbfc83a 100644
Open vSwitch CI 5acaff
--- a/lib/classifier.c
Open vSwitch CI 5acaff
+++ b/lib/classifier.c
Open vSwitch CI 5acaff
@@ -1695,6 +1695,8 @@ find_match_wc(const struct cls_subtable *subtable, ovs_version_t version,
Open vSwitch CI 5acaff
     const struct cls_match *rule = NULL;
Open vSwitch CI 5acaff
     struct flowmap stages_map = FLOWMAP_EMPTY_INITIALIZER;
Open vSwitch CI 5acaff
     unsigned int mask_offset = 0;
Open vSwitch CI 5acaff
+    bool adjust_ports_mask = false;
Open vSwitch CI 5acaff
+    ovs_be32 ports_mask;
Open vSwitch CI 5acaff
     int i;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     /* Try to finish early by checking fields in segments. */
Open vSwitch CI 5acaff
@@ -1722,6 +1724,9 @@ find_match_wc(const struct cls_subtable *subtable, ovs_version_t version,
Open vSwitch CI 5acaff
                     subtable->index_maps[i], flow, wc)) {
Open vSwitch CI 5acaff
         goto no_match;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
+    /* Accumulate the map used so far. */
Open vSwitch CI 5acaff
+    stages_map = flowmap_or(stages_map, subtable->index_maps[i]);
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     hash = flow_hash_in_minimask_range(flow, &subtable->mask,
Open vSwitch CI 5acaff
                                        subtable->index_maps[i],
Open vSwitch CI 5acaff
                                        &mask_offset, &basis);
Open vSwitch CI 5acaff
@@ -1731,14 +1736,16 @@ find_match_wc(const struct cls_subtable *subtable, ovs_version_t version,
Open vSwitch CI 5acaff
          * unwildcarding all the ports bits, use the ports trie to figure out a
Open vSwitch CI 5acaff
          * smaller set of bits to unwildcard. */
Open vSwitch CI 5acaff
         unsigned int mbits;
Open vSwitch CI 5acaff
-        ovs_be32 value, plens, mask;
Open vSwitch CI 5acaff
+        ovs_be32 value, plens;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-        mask = miniflow_get_ports(&subtable->mask.masks);
Open vSwitch CI 5acaff
-        value = ((OVS_FORCE ovs_be32 *)flow)[TP_PORTS_OFS32] & mask;
Open vSwitch CI 5acaff
+        ports_mask = miniflow_get_ports(&subtable->mask.masks);
Open vSwitch CI 5acaff
+        value = ((OVS_FORCE ovs_be32 *) flow)[TP_PORTS_OFS32] & ports_mask;
Open vSwitch CI 5acaff
         mbits = trie_lookup_value(&subtable->ports_trie, &value, &plens, 32);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-        ((OVS_FORCE ovs_be32 *)&wc->masks)[TP_PORTS_OFS32] |=
Open vSwitch CI 5acaff
-            mask & be32_prefix_mask(mbits);
Open vSwitch CI 5acaff
+        ports_mask &= be32_prefix_mask(mbits);
Open vSwitch CI 5acaff
+        ports_mask |= ((OVS_FORCE ovs_be32 *) &wc->masks)[TP_PORTS_OFS32];
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+        adjust_ports_mask = true;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
         goto no_match;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
@@ -1751,6 +1758,14 @@ no_match:
Open vSwitch CI 5acaff
     /* Unwildcard the bits in stages so far, as they were used in determining
Open vSwitch CI 5acaff
      * there is no match. */
Open vSwitch CI 5acaff
     flow_wildcards_fold_minimask_in_map(wc, &subtable->mask, stages_map);
Open vSwitch CI 5acaff
+    if (adjust_ports_mask) {
Open vSwitch CI 5acaff
+        /* This has to be done after updating flow wildcards to overwrite
Open vSwitch CI 5acaff
+         * the ports mask back.  We can't simply disable the corresponding bit
Open vSwitch CI 5acaff
+         * in the stages map, because it has 64-bit resolution, i.e. one
Open vSwitch CI 5acaff
+         * bit covers not only tp_src/dst, but also ct_tp_src/dst, which are
Open vSwitch CI 5acaff
+         * not covered by the trie. */
Open vSwitch CI 5acaff
+        ((OVS_FORCE ovs_be32 *) &wc->masks)[TP_PORTS_OFS32] = ports_mask;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
     return NULL;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
diff --git a/lib/conntrack-tp.h b/lib/conntrack-tp.h
Open vSwitch CI 5acaff
index 4d411d19f..7ece2eae2 100644
Open vSwitch CI 5acaff
--- a/lib/conntrack-tp.h
Open vSwitch CI 5acaff
+++ b/lib/conntrack-tp.h
Open vSwitch CI 5acaff
@@ -17,8 +17,15 @@
Open vSwitch CI 5acaff
 #ifndef CONNTRACK_TP_H
Open vSwitch CI 5acaff
 #define CONNTRACK_TP_H 1
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+#include <stdint.h>
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 #define CT_DPIF_NETDEV_TP_MIN 30
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 enum ct_timeout;
Open vSwitch CI 5acaff
+struct conn;
Open vSwitch CI 5acaff
+struct conntrack;
Open vSwitch CI 5acaff
+struct timeout_policy;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 void timeout_policy_init(struct conntrack *ct);
Open vSwitch CI 5acaff
 int timeout_policy_update(struct conntrack *ct, struct timeout_policy *tp);
Open vSwitch CI 5acaff
 int timeout_policy_delete(struct conntrack *ct, uint32_t tp_id);
Open vSwitch CI 5acaff
diff --git a/lib/conntrack.c b/lib/conntrack.c
Open vSwitch CI 5acaff
index 524670e45..8cf7779c6 100644
Open vSwitch CI 5acaff
--- a/lib/conntrack.c
Open vSwitch CI 5acaff
+++ b/lib/conntrack.c
Open vSwitch CI 5acaff
@@ -1512,12 +1512,12 @@ conntrack_clean(struct conntrack *ct, long long now)
Open vSwitch CI 5acaff
     clean_end = n_conn_limit / 64;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     for (i = ct->next_sweep; i < N_EXP_LISTS; i++) {
Open vSwitch CI 5acaff
-        count += ct_sweep(ct, &ct->exp_lists[i], now);
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
         if (count > clean_end) {
Open vSwitch CI 5acaff
             next_wakeup = 0;
Open vSwitch CI 5acaff
             break;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+        count += ct_sweep(ct, &ct->exp_lists[i], now);
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     ct->next_sweep = (i < N_EXP_LISTS) ? i : 0;
Open vSwitch CI 5acaff
diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c
Open vSwitch CI 5acaff
index 134496ef3..5d2635946 100644
Open vSwitch CI 5acaff
--- a/lib/db-ctl-base.c
Open vSwitch CI 5acaff
+++ b/lib/db-ctl-base.c
Open vSwitch CI 5acaff
@@ -1492,7 +1492,7 @@ cmd_add(struct ctl_context *ctx)
Open vSwitch CI 5acaff
     const struct ovsdb_idl_column *column;
Open vSwitch CI 5acaff
     const struct ovsdb_idl_row *row;
Open vSwitch CI 5acaff
     const struct ovsdb_type *type;
Open vSwitch CI 5acaff
-    struct ovsdb_datum new;
Open vSwitch CI 5acaff
+    struct ovsdb_datum old;
Open vSwitch CI 5acaff
     int i;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     ctx->error = get_table(table_name, &table);
Open vSwitch CI 5acaff
@@ -1516,13 +1516,7 @@ cmd_add(struct ctl_context *ctx)
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     type = &column->type;
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-    if (ctx->last_command) {
Open vSwitch CI 5acaff
-        ovsdb_datum_init_empty(&new;;
Open vSwitch CI 5acaff
-    } else {
Open vSwitch CI 5acaff
-        ovsdb_datum_clone(&new, ovsdb_idl_read(row, column));
Open vSwitch CI 5acaff
-    }
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
+    ovsdb_datum_clone(&old, ovsdb_idl_read(row, column));
Open vSwitch CI 5acaff
     for (i = 4; i < ctx->argc; i++) {
Open vSwitch CI 5acaff
         struct ovsdb_type add_type;
Open vSwitch CI 5acaff
         struct ovsdb_datum add;
Open vSwitch CI 5acaff
@@ -1533,41 +1527,23 @@ cmd_add(struct ctl_context *ctx)
Open vSwitch CI 5acaff
         ctx->error = ovsdb_datum_from_string(&add, &add_type, ctx->argv[i],
Open vSwitch CI 5acaff
                                              ctx->symtab);
Open vSwitch CI 5acaff
         if (ctx->error) {
Open vSwitch CI 5acaff
-            ovsdb_datum_destroy(&new, &column->type);
Open vSwitch CI 5acaff
+            ovsdb_datum_destroy(&old, &column->type);
Open vSwitch CI 5acaff
             return;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
-        ovsdb_datum_union(&new, &add, type);
Open vSwitch CI 5acaff
+        ovsdb_datum_union(&old, &add, type);
Open vSwitch CI 5acaff
         ovsdb_datum_destroy(&add, type);
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-    if (!ctx->last_command && new.n > type->n_max) {
Open vSwitch CI 5acaff
+    if (old.n > type->n_max) {
Open vSwitch CI 5acaff
         ctl_error(ctx, "\"add\" operation would put %u %s in column %s of "
Open vSwitch CI 5acaff
                   "table %s but the maximum number is %u",
Open vSwitch CI 5acaff
-                  new.n,
Open vSwitch CI 5acaff
+                  old.n,
Open vSwitch CI 5acaff
                   type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs",
Open vSwitch CI 5acaff
                   column->name, table->name, type->n_max);
Open vSwitch CI 5acaff
-        ovsdb_datum_destroy(&new, &column->type);
Open vSwitch CI 5acaff
+        ovsdb_datum_destroy(&old, &column->type);
Open vSwitch CI 5acaff
         return;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-    if (ctx->last_command) {
Open vSwitch CI 5acaff
-        /* Partial updates can only be made one by one. */
Open vSwitch CI 5acaff
-        for (i = 0; i < new.n; i++) {
Open vSwitch CI 5acaff
-            struct ovsdb_datum *datum = xmalloc(sizeof *datum);
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-            ovsdb_datum_init_empty(datum);
Open vSwitch CI 5acaff
-            ovsdb_datum_add_from_index_unsafe(datum, &new, i, type);
Open vSwitch CI 5acaff
-            if (ovsdb_type_is_map(type)) {
Open vSwitch CI 5acaff
-                ovsdb_idl_txn_write_partial_map(row, column, datum);
Open vSwitch CI 5acaff
-            } else {
Open vSwitch CI 5acaff
-                ovsdb_idl_txn_write_partial_set(row, column, datum);
Open vSwitch CI 5acaff
-            }
Open vSwitch CI 5acaff
-        }
Open vSwitch CI 5acaff
-        ovsdb_datum_destroy(&new, &column->type);
Open vSwitch CI 5acaff
-    } else {
Open vSwitch CI 5acaff
-        ovsdb_idl_txn_verify(row, column);
Open vSwitch CI 5acaff
-        ovsdb_idl_txn_write(row, column, &new;;
Open vSwitch CI 5acaff
-    }
Open vSwitch CI 5acaff
+    ovsdb_idl_txn_verify(row, column);
Open vSwitch CI 5acaff
+    ovsdb_idl_txn_write(row, column, &old;;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     invalidate_cache(ctx);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
diff --git a/lib/dpctl.c b/lib/dpctl.c
Open vSwitch CI 5acaff
index d12d9b8a5..970373389 100644
Open vSwitch CI 5acaff
--- a/lib/dpctl.c
Open vSwitch CI 5acaff
+++ b/lib/dpctl.c
Open vSwitch CI 5acaff
@@ -1713,10 +1713,16 @@ dpctl_flush_conntrack(int argc, const char *argv[],
Open vSwitch CI 5acaff
     uint16_t zone, *pzone = NULL;
Open vSwitch CI 5acaff
     int error;
Open vSwitch CI 5acaff
     int args = argc - 1;
Open vSwitch CI 5acaff
+    int zone_pos = 1;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+    if (dp_arg_exists(argc, argv)) {
Open vSwitch CI 5acaff
+        args--;
Open vSwitch CI 5acaff
+        zone_pos = 2;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     /* Parse zone. */
Open vSwitch CI 5acaff
-    if (args && !strncmp(argv[1], "zone=", 5)) {
Open vSwitch CI 5acaff
-        if (!ovs_scan(argv[1], "zone=%"SCNu16, &zone)) {
Open vSwitch CI 5acaff
+    if (args && !strncmp(argv[zone_pos], "zone=", 5)) {
Open vSwitch CI 5acaff
+        if (!ovs_scan(argv[zone_pos], "zone=%"SCNu16, &zone)) {
Open vSwitch CI 5acaff
             ds_put_cstr(&ds, "failed to parse zone");
Open vSwitch CI 5acaff
             error = EINVAL;
Open vSwitch CI 5acaff
             goto error;
Open vSwitch CI 5acaff
@@ -1744,7 +1750,7 @@ dpctl_flush_conntrack(int argc, const char *argv[],
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     /* Report error if there is more than one unparsed argument. */
Open vSwitch CI 5acaff
-    if (args > 1) {
Open vSwitch CI 5acaff
+    if (args > 0) {
Open vSwitch CI 5acaff
         ds_put_cstr(&ds, "invalid arguments");
Open vSwitch CI 5acaff
         error = EINVAL;
Open vSwitch CI 5acaff
         goto error;
Open vSwitch CI 5acaff
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
Open vSwitch CI 5acaff
index c9f7179c3..aed2c8fbb 100644
Open vSwitch CI 5acaff
--- a/lib/dpif-netdev.c
Open vSwitch CI 5acaff
+++ b/lib/dpif-netdev.c
Open vSwitch CI 5acaff
@@ -9616,6 +9616,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id,
Open vSwitch CI 5acaff
 const struct dpif_class dpif_netdev_class = {
Open vSwitch CI 5acaff
     "netdev",
Open vSwitch CI 5acaff
     true,                       /* cleanup_required */
Open vSwitch CI 5acaff
+    true,                       /* synced_dp_layers */
Open vSwitch CI 5acaff
     dpif_netdev_init,
Open vSwitch CI 5acaff
     dpif_netdev_enumerate,
Open vSwitch CI 5acaff
     dpif_netdev_port_open_type,
Open vSwitch CI 5acaff
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
Open vSwitch CI 5acaff
index 026b0daa8..2f829f589 100644
Open vSwitch CI 5acaff
--- a/lib/dpif-netlink.c
Open vSwitch CI 5acaff
+++ b/lib/dpif-netlink.c
Open vSwitch CI 5acaff
@@ -2582,7 +2582,7 @@ dpif_netlink_calculate_n_handlers(void)
Open vSwitch CI 5acaff
         n_handlers = MIN(next_prime_num, total_cores);
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-    return n_handlers;
Open vSwitch CI 5acaff
+    return MAX(n_handlers, 1);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static int
Open vSwitch CI 5acaff
@@ -4515,6 +4515,7 @@ dpif_netlink_cache_set_size(struct dpif *dpif_, uint32_t level, uint32_t size)
Open vSwitch CI 5acaff
 const struct dpif_class dpif_netlink_class = {
Open vSwitch CI 5acaff
     "system",
Open vSwitch CI 5acaff
     false,                      /* cleanup_required */
Open vSwitch CI 5acaff
+    false,                      /* synced_dp_layers */
Open vSwitch CI 5acaff
     NULL,                       /* init */
Open vSwitch CI 5acaff
     dpif_netlink_enumerate,
Open vSwitch CI 5acaff
     NULL,
Open vSwitch CI 5acaff
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
Open vSwitch CI 5acaff
index 12477a24f..b8ead8a02 100644
Open vSwitch CI 5acaff
--- a/lib/dpif-provider.h
Open vSwitch CI 5acaff
+++ b/lib/dpif-provider.h
Open vSwitch CI 5acaff
@@ -127,6 +127,14 @@ struct dpif_class {
Open vSwitch CI 5acaff
      * datapaths that can not exist without it (e.g. netdev datapath).  */
Open vSwitch CI 5acaff
     bool cleanup_required;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+    /* If 'true' the specific dpif implementation synchronizes the various
Open vSwitch CI 5acaff
+     * datapath implementation layers, i.e., the dpif's layer in combination
Open vSwitch CI 5acaff
+     * with the underlying netdev offload layers. For example, dpif-netlink
Open vSwitch CI 5acaff
+     * does not sync its kernel flows with the tc ones, i.e., only one gets
Open vSwitch CI 5acaff
+     * installed. On the other hand, dpif-netdev installs both flows,
Open vSwitch CI 5acaff
+     * internally keeps track of both, and represents them as one. */
Open vSwitch CI 5acaff
+    bool synced_dp_layers;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     /* Called when the dpif provider is registered, typically at program
Open vSwitch CI 5acaff
      * startup.  Returning an error from this function will prevent any
Open vSwitch CI 5acaff
      * datapath with this class from being created.
Open vSwitch CI 5acaff
diff --git a/lib/dpif.c b/lib/dpif.c
Open vSwitch CI 5acaff
index fe4db83fb..3305401fe 100644
Open vSwitch CI 5acaff
--- a/lib/dpif.c
Open vSwitch CI 5acaff
+++ b/lib/dpif.c
Open vSwitch CI 5acaff
@@ -2109,3 +2109,9 @@ dpif_cache_set_size(struct dpif *dpif, uint32_t level, uint32_t size)
Open vSwitch CI 5acaff
            ? dpif->dpif_class->cache_set_size(dpif, level, size)
Open vSwitch CI 5acaff
            : EOPNOTSUPP;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+bool
Open vSwitch CI 5acaff
+dpif_synced_dp_layers(struct dpif *dpif)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    return dpif->dpif_class->synced_dp_layers;
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
diff --git a/lib/dpif.h b/lib/dpif.h
Open vSwitch CI 5acaff
index 6cb4dae6d..129cbf6a1 100644
Open vSwitch CI 5acaff
--- a/lib/dpif.h
Open vSwitch CI 5acaff
+++ b/lib/dpif.h
Open vSwitch CI 5acaff
@@ -939,6 +939,7 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, odp_port_t port_no,
Open vSwitch CI 5acaff
 char *dpif_get_dp_version(const struct dpif *);
Open vSwitch CI 5acaff
 bool dpif_supports_tnl_push_pop(const struct dpif *);
Open vSwitch CI 5acaff
 bool dpif_supports_explicit_drop_action(const struct dpif *);
Open vSwitch CI 5acaff
+bool dpif_synced_dp_layers(struct dpif *);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 /* Log functions. */
Open vSwitch CI 5acaff
 struct vlog_module;
Open vSwitch CI 5acaff
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
Open vSwitch CI 5acaff
index c576ae620..474344194 100644
Open vSwitch CI 5acaff
--- a/lib/meta-flow.c
Open vSwitch CI 5acaff
+++ b/lib/meta-flow.c
Open vSwitch CI 5acaff
@@ -3676,3 +3676,28 @@ mf_bitmap_not(struct mf_bitmap x)
Open vSwitch CI 5acaff
     bitmap_not(x.bm, MFF_N_IDS);
Open vSwitch CI 5acaff
     return x;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+void
Open vSwitch CI 5acaff
+mf_set_mask_l3_prereqs(const struct mf_field *mf, const struct flow *fl,
Open vSwitch CI 5acaff
+                       struct flow_wildcards *wc)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    if (is_ip_any(fl) &&
Open vSwitch CI 5acaff
+        ((mf->id == MFF_IPV4_SRC) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IPV4_DST) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IPV6_SRC) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IPV6_DST) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IPV6_LABEL) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IP_DSCP) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IP_ECN) ||
Open vSwitch CI 5acaff
+         (mf->id == MFF_IP_TTL))) {
Open vSwitch CI 5acaff
+        WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
+    } else if ((fl->dl_type == htons(ETH_TYPE_ARP)) &&
Open vSwitch CI 5acaff
+               ((mf->id == MFF_ARP_OP) ||
Open vSwitch CI 5acaff
+                (mf->id == MFF_ARP_SHA) ||
Open vSwitch CI 5acaff
+                (mf->id == MFF_ARP_THA) ||
Open vSwitch CI 5acaff
+                (mf->id == MFF_ARP_SPA) ||
Open vSwitch CI 5acaff
+                (mf->id == MFF_ARP_TPA))) {
Open vSwitch CI 5acaff
+        /* mask only the lower 8 bits. */
Open vSwitch CI 5acaff
+        wc->masks.nw_proto = 0xff;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
Open vSwitch CI 5acaff
index 4c78c4816..c38247423 100644
Open vSwitch CI 5acaff
--- a/lib/netdev-offload-tc.c
Open vSwitch CI 5acaff
+++ b/lib/netdev-offload-tc.c
Open vSwitch CI 5acaff
@@ -276,8 +276,9 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid,
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     err = tc_del_flower_filter(id);
Open vSwitch CI 5acaff
-    if (!err) {
Open vSwitch CI 5acaff
+    if (!err || err == ENODEV) {
Open vSwitch CI 5acaff
         del_ufid_tc_mapping(ufid);
Open vSwitch CI 5acaff
+        return 0;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
     return err;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
@@ -871,7 +872,7 @@ parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
Open vSwitch CI 5acaff
                 outport =
Open vSwitch CI 5acaff
                     netdev_ifindex_to_odp_port(action->out.ifindex_out);
Open vSwitch CI 5acaff
                 if (!outport) {
Open vSwitch CI 5acaff
-                    return ENOENT;
Open vSwitch CI 5acaff
+                    return -ENOENT;
Open vSwitch CI 5acaff
                 }
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport));
Open vSwitch CI 5acaff
@@ -964,7 +965,7 @@ parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
Open vSwitch CI 5acaff
             uint32_t meter_id;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
             if (police_idx_lookup(action->police.index, &meter_id)) {
Open vSwitch CI 5acaff
-                return ENOENT;
Open vSwitch CI 5acaff
+                return -ENOENT;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             nl_msg_put_u32(buf, OVS_ACTION_ATTR_METER, meter_id);
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
@@ -983,6 +984,9 @@ parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
Open vSwitch CI 5acaff
                 buf, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER);
Open vSwitch CI 5acaff
             i = parse_tc_flower_to_actions__(flower, buf, i + 1,
Open vSwitch CI 5acaff
                                              action->police.result_jump);
Open vSwitch CI 5acaff
+            if (i < 0) {
Open vSwitch CI 5acaff
+                return i;
Open vSwitch CI 5acaff
+            }
Open vSwitch CI 5acaff
             nl_msg_end_nested(buf, act_offset);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
             act_offset = nl_msg_start_nested(
Open vSwitch CI 5acaff
@@ -994,6 +998,9 @@ parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             if (jump != 0) {
Open vSwitch CI 5acaff
                 i = parse_tc_flower_to_actions__(flower, buf, i, jump);
Open vSwitch CI 5acaff
+                if (i < 0) {
Open vSwitch CI 5acaff
+                    return i;
Open vSwitch CI 5acaff
+                }
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             nl_msg_end_nested(buf, act_offset);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -1013,11 +1020,11 @@ parse_tc_flower_to_actions__(struct tc_flower *flower, struct ofpbuf *buf,
Open vSwitch CI 5acaff
     return i;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-static void
Open vSwitch CI 5acaff
+static int
Open vSwitch CI 5acaff
 parse_tc_flower_to_actions(struct tc_flower *flower,
Open vSwitch CI 5acaff
                            struct ofpbuf *buf)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
-    parse_tc_flower_to_actions__(flower, buf, 0, 0);
Open vSwitch CI 5acaff
+    return parse_tc_flower_to_actions__(flower, buf, 0, 0);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static int
Open vSwitch CI 5acaff
@@ -1030,9 +1037,10 @@ parse_tc_flower_to_match(const struct netdev *netdev,
Open vSwitch CI 5acaff
                          struct ofpbuf *buf,
Open vSwitch CI 5acaff
                          bool terse)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
-    size_t act_off;
Open vSwitch CI 5acaff
     struct tc_flower_key *key = &flower->key;
Open vSwitch CI 5acaff
     struct tc_flower_key *mask = &flower->mask;
Open vSwitch CI 5acaff
+    size_t act_off;
Open vSwitch CI 5acaff
+    int err;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     if (terse) {
Open vSwitch CI 5acaff
         return parse_tc_flower_terse_to_match(flower, match, stats, attrs);
Open vSwitch CI 5acaff
@@ -1229,7 +1237,10 @@ parse_tc_flower_to_match(const struct netdev *netdev,
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     act_off = nl_msg_start_nested(buf, OVS_FLOW_ATTR_ACTIONS);
Open vSwitch CI 5acaff
-    parse_tc_flower_to_actions(flower, buf);
Open vSwitch CI 5acaff
+    err = parse_tc_flower_to_actions(flower, buf);
Open vSwitch CI 5acaff
+    if (err < 0) {
Open vSwitch CI 5acaff
+        return -err;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
     nl_msg_end_nested(buf, act_off);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     *actions = ofpbuf_at_assert(buf, act_off, sizeof(struct nlattr));
Open vSwitch CI 5acaff
@@ -1272,8 +1283,8 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
Open vSwitch CI 5acaff
             continue;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-        if (flower.act_cookie.len) {
Open vSwitch CI 5acaff
-            *ufid = *((ovs_u128 *) flower.act_cookie.data);
Open vSwitch CI 5acaff
+        if (flower.act_cookie.len >= sizeof *ufid) {
Open vSwitch CI 5acaff
+            *ufid = get_32aligned_u128(flower.act_cookie.data);
Open vSwitch CI 5acaff
         } else if (!find_ufid(netdev, &id, ufid)) {
Open vSwitch CI 5acaff
             continue;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
@@ -2490,15 +2501,23 @@ netdev_tc_flow_get(struct netdev *netdev,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     err = tc_get_flower(&id, &flower);
Open vSwitch CI 5acaff
     if (err) {
Open vSwitch CI 5acaff
-        VLOG_ERR_RL(&error_rl, "flow get failed (dev %s prio %d handle %d): %s",
Open vSwitch CI 5acaff
+        VLOG_ERR_RL(&error_rl,
Open vSwitch CI 5acaff
+                    "flow get failed (dev %s prio %d handle %d): %s",
Open vSwitch CI 5acaff
                     netdev_get_name(netdev), id.prio, id.handle,
Open vSwitch CI 5acaff
                     ovs_strerror(err));
Open vSwitch CI 5acaff
         return err;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     in_port = netdev_ifindex_to_odp_port(id.ifindex);
Open vSwitch CI 5acaff
-    parse_tc_flower_to_match(netdev, &flower, match, actions,
Open vSwitch CI 5acaff
-                             stats, attrs, buf, false);
Open vSwitch CI 5acaff
+    err = parse_tc_flower_to_match(netdev, &flower, match, actions,
Open vSwitch CI 5acaff
+                                   stats, attrs, buf, false);
Open vSwitch CI 5acaff
+    if (err) {
Open vSwitch CI 5acaff
+        VLOG_ERR_RL(&error_rl,
Open vSwitch CI 5acaff
+                    "flow get parse failed (dev %s prio %d handle %d): %s",
Open vSwitch CI 5acaff
+                    netdev_get_name(netdev), id.prio, id.handle,
Open vSwitch CI 5acaff
+                    ovs_strerror(err));
Open vSwitch CI 5acaff
+        return err;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     if (stats) {
Open vSwitch CI 5acaff
         struct dpif_flow_stats adjust_stats;
Open vSwitch CI 5acaff
diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c
Open vSwitch CI 5acaff
index 4ad45ffa1..3fad501e3 100644
Open vSwitch CI 5acaff
--- a/lib/netdev-windows.c
Open vSwitch CI 5acaff
+++ b/lib/netdev-windows.c
Open vSwitch CI 5acaff
@@ -156,6 +156,7 @@ netdev_windows_system_construct(struct netdev *netdev_)
Open vSwitch CI 5acaff
     struct netdev_windows_netdev_info info;
Open vSwitch CI 5acaff
     struct ofpbuf *buf;
Open vSwitch CI 5acaff
     int ret;
Open vSwitch CI 5acaff
+    const char    *type = NULL;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     /* Query the attributes and runtime status of the netdev. */
Open vSwitch CI 5acaff
     ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf;;
Open vSwitch CI 5acaff
@@ -167,6 +168,16 @@ netdev_windows_system_construct(struct netdev *netdev_)
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
     ofpbuf_delete(buf);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+    /* Don't create netdev if ovs-type is "internal"
Open vSwitch CI 5acaff
+     * but the type of netdev->up is "system". */
Open vSwitch CI 5acaff
+    type = netdev_get_type(&netdev->up);
Open vSwitch CI 5acaff
+    if (type && !strcmp(type, "system") &&
Open vSwitch CI 5acaff
+        (info.ovs_type == OVS_VPORT_TYPE_INTERNAL)) {
Open vSwitch CI 5acaff
+        VLOG_DBG("construct device %s, ovs_type: %u failed",
Open vSwitch CI 5acaff
+                 netdev_get_name(&netdev->up), info.ovs_type);
Open vSwitch CI 5acaff
+        return 1;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     netdev->change_seq = 1;
Open vSwitch CI 5acaff
     netdev->dev_type = info.ovs_type;
Open vSwitch CI 5acaff
     netdev->port_no = info.port_no;
Open vSwitch CI 5acaff
diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c
Open vSwitch CI 5acaff
index 2d382f1e8..ac5d2c3d0 100644
Open vSwitch CI 5acaff
--- a/lib/ovs-thread.c
Open vSwitch CI 5acaff
+++ b/lib/ovs-thread.c
Open vSwitch CI 5acaff
@@ -674,7 +674,7 @@ count_cpu_cores(void)
Open vSwitch CI 5acaff
     static int cpu_cores;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     ovs_mutex_lock(&cpu_cores_mutex);
Open vSwitch CI 5acaff
-    if (now - last_updated >= COUNT_CPU_UPDATE_TIME_MS) {
Open vSwitch CI 5acaff
+    if (!last_updated || now - last_updated >= COUNT_CPU_UPDATE_TIME_MS) {
Open vSwitch CI 5acaff
         last_updated = now;
Open vSwitch CI 5acaff
         cpu_cores = count_cpu_cores__();
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
Open vSwitch CI 5acaff
index 742eed399..f13478a88 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto-dpif-ipfix.c
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto-dpif-ipfix.c
Open vSwitch CI 5acaff
@@ -124,11 +124,18 @@ struct dpif_ipfix_port {
Open vSwitch CI 5acaff
     uint32_t ifindex;
Open vSwitch CI 5acaff
 };
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+struct dpif_ipfix_domain {
Open vSwitch CI 5acaff
+    struct hmap_node hmap_node; /* In struct dpif_ipfix_exporter's domains. */
Open vSwitch CI 5acaff
+    time_t last_template_set_time;
Open vSwitch CI 5acaff
+};
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 struct dpif_ipfix_exporter {
Open vSwitch CI 5acaff
     uint32_t exporter_id; /* Exporting Process identifier */
Open vSwitch CI 5acaff
-    struct collectors *collectors;
Open vSwitch CI 5acaff
     uint32_t seq_number;
Open vSwitch CI 5acaff
-    time_t last_template_set_time;
Open vSwitch CI 5acaff
+    struct collectors *collectors;
Open vSwitch CI 5acaff
+    struct hmap domains; /* Contains struct dpif_ipfix_domain indexed by
Open vSwitch CI 5acaff
+                            observation domain id. */
Open vSwitch CI 5acaff
+    time_t last_stats_sent_time;
Open vSwitch CI 5acaff
     struct hmap cache_flow_key_map;  /* ipfix_flow_cache_entry. */
Open vSwitch CI 5acaff
     struct ovs_list cache_flow_start_timestamp_list;  /* ipfix_flow_cache_entry. */
Open vSwitch CI 5acaff
     uint32_t cache_active_timeout;  /* In seconds. */
Open vSwitch CI 5acaff
@@ -617,6 +624,9 @@ static void get_export_time_now(uint64_t *, uint32_t *);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter *, bool);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+static void dpif_ipfix_exporter_del_domain(struct dpif_ipfix_exporter *,
Open vSwitch CI 5acaff
+                                           struct dpif_ipfix_domain *);
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 static bool
Open vSwitch CI 5acaff
 ofproto_ipfix_bridge_exporter_options_equal(
Open vSwitch CI 5acaff
     const struct ofproto_ipfix_bridge_exporter_options *a,
Open vSwitch CI 5acaff
@@ -697,13 +707,14 @@ dpif_ipfix_exporter_init(struct dpif_ipfix_exporter *exporter)
Open vSwitch CI 5acaff
     exporter->exporter_id = ++exporter_total_count;
Open vSwitch CI 5acaff
     exporter->collectors = NULL;
Open vSwitch CI 5acaff
     exporter->seq_number = 1;
Open vSwitch CI 5acaff
-    exporter->last_template_set_time = 0;
Open vSwitch CI 5acaff
+    exporter->last_stats_sent_time = 0;
Open vSwitch CI 5acaff
     hmap_init(&exporter->cache_flow_key_map);
Open vSwitch CI 5acaff
     ovs_list_init(&exporter->cache_flow_start_timestamp_list);
Open vSwitch CI 5acaff
     exporter->cache_active_timeout = 0;
Open vSwitch CI 5acaff
     exporter->cache_max_flows = 0;
Open vSwitch CI 5acaff
     exporter->virtual_obs_id = NULL;
Open vSwitch CI 5acaff
     exporter->virtual_obs_len = 0;
Open vSwitch CI 5acaff
+    hmap_init(&exporter->domains);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     memset(&exporter->ipfix_global_stats, 0,
Open vSwitch CI 5acaff
            sizeof(struct dpif_ipfix_global_stats));
Open vSwitch CI 5acaff
@@ -711,6 +722,7 @@ dpif_ipfix_exporter_init(struct dpif_ipfix_exporter *exporter)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     /* Flush the cache with flow end reason "forced end." */
Open vSwitch CI 5acaff
     dpif_ipfix_cache_expire_now(exporter, true);
Open vSwitch CI 5acaff
@@ -719,22 +731,29 @@ dpif_ipfix_exporter_clear(struct dpif_ipfix_exporter *exporter)
Open vSwitch CI 5acaff
     exporter->exporter_id = 0;
Open vSwitch CI 5acaff
     exporter->collectors = NULL;
Open vSwitch CI 5acaff
     exporter->seq_number = 1;
Open vSwitch CI 5acaff
-    exporter->last_template_set_time = 0;
Open vSwitch CI 5acaff
+    exporter->last_stats_sent_time = 0;
Open vSwitch CI 5acaff
     exporter->cache_active_timeout = 0;
Open vSwitch CI 5acaff
     exporter->cache_max_flows = 0;
Open vSwitch CI 5acaff
     free(exporter->virtual_obs_id);
Open vSwitch CI 5acaff
     exporter->virtual_obs_id = NULL;
Open vSwitch CI 5acaff
     exporter->virtual_obs_len = 0;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+    struct dpif_ipfix_domain *dom;
Open vSwitch CI 5acaff
+    HMAP_FOR_EACH_SAFE (dom, hmap_node, &exporter->domains) {
Open vSwitch CI 5acaff
+        dpif_ipfix_exporter_del_domain(exporter, dom);
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     memset(&exporter->ipfix_global_stats, 0,
Open vSwitch CI 5acaff
            sizeof(struct dpif_ipfix_global_stats));
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_exporter_destroy(struct dpif_ipfix_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     dpif_ipfix_exporter_clear(exporter);
Open vSwitch CI 5acaff
     hmap_destroy(&exporter->cache_flow_key_map);
Open vSwitch CI 5acaff
+    hmap_destroy(&exporter->domains);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static bool
Open vSwitch CI 5acaff
@@ -742,7 +761,7 @@ dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
                                 const struct sset *targets,
Open vSwitch CI 5acaff
                                 const uint32_t cache_active_timeout,
Open vSwitch CI 5acaff
                                 const uint32_t cache_max_flows,
Open vSwitch CI 5acaff
-                                const char *virtual_obs_id)
Open vSwitch CI 5acaff
+                                const char *virtual_obs_id) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     size_t virtual_obs_len;
Open vSwitch CI 5acaff
     collectors_destroy(exporter->collectors);
Open vSwitch CI 5acaff
@@ -769,6 +788,37 @@ dpif_ipfix_exporter_set_options(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
     return true;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+static struct dpif_ipfix_domain *
Open vSwitch CI 5acaff
+dpif_ipfix_exporter_find_domain(const struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
+                                uint32_t domain_id) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    struct dpif_ipfix_domain *dom;
Open vSwitch CI 5acaff
+    HMAP_FOR_EACH_WITH_HASH (dom, hmap_node, hash_int(domain_id, 0),
Open vSwitch CI 5acaff
+                             &exporter->domains) {
Open vSwitch CI 5acaff
+        return dom;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+    return NULL;
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+static struct dpif_ipfix_domain *
Open vSwitch CI 5acaff
+dpif_ipfix_exporter_insert_domain(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
+                                  const uint32_t domain_id) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    struct dpif_ipfix_domain *dom = xmalloc(sizeof *dom);
Open vSwitch CI 5acaff
+    dom->last_template_set_time = 0;
Open vSwitch CI 5acaff
+    hmap_insert(&exporter->domains, &dom->hmap_node, hash_int(domain_id, 0));
Open vSwitch CI 5acaff
+    return dom;
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+static void
Open vSwitch CI 5acaff
+dpif_ipfix_exporter_del_domain(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
+                               struct dpif_ipfix_domain *dom)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    hmap_remove(&exporter->domains, &dom->hmap_node);
Open vSwitch CI 5acaff
+    free(dom);
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 static struct dpif_ipfix_port *
Open vSwitch CI 5acaff
 dpif_ipfix_find_port(const struct dpif_ipfix *di,
Open vSwitch CI 5acaff
                      odp_port_t odp_port) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
@@ -909,6 +959,7 @@ dpif_ipfix_bridge_exporter_init(struct dpif_ipfix_bridge_exporter *exporter)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     dpif_ipfix_exporter_clear(&exporter->exporter);
Open vSwitch CI 5acaff
     ofproto_ipfix_bridge_exporter_options_destroy(exporter->options);
Open vSwitch CI 5acaff
@@ -918,6 +969,7 @@ dpif_ipfix_bridge_exporter_clear(struct dpif_ipfix_bridge_exporter *exporter)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_bridge_exporter_destroy(struct dpif_ipfix_bridge_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     dpif_ipfix_bridge_exporter_clear(exporter);
Open vSwitch CI 5acaff
     dpif_ipfix_exporter_destroy(&exporter->exporter);
Open vSwitch CI 5acaff
@@ -927,7 +979,7 @@ static void
Open vSwitch CI 5acaff
 dpif_ipfix_bridge_exporter_set_options(
Open vSwitch CI 5acaff
     struct dpif_ipfix_bridge_exporter *exporter,
Open vSwitch CI 5acaff
     const struct ofproto_ipfix_bridge_exporter_options *options,
Open vSwitch CI 5acaff
-    bool *options_changed)
Open vSwitch CI 5acaff
+    bool *options_changed) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     if (!options || sset_is_empty(&options->targets)) {
Open vSwitch CI 5acaff
         /* No point in doing any work if there are no targets. */
Open vSwitch CI 5acaff
@@ -1003,6 +1055,7 @@ dpif_ipfix_flow_exporter_init(struct dpif_ipfix_flow_exporter *exporter)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     dpif_ipfix_exporter_clear(&exporter->exporter);
Open vSwitch CI 5acaff
     ofproto_ipfix_flow_exporter_options_destroy(exporter->options);
Open vSwitch CI 5acaff
@@ -1011,6 +1064,7 @@ dpif_ipfix_flow_exporter_clear(struct dpif_ipfix_flow_exporter *exporter)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_flow_exporter_destroy(struct dpif_ipfix_flow_exporter *exporter)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     dpif_ipfix_flow_exporter_clear(exporter);
Open vSwitch CI 5acaff
     dpif_ipfix_exporter_destroy(&exporter->exporter);
Open vSwitch CI 5acaff
@@ -1020,7 +1074,7 @@ static bool
Open vSwitch CI 5acaff
 dpif_ipfix_flow_exporter_set_options(
Open vSwitch CI 5acaff
     struct dpif_ipfix_flow_exporter *exporter,
Open vSwitch CI 5acaff
     const struct ofproto_ipfix_flow_exporter_options *options,
Open vSwitch CI 5acaff
-    bool *options_changed)
Open vSwitch CI 5acaff
+    bool *options_changed) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     if (sset_is_empty(&options->targets)) {
Open vSwitch CI 5acaff
         /* No point in doing any work if there are no targets. */
Open vSwitch CI 5acaff
@@ -1071,6 +1125,7 @@ dpif_ipfix_flow_exporter_set_options(
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 remove_flow_exporter(struct dpif_ipfix *di,
Open vSwitch CI 5acaff
                      struct dpif_ipfix_flow_exporter_map_node *node)
Open vSwitch CI 5acaff
+                     OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     hmap_remove(&di->flow_exporter_map, &node->node);
Open vSwitch CI 5acaff
     dpif_ipfix_flow_exporter_destroy(&node->exporter);
Open vSwitch CI 5acaff
@@ -2000,6 +2055,7 @@ static void
Open vSwitch CI 5acaff
 ipfix_cache_update(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
                    struct ipfix_flow_cache_entry *entry,
Open vSwitch CI 5acaff
                    enum ipfix_sampled_packet_type sampled_pkt_type)
Open vSwitch CI 5acaff
+                   OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     struct ipfix_flow_cache_entry *old_entry;
Open vSwitch CI 5acaff
     size_t current_flows = 0;
Open vSwitch CI 5acaff
@@ -2811,14 +2867,36 @@ dpif_ipfix_flow_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
Open vSwitch CI 5acaff
     ovs_mutex_unlock(&mutex);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+static bool
Open vSwitch CI 5acaff
+dpif_ipfix_should_send_template(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
+                                const uint32_t observation_domain_id,
Open vSwitch CI 5acaff
+                                const uint32_t export_time_sec)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    struct dpif_ipfix_domain *domain;
Open vSwitch CI 5acaff
+    domain = dpif_ipfix_exporter_find_domain(exporter,
Open vSwitch CI 5acaff
+                                             observation_domain_id);
Open vSwitch CI 5acaff
+    if (!domain) {
Open vSwitch CI 5acaff
+        /* First time we see this obs_domain_id. */
Open vSwitch CI 5acaff
+        domain = dpif_ipfix_exporter_insert_domain(exporter,
Open vSwitch CI 5acaff
+                                                   observation_domain_id);
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+    if ((domain->last_template_set_time + IPFIX_TEMPLATE_INTERVAL)
Open vSwitch CI 5acaff
+        <= export_time_sec) {
Open vSwitch CI 5acaff
+        domain->last_template_set_time = export_time_sec;
Open vSwitch CI 5acaff
+        return true;
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+    return false;
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_cache_expire(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
                         bool forced_end, const uint64_t export_time_usec,
Open vSwitch CI 5acaff
-                        const uint32_t export_time_sec)
Open vSwitch CI 5acaff
+                        const uint32_t export_time_sec) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     struct ipfix_flow_cache_entry *entry;
Open vSwitch CI 5acaff
     uint64_t max_flow_start_timestamp_usec;
Open vSwitch CI 5acaff
-    bool template_msg_sent = false;
Open vSwitch CI 5acaff
     enum ipfix_flow_end_reason flow_end_reason;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     if (ovs_list_is_empty(&exporter->cache_flow_start_timestamp_list)) {
Open vSwitch CI 5acaff
@@ -2844,25 +2922,28 @@ dpif_ipfix_cache_expire(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
             break;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-        ovs_list_remove(&entry->cache_flow_start_timestamp_list_node);
Open vSwitch CI 5acaff
-        hmap_remove(&exporter->cache_flow_key_map,
Open vSwitch CI 5acaff
-                    &entry->flow_key_map_node);
Open vSwitch CI 5acaff
+        /* XXX: Make frequency of the (Options) Template and Exporter Process
Open vSwitch CI 5acaff
+         * Statistics transmission configurable.
Open vSwitch CI 5acaff
+         * Cf. IETF RFC 5101 Section 4.3. and 10.3.6. */
Open vSwitch CI 5acaff
+        if ((exporter->last_stats_sent_time + IPFIX_TEMPLATE_INTERVAL)
Open vSwitch CI 5acaff
+             <= export_time_sec) {
Open vSwitch CI 5acaff
+            exporter->last_stats_sent_time = export_time_sec;
Open vSwitch CI 5acaff
+            ipfix_send_exporter_data_msg(exporter, export_time_sec);
Open vSwitch CI 5acaff
+        }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-         /* XXX: Make frequency of the (Options) Template and Exporter Process
Open vSwitch CI 5acaff
-          * Statistics transmission configurable.
Open vSwitch CI 5acaff
-          * Cf. IETF RFC 5101 Section 4.3. and 10.3.6. */
Open vSwitch CI 5acaff
-        if (!template_msg_sent
Open vSwitch CI 5acaff
-            && (exporter->last_template_set_time + IPFIX_TEMPLATE_INTERVAL)
Open vSwitch CI 5acaff
-                <= export_time_sec) {
Open vSwitch CI 5acaff
+        if (dpif_ipfix_should_send_template(exporter,
Open vSwitch CI 5acaff
+                                            entry->flow_key.obs_domain_id,
Open vSwitch CI 5acaff
+                                            export_time_sec)) {
Open vSwitch CI 5acaff
+            VLOG_DBG("Sending templates for ObservationDomainID %"PRIu32,
Open vSwitch CI 5acaff
+                     entry->flow_key.obs_domain_id);
Open vSwitch CI 5acaff
             ipfix_send_template_msgs(exporter, export_time_sec,
Open vSwitch CI 5acaff
                                      entry->flow_key.obs_domain_id);
Open vSwitch CI 5acaff
-            exporter->last_template_set_time = export_time_sec;
Open vSwitch CI 5acaff
-            template_msg_sent = true;
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-            /* Send Exporter Process Statistics. */
Open vSwitch CI 5acaff
-            ipfix_send_exporter_data_msg(exporter, export_time_sec);
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+        ovs_list_remove(&entry->cache_flow_start_timestamp_list_node);
Open vSwitch CI 5acaff
+        hmap_remove(&exporter->cache_flow_key_map,
Open vSwitch CI 5acaff
+                    &entry->flow_key_map_node);
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
         /* XXX: Group multiple data records for the same obs domain id
Open vSwitch CI 5acaff
          * into the same message. */
Open vSwitch CI 5acaff
         ipfix_send_data_msg(exporter, export_time_sec, entry, flow_end_reason);
Open vSwitch CI 5acaff
@@ -2883,7 +2964,7 @@ get_export_time_now(uint64_t *export_time_usec, uint32_t *export_time_sec)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static void
Open vSwitch CI 5acaff
 dpif_ipfix_cache_expire_now(struct dpif_ipfix_exporter *exporter,
Open vSwitch CI 5acaff
-                            bool forced_end)
Open vSwitch CI 5acaff
+                            bool forced_end) OVS_REQUIRES(mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     uint64_t export_time_usec;
Open vSwitch CI 5acaff
     uint32_t export_time_sec;
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
Open vSwitch CI 5acaff
index e05ffe312..89df92242 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto-dpif-upcall.c
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto-dpif-upcall.c
Open vSwitch CI 5acaff
@@ -47,17 +47,20 @@
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 #define UPCALL_MAX_BATCH 64
Open vSwitch CI 5acaff
 #define REVALIDATE_MAX_BATCH 50
Open vSwitch CI 5acaff
+#define UINT64_THREE_QUARTERS (UINT64_MAX / 4 * 3)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 VLOG_DEFINE_THIS_MODULE(ofproto_dpif_upcall);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(dumped_duplicate_flow);
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(dumped_new_flow);
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(handler_duplicate_upcall);
Open vSwitch CI 5acaff
-COVERAGE_DEFINE(upcall_ukey_contention);
Open vSwitch CI 5acaff
-COVERAGE_DEFINE(upcall_ukey_replace);
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(revalidate_missed_dp_flow);
Open vSwitch CI 5acaff
+COVERAGE_DEFINE(ukey_dp_change);
Open vSwitch CI 5acaff
+COVERAGE_DEFINE(ukey_invalid_stat_reset);
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(upcall_flow_limit_hit);
Open vSwitch CI 5acaff
 COVERAGE_DEFINE(upcall_flow_limit_kill);
Open vSwitch CI 5acaff
+COVERAGE_DEFINE(upcall_ukey_contention);
Open vSwitch CI 5acaff
+COVERAGE_DEFINE(upcall_ukey_replace);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 /* A thread that reads upcalls from dpif, forwards each upcall's packet,
Open vSwitch CI 5acaff
  * and possibly sets up a kernel flow as a cache. */
Open vSwitch CI 5acaff
@@ -287,6 +290,7 @@ struct udpif_key {
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     struct ovs_mutex mutex;                   /* Guards the following. */
Open vSwitch CI 5acaff
     struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/
Open vSwitch CI 5acaff
+    const char *dp_layer OVS_GUARDED;         /* Last known dp_layer. */
Open vSwitch CI 5acaff
     long long int created OVS_GUARDED;        /* Estimate of creation time. */
Open vSwitch CI 5acaff
     uint64_t dump_seq OVS_GUARDED;            /* Tracks udpif->dump_seq. */
Open vSwitch CI 5acaff
     uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
Open vSwitch CI 5acaff
@@ -780,6 +784,17 @@ udpif_get_n_flows(struct udpif *udpif)
Open vSwitch CI 5acaff
         atomic_store_relaxed(&udpif->n_flows_timestamp, now);
Open vSwitch CI 5acaff
         dpif_get_dp_stats(udpif->dpif, &stats);
Open vSwitch CI 5acaff
         flow_count = stats.n_flows;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+        if (!dpif_synced_dp_layers(udpif->dpif)) {
Open vSwitch CI 5acaff
+            /* If the dpif layer does not sync the flows, we need to include
Open vSwitch CI 5acaff
+             * the hardware offloaded flows separately. */
Open vSwitch CI 5acaff
+            uint64_t hw_flows;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+            if (!dpif_get_n_offloaded_flows(udpif->dpif, &hw_flows)) {
Open vSwitch CI 5acaff
+                flow_count += hw_flows;
Open vSwitch CI 5acaff
+            }
Open vSwitch CI 5acaff
+        }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
         atomic_store_relaxed(&udpif->n_flows, flow_count);
Open vSwitch CI 5acaff
         ovs_mutex_unlock(&udpif->n_flows_mutex);
Open vSwitch CI 5acaff
     } else {
Open vSwitch CI 5acaff
@@ -1766,6 +1781,7 @@ ukey_create__(const struct nlattr *key, size_t key_len,
Open vSwitch CI 5acaff
     ukey->created = ukey->flow_time = time_msec();
Open vSwitch CI 5acaff
     memset(&ukey->stats, 0, sizeof ukey->stats);
Open vSwitch CI 5acaff
     ukey->stats.used = used;
Open vSwitch CI 5acaff
+    ukey->dp_layer = NULL;
Open vSwitch CI 5acaff
     ukey->xcache = NULL;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     ukey->offloaded = false;
Open vSwitch CI 5acaff
@@ -2095,10 +2111,12 @@ ukey_delete(struct umap *umap, struct udpif_key *ukey)
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static bool
Open vSwitch CI 5acaff
-should_revalidate(const struct udpif *udpif, uint64_t packets,
Open vSwitch CI 5acaff
-                  long long int used)
Open vSwitch CI 5acaff
+should_revalidate(const struct udpif *udpif, const struct udpif_key *ukey,
Open vSwitch CI 5acaff
+                  uint64_t packets)
Open vSwitch CI 5acaff
+    OVS_REQUIRES(ukey->mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     long long int metric, now, duration;
Open vSwitch CI 5acaff
+    long long int used = ukey->stats.used;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     if (!used) {
Open vSwitch CI 5acaff
         /* Always revalidate the first time a flow is dumped. */
Open vSwitch CI 5acaff
@@ -2125,8 +2143,12 @@ should_revalidate(const struct udpif *udpif, uint64_t packets,
Open vSwitch CI 5acaff
     duration = now - used;
Open vSwitch CI 5acaff
     metric = duration / packets;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-    if (metric < 1000 / ofproto_min_revalidate_pps) {
Open vSwitch CI 5acaff
-        /* The flow is receiving more than min-revalidate-pps, so keep it. */
Open vSwitch CI 5acaff
+    if (metric < 1000 / ofproto_min_revalidate_pps ||
Open vSwitch CI 5acaff
+        (ukey->offloaded && duration < ofproto_offloaded_stats_delay)) {
Open vSwitch CI 5acaff
+        /* The flow is receiving more than min-revalidate-pps, so keep it.
Open vSwitch CI 5acaff
+         * Or it's a hardware offloaded flow that might take up to X seconds
Open vSwitch CI 5acaff
+         * to update its statistics. Until we are sure the statistics had a
Open vSwitch CI 5acaff
+         * chance to be updated, also keep it. */
Open vSwitch CI 5acaff
         return true;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
     return false;
Open vSwitch CI 5acaff
@@ -2324,7 +2346,7 @@ static enum reval_result
Open vSwitch CI 5acaff
 revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
Open vSwitch CI 5acaff
                 const struct dpif_flow_stats *stats,
Open vSwitch CI 5acaff
                 struct ofpbuf *odp_actions, uint64_t reval_seq,
Open vSwitch CI 5acaff
-                struct recirc_refs *recircs, bool offloaded)
Open vSwitch CI 5acaff
+                struct recirc_refs *recircs)
Open vSwitch CI 5acaff
     OVS_REQUIRES(ukey->mutex)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
     bool need_revalidate = ukey->reval_seq != reval_seq;
Open vSwitch CI 5acaff
@@ -2342,8 +2364,15 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
Open vSwitch CI 5acaff
                     ? stats->n_bytes - ukey->stats.n_bytes
Open vSwitch CI 5acaff
                     : 0);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+    if (stats->n_packets < ukey->stats.n_packets &&
Open vSwitch CI 5acaff
+        ukey->stats.n_packets < UINT64_THREE_QUARTERS) {
Open vSwitch CI 5acaff
+        /* Report cases where the packet counter is lower than the previous
Open vSwitch CI 5acaff
+         * instance, but exclude the potential wrapping of an uint64_t. */
Open vSwitch CI 5acaff
+        COVERAGE_INC(ukey_invalid_stat_reset);
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     if (need_revalidate) {
Open vSwitch CI 5acaff
-        if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) {
Open vSwitch CI 5acaff
+        if (should_revalidate(udpif, ukey, push.n_packets)) {
Open vSwitch CI 5acaff
             if (!ukey->xcache) {
Open vSwitch CI 5acaff
                 ukey->xcache = xlate_cache_new();
Open vSwitch CI 5acaff
             } else {
Open vSwitch CI 5acaff
@@ -2359,7 +2388,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     /* Stats for deleted flows will be attributed upon flow deletion. Skip. */
Open vSwitch CI 5acaff
     if (result != UKEY_DELETE) {
Open vSwitch CI 5acaff
-        xlate_push_stats(ukey->xcache, &push, offloaded);
Open vSwitch CI 5acaff
+        xlate_push_stats(ukey->xcache, &push, ukey->offloaded);
Open vSwitch CI 5acaff
         ukey->stats = *stats;
Open vSwitch CI 5acaff
         ukey->reval_seq = reval_seq;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
@@ -2455,6 +2484,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
Open vSwitch CI 5acaff
             push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags;
Open vSwitch CI 5acaff
             push->n_packets = stats->n_packets - op->ukey->stats.n_packets;
Open vSwitch CI 5acaff
             push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+            if (stats->n_packets < op->ukey->stats.n_packets &&
Open vSwitch CI 5acaff
+                op->ukey->stats.n_packets < UINT64_THREE_QUARTERS) {
Open vSwitch CI 5acaff
+                /* Report cases where the packet counter is lower than the
Open vSwitch CI 5acaff
+                 * previous instance, but exclude the potential wrapping of an
Open vSwitch CI 5acaff
+                 * uint64_t. */
Open vSwitch CI 5acaff
+                COVERAGE_INC(ukey_invalid_stat_reset);
Open vSwitch CI 5acaff
+            }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
             ovs_mutex_unlock(&op->ukey->mutex);
Open vSwitch CI 5acaff
         } else {
Open vSwitch CI 5acaff
             push = stats;
Open vSwitch CI 5acaff
@@ -2759,6 +2797,22 @@ revalidate(struct revalidator *revalidator)
Open vSwitch CI 5acaff
                 continue;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+            ukey->offloaded = f->attrs.offloaded;
Open vSwitch CI 5acaff
+            if (!ukey->dp_layer
Open vSwitch CI 5acaff
+                || (!dpif_synced_dp_layers(udpif->dpif)
Open vSwitch CI 5acaff
+                    && strcmp(ukey->dp_layer, f->attrs.dp_layer))) {
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+                if (ukey->dp_layer) {
Open vSwitch CI 5acaff
+                    /* The dp_layer has changed this is probably due to an
Open vSwitch CI 5acaff
+                     * earlier revalidate cycle moving it to/from hw offload.
Open vSwitch CI 5acaff
+                     * In this case we should reset the ukey stored statistics,
Open vSwitch CI 5acaff
+                     * as they are from the deleted DP flow. */
Open vSwitch CI 5acaff
+                    COVERAGE_INC(ukey_dp_change);
Open vSwitch CI 5acaff
+                    memset(&ukey->stats, 0, sizeof ukey->stats);
Open vSwitch CI 5acaff
+                }
Open vSwitch CI 5acaff
+                ukey->dp_layer = f->attrs.dp_layer;
Open vSwitch CI 5acaff
+            }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
             already_dumped = ukey->dump_seq == dump_seq;
Open vSwitch CI 5acaff
             if (already_dumped) {
Open vSwitch CI 5acaff
                 /* The flow has already been handled during this flow dump
Open vSwitch CI 5acaff
@@ -2790,8 +2844,7 @@ revalidate(struct revalidator *revalidator)
Open vSwitch CI 5acaff
                 result = UKEY_DELETE;
Open vSwitch CI 5acaff
             } else {
Open vSwitch CI 5acaff
                 result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
Open vSwitch CI 5acaff
-                                         reval_seq, &recircs,
Open vSwitch CI 5acaff
-                                         f->attrs.offloaded);
Open vSwitch CI 5acaff
+                                         reval_seq, &recircs);
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             ukey->dump_seq = dump_seq;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -2876,7 +2929,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
Open vSwitch CI 5acaff
                     COVERAGE_INC(revalidate_missed_dp_flow);
Open vSwitch CI 5acaff
                     memcpy(&stats, &ukey->stats, sizeof stats);
Open vSwitch CI 5acaff
                     result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
Open vSwitch CI 5acaff
-                                             reval_seq, &recircs, false);
Open vSwitch CI 5acaff
+                                             reval_seq, &recircs);
Open vSwitch CI 5acaff
                 }
Open vSwitch CI 5acaff
                 if (result != UKEY_KEEP) {
Open vSwitch CI 5acaff
                     /* Clears 'recircs' if filled by revalidate_ukey(). */
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
Open vSwitch CI 5acaff
index a9cf3cbee..cffd733c5 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto-dpif-xlate.c
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto-dpif-xlate.c
Open vSwitch CI 5acaff
@@ -5211,6 +5211,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     ctx->wc->masks.nw_ttl = 0xff;
Open vSwitch CI 5acaff
+    WC_MASK_FIELD(ctx->wc, nw_proto);
Open vSwitch CI 5acaff
     if (flow->nw_ttl > 1) {
Open vSwitch CI 5acaff
         flow->nw_ttl--;
Open vSwitch CI 5acaff
         return false;
Open vSwitch CI 5acaff
@@ -7128,6 +7129,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
         case OFPACT_SET_IPV4_SRC:
Open vSwitch CI 5acaff
             if (flow->dl_type == htons(ETH_TYPE_IP)) {
Open vSwitch CI 5acaff
                 memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
Open vSwitch CI 5acaff
+                WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
                 flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             break;
Open vSwitch CI 5acaff
@@ -7135,12 +7137,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
         case OFPACT_SET_IPV4_DST:
Open vSwitch CI 5acaff
             if (flow->dl_type == htons(ETH_TYPE_IP)) {
Open vSwitch CI 5acaff
                 memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
Open vSwitch CI 5acaff
+                WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
                 flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
             break;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
         case OFPACT_SET_IP_DSCP:
Open vSwitch CI 5acaff
             if (is_ip_any(flow)) {
Open vSwitch CI 5acaff
+                WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
                 wc->masks.nw_tos |= IP_DSCP_MASK;
Open vSwitch CI 5acaff
                 flow->nw_tos &= ~IP_DSCP_MASK;
Open vSwitch CI 5acaff
                 flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp;
Open vSwitch CI 5acaff
@@ -7149,6 +7153,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
         case OFPACT_SET_IP_ECN:
Open vSwitch CI 5acaff
             if (is_ip_any(flow)) {
Open vSwitch CI 5acaff
+                WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
                 wc->masks.nw_tos |= IP_ECN_MASK;
Open vSwitch CI 5acaff
                 flow->nw_tos &= ~IP_ECN_MASK;
Open vSwitch CI 5acaff
                 flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn;
Open vSwitch CI 5acaff
@@ -7157,6 +7162,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
         case OFPACT_SET_IP_TTL:
Open vSwitch CI 5acaff
             if (is_ip_any(flow)) {
Open vSwitch CI 5acaff
+                WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
                 wc->masks.nw_ttl = 0xff;
Open vSwitch CI 5acaff
                 flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
@@ -7224,6 +7230,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
             /* Set the field only if the packet actually has it. */
Open vSwitch CI 5acaff
             if (mf_are_prereqs_ok(mf, flow, wc)) {
Open vSwitch CI 5acaff
+                mf_set_mask_l3_prereqs(mf, flow, wc);
Open vSwitch CI 5acaff
                 mf_mask_field_masked(mf, ofpact_set_field_mask(set_field), wc);
Open vSwitch CI 5acaff
                 mf_set_flow_value_masked(mf, set_field->value,
Open vSwitch CI 5acaff
                                          ofpact_set_field_mask(set_field),
Open vSwitch CI 5acaff
@@ -7280,6 +7287,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
         case OFPACT_DEC_TTL:
Open vSwitch CI 5acaff
             wc->masks.nw_ttl = 0xff;
Open vSwitch CI 5acaff
+            WC_MASK_FIELD(wc, nw_proto);
Open vSwitch CI 5acaff
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
Open vSwitch CI 5acaff
                 return;
Open vSwitch CI 5acaff
             }
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
Open vSwitch CI 5acaff
index f87e27a8c..fad7342b0 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto-dpif.c
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto-dpif.c
Open vSwitch CI 5acaff
@@ -714,12 +714,6 @@ close_dpif_backer(struct dpif_backer *backer, bool del)
Open vSwitch CI 5acaff
     free(backer);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-/* Datapath port slated for removal from datapath. */
Open vSwitch CI 5acaff
-struct odp_garbage {
Open vSwitch CI 5acaff
-    struct ovs_list list_node;
Open vSwitch CI 5acaff
-    odp_port_t odp_port;
Open vSwitch CI 5acaff
-};
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
 static void check_support(struct dpif_backer *backer);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static int
Open vSwitch CI 5acaff
@@ -729,8 +723,6 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
Open vSwitch CI 5acaff
     struct dpif_port_dump port_dump;
Open vSwitch CI 5acaff
     struct dpif_port port;
Open vSwitch CI 5acaff
     struct shash_node *node;
Open vSwitch CI 5acaff
-    struct ovs_list garbage_list;
Open vSwitch CI 5acaff
-    struct odp_garbage *garbage;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     struct sset names;
Open vSwitch CI 5acaff
     char *backer_name;
Open vSwitch CI 5acaff
@@ -792,25 +784,23 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
Open vSwitch CI 5acaff
         dpif_flow_flush(backer->dpif);
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-    /* Loop through the ports already on the datapath and remove any
Open vSwitch CI 5acaff
-     * that we don't need anymore. */
Open vSwitch CI 5acaff
-    ovs_list_init(&garbage_list);
Open vSwitch CI 5acaff
+    /* Loop through the ports already on the datapath and find ones that are
Open vSwitch CI 5acaff
+     * not on the initial OpenFlow ports list.  These are stale ports, that we
Open vSwitch CI 5acaff
+     * do not need anymore, or tunnel backing interfaces, that do not generally
Open vSwitch CI 5acaff
+     * match the name of OpenFlow tunnel ports, or both.  Add all of them to
Open vSwitch CI 5acaff
+     * the list of tunnel backers.  type_run() will garbage collect those that
Open vSwitch CI 5acaff
+     * are not active tunnel backing interfaces during revalidation. */
Open vSwitch CI 5acaff
     dpif_port_dump_start(&port_dump, backer->dpif);
Open vSwitch CI 5acaff
     while (dpif_port_dump_next(&port_dump, &port)) {
Open vSwitch CI 5acaff
         node = shash_find(&init_ofp_ports, port.name);
Open vSwitch CI 5acaff
         if (!node && strcmp(port.name, dpif_base_name(backer->dpif))) {
Open vSwitch CI 5acaff
-            garbage = xmalloc(sizeof *garbage);
Open vSwitch CI 5acaff
-            garbage->odp_port = port.port_no;
Open vSwitch CI 5acaff
-            ovs_list_push_front(&garbage_list, &garbage->list_node);
Open vSwitch CI 5acaff
+            simap_put(&backer->tnl_backers, port.name,
Open vSwitch CI 5acaff
+                      odp_to_u32(port.port_no));
Open vSwitch CI 5acaff
+            backer->need_revalidate = REV_RECONFIGURE;
Open vSwitch CI 5acaff
         }
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
     dpif_port_dump_done(&port_dump);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-    LIST_FOR_EACH_POP (garbage, list_node, &garbage_list) {
Open vSwitch CI 5acaff
-        dpif_port_del(backer->dpif, garbage->odp_port, false);
Open vSwitch CI 5acaff
-        free(garbage);
Open vSwitch CI 5acaff
-    }
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
     shash_add(&all_dpif_backers, type, backer);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     check_support(backer);
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
Open vSwitch CI 5acaff
index a84ddc1d0..143ded690 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto-provider.h
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto-provider.h
Open vSwitch CI 5acaff
@@ -541,6 +541,11 @@ extern unsigned ofproto_max_revalidator;
Open vSwitch CI 5acaff
  * duration exceeds half of max-revalidator config variable. */
Open vSwitch CI 5acaff
 extern unsigned ofproto_min_revalidate_pps;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+/* Worst case delay (in ms) it might take before statistics of offloaded flows
Open vSwitch CI 5acaff
+ * are updated. Offloaded flows younger than this delay will always be
Open vSwitch CI 5acaff
+ * revalidated regardless of ofproto_min_revalidate_pps. */
Open vSwitch CI 5acaff
+extern unsigned ofproto_offloaded_stats_delay;
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 /* Number of upcall handler and revalidator threads. Only affects the
Open vSwitch CI 5acaff
  * ofproto-dpif implementation. */
Open vSwitch CI 5acaff
 extern uint32_t n_handlers, n_revalidators;
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
Open vSwitch CI 5acaff
index 17f636ed9..5fc1a7409 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto.c
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto.c
Open vSwitch CI 5acaff
@@ -311,6 +311,7 @@ unsigned ofproto_flow_limit = OFPROTO_FLOW_LIMIT_DEFAULT;
Open vSwitch CI 5acaff
 unsigned ofproto_max_idle = OFPROTO_MAX_IDLE_DEFAULT;
Open vSwitch CI 5acaff
 unsigned ofproto_max_revalidator = OFPROTO_MAX_REVALIDATOR_DEFAULT;
Open vSwitch CI 5acaff
 unsigned ofproto_min_revalidate_pps = OFPROTO_MIN_REVALIDATE_PPS_DEFAULT;
Open vSwitch CI 5acaff
+unsigned ofproto_offloaded_stats_delay = OFPROTO_OFFLOADED_STATS_DELAY;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 uint32_t n_handlers, n_revalidators;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -727,6 +728,15 @@ ofproto_set_min_revalidate_pps(unsigned min_revalidate_pps)
Open vSwitch CI 5acaff
     ofproto_min_revalidate_pps = min_revalidate_pps ? min_revalidate_pps : 1;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+/* Set worst case delay (in ms) it might take before statistics of offloaded
Open vSwitch CI 5acaff
+ * flows are updated. Offloaded flows younger than this delay will always be
Open vSwitch CI 5acaff
+ * revalidated regardless of ofproto_min_revalidate_pps. */
Open vSwitch CI 5acaff
+void
Open vSwitch CI 5acaff
+ofproto_set_offloaded_stats_delay(unsigned offloaded_stats_delay)
Open vSwitch CI 5acaff
+{
Open vSwitch CI 5acaff
+    ofproto_offloaded_stats_delay = offloaded_stats_delay;
Open vSwitch CI 5acaff
+}
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 /* If forward_bpdu is true, the NORMAL action will forward frames with
Open vSwitch CI 5acaff
  * reserved (e.g. STP) destination Ethernet addresses. if forward_bpdu is false,
Open vSwitch CI 5acaff
  * the NORMAL action will drop these frames. */
Open vSwitch CI 5acaff
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
Open vSwitch CI 5acaff
index 4e15167ab..fa7973ac7 100644
Open vSwitch CI 5acaff
--- a/ofproto/ofproto.h
Open vSwitch CI 5acaff
+++ b/ofproto/ofproto.h
Open vSwitch CI 5acaff
@@ -311,6 +311,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
Open vSwitch CI 5acaff
 #define OFPROTO_MAX_IDLE_DEFAULT 10000 /* ms */
Open vSwitch CI 5acaff
 #define OFPROTO_MAX_REVALIDATOR_DEFAULT 500 /* ms */
Open vSwitch CI 5acaff
 #define OFPROTO_MIN_REVALIDATE_PPS_DEFAULT 5
Open vSwitch CI 5acaff
+#define OFPROTO_OFFLOADED_STATS_DELAY 2000 /* ms */
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 const char *ofproto_port_open_type(const struct ofproto *,
Open vSwitch CI 5acaff
                                    const char *port_type);
Open vSwitch CI 5acaff
@@ -340,6 +341,7 @@ void ofproto_set_flow_limit(unsigned limit);
Open vSwitch CI 5acaff
 void ofproto_set_max_idle(unsigned max_idle);
Open vSwitch CI 5acaff
 void ofproto_set_max_revalidator(unsigned max_revalidator);
Open vSwitch CI 5acaff
 void ofproto_set_min_revalidate_pps(unsigned min_revalidate_pps);
Open vSwitch CI 5acaff
+void ofproto_set_offloaded_stats_delay(unsigned offloaded_stats_delay);
Open vSwitch CI 5acaff
 void ofproto_set_forward_bpdu(struct ofproto *, bool forward_bpdu);
Open vSwitch CI 5acaff
 void ofproto_set_mac_table_config(struct ofproto *, unsigned idle_time,
Open vSwitch CI 5acaff
                                   size_t max_entries);
Open vSwitch CI 38c5a5
diff --git a/ovsdb/log.c b/ovsdb/log.c
Open vSwitch CI 38c5a5
index e42f00246..fff7c6ba1 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/log.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/log.c
Open vSwitch CI 38c5a5
@@ -552,6 +552,23 @@ ovsdb_log_truncate(struct ovsdb_log *file)
Open vSwitch CI 38c5a5
     return error;
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
+/* Removes all the data from the log by moving current offset to zero and
Open vSwitch CI 38c5a5
+ * truncating the file to zero bytes.  After this operation the file is empty
Open vSwitch CI 38c5a5
+ * and in a write state. */
Open vSwitch CI 38c5a5
+struct ovsdb_error * OVS_WARN_UNUSED_RESULT
Open vSwitch CI 38c5a5
+ovsdb_log_reset(struct ovsdb_log *file)
Open vSwitch CI 38c5a5
+{
Open vSwitch CI 38c5a5
+    ovsdb_error_destroy(file->error);
Open vSwitch CI 38c5a5
+    file->offset = file->prev_offset = 0;
Open vSwitch CI 38c5a5
+    file->error = ovsdb_log_truncate(file);
Open vSwitch CI 38c5a5
+    if (file->error) {
Open vSwitch CI 38c5a5
+        file->state = OVSDB_LOG_WRITE_ERROR;
Open vSwitch CI 38c5a5
+        return ovsdb_error_clone(file->error);
Open vSwitch CI 38c5a5
+    }
Open vSwitch CI 38c5a5
+    file->state = OVSDB_LOG_WRITE;
Open vSwitch CI 38c5a5
+    return NULL;
Open vSwitch CI 38c5a5
+}
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
 /* Composes a log record for 'json' by filling 'header' with a header line and
Open vSwitch CI 38c5a5
  * 'data' with a data line (each ending with a new-line).  To write the record
Open vSwitch CI 38c5a5
  * to a file, write 'header' followed by 'data'.
Open vSwitch CI 38c5a5
diff --git a/ovsdb/log.h b/ovsdb/log.h
Open vSwitch CI 38c5a5
index 90714ea13..63e5681a0 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/log.h
Open vSwitch CI 38c5a5
+++ b/ovsdb/log.h
Open vSwitch CI 38c5a5
@@ -66,6 +66,9 @@ struct ovsdb_error *ovsdb_log_read(struct ovsdb_log *, struct json **)
Open vSwitch CI 38c5a5
     OVS_WARN_UNUSED_RESULT;
Open vSwitch CI 38c5a5
 void ovsdb_log_unread(struct ovsdb_log *);
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
+struct ovsdb_error *ovsdb_log_reset(struct ovsdb_log *)
Open vSwitch CI 38c5a5
+    OVS_WARN_UNUSED_RESULT;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
 void ovsdb_log_compose_record(const struct json *, const char *magic,
Open vSwitch CI 38c5a5
                               struct ds *header, struct ds *data);
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
Open vSwitch CI 38c5a5
index 33ca4910d..cb4671d51 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/ovsdb-server.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/ovsdb-server.c
Open vSwitch CI 38c5a5
@@ -573,8 +573,9 @@ close_db(struct server_config *config, struct db *db, char *comment)
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-static void
Open vSwitch CI 38c5a5
-update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux)
Open vSwitch CI 38c5a5
+static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
Open vSwitch CI 38c5a5
+update_schema(struct ovsdb *db, const struct ovsdb_schema *schema,
Open vSwitch CI 38c5a5
+              bool conversion_with_no_data, void *aux)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
     struct server_config *config = aux;
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
@@ -586,13 +587,27 @@ update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux)
Open vSwitch CI 38c5a5
             : xasprintf("database %s connected to storage", db->name)));
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-    ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL));
Open vSwitch CI 38c5a5
+    if (db->schema && conversion_with_no_data) {
Open vSwitch CI 38c5a5
+        struct ovsdb *new_db = NULL;
Open vSwitch CI 38c5a5
+        struct ovsdb_error *error;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+        error = ovsdb_convert(db, schema, &new_db);
Open vSwitch CI 38c5a5
+        if (error) {
Open vSwitch CI 38c5a5
+            /* Should never happen, because conversion should have been
Open vSwitch CI 38c5a5
+             * checked before writing the schema to the storage. */
Open vSwitch CI 38c5a5
+            return error;
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
+        ovsdb_replace(db, new_db);
Open vSwitch CI 38c5a5
+    } else {
Open vSwitch CI 38c5a5
+        ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL));
Open vSwitch CI 38c5a5
+    }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
     /* Force update to schema in _Server database. */
Open vSwitch CI 38c5a5
     struct db *dbp = shash_find_data(config->all_dbs, db->name);
Open vSwitch CI 38c5a5
     if (dbp) {
Open vSwitch CI 38c5a5
         dbp->row_uuid = UUID_ZERO;
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
+    return NULL;
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
Open vSwitch CI 38c5a5
@@ -600,23 +615,30 @@ parse_txn(struct server_config *config, struct db *db,
Open vSwitch CI 38c5a5
           const struct ovsdb_schema *schema, const struct json *txn_json,
Open vSwitch CI 38c5a5
           const struct uuid *txnid)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
+    struct ovsdb_error *error = NULL;
Open vSwitch CI 38c5a5
+    struct ovsdb_txn *txn = NULL;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
     if (schema) {
Open vSwitch CI 38c5a5
-        /* We're replacing the schema (and the data).  Destroy the database
Open vSwitch CI 38c5a5
-         * (first grabbing its storage), then replace it with the new schema.
Open vSwitch CI 38c5a5
-         * The transaction must also include the replacement data.
Open vSwitch CI 38c5a5
+        /* We're replacing the schema (and the data).  If transaction includes
Open vSwitch CI 38c5a5
+         * replacement data, destroy the database (first grabbing its storage),
Open vSwitch CI 38c5a5
+         * then replace it with the new schema.  If not, it's a conversion
Open vSwitch CI 38c5a5
+         * without data specified.  In this case, convert the current database
Open vSwitch CI 38c5a5
+         * to a new schema instead.
Open vSwitch CI 38c5a5
          *
Open vSwitch CI 38c5a5
          * Only clustered database schema changes and snapshot installs
Open vSwitch CI 38c5a5
          * go through this path.
Open vSwitch CI 38c5a5
          */
Open vSwitch CI 38c5a5
-        ovs_assert(txn_json);
Open vSwitch CI 38c5a5
         ovs_assert(ovsdb_storage_is_clustered(db->db->storage));
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-        struct ovsdb_error *error = ovsdb_schema_check_for_ephemeral_columns(
Open vSwitch CI 38c5a5
-            schema);
Open vSwitch CI 38c5a5
+        error = ovsdb_schema_check_for_ephemeral_columns(schema);
Open vSwitch CI 38c5a5
+        if (error) {
Open vSwitch CI 38c5a5
+            return error;
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+        error = update_schema(db->db, schema, txn_json == NULL, config);
Open vSwitch CI 38c5a5
         if (error) {
Open vSwitch CI 38c5a5
             return error;
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
-        update_schema(db->db, schema, config);
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
     if (txn_json) {
Open vSwitch CI 38c5a5
@@ -624,24 +646,25 @@ parse_txn(struct server_config *config, struct db *db,
Open vSwitch CI 38c5a5
             return ovsdb_error(NULL, "%s: data without schema", db->filename);
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-        struct ovsdb_txn *txn;
Open vSwitch CI 38c5a5
-        struct ovsdb_error *error;
Open vSwitch CI 38c5a5
-
Open vSwitch CI 38c5a5
         error = ovsdb_file_txn_from_json(db->db, txn_json, false, &txn);
Open vSwitch CI 38c5a5
-        if (!error) {
Open vSwitch CI 38c5a5
-            ovsdb_txn_set_txnid(txnid, txn);
Open vSwitch CI 38c5a5
-            log_and_free_error(ovsdb_txn_replay_commit(txn));
Open vSwitch CI 38c5a5
-        }
Open vSwitch CI 38c5a5
-        if (!error && !uuid_is_zero(txnid)) {
Open vSwitch CI 38c5a5
-            db->db->prereq = *txnid;
Open vSwitch CI 38c5a5
-        }
Open vSwitch CI 38c5a5
         if (error) {
Open vSwitch CI 38c5a5
             ovsdb_storage_unread(db->db->storage);
Open vSwitch CI 38c5a5
             return error;
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
+    } else if (schema) {
Open vSwitch CI 38c5a5
+        /* We just performed conversion without data.  Transaction history
Open vSwitch CI 38c5a5
+         * was destroyed.  Commit a dummy transaction to set the txnid. */
Open vSwitch CI 38c5a5
+        txn = ovsdb_txn_create(db->db);
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-    return NULL;
Open vSwitch CI 38c5a5
+    if (txn) {
Open vSwitch CI 38c5a5
+        ovsdb_txn_set_txnid(txnid, txn);
Open vSwitch CI 38c5a5
+        error = ovsdb_txn_replay_commit(txn);
Open vSwitch CI 38c5a5
+        if (!error && !uuid_is_zero(txnid)) {
Open vSwitch CI 38c5a5
+            db->db->prereq = *txnid;
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
+    }
Open vSwitch CI 38c5a5
+    return error;
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 static void
Open vSwitch CI 38c5a5
diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c
Open vSwitch CI 38c5a5
index 60f353197..e26536532 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/ovsdb-tool.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/ovsdb-tool.c
Open vSwitch CI 38c5a5
@@ -1006,7 +1006,8 @@ raft_header_to_standalone_log(const struct raft_header *h,
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 static void
Open vSwitch CI 38c5a5
-raft_record_to_standalone_log(const struct raft_record *r,
Open vSwitch CI 38c5a5
+raft_record_to_standalone_log(const char *db_file_name,
Open vSwitch CI 38c5a5
+                              const struct raft_record *r,
Open vSwitch CI 38c5a5
                               struct ovsdb_log *db_log_data)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
     if (r->type == RAFT_REC_ENTRY) {
Open vSwitch CI 38c5a5
@@ -1018,7 +1019,40 @@ raft_record_to_standalone_log(const struct raft_record *r,
Open vSwitch CI 38c5a5
         if (pa->n != 2) {
Open vSwitch CI 38c5a5
             ovs_fatal(0, "Incorrect raft record array length");
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+        struct json *schema_json = pa->elems[0];
Open vSwitch CI 38c5a5
         struct json *data_json = pa->elems[1];
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+        if (schema_json->type != JSON_NULL) {
Open vSwitch CI 38c5a5
+            /* This is a database conversion record.  Reset the log and
Open vSwitch CI 38c5a5
+             * write the new schema. */
Open vSwitch CI 38c5a5
+            struct ovsdb_schema *schema;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            check_ovsdb_error(ovsdb_schema_from_json(schema_json, &schema));
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            if (data_json->type == JSON_NULL) {
Open vSwitch CI 38c5a5
+                /* We have a conversion request with no data.  There is no
Open vSwitch CI 38c5a5
+                 * other way as to read back what we have and convert. */
Open vSwitch CI 38c5a5
+                struct ovsdb *old_db, *new_db;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+                check_ovsdb_error(ovsdb_log_commit_block(db_log_data));
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+                old_db = ovsdb_file_read(db_file_name, false);
Open vSwitch CI 38c5a5
+                check_ovsdb_error(ovsdb_convert(old_db, schema, &new_db));
Open vSwitch CI 38c5a5
+                ovsdb_destroy(old_db);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+                pa->elems[1] = ovsdb_to_txn_json(
Open vSwitch CI 38c5a5
+                                    new_db, "converted by ovsdb-tool", true);
Open vSwitch CI 38c5a5
+                ovsdb_destroy(new_db);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+                json_destroy(data_json);
Open vSwitch CI 38c5a5
+                data_json = pa->elems[1];
Open vSwitch CI 38c5a5
+            }
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            ovsdb_schema_destroy(schema);
Open vSwitch CI 38c5a5
+            check_ovsdb_error(ovsdb_log_reset(db_log_data));
Open vSwitch CI 38c5a5
+            check_ovsdb_error(ovsdb_log_write(db_log_data, schema_json));
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
         if (data_json->type != JSON_NULL) {
Open vSwitch CI 38c5a5
             check_ovsdb_error(ovsdb_log_write(db_log_data, data_json));
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
@@ -1636,7 +1670,8 @@ do_compare_versions(struct ovs_cmdl_context *ctx)
Open vSwitch CI 38c5a5
 }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 static void
Open vSwitch CI 38c5a5
-do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data)
Open vSwitch CI 38c5a5
+do_convert_to_standalone(const char *db_file_name,
Open vSwitch CI 38c5a5
+                         struct ovsdb_log *log, struct ovsdb_log *db_log_data)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
     for (unsigned int i = 0; ; i++) {
Open vSwitch CI 38c5a5
         struct json *json;
Open vSwitch CI 38c5a5
@@ -1653,7 +1688,7 @@ do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data)
Open vSwitch CI 38c5a5
         } else {
Open vSwitch CI 38c5a5
             struct raft_record r;
Open vSwitch CI 38c5a5
             check_ovsdb_error(raft_record_from_json(&r, json));
Open vSwitch CI 38c5a5
-            raft_record_to_standalone_log(&r, db_log_data);
Open vSwitch CI 38c5a5
+            raft_record_to_standalone_log(db_file_name, &r, db_log_data);
Open vSwitch CI 38c5a5
             raft_record_uninit(&r);
Open vSwitch CI 38c5a5
         }
Open vSwitch CI 38c5a5
         json_destroy(json);
Open vSwitch CI 38c5a5
@@ -1676,7 +1711,7 @@ do_cluster_standalone(struct ovs_cmdl_context *ctx)
Open vSwitch CI 38c5a5
     if (strcmp(ovsdb_log_get_magic(log), RAFT_MAGIC) != 0) {
Open vSwitch CI 38c5a5
         ovs_fatal(0, "Database is not clustered db.\n");
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
-    do_convert_to_standalone(log, db_log_data);
Open vSwitch CI 38c5a5
+    do_convert_to_standalone(db_file_name, log, db_log_data);
Open vSwitch CI 38c5a5
     check_ovsdb_error(ovsdb_log_commit_block(db_log_data));
Open vSwitch CI 38c5a5
     ovsdb_log_close(db_log_data);
Open vSwitch CI 38c5a5
     ovsdb_log_close(log);
Open vSwitch CI 38c5a5
diff --git a/ovsdb/relay.c b/ovsdb/relay.c
Open vSwitch CI 38c5a5
index 9ff6ed8f3..94ffe01e5 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/relay.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/relay.c
Open vSwitch CI 38c5a5
@@ -301,6 +301,8 @@ static void
Open vSwitch CI 38c5a5
 ovsdb_relay_parse_update(struct relay_ctx *ctx,
Open vSwitch CI 38c5a5
                          const struct ovsdb_cs_update_event *update)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
+    struct ovsdb_error *error = NULL;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
     if (!ctx->db) {
Open vSwitch CI 38c5a5
         return;
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
@@ -308,15 +310,27 @@ ovsdb_relay_parse_update(struct relay_ctx *ctx,
Open vSwitch CI 38c5a5
     if (update->monitor_reply && ctx->new_schema) {
Open vSwitch CI 38c5a5
         /* There was a schema change.  Updating a database with a new schema
Open vSwitch CI 38c5a5
          * before processing monitor reply with the new data. */
Open vSwitch CI 38c5a5
-        ctx->schema_change_cb(ctx->db, ctx->new_schema,
Open vSwitch CI 38c5a5
-                              ctx->schema_change_aux);
Open vSwitch CI 38c5a5
+        error = ctx->schema_change_cb(ctx->db, ctx->new_schema, false,
Open vSwitch CI 38c5a5
+                                      ctx->schema_change_aux);
Open vSwitch CI 38c5a5
+        if (error) {
Open vSwitch CI 38c5a5
+            /* Should never happen, but handle this case anyway. */
Open vSwitch CI 38c5a5
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
Open vSwitch CI 38c5a5
+            char *s = ovsdb_error_to_string_free(error);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            VLOG_ERR_RL(&rl, "%s", s);
Open vSwitch CI 38c5a5
+            free(s);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            ovsdb_cs_flag_inconsistency(ctx->cs);
Open vSwitch CI 38c5a5
+            return;
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
         ovsdb_schema_destroy(ctx->new_schema);
Open vSwitch CI 38c5a5
         ctx->new_schema = NULL;
Open vSwitch CI 38c5a5
     }
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
     struct ovsdb_cs_db_update *du;
Open vSwitch CI 38c5a5
-    struct ovsdb_error *error = ovsdb_cs_parse_db_update(update->table_updates,
Open vSwitch CI 38c5a5
-                                                         update->version, &du);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+    error = ovsdb_cs_parse_db_update(update->table_updates,
Open vSwitch CI 38c5a5
+                                     update->version, &du);
Open vSwitch CI 38c5a5
     if (!error) {
Open vSwitch CI 38c5a5
         if (update->clear) {
Open vSwitch CI 38c5a5
             error = ovsdb_relay_clear(ctx->db);
Open vSwitch CI 38c5a5
diff --git a/ovsdb/relay.h b/ovsdb/relay.h
Open vSwitch CI 38c5a5
index 390ea70c8..2d66b5e5f 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/relay.h
Open vSwitch CI 38c5a5
+++ b/ovsdb/relay.h
Open vSwitch CI 38c5a5
@@ -23,8 +23,11 @@ struct json;
Open vSwitch CI 38c5a5
 struct ovsdb;
Open vSwitch CI 38c5a5
 struct ovsdb_schema;
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
-typedef void (*schema_change_callback)(struct ovsdb *,
Open vSwitch CI 38c5a5
-                                       const struct ovsdb_schema *, void *aux);
Open vSwitch CI 38c5a5
+typedef struct ovsdb_error *(*schema_change_callback)(
Open vSwitch CI 38c5a5
+                                       struct ovsdb *,
Open vSwitch CI 38c5a5
+                                       const struct ovsdb_schema *,
Open vSwitch CI 38c5a5
+                                       bool conversion_with_no_data,
Open vSwitch CI 38c5a5
+                                       void *aux);
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 void ovsdb_relay_add_db(struct ovsdb *, const char *remote,
Open vSwitch CI 38c5a5
                         schema_change_callback schema_change_cb,
Open vSwitch CI 38c5a5
diff --git a/ovsdb/storage.c b/ovsdb/storage.c
Open vSwitch CI 38c5a5
index e8f95ce64..6c395106c 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/storage.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/storage.c
Open vSwitch CI 38c5a5
@@ -623,7 +623,7 @@ ovsdb_storage_store_snapshot(struct ovsdb_storage *storage,
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 struct ovsdb_write * OVS_WARN_UNUSED_RESULT
Open vSwitch CI 38c5a5
 ovsdb_storage_write_schema_change(struct ovsdb_storage *storage,
Open vSwitch CI 38c5a5
-                                  const struct json *schema,
Open vSwitch CI 38c5a5
+                                  const struct ovsdb_schema *schema,
Open vSwitch CI 38c5a5
                                   const struct json *data,
Open vSwitch CI 38c5a5
                                   const struct uuid *prereq,
Open vSwitch CI 38c5a5
                                   struct uuid *resultp)
Open vSwitch CI 38c5a5
@@ -633,13 +633,23 @@ ovsdb_storage_write_schema_change(struct ovsdb_storage *storage,
Open vSwitch CI 38c5a5
     if (storage->error) {
Open vSwitch CI 38c5a5
         w->error = ovsdb_error_clone(storage->error);
Open vSwitch CI 38c5a5
     } else if (storage->raft) {
Open vSwitch CI 38c5a5
-        struct json *txn_json = json_array_create_2(json_clone(schema),
Open vSwitch CI 38c5a5
-                                                    json_clone(data));
Open vSwitch CI 38c5a5
-        w->command = raft_command_execute(storage->raft, txn_json,
Open vSwitch CI 38c5a5
-                                          prereq, &result);
Open vSwitch CI 38c5a5
-        json_destroy(txn_json);
Open vSwitch CI 38c5a5
+        /* Clustered storage doesn't support ephemeral columns. */
Open vSwitch CI 38c5a5
+        w->error = ovsdb_schema_check_for_ephemeral_columns(schema);
Open vSwitch CI 38c5a5
+        if (!w->error) {
Open vSwitch CI 38c5a5
+            struct json *schema_json, *txn_json;
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+            schema_json = ovsdb_schema_to_json(schema);
Open vSwitch CI 38c5a5
+            txn_json = json_array_create_2(schema_json, json_clone(data));
Open vSwitch CI 38c5a5
+            w->command = raft_command_execute(storage->raft, txn_json,
Open vSwitch CI 38c5a5
+                                              prereq, &result);
Open vSwitch CI 38c5a5
+            json_destroy(txn_json);
Open vSwitch CI 38c5a5
+        }
Open vSwitch CI 38c5a5
     } else if (storage->log) {
Open vSwitch CI 38c5a5
-        w->error = ovsdb_storage_store_snapshot__(storage, schema, data, 0);
Open vSwitch CI 38c5a5
+        struct json *schema_json = ovsdb_schema_to_json(schema);
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+        w->error = ovsdb_storage_store_snapshot__(storage, schema_json,
Open vSwitch CI 38c5a5
+                                                  data, 0);
Open vSwitch CI 38c5a5
+        json_destroy(schema_json);
Open vSwitch CI 38c5a5
     } else {
Open vSwitch CI 38c5a5
         /* When 'error' and 'command' are both null, it indicates that the
Open vSwitch CI 38c5a5
          * command is complete.  This is fine since this unbacked storage drops
Open vSwitch CI 38c5a5
diff --git a/ovsdb/storage.h b/ovsdb/storage.h
Open vSwitch CI 38c5a5
index a1fdaa564..05f40ce93 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/storage.h
Open vSwitch CI 38c5a5
+++ b/ovsdb/storage.h
Open vSwitch CI 38c5a5
@@ -85,7 +85,7 @@ struct ovsdb_error *ovsdb_storage_store_snapshot(struct ovsdb_storage *storage,
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 struct ovsdb_write *ovsdb_storage_write_schema_change(
Open vSwitch CI 38c5a5
     struct ovsdb_storage *,
Open vSwitch CI 38c5a5
-    const struct json *schema, const struct json *data,
Open vSwitch CI 38c5a5
+    const struct ovsdb_schema *, const struct json *data,
Open vSwitch CI 38c5a5
     const struct uuid *prereq, struct uuid *result)
Open vSwitch CI 38c5a5
     OVS_WARN_UNUSED_RESULT;
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
Open vSwitch CI 38c5a5
index 03541af85..f01de2a34 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/transaction.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/transaction.c
Open vSwitch CI 38c5a5
@@ -1251,7 +1251,7 @@ ovsdb_txn_precheck_prereq(const struct ovsdb *db)
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 struct ovsdb_txn_progress *
Open vSwitch CI 38c5a5
 ovsdb_txn_propose_schema_change(struct ovsdb *db,
Open vSwitch CI 38c5a5
-                                const struct json *schema,
Open vSwitch CI 38c5a5
+                                const struct ovsdb_schema *schema,
Open vSwitch CI 38c5a5
                                 const struct json *data)
Open vSwitch CI 38c5a5
 {
Open vSwitch CI 38c5a5
     struct ovsdb_txn_progress *progress = xzalloc(sizeof *progress);
Open vSwitch CI 38c5a5
diff --git a/ovsdb/transaction.h b/ovsdb/transaction.h
Open vSwitch CI 38c5a5
index 6b5bb7f24..9991f34d2 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/transaction.h
Open vSwitch CI 38c5a5
+++ b/ovsdb/transaction.h
Open vSwitch CI 38c5a5
@@ -21,6 +21,7 @@
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 struct json;
Open vSwitch CI 38c5a5
 struct ovsdb;
Open vSwitch CI 38c5a5
+struct ovsdb_schema;
Open vSwitch CI 38c5a5
 struct ovsdb_table;
Open vSwitch CI 38c5a5
 struct uuid;
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
@@ -41,7 +42,7 @@ struct ovsdb_error *ovsdb_txn_propose_commit_block(struct ovsdb_txn *,
Open vSwitch CI 38c5a5
 void ovsdb_txn_complete(struct ovsdb_txn *);
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 struct ovsdb_txn_progress *ovsdb_txn_propose_schema_change(
Open vSwitch CI 38c5a5
-    struct ovsdb *, const struct json *schema, const struct json *data);
Open vSwitch CI 38c5a5
+    struct ovsdb *, const struct ovsdb_schema *, const struct json *data);
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
 bool ovsdb_txn_progress_is_complete(const struct ovsdb_txn_progress *);
Open vSwitch CI 38c5a5
 const struct ovsdb_error *ovsdb_txn_progress_get_error(
Open vSwitch CI 38c5a5
diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c
Open vSwitch CI 38c5a5
index 01bb80e28..3c93ae580 100644
Open vSwitch CI 38c5a5
--- a/ovsdb/trigger.c
Open vSwitch CI 38c5a5
+++ b/ovsdb/trigger.c
Open vSwitch CI 38c5a5
@@ -274,8 +274,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
Open vSwitch CI 38c5a5
             if (!error) {
Open vSwitch CI 38c5a5
                 error = ovsdb_convert(t->db, new_schema, &newdb);
Open vSwitch CI 38c5a5
             }
Open vSwitch CI 38c5a5
-            ovsdb_schema_destroy(new_schema);
Open vSwitch CI 38c5a5
             if (error) {
Open vSwitch CI 38c5a5
+                ovsdb_schema_destroy(new_schema);
Open vSwitch CI 38c5a5
                 trigger_convert_error(t, error);
Open vSwitch CI 38c5a5
                 return false;
Open vSwitch CI 38c5a5
             }
Open vSwitch CI 38c5a5
@@ -286,7 +286,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now)
Open vSwitch CI 38c5a5
 
Open vSwitch CI 38c5a5
             /* Propose the change. */
Open vSwitch CI 38c5a5
             t->progress = ovsdb_txn_propose_schema_change(
Open vSwitch CI 38c5a5
-                t->db, new_schema_json, txn_json);
Open vSwitch CI 38c5a5
+                t->db, new_schema, txn_json);
Open vSwitch CI 38c5a5
+            ovsdb_schema_destroy(new_schema);
Open vSwitch CI 38c5a5
             json_destroy(txn_json);
Open vSwitch CI 38c5a5
             t->reply = jsonrpc_create_reply(json_object_create(),
Open vSwitch CI 38c5a5
                                             t->request->id);
Open vSwitch CI 5acaff
diff --git a/tests/classifier.at b/tests/classifier.at
Open vSwitch CI 5acaff
index f652b5983..de2705653 100644
Open vSwitch CI 5acaff
--- a/tests/classifier.at
Open vSwitch CI 5acaff
+++ b/tests/classifier.at
Open vSwitch CI 5acaff
@@ -65,6 +65,94 @@ Datapath actions: 2
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
 AT_CLEANUP
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+AT_SETUP([flow classifier - lookup segmentation - final stage])
Open vSwitch CI 5acaff
+OVS_VSWITCHD_START
Open vSwitch CI 5acaff
+add_of_ports br0 1 2 3
Open vSwitch CI 5acaff
+AT_DATA([flows.txt], [dnl
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=33,tcp,tp_dst=80,tcp_flags=+psh,action=output(2)
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=0,ip,action=drop
Open vSwitch CI 5acaff
+table=0 in_port=2 priority=16,icmp6,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=1000::1 ,action=output(1)
Open vSwitch CI 5acaff
+table=0 in_port=2 priority=0,ip,action=drop
Open vSwitch CI 5acaff
+table=0 in_port=3 action=resubmit(,1)
Open vSwitch CI 5acaff
+table=1 in_port=3 priority=45,ct_state=+trk+rpl,ct_nw_proto=6,ct_tp_src=3/0x1,tcp,tp_dst=80,tcp_flags=+psh,action=output(2)
Open vSwitch CI 5acaff
+table=1 in_port=3 priority=10,ip,action=drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80,tcp_flags=syn'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=80,tcp_flags=-psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80,tcp_flags=syn|ack'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=80,tcp_flags=-psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80,tcp_flags=ack|psh'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=80,tcp_flags=+psh
Open vSwitch CI 5acaff
+Datapath actions: 2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=80,tcp_flags=-psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=0x40/0xfff0,tcp_flags=-psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Having both the port and the tcp flags in the resulting megaflow below
Open vSwitch CI 5acaff
+dnl is redundant, but that is how ports trie logic is implemented.
Open vSwitch CI 5acaff
+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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=81'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_frag=no,tp_dst=81,tcp_flags=-psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl nd_target is redundant in the megaflow below and it is also not relevant
Open vSwitch CI 5acaff
+dnl for an icmp reply.  Datapath may discard that match, but it is OK as long
Open vSwitch CI 5acaff
+dnl as we have prerequisites (icmp_type) in the match as well.
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,eth_src=f6:d2:b0:19:5e:7b,eth_dst=d2:49:19:91:78:fe,dl_type=0x86dd,ipv6_src=1000::3,ipv6_dst=1000::4,nw_proto=58,nw_ttl=255,icmpv6_type=128,icmpv6_code=0"], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp6,in_port=2,nw_ttl=255,nw_frag=no,icmp_type=0x80/0xfc,nd_target=::
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,eth_src=f6:d2:b0:19:5e:7b,eth_dst=d2:49:19:91:78:fe,dl_type=0x86dd,ipv6_src=1000::3,ipv6_dst=1000::4,nw_proto=58,nw_ttl=255,icmpv6_type=135,icmpv6_code=0"], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp6,in_port=2,nw_ttl=255,nw_frag=no,icmp_type=0x87/0xff,icmp_code=0x0/0xff,nd_target=::
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,eth_src=f6:d2:b0:19:5e:7b,eth_dst=d2:49:19:91:78:fe,dl_type=0x86dd,ipv6_src=1000::3,ipv6_dst=1000::4,nw_proto=58,nw_ttl=255,icmpv6_type=135,icmpv6_code=0,nd_target=1000::1"], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp6,in_port=2,nw_ttl=255,nw_frag=no,icmp_type=0x87/0xff,icmp_code=0x0/0xff,nd_target=1000::1
Open vSwitch CI 5acaff
+Datapath actions: 1
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,eth_src=f6:d2:b0:19:5e:7b,eth_dst=d2:49:19:91:78:fe,dl_type=0x86dd,ipv6_src=1000::3,ipv6_dst=1000::4,nw_proto=58,nw_ttl=255,icmpv6_type=135,icmpv6_code=0,nd_target=1000::2"], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp6,in_port=2,nw_ttl=255,nw_frag=no,icmp_type=0x87/0xff,icmp_code=0x0/0xff,nd_target=1000::2
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Check that ports' mask doesn't affect ct ports.
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=3,ct_state=trk|rpl,ct_nw_proto=6,ct_tp_src=3,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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80,tcp_flags=psh'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,ct_state=+rpl+trk,ct_nw_proto=6,ct_tp_src=0x1/0x1,eth,tcp,in_port=3,nw_frag=no,tp_dst=80,tcp_flags=+psh
Open vSwitch CI 5acaff
+Datapath actions: 2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=3,ct_state=trk|rpl,ct_nw_proto=6,ct_tp_src=3,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=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79,tcp_flags=psh'], [0], [stdout])
Open vSwitch CI 5acaff
+AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,ct_state=+rpl+trk,ct_nw_proto=6,ct_tp_src=0x1/0x1,eth,tcp,in_port=3,nw_frag=no,tp_dst=0x40/0xfff0,tcp_flags=+psh
Open vSwitch CI 5acaff
+Datapath actions: drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 AT_BANNER([flow classifier prefix lookup])
Open vSwitch CI 5acaff
 AT_SETUP([flow classifier - prefix lookup])
Open vSwitch CI 5acaff
 OVS_VSWITCHD_START
Open vSwitch CI 5acaff
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
Open vSwitch CI 5acaff
index fa6111c1e..6b58cabec 100644
Open vSwitch CI 5acaff
--- a/tests/ofproto-dpif.at
Open vSwitch CI 5acaff
+++ b/tests/ofproto-dpif.at
Open vSwitch CI 5acaff
@@ -849,7 +849,7 @@ table=2 ip actions=set_field:192.168.3.91->ip_src,output(11)
Open vSwitch CI 5acaff
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
Open vSwitch CI 5acaff
 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=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,nw_frag=no,icmp_type=8,icmp_code=0'], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: 10,set(ipv4(src=192.168.3.91)),11,set(ipv4(src=192.168.3.90)),13
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
@@ -912,7 +912,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
Open vSwitch CI 5acaff
 # Must match on the source address to be able to restore it's value for
Open vSwitch CI 5acaff
 # the second bucket
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),11
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
@@ -944,7 +944,7 @@ done
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/dp_hash(.*\/0xf)/dp_hash(0xXXXX\/0xf)/' |  sed 's/packets.*actions:/actions:/' | strip_ufid | strip_used | sort], [0], [dnl
Open vSwitch CI 5acaff
 flow-dump from the main thread:
Open vSwitch CI 5acaff
 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:hash(sym_l4(0)),recirc(0x1)
Open vSwitch CI 5acaff
-recirc_id(0x1),dp_hash(0xXXXX/0xf),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.0.1,frag=no), actions:set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),10
Open vSwitch CI 5acaff
+recirc_id(0x1),dp_hash(0xXXXX/0xf),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.0.1,proto=1,frag=no), actions:set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),10
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
@@ -959,7 +959,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
Open vSwitch CI 5acaff
 # Must match on the source address to be able to restore it's value for
Open vSwitch CI 5acaff
 # the third bucket
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,icmp,in_port=1,nw_src=192.168.0.1,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),11
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
@@ -1536,17 +1536,17 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -4 stdout], [0], [
Open vSwitch CI 5acaff
 Final flow: ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1,nw_frag=no
Open vSwitch CI 5acaff
-Megaflow: recirc_id=0,eth,ip,in_port=1,nw_ttl=2,nw_frag=no
Open vSwitch CI 5acaff
+Megaflow: recirc_id=0,eth,ip,in_port=1,nw_proto=111,nw_ttl=2,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: set(ipv4(ttl=1)),2,userspace(pid=0,controller(reason=2,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535)),4
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=3,frag=no)'], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_ttl=3,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_proto=111,nw_ttl=3,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: set(ipv4(ttl=2)),2,set(ipv4(ttl=1)),3,4
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,eth,ipv6,in_port=1,nw_ttl=128,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,eth,ipv6,in_port=1,nw_proto=10,nw_ttl=128,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: set(ipv6(hlimit=127)),2,set(ipv6(hlimit=126)),3,4
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -1656,7 +1656,7 @@ AT_CHECK([ovs-vsctl -- \
Open vSwitch CI 5acaff
         --id=@q2 create Queue dscp=2], [0], [ignore])
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(9),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xff,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -2 stdout], [0],
Open vSwitch CI 5acaff
-  [Megaflow: recirc_id=0,skb_priority=0,eth,ip,in_port=9,nw_tos=252,nw_frag=no
Open vSwitch CI 5acaff
+  [Megaflow: recirc_id=0,skb_priority=0,eth,icmp,in_port=9,nw_tos=252,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: dnl
Open vSwitch CI 5acaff
 100,dnl
Open vSwitch CI 5acaff
 set(ipv4(tos=0x4/0xfc)),set(skb_priority(0x1)),1,dnl
Open vSwitch CI 5acaff
@@ -11884,7 +11884,7 @@ ovs-ofctl dump-flows br0
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
Open vSwitch CI 5acaff
 AT_CHECK([tail -3 stdout], [0], [dnl
Open vSwitch CI 5acaff
-Megaflow: recirc_id=0,eth,ip,reg0=0/0x1,in_port=1,nw_src=10.10.10.2,nw_frag=no
Open vSwitch CI 5acaff
+Megaflow: recirc_id=0,eth,icmp,reg0=0/0x1,in_port=1,nw_src=10.10.10.2,nw_frag=no
Open vSwitch CI 5acaff
 Datapath actions: drop
Open vSwitch CI 5acaff
 Translation failed (Recursion too deep), packet is dropped.
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
diff --git a/tests/ofproto.at b/tests/ofproto.at
Open vSwitch CI 5acaff
index a666bebca..2fa8486a8 100644
Open vSwitch CI 5acaff
--- a/tests/ofproto.at
Open vSwitch CI 5acaff
+++ b/tests/ofproto.at
Open vSwitch CI 5acaff
@@ -6538,3 +6538,185 @@ verify_deleted
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 OVS_VSWITCHD_STOP(["/
Open vSwitch CI 5acaff
 AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([ofproto - implicit mask of ipv4 proto with invalid proto field])
Open vSwitch CI 5acaff
+OVS_VSWITCHD_START
Open vSwitch CI 5acaff
+add_of_ports br0 1 2
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_DATA([flows.txt], [dnl
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=90,ip,nw_dst=192.168.1.20,actions=mod_nw_dst:192.168.20.20,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=89,ip,nw_dst=192.168.1.21,actions=mod_nw_src:192.168.20.21,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=88,ip,nw_dst=192.168.1.10,actions=dec_ttl,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=87,ip,nw_dst=192.168.1.19,actions=mod_nw_ttl:8,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=86,ip,nw_dst=192.168.1.18,actions=mod_nw_ecn:2,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=85,ip,nw_dst=192.168.1.17,actions=mod_nw_tos:0x40,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=84,ip,nw_dst=192.168.1.16,actions=set_field:192.168.20.26->nw_dst,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=83,ip,nw_dst=192.168.1.15,actions=set_field:192.168.21.26->nw_src,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=82,ip,nw_dst=192.168.1.14,actions=set_field:0x40->nw_tos,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=0,actions=drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl del-flows br0])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send a proto 0 packet to try and poison the DP flow path
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
Open vSwitch CI 5acaff
+ '5054000000075054000000050800450000548de140004000289fc0a801c4c0a8011408003bf60002001bbf080a640000000032ad010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=0,frag=no), packets:0, bytes:0, used:never, actions:2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send ICMP for mod nw_src and mod nw_dst
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.21,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.20,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will dec TTL
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.10,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod TTL
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.19,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod ECN
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.18,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod TOS
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.17,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will set DST
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.16,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will set SRC
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.15,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will set TOS
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.14,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.10,proto=1,ttl=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(ttl=63)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.14,proto=1,tos=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x40/0xfc)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.16,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(dst=192.168.20.26)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.17,proto=1,tos=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x40/0xfc)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.18,proto=1,tos=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(tos=0x2/0x3)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.19,proto=1,ttl=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(ttl=8)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=0,frag=no), packets:0, bytes:0, used:never, actions:2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.1.20,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(dst=192.168.20.20)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.15,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(src=192.168.21.26)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(src=192.168.1.1,dst=192.168.1.21,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv4(src=192.168.20.21)),2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([ofproto - implicit mask of ipv6 proto with HOPOPT field])
Open vSwitch CI 5acaff
+OVS_VSWITCHD_START
Open vSwitch CI 5acaff
+add_of_ports br0 1 2
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_DATA([flows.txt], [dnl
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=77,ip6,ipv6_dst=111:db8::3,actions=dec_ttl,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=76,ip6,ipv6_dst=111:db8::4,actions=mod_nw_ttl:8,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=75,ip6,ipv6_dst=111:db8::5,actions=mod_nw_ecn:2,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=74,ip6,ipv6_dst=111:db8::6,actions=mod_nw_tos:0x40,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=73,ip6,ipv6_dst=111:db8::7,actions=set_field:2112:db8::2->ipv6_dst,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=72,ip6,ipv6_dst=111:db8::8,actions=set_field:2112:db8::3->ipv6_src,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=72,ip6,ipv6_dst=111:db8::9,actions=set_field:44->ipv6_label,output=2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=0,actions=drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl del-flows br0])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send a proto 0 packet to try and poison the DP flow path
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::3,proto=0,tclass=0,hlimit=64,frag=no)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=0,hlimit=0,frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=2,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535))
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send ICMP for mod nw_src and mod nw_dst
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::3,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::4,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will dec TTL
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::5,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod TTL
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::6,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod ECN
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::7,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will mod TOS
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::8,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl send ICMP that will set LABEL
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::9,proto=1,tclass=0,hlimit=64,frag=no),icmpv6(type=0,code=8)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=0,hlimit=0,frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,controller(reason=2,dont_send=0,continuation=0,recirc_id=1,rule_cookie=0,controller_id=0,max_len=65535))
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::3,proto=1,hlimit=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(hlimit=63)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::4,proto=1,hlimit=64,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(hlimit=8)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::5,proto=1,tclass=0/0x3,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(tclass=0x2/0x3)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::6,proto=1,tclass=0/0xfc,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(tclass=0x40/0xfc)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::7,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(dst=2112:db8::2)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(dst=111:db8::9,label=0,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(label=0x2c)),2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x86dd),ipv6(src=2001:db8::1,dst=111:db8::8,proto=1,frag=no), packets:0, bytes:0, used:never, actions:set(ipv6(src=2112:db8::3)),2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([ofproto - implicit mask of ARP OPer field])
Open vSwitch CI 5acaff
+OVS_VSWITCHD_START
Open vSwitch CI 5acaff
+add_of_ports br0 1 2
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_DATA([flows.txt], [dnl
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=77,arp,arp_sha=00:01:02:03:04:06,actions=set_field:0x1->arp_op,2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=76,arp,arp_sha=00:01:02:03:04:07,actions=set_field:00:02:03:04:05:06->arp_sha,2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=75,arp,arp_sha=00:01:02:03:04:08,actions=set_field:ff:00:00:00:00:ff->arp_tha,2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=74,arp,arp_sha=00:01:02:03:04:09,actions=set_field:172.31.110.26->arp_spa,2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=73,arp,arp_sha=00:01:02:03:04:0a,actions=set_field:172.31.110.10->arp_tpa,2
Open vSwitch CI 5acaff
+table=0 in_port=1 priority=1,actions=drop
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl del-flows br0])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op == 0 packet
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 \
Open vSwitch CI 5acaff
+ 'ffffffffffffaa55aa550000080600010800060400000001020304070c0a00010000000000000c0a0002'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=0,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op 2 -> set op
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=2,sha=00:01:02:03:04:06,tha=ff:ff:ff:ff:ff:ff)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op 1 -> set SHA
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:07,tha=ff:ff:ff:ff:ff:ff)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op 1 -> set THA
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:08,tha=ff:ff:ff:ff:ff:ff)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op 1 -> set SIP
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:09,tha=ff:ff:ff:ff:ff:ff)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Send op 1 -> set TIP
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0806),arp(sip=172.31.110.1,tip=172.31.110.25,op=1,sha=00:01:02:03:04:0a,tha=ff:ff:ff:ff:ff:ff)'])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows | sort], [0], [dnl
Open vSwitch CI 5acaff
+flow-dump from the main thread:
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=0,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:2
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=1,sha=00:01:02:03:04:07), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=1,sha=00:01:02:03:04:08,tha=ff:ff:ff:ff:ff:ff), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(op=2,sha=00:01:02:03:04:06), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(sip=172.31.110.1,op=1,sha=00:01:02:03:04:09), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
Open vSwitch CI 5acaff
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0806),arp(tip=172.31.110.25,op=1,sha=00:01:02:03:04:0a), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(action))
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at
Open vSwitch CI 5acaff
index a92156f00..a368bff6e 100644
Open vSwitch CI 5acaff
--- a/tests/ovs-vsctl.at
Open vSwitch CI 5acaff
+++ b/tests/ovs-vsctl.at
Open vSwitch CI 5acaff
@@ -425,6 +425,7 @@ AT_CHECK([RUN_OVS_VSCTL_ONELINE(
Open vSwitch CI 5acaff
   [add-port a a1],
Open vSwitch CI 5acaff
   [add-bond a bond0 a2 a3],
Open vSwitch CI 5acaff
   [br-set-external-id a key0 value0],
Open vSwitch CI 5acaff
+  [add Bridge a external_ids key0=value1],
Open vSwitch CI 5acaff
   [set port a1 external-ids:key1=value1],
Open vSwitch CI 5acaff
   [set interface a2 external-ids:key2=value2],
Open vSwitch CI 5acaff
   [set interface a2 external-ids:key3=value3],
Open vSwitch CI 5acaff
@@ -446,6 +447,7 @@ AT_CHECK([RUN_OVS_VSCTL_ONELINE(
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 key0=value0
Open vSwitch CI 5acaff
 value0
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -1071,13 +1073,9 @@ AT_CHECK([RUN_OVS_VSCTL([set controller br1 'connection-mode=xyz'])],
Open vSwitch CI 5acaff
 AT_CHECK([RUN_OVS_VSCTL([set controller br1 connection-mode:x=y])],
Open vSwitch CI 5acaff
   [1], [], [ovs-vsctl: cannot specify key to set for non-map column connection_mode
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
-AT_CHECK([RUN_OVS_VSCTL([add bridge br1 datapath_id x y -- show])],
Open vSwitch CI 5acaff
+AT_CHECK([RUN_OVS_VSCTL([add bridge br1 datapath_id x y])],
Open vSwitch CI 5acaff
   [1], [], [ovs-vsctl: "add" operation would put 2 values in column datapath_id of table Bridge but the maximum number is 1
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
-AT_CHECK([RUN_OVS_VSCTL([add bridge br1 datapath_id x y])], [1], [], [stderr])
Open vSwitch CI 5acaff
-AT_CHECK([sed "/^.*|WARN|.*/d" < stderr], [0], [dnl
Open vSwitch CI 5acaff
-ovs-vsctl: transaction error: {"details":"set must have 0 to 1 members but 2 are present","error":"syntax error","syntax":"[[\"set\",[\"x\",\"y\"]]]"}
Open vSwitch CI 5acaff
-])
Open vSwitch CI 5acaff
 AT_CHECK([RUN_OVS_VSCTL([remove netflow `cat netflow-uuid` targets '"1.2.3.4:567"'])],
Open vSwitch CI 5acaff
   [1], [], [ovs-vsctl: "remove" operation would put 0 values in column targets of table NetFlow but the minimum number is 1
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 38c5a5
diff --git a/tests/ovsdb-tool.at b/tests/ovsdb-tool.at
Open vSwitch CI 38c5a5
index 12ad6fb3f..5496ccda7 100644
Open vSwitch CI 38c5a5
--- a/tests/ovsdb-tool.at
Open vSwitch CI 38c5a5
+++ b/tests/ovsdb-tool.at
Open vSwitch CI 38c5a5
@@ -465,6 +465,7 @@ AT_SETUP([ovsdb-tool convert-to-standalone])
Open vSwitch CI 38c5a5
 AT_KEYWORDS([ovsdb file positive])
Open vSwitch CI 38c5a5
 ordinal_schema > schema
Open vSwitch CI 38c5a5
 AT_CHECK([ovsdb-tool create-cluster db schema unix:s1.raft], [0], [stdout], [ignore])
Open vSwitch CI 38c5a5
+on_exit 'kill `cat ovsdb-server.pid`'
Open vSwitch CI 38c5a5
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file db >/dev/null 2>&1])
Open vSwitch CI 38c5a5
 for txn in m4_foreach([txn], [[[["ordinals",
Open vSwitch CI 38c5a5
       {"op": "insert",
Open vSwitch CI 38c5a5
@@ -498,3 +499,71 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server])
Open vSwitch CI 38c5a5
 # Make sure both standalone and cluster db data matches.
Open vSwitch CI 38c5a5
 AT_CHECK([diff standalonedump clusterdump])
Open vSwitch CI 38c5a5
 AT_CLEANUP
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+AT_SETUP([ovsdb-tool convert-to-standalone after schema conversion])
Open vSwitch CI 38c5a5
+AT_KEYWORDS([ovsdb file positive])
Open vSwitch CI 38c5a5
+ordinal_schema > schema
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-tool create-cluster db schema unix:s1.raft], [0], [stdout], [ignore])
Open vSwitch CI 38c5a5
+on_exit 'kill `cat ovsdb-server.pid`'
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket dnl
Open vSwitch CI 38c5a5
+                       --log-file db >/dev/null 2>&1])
Open vSwitch CI 38c5a5
+for txn in m4_foreach([txn], [[[["ordinals",
Open vSwitch CI 38c5a5
+      {"op": "insert",
Open vSwitch CI 38c5a5
+       "table": "ordinals",
Open vSwitch CI 38c5a5
+       "row": {"number": 0, "name": "zero"}},
Open vSwitch CI 38c5a5
+      {"op": "insert",
Open vSwitch CI 38c5a5
+       "table": "ordinals",
Open vSwitch CI 38c5a5
+       "row": {"number": 1, "name": "one"}},
Open vSwitch CI 38c5a5
+      {"op": "insert",
Open vSwitch CI 38c5a5
+       "table": "ordinals",
Open vSwitch CI 38c5a5
+       "row": {"number": 2, "name": "two"}}]]]], ['txn' ]); do
Open vSwitch CI 38c5a5
+  AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0], [ignore], [ignore])
Open vSwitch CI 38c5a5
+done
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Change the schema.
Open vSwitch CI 38c5a5
+AT_CHECK([sed 's/5\.1\.3/5.1.4/' < schema > schema2])
Open vSwitch CI 38c5a5
+AT_CHECK([sed -i'back' -e '/.*"number":.*/a \
Open vSwitch CI 38c5a5
+           "is_seven": {"type": "boolean"},
Open vSwitch CI 38c5a5
+           ' schema2])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Convert the database.
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-client convert unix:socket schema2])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Add a new row with a new column.
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-client transact unix:socket dnl
Open vSwitch CI 38c5a5
+  '[["ordinals",
Open vSwitch CI 38c5a5
+     {"op": "insert",
Open vSwitch CI 38c5a5
+      "table": "ordinals",
Open vSwitch CI 38c5a5
+      "row": {"number": 7, "name": "seven", "is_seven": true}
Open vSwitch CI 38c5a5
+     }]]'], [0], [ignore], [ignore])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-client dump unix:socket > clusterdump])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+AT_CHECK([uuidfilt clusterdump], [0], [dnl
Open vSwitch CI 38c5a5
+ordinals table
Open vSwitch CI 38c5a5
+_uuid                                is_seven name  number
Open vSwitch CI 38c5a5
+------------------------------------ -------- ----- ------
Open vSwitch CI 38c5a5
+<0> false    one   1
Open vSwitch CI 38c5a5
+<1> false    two   2
Open vSwitch CI 38c5a5
+<2> false    zero  0
Open vSwitch CI 38c5a5
+<3> true     seven 7
Open vSwitch CI 38c5a5
+])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Convert to standalone database from clustered database.
Open vSwitch CI 38c5a5
+AT_CHECK(ovsdb-tool cluster-to-standalone db1 db)
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Check it's a standalone db.
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-tool db-is-standalone db1])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Dump the standalone db data.
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-server -vconsole:off -vfile -vvlog:off --detach --no-chdir dnl
Open vSwitch CI 38c5a5
+                       --pidfile --log-file --remote=punix:db.sock db1])
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb_client_wait ordinals connected])
Open vSwitch CI 38c5a5
+AT_CHECK([ovsdb-client dump > standalonedump])
Open vSwitch CI 38c5a5
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
+dnl Make sure both standalone and cluster db data matches.
Open vSwitch CI 38c5a5
+AT_CHECK([diff standalonedump clusterdump])
Open vSwitch CI 38c5a5
+AT_CLEANUP
Open vSwitch CI 5acaff
diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
Open vSwitch CI 5acaff
index 3b5c66fe5..d63528e69 100644
Open vSwitch CI 5acaff
--- a/tests/packet-type-aware.at
Open vSwitch CI 5acaff
+++ b/tests/packet-type-aware.at
Open vSwitch CI 5acaff
@@ -1021,7 +1021,7 @@ AT_CHECK([
Open vSwitch CI 5acaff
 ], [0], [flow-dump from the main thread:
Open vSwitch CI 5acaff
 recirc_id(0),in_port(p0),packet_type(ns=0,id=0),eth(src=aa:bb:cc:00:00:02,dst=aa:bb:cc:00:00:01),eth_type(0x0800),ipv4(dst=20.0.0.1,proto=47,frag=no), packets:3, bytes:378, used:0.0s, actions:tnl_pop(gre_sys)
Open vSwitch CI 5acaff
 tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x8847),eth_type(0x8847),mpls(label=999/0x0,tc=0/0,ttl=64/0x0,bos=1/1), packets:3, bytes:264, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=00:00:00:00:00:00),pop_mpls(eth_type=0x800),recirc(0x1)
Open vSwitch CI 5acaff
-tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0x1),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(ttl=64,frag=no), packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
Open vSwitch CI 5acaff
+tunnel(src=20.0.0.2,dst=20.0.0.1,flags(-df-csum)),recirc_id(0x1),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=1,ttl=64,frag=no), packets:3, bytes:294, used:0.0s, actions:set(ipv4(ttl=63)),int-br
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 ovs-appctl time/warp 1000
Open vSwitch CI 5acaff
diff --git a/tests/system-interface.at b/tests/system-interface.at
Open vSwitch CI 5acaff
index 784bada12..3bf339582 100644
Open vSwitch CI 5acaff
--- a/tests/system-interface.at
Open vSwitch CI 5acaff
+++ b/tests/system-interface.at
Open vSwitch CI 5acaff
@@ -63,3 +63,62 @@ AT_CHECK([
Open vSwitch CI 5acaff
     [stdout], [Device "br-p1" does not exist.]
Open vSwitch CI 5acaff
 )
Open vSwitch CI 5acaff
 AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([interface - datapath ports garbage collection])
Open vSwitch CI 5acaff
+OVS_CHECK_GENEVE()
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_START()
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Not relevant for userspace datapath.
Open vSwitch CI 5acaff
+AT_SKIP_IF([! ovs-appctl dpctl/show | grep -q ovs-system])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-vsctl add-port br0 tunnel_port dnl
Open vSwitch CI 5acaff
+            -- set Interface tunnel_port dnl
Open vSwitch CI 5acaff
+                   type=geneve options:remote_ip=flow options:key=123])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ip link add ovs-veth0 type veth peer name ovs-veth1])
Open vSwitch CI 5acaff
+on_exit 'ip link del ovs-veth0'
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-vsctl add-port br0 ovs-veth0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_WAIT_UNTIL([ip link show | grep -q " genev_sys_[[0-9]]*: .* ovs-system "])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Store the output of ip link for geneve port to compare ifindex later.
Open vSwitch CI 5acaff
+AT_CHECK([ip link show | grep " genev_sys_[[0-9]]*: .* ovs-system " > geneve.0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/show | grep port], [0], [dnl
Open vSwitch CI 5acaff
+  port 0: ovs-system (internal)
Open vSwitch CI 5acaff
+  port 1: br0 (internal)
Open vSwitch CI 5acaff
+  port 2: genev_sys_6081 (geneve: packet_type=ptap)
Open vSwitch CI 5acaff
+  port 3: ovs-veth0
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_APP_EXIT_AND_WAIT_BY_TARGET([ovs-vswitchd], [ovs-vswitchd.pid])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Check that geneve backing interface is still in the datapath.
Open vSwitch CI 5acaff
+AT_CHECK([ip link show | grep " genev_sys_[[0-9]]*: .* ovs-system " | diff -u - geneve.0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Remove the veth port from the database while ovs-vswitchd is down.
Open vSwitch CI 5acaff
+AT_CHECK([ovs-vsctl --no-wait del-port ovs-veth0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Check that it is still tied to the OVS datapath.
Open vSwitch CI 5acaff
+AT_CHECK([ip link show ovs-veth0 | grep -q ovs-system])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Bring ovs-vswitchd back up.
Open vSwitch CI 5acaff
+AT_CHECK([ovs-vswitchd --detach --no-chdir --pidfile --log-file -vdpif:dbg],
Open vSwitch CI 5acaff
+         [0], [], [stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Wait for the veth port to be removed from the datapath.
Open vSwitch CI 5acaff
+OVS_WAIT_WHILE([ip link show ovs-veth0 | grep -q ovs-system])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/show | grep port], [0], [dnl
Open vSwitch CI 5acaff
+  port 0: ovs-system (internal)
Open vSwitch CI 5acaff
+  port 1: br0 (internal)
Open vSwitch CI 5acaff
+  port 2: genev_sys_6081 (geneve: packet_type=ptap)
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Check that geneve backing interface is still in the datapath and it wasn't
Open vSwitch CI 5acaff
+dnl re-created, i.e. the ifindex is the same.
Open vSwitch CI 5acaff
+AT_CHECK([ip link show | grep " genev_sys_[[0-9]]*: .* ovs-system " | diff -u - geneve.0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at
Open vSwitch CI 5acaff
index d36da0580..8dd3bdf88 100644
Open vSwitch CI 5acaff
--- a/tests/system-offloads-traffic.at
Open vSwitch CI 5acaff
+++ b/tests/system-offloads-traffic.at
Open vSwitch CI 5acaff
@@ -742,3 +742,118 @@ recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 OVS_TRAFFIC_VSWITCHD_STOP
Open vSwitch CI 5acaff
 AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([offloads - offload flow to none-offload])
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_START([], [], [-- set Open_vSwitch . other_config:hw-offload=true])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+ADD_NAMESPACES(at_ns0, at_ns1)
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
Open vSwitch CI 5acaff
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_DATA([flows.txt], [dnl
Open vSwitch CI 5acaff
+add in_port=ovs-p0,actions=ovs-p1
Open vSwitch CI 5acaff
+add in_port=ovs-p1,actions=ovs-p0
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+10 packets transmitted, 10 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:3
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Here we use an output action with truncate, which will force a kernel flow.
Open vSwitch CI 5acaff
+AT_DATA([flows2.txt], [dnl
Open vSwitch CI 5acaff
+modify in_port=ovs-p0,actions=output(port=ovs-p1, max_len=128)
Open vSwitch CI 5acaff
+modify in_port=ovs-p1,actions=output(port=ovs-p0, max_len=128)
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows2.txt])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl revalidator/wait], [0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+10 packets transmitted, 10 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows type=ovs | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),3
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl revalidator/wait], [0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+10 packets transmitted, 10 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:3
Open vSwitch CI 5acaff
+recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:2
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl coverage/read-counter ukey_invalid_stat_reset], [0], [dnl
Open vSwitch CI 5acaff
+0
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_STOP
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_SETUP([offloads - delete ufid mapping if device not exist - offloads enabled])
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_START([], [], [-- set Open_vSwitch . other_config:hw-offload=true])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+ADD_NAMESPACES(at_ns0, at_ns1, at_ns2)
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Disable IPv6 to skip unexpected flow
Open vSwitch CI 5acaff
+AT_CHECK([sysctl -w net.ipv6.conf.br0.disable_ipv6=1], [0], [ignore])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns1], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns2], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "aa:1a:54:e9:c5:56")
Open vSwitch CI 5acaff
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.2 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+2 packets transmitted, 2 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Delete and add interface ovs-p0/p0
Open vSwitch CI 5acaff
+AT_CHECK([ip link del dev ovs-p0])
Open vSwitch CI 5acaff
+AT_CHECK([ip link add p0 type veth peer name ovs-p0 || return 77])
Open vSwitch CI 5acaff
+AT_CHECK([ip link set p0 netns at_ns0])
Open vSwitch CI 5acaff
+AT_CHECK([ip link set dev ovs-p0 up])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ip addr add dev p0 "10.1.1.1/24"])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ip link set dev p0 up])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address "aa:1a:54:e9:c5:56"])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl revalidator/purge], [0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Generate flows to trigger the hmap expand once
Open vSwitch CI 5acaff
+ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24")
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.2 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+2 packets transmitted, 2 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.3 | FORMAT_PING], [0], [dnl
Open vSwitch CI 5acaff
+2 packets transmitted, 2 received, 0% packet loss, time 0ms
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl revalidator/purge], [0])
Open vSwitch CI 5acaff
+dnl Fix purge fail occasionally
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl revalidator/purge], [0])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([test $(ovs-appctl dpctl/dump-flows | grep -c "eth_type(0x0800)") -eq 0], [0], [ignore])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+OVS_TRAFFIC_VSWITCHD_STOP(["/could not open network device ovs-p0/d
Open vSwitch CI 5acaff
+/on nonexistent port/d
Open vSwitch CI 5acaff
+/failed to flow_get/d
Open vSwitch CI 5acaff
+/Failed to acquire udpif_key/d
Open vSwitch CI 5acaff
+/No such device/d
Open vSwitch CI 5acaff
+/failed to offload flow/d
Open vSwitch CI 5acaff
+"])
Open vSwitch CI 5acaff
+AT_CLEANUP
Open vSwitch CI 5acaff
diff --git a/tests/system-traffic.at b/tests/system-traffic.at
Open vSwitch CI 5acaff
index 221d96aef..6678911b4 100644
Open vSwitch CI 5acaff
--- a/tests/system-traffic.at
Open vSwitch CI 5acaff
+++ b/tests/system-traffic.at
Open vSwitch CI 5acaff
@@ -2360,8 +2360,10 @@ priority=100,in_port=2,icmp,action=ct(zone=5,commit),1
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
Open vSwitch CI 5acaff
+dp=$(ovs-appctl dpctl/dump-dps)
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 m4_foreach([FLUSH_CMD], [[ovs-appctl dpctl/flush-conntrack],
Open vSwitch CI 5acaff
+                         [ovs-appctl dpctl/flush-conntrack $dp],
Open vSwitch CI 5acaff
                          [ovs-ofctl ct-flush br0]], [
Open vSwitch CI 5acaff
 AS_BOX([Testing with FLUSH_CMD])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -2504,8 +2506,48 @@ udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.
Open vSwitch CI 5acaff
 AT_CHECK([FLUSH_CMD zone=5 '' 'ct_nw_src=10.1.1.1'])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Test UDP from port 1 and 2, flush without arguments
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"])
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=2 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101020a0101010002000100080000 actions=resubmit(,0)"])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1" | sort], [0], [dnl
Open vSwitch CI 5acaff
+udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),reply=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1)
Open vSwitch CI 5acaff
+udp,orig=(src=10.1.1.2,dst=10.1.1.1,sport=2,dport=1),reply=(src=10.1.1.1,dst=10.1.1.2,sport=1,dport=2),zone=5
Open vSwitch CI 5acaff
 ])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+AT_CHECK([FLUSH_CMD])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep "10\.1\.1\.1"], [1])
Open vSwitch CI 5acaff
+])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+dnl Test flush with invalid arguments
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=invalid 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "failed to parse zone" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_src=10.1.1.1,invalid=invalid' 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "invalid conntrack tuple field: invalid" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_src=invalid' 'ct_nw_dst=10.1.1.1'], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "failed to parse field ct_nw_src" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "invalid arguments" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack $dp zone=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "command takes at most 4 arguments" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-appctl dpctl/flush-conntrack $dp 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [2], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "invalid arguments" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl ct-flush br0 zone=1 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [1], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "command takes at most 4 arguments" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
+AT_CHECK([ovs-ofctl ct-flush br0 'ct_nw_src=10.1.1.1' 'ct_nw_dst=10.1.1.1' invalid], [1], [ignore], [stderr])
Open vSwitch CI 5acaff
+AT_CHECK([grep -q "Invalid arguments" stderr])
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 OVS_TRAFFIC_VSWITCHD_STOP
Open vSwitch CI 5acaff
 AT_CLEANUP
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -7220,7 +7262,7 @@ table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client
Open vSwitch CI 5acaff
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 rm server.pcap
Open vSwitch CI 5acaff
-OVS_DAEMONIZE([tcpdump -l -U -i ovs-server -w server.pcap 2>tcpdump0_err], [tcpdump0.pid])
Open vSwitch CI 5acaff
+NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -w server.pcap 2>tcpdump0_err], [tcpdump0.pid])
Open vSwitch CI 5acaff
 OVS_WAIT_UNTIL([grep "listening" tcpdump0_err])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 dnl Send UDP client->server
Open vSwitch CI 5acaff
@@ -7262,7 +7304,7 @@ dnl Check the ICMP error in reply direction
Open vSwitch CI 5acaff
 AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=42])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 rm client.pcap
Open vSwitch CI 5acaff
-OVS_DAEMONIZE([tcpdump -l -U -i ovs-client -w client.pcap 2>tcpdump1_err], [tcpdump1.pid])
Open vSwitch CI 5acaff
+NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -w client.pcap 2>tcpdump1_err], [tcpdump1.pid])
Open vSwitch CI 5acaff
 OVS_WAIT_UNTIL([grep "listening" tcpdump1_err])
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 dnl Send UDP client->server
Open vSwitch CI 5acaff
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
Open vSwitch CI 5acaff
index eabec18a3..3ce4e82ec 100644
Open vSwitch CI 5acaff
--- a/utilities/ovs-ofctl.c
Open vSwitch CI 5acaff
+++ b/utilities/ovs-ofctl.c
Open vSwitch CI 5acaff
@@ -3089,6 +3089,10 @@ ofctl_ct_flush(struct ovs_cmdl_context *ctx)
Open vSwitch CI 5acaff
         args--;
Open vSwitch CI 5acaff
     }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+    if (args > 0) {
Open vSwitch CI 5acaff
+        ovs_fatal(0, "Invalid arguments");
Open vSwitch CI 5acaff
+    }
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
     open_vconn(ctx->argv[1], &vconn);
Open vSwitch CI 5acaff
     enum ofp_version version = vconn_get_version(vconn);
Open vSwitch CI 5acaff
     struct ofpbuf *msg = ofp_ct_match_encode(&match, pzone, version);
Open vSwitch CI 38c5a5
diff --git a/utilities/ovs-tcpdump.in b/utilities/ovs-tcpdump.in
Open vSwitch CI 38c5a5
index a49ec9f94..420c11eb8 100755
Open vSwitch CI 38c5a5
--- a/utilities/ovs-tcpdump.in
Open vSwitch CI 38c5a5
+++ b/utilities/ovs-tcpdump.in
Open vSwitch CI 38c5a5
@@ -538,6 +538,17 @@ def main():
Open vSwitch CI 38c5a5
             print(data.decode('utf-8'))
Open vSwitch CI 38c5a5
         raise KeyboardInterrupt
Open vSwitch CI 38c5a5
     except KeyboardInterrupt:
Open vSwitch CI 38c5a5
+        # If there is a pipe behind ovs-tcpdump (such as ovs-tcpdump
Open vSwitch CI 38c5a5
+        # -i eth0 | grep "192.168.1.1"), the pipe is no longer available
Open vSwitch CI 38c5a5
+        # after received Ctrl+C.
Open vSwitch CI 38c5a5
+        # If we write data to an unavailable pipe, a pipe error will be
Open vSwitch CI 38c5a5
+        # reported, so we turn off stdout to avoid subsequent flushing
Open vSwitch CI 38c5a5
+        # of data into the pipe.
Open vSwitch CI 38c5a5
+        try:
Open vSwitch CI 38c5a5
+            sys.stdout.close()
Open vSwitch CI 38c5a5
+        except IOError:
Open vSwitch CI 38c5a5
+            pass
Open vSwitch CI 38c5a5
+
Open vSwitch CI 38c5a5
         if pipes.poll() is None:
Open vSwitch CI 38c5a5
             pipes.terminate()
Open vSwitch CI 38c5a5
 
Open vSwitch CI 5acaff
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
Open vSwitch CI 5acaff
index bfb2adef1..0deca14b9 100644
Open vSwitch CI 5acaff
--- a/vswitchd/bridge.c
Open vSwitch CI 5acaff
+++ b/vswitchd/bridge.c
Open vSwitch CI 5acaff
@@ -832,6 +832,9 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
Open vSwitch CI 5acaff
     ofproto_set_min_revalidate_pps(
Open vSwitch CI 5acaff
         smap_get_uint(&ovs_cfg->other_config, "min-revalidate-pps",
Open vSwitch CI 5acaff
                      OFPROTO_MIN_REVALIDATE_PPS_DEFAULT));
Open vSwitch CI 5acaff
+    ofproto_set_offloaded_stats_delay(
Open vSwitch CI 5acaff
+        smap_get_uint(&ovs_cfg->other_config, "offloaded-stats-delay",
Open vSwitch CI 5acaff
+                      OFPROTO_OFFLOADED_STATS_DELAY));
Open vSwitch CI 5acaff
     ofproto_set_vlan_limit(smap_get_int(&ovs_cfg->other_config, "vlan-limit",
Open vSwitch CI 5acaff
                                        LEGACY_MAX_VLAN_HEADERS));
Open vSwitch CI 5acaff
     ofproto_set_bundle_idle_timeout(smap_get_uint(&ovs_cfg->other_config,
Open vSwitch CI 5acaff
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
Open vSwitch CI 5acaff
index 2b57fc0e3..1204805b1 100644
Open vSwitch CI 5acaff
--- a/vswitchd/vswitch.xml
Open vSwitch CI 5acaff
+++ b/vswitchd/vswitch.xml
Open vSwitch CI 5acaff
@@ -215,6 +215,19 @@
Open vSwitch CI 5acaff
         

Open vSwitch CI 5acaff
       </column>
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+      
Open vSwitch CI 5acaff
+              type='{"type": "integer", "minInteger": 0}'>
Open vSwitch CI 5acaff
+        

Open vSwitch CI 5acaff
+          Set worst case delay (in ms) it might take before statistics of
Open vSwitch CI 5acaff
+          offloaded flows are updated. Offloaded flows younger than this
Open vSwitch CI 5acaff
+          delay will always be revalidated regardless of
Open vSwitch CI 5acaff
+          <ref column="other_config" key="min-revalidate-pps"/>.
Open vSwitch CI 5acaff
+        

Open vSwitch CI 5acaff
+        

Open vSwitch CI 5acaff
+          The default is 2000.
Open vSwitch CI 5acaff
+        

Open vSwitch CI 5acaff
+      </column>
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
       
Open vSwitch CI 5acaff
               type='{"type": "boolean"}'>
Open vSwitch CI 5acaff
         

Open vSwitch CI 5acaff
@@ -6296,6 +6309,12 @@ ovs-vsctl add-port br0 p0 -- set Interface p0 type=patch options:peer=p1 \
Open vSwitch CI 5acaff
         translated to an ephemeral port. If there is no collision, no SNAT
Open vSwitch CI 5acaff
         is performed.
Open vSwitch CI 5acaff
       </column>
Open vSwitch CI 5acaff
+      
Open vSwitch CI 5acaff
+              type='{"type": "boolean"}'>
Open vSwitch CI 5acaff
+        True if the datapath supports CT flush OpenFlow Nicira extension
Open vSwitch CI 5acaff
+        called NXT_CT_FLUSH. The NXT_CT_FLUSH
Open vSwitch CI 5acaff
+        extensions allows to flush CT entries based on specified parameters.
Open vSwitch CI 5acaff
+      </column>
Open vSwitch CI 5acaff
     </group>
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
     <group title="Common Columns">
Open vSwitch CI 5acaff
Submodule dpdk 9dae7a15a..3812e23f6:
Open vSwitch CI 5acaff
diff --git a/dpdk/drivers/net/i40e/i40e_ethdev.c b/dpdk/drivers/net/i40e/i40e_ethdev.c
Open vSwitch CI 5acaff
index 7726a89d99..a982e42264 100644
Open vSwitch CI 5acaff
--- a/dpdk/drivers/net/i40e/i40e_ethdev.c
Open vSwitch CI 5acaff
+++ b/dpdk/drivers/net/i40e/i40e_ethdev.c
Open vSwitch CI 5acaff
@@ -387,7 +387,6 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
Open vSwitch CI 5acaff
 				      struct rte_ether_addr *mac_addr);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
Open vSwitch CI 5acaff
-static void i40e_set_mac_max_frame(struct rte_eth_dev *dev, uint16_t size);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 static int i40e_ethertype_filter_convert(
Open vSwitch CI 5acaff
 	const struct rte_eth_ethertype_filter *input,
Open vSwitch CI 5acaff
@@ -1711,6 +1710,11 @@ eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
Open vSwitch CI 5acaff
 	 */
Open vSwitch CI 5acaff
 	i40e_add_tx_flow_control_drop_filter(pf);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
+	/* Set the max frame size to 0x2600 by default,
Open vSwitch CI 5acaff
+	 * in case other drivers changed the default value.
Open vSwitch CI 5acaff
+	 */
Open vSwitch CI 5acaff
+	i40e_aq_set_mac_config(hw, I40E_FRAME_SIZE_MAX, TRUE, false, 0, NULL);
Open vSwitch CI 5acaff
+
Open vSwitch CI 5acaff
 	/* initialize RSS rule list */
Open vSwitch CI 5acaff
 	TAILQ_INIT(&pf->rss_config_list);
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -2328,7 +2332,6 @@ i40e_dev_start(struct rte_eth_dev *dev)
Open vSwitch CI 5acaff
 	uint32_t intr_vector = 0;
Open vSwitch CI 5acaff
 	struct i40e_vsi *vsi;
Open vSwitch CI 5acaff
 	uint16_t nb_rxq, nb_txq;
Open vSwitch CI 5acaff
-	uint16_t max_frame_size;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 	hw->adapter_stopped = 0;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
@@ -2467,9 +2470,6 @@ i40e_dev_start(struct rte_eth_dev *dev)
Open vSwitch CI 5acaff
 			    "please call hierarchy_commit() "
Open vSwitch CI 5acaff
 			    "before starting the port");
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-	max_frame_size = dev->data->mtu + I40E_ETH_OVERHEAD;
Open vSwitch CI 5acaff
-	i40e_set_mac_max_frame(dev, max_frame_size);
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
 	return I40E_SUCCESS;
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
 tx_err:
Open vSwitch CI 5acaff
@@ -2809,9 +2809,6 @@ i40e_dev_set_link_down(struct rte_eth_dev *dev)
Open vSwitch CI 5acaff
 	return i40e_phy_conf_link(hw, abilities, speed, false);
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-#define CHECK_INTERVAL             100  /* 100ms */
Open vSwitch CI 5acaff
-#define MAX_REPEAT_TIME            10  /* 1s (10 * 100ms) in total */
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
 static __rte_always_inline void
Open vSwitch CI 5acaff
 update_link_reg(struct i40e_hw *hw, struct rte_eth_link *link)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
@@ -2878,6 +2875,8 @@ static __rte_always_inline void
Open vSwitch CI 5acaff
 update_link_aq(struct i40e_hw *hw, struct rte_eth_link *link,
Open vSwitch CI 5acaff
 	bool enable_lse, int wait_to_complete)
Open vSwitch CI 5acaff
 {
Open vSwitch CI 5acaff
+#define CHECK_INTERVAL             100  /* 100ms */
Open vSwitch CI 5acaff
+#define MAX_REPEAT_TIME            10  /* 1s (10 * 100ms) in total */
Open vSwitch CI 5acaff
 	uint32_t rep_cnt = MAX_REPEAT_TIME;
Open vSwitch CI 5acaff
 	struct i40e_link_status link_status;
Open vSwitch CI 5acaff
 	int status;
Open vSwitch CI 5acaff
@@ -6738,7 +6737,6 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
Open vSwitch CI 5acaff
 			if (!ret)
Open vSwitch CI 5acaff
 				rte_eth_dev_callback_process(dev,
Open vSwitch CI 5acaff
 					RTE_ETH_EVENT_INTR_LSC, NULL);
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
 			break;
Open vSwitch CI 5acaff
 		default:
Open vSwitch CI 5acaff
 			PMD_DRV_LOG(DEBUG, "Request %u is not supported yet",
Open vSwitch CI 5acaff
@@ -12123,40 +12121,6 @@ i40e_cloud_filter_qinq_create(struct i40e_pf *pf)
Open vSwitch CI 5acaff
 	return ret;
Open vSwitch CI 5acaff
 }
Open vSwitch CI 5acaff
 
Open vSwitch CI 5acaff
-static void
Open vSwitch CI 5acaff
-i40e_set_mac_max_frame(struct rte_eth_dev *dev, uint16_t size)
Open vSwitch CI 5acaff
-{
Open vSwitch CI 5acaff
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
Open vSwitch CI 5acaff
-	uint32_t rep_cnt = MAX_REPEAT_TIME;
Open vSwitch CI 5acaff
-	struct rte_eth_link link;
Open vSwitch CI 5acaff
-	enum i40e_status_code status;
Open vSwitch CI 5acaff
-	bool can_be_set = true;
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-	/*
Open vSwitch CI 5acaff
-	 * I40E_MEDIA_TYPE_BASET link up can be ignored
Open vSwitch CI 5acaff
-	 * I40E_MEDIA_TYPE_BASET link down that hw->phy.media_type
Open vSwitch CI 5acaff
-	 * is I40E_MEDIA_TYPE_UNKNOWN
Open vSwitch CI 5acaff
-	 */
Open vSwitch CI 5acaff
-	if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET &&
Open vSwitch CI 5acaff
-	    hw->phy.media_type != I40E_MEDIA_TYPE_UNKNOWN) {
Open vSwitch CI 5acaff
-		do {
Open vSwitch CI 5acaff
-			update_link_reg(hw, &link);
Open vSwitch CI 5acaff
-			if (link.link_status)
Open vSwitch CI 5acaff
-				break;
Open vSwitch CI 5acaff
-			rte_delay_ms(CHECK_INTERVAL);
Open vSwitch CI 5acaff
-		} while (--rep_cnt);
Open vSwitch CI 5acaff
-		can_be_set = !!link.link_status;
Open vSwitch CI 5acaff
-	}
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
-	if (can_be_set) {
Open vSwitch CI 5acaff
-		status = i40e_aq_set_mac_config(hw, size, TRUE, 0, false, NULL);
Open vSwitch CI 5acaff
-		if (status != I40E_SUCCESS)
Open vSwitch CI 5acaff
-			PMD_DRV_LOG(ERR, "Failed to set max frame size at port level");
Open vSwitch CI 5acaff
-	} else {
Open vSwitch CI 5acaff
-		PMD_DRV_LOG(ERR, "Set max frame size at port level not applicable on link down");
Open vSwitch CI 5acaff
-	}
Open vSwitch CI 5acaff
-}
Open vSwitch CI 5acaff
-
Open vSwitch CI 5acaff
 RTE_LOG_REGISTER_SUFFIX(i40e_logtype_init, init, NOTICE);
Open vSwitch CI 5acaff
 RTE_LOG_REGISTER_SUFFIX(i40e_logtype_driver, driver, NOTICE);
Open vSwitch CI 5acaff
 #ifdef RTE_ETHDEV_DEBUG_RX