ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch b/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch
new file mode 100644
index 0000000..243b2a9
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0001-netdev-linux-Let-interface-flag-survive-internal-por.patch
@@ -0,0 +1,35 @@
+From 974dc36a87274d7bae13e7dddd3364fecf5b3e7c Mon Sep 17 00:00:00 2001
+From: Helmut Schaa <helmut.schaa@googlemail.com>
+Date: Wed, 8 Jan 2014 13:48:49 +0100
+Subject: [PATCH] netdev-linux: Let interface flag survive internal port setup
+
+Due to a race condition when bringing up an internal port on Linux
+some interface flags (e.g. IFF_MULTICAST) are falsely reset. This
+happens because netlink events may be processed after the according
+netdev has been brought up (which sets interface flags).
+
+Fix this by reading the interface flags just before updating them
+if they have not been updated by from the kernel yet.
+
+Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
+---
+ lib/netdev-linux.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/lib/netdev-linux.c
++++ b/lib/netdev-linux.c
+@@ -3571,7 +3571,13 @@ update_flags(struct netdev_linux *netdev
+ unsigned int old_flags, new_flags;
+ int error = 0;
+
+- old_flags = netdev->ifi_flags;
++ if (!(netdev->cache_valid & VALID_DRVINFO)) {
++ /* Most likely the debvice flags are not in sync yet, fetch them now */
++ get_flags(&netdev->up, &old_flags);
++ } else {
++ old_flags = netdev->ifi_flags;
++ }
++
+ *old_flagsp = iff_to_nd_flags(old_flags);
+ new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
+ if (new_flags != old_flags) {
diff --git a/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch b/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch
new file mode 100644
index 0000000..5cd8d70
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0002-python-separate-host-target-python-for-cross-compile.patch
@@ -0,0 +1,51 @@
+From 54484e79aca0981ebc42ddc68487e6531da9b59d Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Fri, 20 Mar 2020 15:11:31 +0800
+Subject: [PATCH] python: separate host/target python for cross-compile
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ Makefile.am | 2 +-
+ m4/openvswitch.m4 | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -60,7 +60,7 @@ endif
+ # foo/__init__.pyc will cause Python to ignore foo.py.
+ run_python = \
+ PYTHONPATH=$(top_srcdir)/python$(psep)$$PYTHONPATH \
+- PYTHONDONTWRITEBYTECODE=yes $(PYTHON3)
++ PYTHONDONTWRITEBYTECODE=yes $(PYTHON3_HOST)
+
+ ALL_LOCAL =
+ BUILT_SOURCES =
+@@ -148,7 +148,7 @@ ro_shell = printf '\043 Generated automa
+
+ SUFFIXES += .in
+ .in:
+- $(AM_V_GEN)PYTHONPATH=$$PYTHONPATH$(psep)$(srcdir)/python $(PYTHON3) $(srcdir)/build-aux/soexpand.py -I$(srcdir) < $< | \
++ $(AM_V_GEN)$(run_python) $(srcdir)/build-aux/soexpand.py -I$(srcdir) < $< | \
+ $(PYTHON3) $(srcdir)/build-aux/dpdkstrip.py $(DPDKSTRIP_FLAGS) | \
+ sed \
+ -e 's,[@]PKIDIR[@],$(PKIDIR),g' \
+@@ -415,7 +415,7 @@ CLEANFILES += flake8-check
+
+ -include manpages.mk
+ manpages.mk: $(MAN_ROOTS) build-aux/sodepends.py python/ovs_build_helpers/soutil.py
+- @PYTHONPATH=$$PYTHONPATH$(psep)$(srcdir)/python $(PYTHON3) $(srcdir)/build-aux/sodepends.py -I. -I$(srcdir) $(MAN_ROOTS) >$(@F).tmp
++ @$(run_python) $(srcdir)/build-aux/sodepends.py -I. -I$(srcdir) $(MAN_ROOTS) >$(@F).tmp
+ @if cmp -s $(@F).tmp $@; then \
+ touch $@; \
+ rm -f $(@F).tmp; \
+--- a/m4/openvswitch.m4
++++ b/m4/openvswitch.m4
+@@ -400,6 +400,8 @@ else:
+ AC_MSG_ERROR([Python 3.4 or later is required but not found in $PATH, please install it or set $PYTHON3 to point to it])
+ fi
+ AC_ARG_VAR([PYTHON3])
++ PYTHON3_HOST=$ovs_cv_python3_host
++ AM_MISSING_PROG([PYTHON3_HOST], [python3])
+ PYTHON3=$ovs_cv_python3])
+
+ dnl Checks for flake8.
diff --git a/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch b/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch
new file mode 100644
index 0000000..373c6a6
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0003-ovs-lib-fix-install_dir.patch
@@ -0,0 +1,26 @@
+From 444991b95ed25d58c3cd1646fa823620380b6ce6 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Wed, 14 Mar 2018 16:44:13 +0800
+Subject: [PATCH] ovs-lib: fix install_dir()
+
+The command "install" is not available in OpenWrt by default
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ utilities/ovs-lib.in | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/utilities/ovs-lib.in
++++ b/utilities/ovs-lib.in
+@@ -159,7 +159,10 @@ install_dir () {
+ [ "${OVS_USER##*:}" != "" ] && INSTALL_GROUP="${OVS_USER##*:}"
+
+ if test ! -d "$DIR"; then
+- install -d -m "$INSTALL_MODE" -o "$INSTALL_USER" -g "$INSTALL_GROUP" "$DIR"
++ mkdir -p "$DIR"
++ chmod "$INSTALL_MODE" "$DIR"
++ chown "$INSTALL_USER" "$DIR"
++ chgrp "$INSTALL_GROUP" "$DIR"
+ restorecon "$DIR" >/dev/null 2>&1
+ fi
+ }
diff --git a/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch b/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch
new file mode 100644
index 0000000..3e0eca5
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0004-build-trim-build.patch
@@ -0,0 +1,25 @@
+From 31514742de07d595ac23c2b0abf0e092f8b26140 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <zhouyousong@yunionyun.com>
+Date: Tue, 21 Aug 2018 13:02:21 +0000
+Subject: [PATCH] build: trim build
+
+Signed-off-by: Yousong Zhou <zhouyousong@yunionyun.com>
+---
+ Makefile.am | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -477,12 +477,10 @@ dist-docs:
+ VERSION=$(VERSION) MAKE='$(MAKE)' $(srcdir)/build-aux/dist-docs $(srcdir) $(docs)
+ .PHONY: dist-docs
+
+-include Documentation/automake.mk
+ include m4/automake.mk
+ include lib/automake.mk
+ include ofproto/automake.mk
+ include utilities/automake.mk
+-include tests/automake.mk
+ include include/automake.mk
+ include third-party/automake.mk
+ include debian/automake.mk
diff --git a/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch b/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch
new file mode 100644
index 0000000..3993c60
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0006-datapath-allow-passing-additional-OVS_KERNEL_MAKE_FL.patch
@@ -0,0 +1,23 @@
+From 1df5a0eaf78e93e21d21f1438afbe5fa8a37ea61 Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Tue, 26 May 2020 22:45:53 +0800
+Subject: [PATCH] datapath: allow passing additional $(OVS_KERNEL_MAKE_FLAGS)
+
+This can be useful for passing args like -iremap for reproducible builds
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ datapath/linux/Makefile.main.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/datapath/linux/Makefile.main.in
++++ b/datapath/linux/Makefile.main.in
+@@ -68,7 +68,7 @@ ifeq (,$(wildcard $(CONFIG_FILE)))
+ endif
+
+ default:
+- $(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules
++ $(MAKE) -C $(KSRC) $(OVS_KERNEL_MAKE_FLAGS) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules
+
+ modules_install:
+ $(MAKE) -C $(KSRC) $(if @KARCH@,ARCH=@KARCH@) M=$(builddir) modules_install
diff --git a/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch b/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch
new file mode 100644
index 0000000..3da8dc1
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0007-build-only-link-libopenvswitch-with-libunwind-libunb.patch
@@ -0,0 +1,54 @@
+From e81ccb671014db62bf622cd8f960d7930d27d9dc Mon Sep 17 00:00:00 2001
+From: Yousong Zhou <yszhou4tech@gmail.com>
+Date: Wed, 29 Jul 2020 17:29:14 +0800
+Subject: [PATCH] build: only link libopenvswitch with libunwind, libunbound
+
+Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
+---
+ lib/automake.mk | 2 ++
+ lib/libopenvswitch.pc.in | 2 +-
+ m4/openvswitch.m4 | 6 ++++--
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/lib/automake.mk
++++ b/lib/automake.mk
+@@ -10,6 +10,8 @@ lib_LTLIBRARIES += lib/libopenvswitch.la
+ lib_libopenvswitch_la_LIBADD = $(SSL_LIBS)
+ lib_libopenvswitch_la_LIBADD += $(CAPNG_LDADD)
+ lib_libopenvswitch_la_LIBADD += $(LIBBPF_LDADD)
++lib_libopenvswitch_la_LIBADD += $(LIBUNBOUND_LDADD)
++lib_libopenvswitch_la_LIBADD += $(LIBUNWIND_LDADD)
+
+
+ if WIN32
+--- a/lib/libopenvswitch.pc.in
++++ b/lib/libopenvswitch.pc.in
+@@ -7,5 +7,5 @@ Name: libopenvswitch
+ Description: Open vSwitch library
+ Version: @VERSION@
+ Libs: -L${libdir} -lopenvswitch
+-Libs.private: @LIBS@ @SSL_LIBS@ @CAPNG_LDADD@ @LIBBPF_LDADD@
++Libs.private: @LIBS@ @SSL_LIBS@ @CAPNG_LDADD@ @LIBBPF_LDADD@ @LIBUNBOUND_LDADD@ @LIBUNWIND_LDADD@
+ Cflags: -I${includedir}
+--- a/m4/openvswitch.m4
++++ b/m4/openvswitch.m4
+@@ -677,7 +677,8 @@ AC_DEFUN([OVS_CHECK_UNBOUND],
+ [AC_CHECK_LIB(unbound, ub_ctx_create, [HAVE_UNBOUND=yes], [HAVE_UNBOUND=no])
+ if test "$HAVE_UNBOUND" = yes; then
+ AC_DEFINE([HAVE_UNBOUND], [1], [Define to 1 if unbound is detected.])
+- LIBS="$LIBS -lunbound"
++ LIBUNBOUND_LDADD="-lunbound"
++ AC_SUBST(LIBUNBOUND_LDADD)
+ fi
+ AM_CONDITIONAL([HAVE_UNBOUND], [test "$HAVE_UNBOUND" = yes])
+ AC_SUBST([HAVE_UNBOUND])])
+@@ -689,7 +690,8 @@ AC_DEFUN([OVS_CHECK_UNWIND],
+ [HAVE_UNWIND=no])
+ if test "$HAVE_UNWIND" = yes; then
+ AC_DEFINE([HAVE_UNWIND], [1], [Define to 1 if unwind is detected.])
+- LIBS="$LIBS -lunwind"
++ LIBUNWIND_LDADD="-lunwind"
++ AC_SUBST(LIBUNWIND_LDADD)
+ fi
+ AM_CONDITIONAL([HAVE_UNWIND], [test "$HAVE_UNWIND" = yes])
+ AC_SUBST([HAVE_UNWIND])])
diff --git a/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch b/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch
new file mode 100644
index 0000000..c39141f
--- /dev/null
+++ b/external/subpack/net/openvswitch/patches/0008-backport-d94cd0d-ovsdb-idl-Support-write-only-change.patch
@@ -0,0 +1,318 @@
+From d94cd0d3eec33e4290d7ca81918f5ac61444886e Mon Sep 17 00:00:00 2001
+From: Dumitru Ceara <dceara@redhat.com>
+Date: Tue, 26 Apr 2022 12:37:08 +0200
+Subject: [PATCH] ovsdb-idl: Support write-only-changed IDL monitor mode.
+
+At a first glance, change tracking should never be allowed for
+write-only columns. However, some clients (e.g., ovn-northd) that are
+mostly exclusive writers of a database, use change tracking to avoid
+duplicating the IDL row records into a local cache when implementing
+incremental processing.
+
+The default behavior of the IDL is to automatically turn a write-only
+column into a read-write column whenever the client enables change
+tracking for that column.
+
+For the afore mentioned clients, this becomes a performance issue.
+Commit 1cc618c32524 ("ovsdb-idl: Fix atomicity of writes that don't
+change a column's value.") explains why writes that don't change a
+column's value cannot be optimized out early if the column is
+read/write.
+
+Furthermore, if there is at least one record in any table that
+changed during a transaction, then *all* records that have been
+written are added to the transaction, even if their values didn't
+change. If there are many such rows (e.g., like in ovn-northd's
+case) this incurs a significant overhead because:
+a. the client has to build this large transaction
+b. the transaction has to be sent over the network
+c. the server needs to parse this (mostly) no-op update
+
+We now introduce new IDL APIs allowing users to set a new monitoring
+mode flag, OVSDB_IDL_WRITE_CHANGED_ONLY, to indicate to the IDL that the
+atomicity constraints may be relaxed and written columns that don't
+change value can be skipped from the current transaction.
+
+We benchmarked ovn-northd performance when using this new mode
+against NB and SB databases taken from ovn-kubernetes scale tests.
+We noticed that when a minor change is performed to the Northbound
+database (e.g., NB_Global.nb_cfg is incremented) the time it takes to
+build the Southbound transaction becomes negligible (vs ~1.5 seconds
+before this change).
+
+End-to-end ovn-kubernetes scale tests on 120-node clusters also show
+significant reduction of latency to bring up pods; both average and P99
+latency decreased by ~30%.
+
+Acked-by: Han Zhou <hzhou@ovn.org>
+Signed-off-by: Dumitru Ceara <dceara@redhat.com>
+Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+---
+ lib/ovsdb-idl.c | 60 +++++++++++++++++++++++++++++++++++++++++-----
+ lib/ovsdb-idl.h | 16 +++++++++++--
+ tests/ovsdb-idl.at | 31 +++++++++++++++++++++++-
+ tests/test-ovsdb.c | 18 ++++++++++----
+ 5 files changed, 115 insertions(+), 14 deletions(-)
+
+--- a/lib/ovsdb-idl.c
++++ b/lib/ovsdb-idl.c
+@@ -1398,6 +1398,45 @@ ovsdb_idl_track_clear(struct ovsdb_idl *
+ {
+ ovsdb_idl_track_clear__(idl, false);
+ }
++
++/* Sets or clears (depending on 'enable') OVSDB_IDL_WRITE_CHANGED_ONLY
++ * for 'column' in 'idl', ensuring that the column will be included in a
++ * transaction only if its value has actually changed locally. Normally
++ * read/write columns that are written to are always included in the
++ * transaction but, in specific cases, when the application doesn't
++ * require atomicity of writes across different columns, the ones that
++ * don't change value may be skipped.
++ *
++ * This function should be called between ovsdb_idl_create() and
++ * the first call to ovsdb_idl_run().
++ */
++void
++ovsdb_idl_set_write_changed_only(struct ovsdb_idl *idl,
++ const struct ovsdb_idl_column *column,
++ bool enable)
++{
++ if (enable) {
++ *ovsdb_idl_get_mode(idl, column) |= OVSDB_IDL_WRITE_CHANGED_ONLY;
++ } else {
++ *ovsdb_idl_get_mode(idl, column) &= ~OVSDB_IDL_WRITE_CHANGED_ONLY;
++ }
++}
++
++/* Helper function to wrap calling ovsdb_idl_set_write_changed_only() for
++ * all columns that are part of 'idl'.
++ */
++void
++ovsdb_idl_set_write_changed_only_all(struct ovsdb_idl *idl, bool enable)
++{
++ for (size_t i = 0; i < idl->class_->n_tables; i++) {
++ const struct ovsdb_idl_table_class *tc = &idl->class_->tables[i];
++
++ for (size_t j = 0; j < tc->n_columns; j++) {
++ const struct ovsdb_idl_column *column = &tc->columns[j];
++ ovsdb_idl_set_write_changed_only(idl, column, enable);
++ }
++ }
++}
+
+ static void
+ log_parse_update_error(struct ovsdb_error *error)
+@@ -3502,6 +3541,8 @@ ovsdb_idl_txn_write__(const struct ovsdb
+ {
+ struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
+ const struct ovsdb_idl_table_class *class;
++ unsigned char column_mode;
++ bool optimize_rewritten;
+ size_t column_idx;
+ bool write_only;
+
+@@ -3512,12 +3553,15 @@ ovsdb_idl_txn_write__(const struct ovsdb
+
+ class = row->table->class_;
+ column_idx = column - class->columns;
+- write_only = row->table->modes[column_idx] == OVSDB_IDL_MONITOR;
++ column_mode = row->table->modes[column_idx];
++ write_only = column_mode == OVSDB_IDL_MONITOR;
++ optimize_rewritten =
++ write_only || (column_mode & OVSDB_IDL_WRITE_CHANGED_ONLY);
++
+
+ ovs_assert(row->new_datum != NULL);
+ ovs_assert(column_idx < class->n_columns);
+- ovs_assert(row->old_datum == NULL ||
+- row->table->modes[column_idx] & OVSDB_IDL_MONITOR);
++ ovs_assert(row->old_datum == NULL || column_mode & OVSDB_IDL_MONITOR);
+
+ if (row->table->idl->verify_write_only && !write_only) {
+ VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
+@@ -3535,9 +3579,13 @@ ovsdb_idl_txn_write__(const struct ovsdb
+ * different value in that column since we read it. (But if a whole
+ * transaction only does writes of existing values, without making any real
+ * changes, we will drop the whole transaction later in
+- * ovsdb_idl_txn_commit().) */
+- if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
+- datum, &column->type)) {
++ * ovsdb_idl_txn_commit().)
++ *
++ * The application may choose to bypass this restriction and always
++ * optimize by setting OVSDB_IDL_WRITE_CHANGED_ONLY.
++ */
++ if (optimize_rewritten && ovsdb_datum_equals(ovsdb_idl_read(row, column),
++ datum, &column->type)) {
+ goto discard_datum;
+ }
+
+--- a/lib/ovsdb-idl.h
++++ b/lib/ovsdb-idl.h
+@@ -158,7 +158,7 @@ bool ovsdb_idl_server_has_column(const s
+ * IDL will change the value returned by ovsdb_idl_get_seqno() when the
+ * column's value changes in any row.
+ *
+- * The possible mode combinations are:
++ * Typical mode combinations are:
+ *
+ * - 0, for a column that a client doesn't care about. This is the default
+ * for every column in every table, if the client passes false for
+@@ -181,10 +181,17 @@ bool ovsdb_idl_server_has_column(const s
+ * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_TRACK), for a column
+ * that a client wants to track using the change tracking
+ * ovsdb_idl_track_get_*() functions.
++ *
++ * - (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT | OVSDB_IDL_WRITE_CHANGED_ONLY)
++ * is similar to (OVSDB_IDL_MONITOR | OVSDB_IDL_ALERT) except that it
++ * only adds a written column to a transaction if the column's value
++ * has actually changed.
+ */
+ #define OVSDB_IDL_MONITOR (1 << 0) /* Replicate this column? */
+ #define OVSDB_IDL_ALERT (1 << 1) /* Alert client when column changes? */
+-#define OVSDB_IDL_TRACK (1 << 2)
++#define OVSDB_IDL_TRACK (1 << 2) /* Track column changes? */
++#define OVSDB_IDL_WRITE_CHANGED_ONLY \
++ (1 << 3) /* Write back only changed columns? */
+
+ void ovsdb_idl_add_column(struct ovsdb_idl *, const struct ovsdb_idl_column *);
+ void ovsdb_idl_add_table(struct ovsdb_idl *,
+@@ -233,6 +240,11 @@ bool ovsdb_idl_track_is_updated(const st
+ const struct ovsdb_idl_column *column);
+ void ovsdb_idl_track_clear(struct ovsdb_idl *);
+
++void ovsdb_idl_set_write_changed_only(struct ovsdb_idl *idl,
++ const struct ovsdb_idl_column *column,
++ bool enable);
++void ovsdb_idl_set_write_changed_only_all(struct ovsdb_idl *idl, bool enable);
++
+
+ /* Reading the database replica. */
+
+--- a/tests/ovsdb-idl.at
++++ b/tests/ovsdb-idl.at
+@@ -94,6 +94,20 @@ m4_define([OVSDB_CHECK_IDL_C],
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
++# same as OVSDB_CHECK_IDL but uses OVSDB_IDL_WRITE_CHANGED_ONLY.
++m4_define([OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C],
++ [AT_SETUP([$1 - write-changed-only - C])
++ AT_KEYWORDS([ovsdb server idl positive $5])
++ AT_CHECK([ovsdb_start_idltest])
++ m4_if([$2], [], [],
++ [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
++ AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $3],
++ [0], [stdout], [ignore])
++ AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
++ [0], [$4])
++ OVSDB_SERVER_SHUTDOWN
++ AT_CLEANUP])
++
+ # same as OVSDB_CHECK_IDL but uses tcp.
+ m4_define([OVSDB_CHECK_IDL_TCP_C],
+ [AT_SETUP([$1 - C - tcp])
+@@ -264,6 +278,7 @@ m4_define([OVSDB_CHECK_IDL_SSL_PY],
+
+ m4_define([OVSDB_CHECK_IDL],
+ [OVSDB_CHECK_IDL_C($@)
++ OVSDB_CHECK_IDL_WRITE_CHANGED_ONLY_C($@)
+ OVSDB_CHECK_IDL_TCP_C($@)
+ OVSDB_CHECK_IDL_TCP6_C($@)
+ OVSDB_CHECK_IDL_PY($@)
+@@ -1202,8 +1217,22 @@ m4_define([OVSDB_CHECK_IDL_TRACK_C],
+ OVSDB_SERVER_SHUTDOWN
+ AT_CLEANUP])
+
++m4_define([OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C],
++ [AT_SETUP([$1 - write-changed-only - C])
++ AT_KEYWORDS([ovsdb server idl tracking positive $5])
++ AT_CHECK([ovsdb_start_idltest])
++ m4_if([$2], [], [],
++ [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
++ AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c -w idl unix:socket $3],
++ [0], [stdout], [ignore])
++ AT_CHECK([sort stdout | uuidfilt]m4_if([$6],,, [[| $6]]),
++ [0], [$4])
++ OVSDB_SERVER_SHUTDOWN
++ AT_CLEANUP])
++
+ m4_define([OVSDB_CHECK_IDL_TRACK],
+- [OVSDB_CHECK_IDL_TRACK_C($@)])
++ [OVSDB_CHECK_IDL_TRACK_C($@)
++ OVSDB_CHECK_IDL_TRACK_WRITE_CHANGED_ONLY_C($@)])
+
+ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated],
+ [['["idltest",
+--- a/tests/test-ovsdb.c
++++ b/tests/test-ovsdb.c
+@@ -56,6 +56,7 @@
+ VLOG_DEFINE_THIS_MODULE(test_ovsdb);
+
+ struct test_ovsdb_pvt_context {
++ bool write_changed_only;
+ bool track;
+ };
+
+@@ -91,6 +92,7 @@ parse_options(int argc, char *argv[], st
+ {"timeout", required_argument, NULL, 't'},
+ {"verbose", optional_argument, NULL, 'v'},
+ {"change-track", optional_argument, NULL, 'c'},
++ {"write-changed-only", optional_argument, NULL, 'w'},
+ {"magic", required_argument, NULL, OPT_MAGIC},
+ {"no-rename-open-files", no_argument, NULL, OPT_NO_RENAME_OPEN_FILES},
+ {"help", no_argument, NULL, 'h'},
+@@ -125,6 +127,10 @@ parse_options(int argc, char *argv[], st
+ pvt->track = true;
+ break;
+
++ case 'w':
++ pvt->write_changed_only = true;
++ break;
++
+ case OPT_MAGIC:
+ magic = optarg;
+ break;
+@@ -2681,6 +2687,7 @@ update_conditions(struct ovsdb_idl *idl,
+ static void
+ do_idl(struct ovs_cmdl_context *ctx)
+ {
++ struct test_ovsdb_pvt_context *pvt = ctx->pvt;
+ struct jsonrpc *rpc;
+ struct ovsdb_idl *idl;
+ unsigned int next_cond_seqno = 0;
+@@ -2690,9 +2697,6 @@ do_idl(struct ovs_cmdl_context *ctx)
+ int step = 0;
+ int error;
+ int i;
+- bool track;
+-
+- track = ((struct test_ovsdb_pvt_context *)(ctx->pvt))->track;
+
+ idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, true, true);
+ ovsdb_idl_set_leader_only(idl, false);
+@@ -2709,10 +2713,14 @@ do_idl(struct ovs_cmdl_context *ctx)
+ rpc = NULL;
+ }
+
+- if (track) {
++ if (pvt->track) {
+ ovsdb_idl_track_add_all(idl);
+ }
+
++ if (pvt->write_changed_only) {
++ ovsdb_idl_set_write_changed_only_all(idl, true);
++ }
++
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ symtab = ovsdb_symbol_table_create();
+@@ -2770,7 +2778,7 @@ do_idl(struct ovs_cmdl_context *ctx)
+ }
+
+ /* Print update. */
+- if (track) {
++ if (pvt->track) {
+ print_idl_track(idl, step++, terse);
+ ovsdb_idl_track_clear(idl);
+ } else {