diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch
index dc7a56d..2691b90 100644
--- a/SOURCES/openvswitch-2.16.0.patch
+++ b/SOURCES/openvswitch-2.16.0.patch
@@ -148,6 +148,19 @@ index d8fa931fab..9ce5285c58 100644
  
  .. note::
  
+diff --git a/Documentation/intro/install/general.rst b/Documentation/intro/install/general.rst
+index c4300cd53e..a297aadac8 100644
+--- a/Documentation/intro/install/general.rst
++++ b/Documentation/intro/install/general.rst
+@@ -169,7 +169,7 @@ other than plain text, only if you have the following:
+ If you are going to extensively modify Open vSwitch, consider installing the
+ following to obtain better warnings:
+ 
+-- "sparse" version 0.5.1 or later
++- "sparse" version 0.6.2 or later
+   (https://git.kernel.org/pub/scm/devel/sparse/sparse.git/).
+ 
+ - GNU make.
 diff --git a/Documentation/topics/dpdk/pmd.rst b/Documentation/topics/dpdk/pmd.rst
 index 95fa7af128..c1a35eb13a 100644
 --- a/Documentation/topics/dpdk/pmd.rst
@@ -206,7 +219,7 @@ index 559a51ba3f..80720f2607 100644
  ---------------------
     - Removed support for 1024-bit Diffie-Hellman key exchange, which is now
 diff --git a/acinclude.m4 b/acinclude.m4
-index dba365ea1a..5619ab3573 100644
+index dba365ea1a..1b957c3dcd 100644
 --- a/acinclude.m4
 +++ b/acinclude.m4
 @@ -77,7 +77,7 @@ dnl Checks if compiler and binutils supports AVX512.
@@ -232,6 +245,15 @@ index dba365ea1a..5619ab3573 100644
  ])
  
  dnl OVS_CHECK_LINUX_SCTP_CT
+@@ -1417,7 +1424,7 @@ AC_DEFUN([OVS_ENABLE_SPARSE],
+    : ${SPARSE=sparse}
+    AC_SUBST([SPARSE])
+    AC_CONFIG_COMMANDS_PRE(
+-     [CC='$(if $(C:0=),env REAL_CC="'"$CC"'" CHECK="$(SPARSE) $(SPARSE_WERROR) -I $(top_srcdir)/include/sparse $(SPARSEFLAGS) $(SPARSE_EXTRA_INCLUDES) " cgcc $(CGCCFLAGS),'"$CC"')'])
++     [CC='$(if $(C:0=),env REAL_CC="'"$CC"'" CHECK="$(SPARSE) $(SPARSE_WERROR) -I $(top_srcdir)/include/sparse -I $(top_srcdir)/include $(SPARSEFLAGS) $(SPARSE_EXTRA_INCLUDES) " cgcc $(CGCCFLAGS),'"$CC"')'])
+ 
+    AC_ARG_ENABLE(
+      [sparse],
 diff --git a/configure.ac b/configure.ac
 index 16b32be965..92817b62e1 100644
 --- a/configure.ac
@@ -739,6 +761,133 @@ index 0000000000..6fae6f727c
 +
 +#endif /* __KERNEL__ || !HAVE_TCA_STATS_PKT64 */
 +#endif /* __LINUX_GEN_STATS_WRAPPER_H */
+diff --git a/include/openvswitch/hmap.h b/include/openvswitch/hmap.h
+index 4e001cc692..68c284cf14 100644
+--- a/include/openvswitch/hmap.h
++++ b/include/openvswitch/hmap.h
+@@ -134,17 +134,17 @@ struct hmap_node *hmap_random_node(const struct hmap *);
+  * without using 'break', NODE will be NULL.  This is true for all of the
+  * HMAP_FOR_EACH_*() macros.
+  */
+-#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP)               \
+-    for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
+-         || ((NODE = NULL), false);                                     \
+-         ASSIGN_CONTAINER(NODE, hmap_next_with_hash(&(NODE)->MEMBER),   \
+-                          MEMBER))
+-#define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP)               \
+-    for (INIT_CONTAINER(NODE, hmap_first_in_bucket(HMAP, HASH), MEMBER); \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
+-         || ((NODE = NULL), false);                                     \
+-         ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER))
++#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP)                     \
++    for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_with_hash(HMAP, HASH),        \
++                       struct hmap_node);                                     \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
++         UPDATE_MULTIVAR(NODE, hmap_next_with_hash(ITER_VAR(NODE))))
++
++#define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP)                     \
++    for (INIT_MULTIVAR(NODE, MEMBER, hmap_first_in_bucket(HMAP, HASH),        \
++                       struct hmap_node);                                     \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
++         UPDATE_MULTIVAR(NODE, hmap_next_in_bucket(ITER_VAR(NODE))))
+ 
+ static inline struct hmap_node *hmap_first_with_hash(const struct hmap *,
+                                                      size_t hash);
+@@ -170,54 +170,62 @@ bool hmap_contains(const struct hmap *, const struct hmap_node *);
+ /* Iterates through every node in HMAP. */
+ #define HMAP_FOR_EACH(NODE, MEMBER, HMAP) \
+     HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, (void) 0)
+-#define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...)                     \
+-    for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__;   \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
+-         || ((NODE = NULL), false);                                     \
+-         ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
++#define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...)                           \
++    for (INIT_MULTIVAR_EXP(NODE, MEMBER, hmap_first(HMAP), struct hmap_node,  \
++                           __VA_ARGS__);                                      \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
++         UPDATE_MULTIVAR(NODE, hmap_next(HMAP, ITER_VAR(NODE))))
+ 
+ /* Safe when NODE may be freed (not needed when NODE may be removed from the
+  * hash map but its members remain accessible and intact). */
+ #define HMAP_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HMAP) \
+-    HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, (void) 0)
+-#define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...)          \
+-    for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__;   \
+-         ((NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))               \
+-          || ((NODE = NULL), false)                                     \
+-          ? INIT_CONTAINER(NEXT, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), 1 \
+-          : 0);                                                         \
+-         (NODE) = (NEXT))
++    HMAP_FOR_EACH_SAFE_INIT (NODE, NEXT, MEMBER, HMAP, (void) NEXT)
++
++#define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...)                \
++    for (INIT_MULTIVAR_SAFE_LONG_EXP(NODE, NEXT, MEMBER, hmap_first(HMAP),    \
++                                      struct hmap_node, __VA_ARGS__);         \
++         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                     \
++                                      ITER_VAR(NODE) != NULL,                 \
++                            ITER_VAR(NEXT) = hmap_next(HMAP, ITER_VAR(NODE)), \
++                                      ITER_VAR(NEXT) != NULL);                \
++         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
+ 
+ /* Continues an iteration from just after NODE. */
+ #define HMAP_FOR_EACH_CONTINUE(NODE, MEMBER, HMAP) \
+     HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, (void) 0)
+-#define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...)            \
+-    for (ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), \
+-         __VA_ARGS__;                                                   \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                \
+-         || ((NODE = NULL), false);                                     \
+-         ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
++#define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...)                  \
++    for (INIT_MULTIVAR_EXP(NODE, MEMBER, hmap_next(HMAP, &(NODE)->MEMBER),    \
++                           struct hmap_node, __VA_ARGS__);                    \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
++         UPDATE_MULTIVAR(NODE, hmap_next(HMAP, ITER_VAR(NODE))))
++
++struct hmap_pop_helper_iter__ {
++    size_t bucket;
++    struct hmap_node *node;
++};
+ 
+-static inline struct hmap_node *
+-hmap_pop_helper__(struct hmap *hmap, size_t *bucket) {
++static inline void
++hmap_pop_helper__(struct hmap *hmap, struct hmap_pop_helper_iter__ *iter) {
+ 
+-    for (; *bucket <= hmap->mask; (*bucket)++) {
+-        struct hmap_node *node = hmap->buckets[*bucket];
++    for (; iter->bucket <= hmap->mask; (iter->bucket)++) {
++        struct hmap_node *node = hmap->buckets[iter->bucket];
+ 
+         if (node) {
+             hmap_remove(hmap, node);
+-            return node;
++            iter->node = node;
++            return;
+         }
+     }
+-
+-    return NULL;
++    iter->node = NULL;
+ }
+ 
+-#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP)                               \
+-    for (size_t bucket__ = 0;                                               \
+-         INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER),  \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER))                    \
+-         || ((NODE = NULL), false);)
++#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP)                                 \
++    for (struct hmap_pop_helper_iter__ ITER_VAR(NODE) = { 0, NULL };          \
++         hmap_pop_helper__(HMAP, &ITER_VAR(NODE)),                            \
++         (ITER_VAR(NODE).node != NULL) ?                                      \
++            (((NODE) = OBJECT_CONTAINING(ITER_VAR(NODE).node,                 \
++                                         NODE, MEMBER)),1):                   \
++            (((NODE) = NULL), 0);)
+ 
+ static inline struct hmap_node *hmap_first(const struct hmap *);
+ static inline struct hmap_node *hmap_next(const struct hmap *,
 diff --git a/include/openvswitch/json.h b/include/openvswitch/json.h
 index 73b562e03d..0831a9cee1 100644
 --- a/include/openvswitch/json.h
@@ -787,6 +936,90 @@ index 73b562e03d..0831a9cee1 100644
  struct json *json_from_file(const char *file_name);
  struct json *json_from_stream(FILE *stream);
  
+diff --git a/include/openvswitch/list.h b/include/openvswitch/list.h
+index 8ad5eeb327..bbd2edbd0c 100644
+--- a/include/openvswitch/list.h
++++ b/include/openvswitch/list.h
+@@ -72,37 +72,48 @@ static inline bool ovs_list_is_empty(const struct ovs_list *);
+ static inline bool ovs_list_is_singleton(const struct ovs_list *);
+ static inline bool ovs_list_is_short(const struct ovs_list *);
+ 
+-#define LIST_FOR_EACH(ITER, MEMBER, LIST)                               \
+-    for (INIT_CONTAINER(ITER, (LIST)->next, MEMBER);                    \
+-         &(ITER)->MEMBER != (LIST);                                     \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
+-#define LIST_FOR_EACH_CONTINUE(ITER, MEMBER, LIST)                      \
+-    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER);             \
+-         &(ITER)->MEMBER != (LIST);                                     \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
+-#define LIST_FOR_EACH_REVERSE(ITER, MEMBER, LIST)                       \
+-    for (INIT_CONTAINER(ITER, (LIST)->prev, MEMBER);                    \
+-         &(ITER)->MEMBER != (LIST);                                     \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+-#define LIST_FOR_EACH_REVERSE_SAFE(ITER, PREV, MEMBER, LIST)        \
+-    for (INIT_CONTAINER(ITER, (LIST)->prev, MEMBER);                \
+-         (&(ITER)->MEMBER != (LIST)                                 \
+-          ? INIT_CONTAINER(PREV, (ITER)->MEMBER.prev, MEMBER), 1    \
+-          : 0);                                                     \
+-         (ITER) = (PREV))
+-#define LIST_FOR_EACH_REVERSE_CONTINUE(ITER, MEMBER, LIST)              \
+-    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER);           \
+-         &(ITER)->MEMBER != (LIST);                                     \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+-#define LIST_FOR_EACH_SAFE(ITER, NEXT, MEMBER, LIST)               \
+-    for (INIT_CONTAINER(ITER, (LIST)->next, MEMBER);               \
+-         (&(ITER)->MEMBER != (LIST)                                \
+-          ? INIT_CONTAINER(NEXT, (ITER)->MEMBER.next, MEMBER), 1   \
+-          : 0);                                                    \
+-         (ITER) = (NEXT))
+-#define LIST_FOR_EACH_POP(ITER, MEMBER, LIST)                      \
+-    while (!ovs_list_is_empty(LIST)                                    \
+-           && (INIT_CONTAINER(ITER, ovs_list_pop_front(LIST), MEMBER), 1))
++#define LIST_FOR_EACH(VAR, MEMBER, LIST)                                      \
++    for (INIT_MULTIVAR(VAR, MEMBER, (LIST)->next, struct ovs_list);           \
++         CONDITION_MULTIVAR(VAR, MEMBER, ITER_VAR(VAR) != (LIST));            \
++         UPDATE_MULTIVAR(VAR, ITER_VAR(VAR)->next))
++
++#define LIST_FOR_EACH_CONTINUE(VAR, MEMBER, LIST)                             \
++    for (INIT_MULTIVAR(VAR, MEMBER, VAR->MEMBER.next, struct ovs_list);       \
++         CONDITION_MULTIVAR(VAR, MEMBER, ITER_VAR(VAR) != (LIST));            \
++         UPDATE_MULTIVAR(VAR, ITER_VAR(VAR)->next))
++
++#define LIST_FOR_EACH_REVERSE(VAR, MEMBER, LIST)                              \
++    for (INIT_MULTIVAR(VAR, MEMBER, (LIST)->prev, struct ovs_list);           \
++         CONDITION_MULTIVAR(VAR, MEMBER, ITER_VAR(VAR) != (LIST));            \
++         UPDATE_MULTIVAR(VAR, ITER_VAR(VAR)->prev))
++
++#define LIST_FOR_EACH_REVERSE_CONTINUE(VAR, MEMBER, LIST)                     \
++    for (INIT_MULTIVAR(VAR, MEMBER, VAR->MEMBER.prev, struct ovs_list);       \
++         CONDITION_MULTIVAR(VAR, MEMBER, ITER_VAR(VAR) != (LIST));            \
++         UPDATE_MULTIVAR(VAR, ITER_VAR(VAR)->prev))
++
++#define LIST_FOR_EACH_REVERSE_SAFE(VAR, PREV, MEMBER, LIST)                   \
++    for (INIT_MULTIVAR_SAFE_LONG(VAR, PREV, MEMBER, (LIST)->prev,             \
++                                 struct ovs_list);                            \
++         CONDITION_MULTIVAR_SAFE_LONG(VAR, PREV, MEMBER,                      \
++                                      ITER_VAR(VAR) != (LIST),                \
++                                      ITER_VAR(PREV) = ITER_VAR(VAR)->prev,   \
++                                      ITER_VAR(PREV) != (LIST));              \
++         UPDATE_MULTIVAR_SAFE_LONG(VAR, PREV))
++
++#define LIST_FOR_EACH_SAFE(VAR, NEXT, MEMBER, LIST)                           \
++    for (INIT_MULTIVAR_SAFE_LONG(VAR, NEXT, MEMBER, (LIST)->next,             \
++                                 struct ovs_list);                            \
++         CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT, MEMBER,                      \
++                                      ITER_VAR(VAR) != (LIST),                \
++                                      ITER_VAR(NEXT) = ITER_VAR(VAR)->next,   \
++                                      ITER_VAR(NEXT) != (LIST));              \
++         UPDATE_MULTIVAR_SAFE_LONG(VAR, NEXT))
++
++#define LIST_FOR_EACH_POP(ITER, MEMBER, LIST)                                 \
++    while (!ovs_list_is_empty(LIST) ?                                         \
++           (INIT_CONTAINER(ITER, ovs_list_pop_front(LIST), MEMBER), 1) :      \
++           (ITER = NULL, 0))
+ 
+ /* Inline implementations. */
+ 
 diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h
 index 95e52e3587..045dce8f5f 100644
 --- a/include/openvswitch/meta-flow.h
@@ -799,6 +1032,161 @@ index 95e52e3587..045dce8f5f 100644
  bool mf_is_pipeline_field(const struct mf_field *);
  bool mf_is_set(const struct mf_field *, const struct flow *);
  void mf_mask_field(const struct mf_field *, struct flow_wildcards *);
+diff --git a/include/openvswitch/util.h b/include/openvswitch/util.h
+index 228b185c3a..96f600160b 100644
+--- a/include/openvswitch/util.h
++++ b/include/openvswitch/util.h
+@@ -145,6 +145,150 @@ OVS_NO_RETURN void ovs_assert_failure(const char *, const char *, const char *);
+ #define INIT_CONTAINER(OBJECT, POINTER, MEMBER) \
+     ((OBJECT) = NULL, ASSIGN_CONTAINER(OBJECT, POINTER, MEMBER))
+ 
++/* Multi-variable container iterators.
++ *
++ * The following macros facilitate safe iteration over data structures
++ * contained in objects. It does so by using an internal iterator variable of
++ * the type of the member object pointer (i.e: pointer to the data structure).
++ */
++
++/* Multi-variable iterator variable name.
++ * Returns the name of the internal iterator variable.
++ */
++#define ITER_VAR(NAME) NAME ## __iterator__
++
++/* Multi-variable initialization. Creates an internal iterator variable that
++ * points to the provided pointer. The type of the iterator variable is
++ * ITER_TYPE*. It must be the same type as &VAR->MEMBER.
++ *
++ * The _EXP version evaluates the extra expressions once.
++ */
++#define INIT_MULTIVAR(VAR, MEMBER, POINTER, ITER_TYPE)                  \
++    INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, ITER_TYPE, (void) 0)
++
++#define INIT_MULTIVAR_EXP(VAR, MEMBER, POINTER, ITER_TYPE, ...)         \
++    ITER_TYPE *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER)
++
++/* Multi-variable condition.
++ * Evaluates the condition expression (that must be based on the internal
++ * iterator variable). Only if the result of expression is true, the OBJECT is
++ * set to the object containing the current value of the iterator variable.
++ *
++ * It is up to the caller to make sure it is safe to run OBJECT_CONTAINING on
++ * the pointers that verify the condition.
++ */
++#define CONDITION_MULTIVAR(VAR, MEMBER, EXPR)                                 \
++    ((EXPR) ?                                                                 \
++     (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)), 1) :           \
++     (((VAR) = NULL), 0))
++
++/* Multi-variable update.
++ * Sets the iterator value to NEXT_ITER.
++ */
++#define UPDATE_MULTIVAR(VAR, NEXT_ITER)                                       \
++    (ITER_VAR(VAR) = NEXT_ITER)
++
++/* In the safe version of the multi-variable container iteration, the next
++ * value of the iterator is precalculated on the condition expression.
++ * This allows for the iterator to be freed inside the loop.
++ *
++ * Two versions of the macros are provided:
++ *
++ * * In the _SHORT version, the user does not have to provide a variable to
++ * store the next value of the iterator. Instead, a second iterator variable
++ * is declared in the INIT_ macro and its name is determined by
++ * ITER_NEXT_VAR(OBJECT).
++ *
++ * * In the _LONG version, the user provides another variable of the same type
++ * as the iterator object variable to store the next containing object.
++ * We still declare an iterator variable inside the loop but in this case it's
++ * name is derived from the name of the next containing variable.
++ * The value of the next containing object will only be set
++ * (via OBJECT_CONTAINING) if an additional condition is statisfied. This
++ * second condition must ensure it is safe to call OBJECT_CONTAINING on the
++ * next iterator variable.
++ * With respect to the value of the next containing object:
++ *  - Inside of the loop: the variable is either NULL or safe to use.
++ *  - Outside of the loop: the variable is NULL if the loop ends normally.
++ *     If the loop ends with a "break;" statement, rules of Inside the loop
++ *     apply.
++ */
++#define ITER_NEXT_VAR(NAME) NAME ## __iterator__next__
++
++/* Safe initialization declares both iterators. */
++#define INIT_MULTIVAR_SAFE_SHORT(VAR, MEMBER, POINTER, ITER_TYPE)             \
++    INIT_MULTIVAR_SAFE_SHORT_EXP(VAR, MEMBER, POINTER, ITER_TYPE, (void) 0)
++
++#define INIT_MULTIVAR_SAFE_SHORT_EXP(VAR, MEMBER, POINTER, ITER_TYPE, ...)    \
++    ITER_TYPE *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER),        \
++        *ITER_NEXT_VAR(VAR) = NULL
++
++/* Evaluate the condition expression and, if satisfied, update the _next_
++ * iterator with the NEXT_EXPR.
++ * Both EXPR and NEXT_EXPR should only use ITER_VAR(VAR) and
++ * ITER_NEXT_VAR(VAR).
++ */
++#define CONDITION_MULTIVAR_SAFE_SHORT(VAR, MEMBER, EXPR, NEXT_EXPR)           \
++    ((EXPR) ?                                                                 \
++     (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)),                \
++      (NEXT_EXPR), 1) :                                                       \
++     (((VAR) = NULL), 0))
++
++#define UPDATE_MULTIVAR_SAFE_SHORT(VAR)                                       \
++    UPDATE_MULTIVAR(VAR, ITER_NEXT_VAR(VAR))
++
++/* _LONG versions of the macros. */
++
++#define INIT_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR, MEMBER, POINTER, ITER_TYPE)    \
++    INIT_MULTIVAR_SAFE_LONG_EXP(VAR, NEXT_VAR, MEMBER, POINTER, ITER_TYPE,    \
++                                (void) 0)                                     \
++
++#define INIT_MULTIVAR_SAFE_LONG_EXP(VAR, NEXT_VAR, MEMBER, POINTER,           \
++                                    ITER_TYPE, ...)                           \
++    ITER_TYPE  *ITER_VAR(VAR) = ( __VA_ARGS__ , (ITER_TYPE *) POINTER),       \
++        *ITER_VAR(NEXT_VAR) = NULL
++
++/* Evaluate the condition expression and, if satisfied, update the _next_
++ * iterator with the NEXT_EXPR. After, evaluate the NEXT_COND and, if
++ * satisfied, set the value to NEXT_VAR. NEXT_COND must use ITER_VAR(NEXT_VAR).
++ *
++ * Both EXPR and NEXT_EXPR should only use ITER_VAR(VAR) and
++ * ITER_VAR(NEXT_VAR).
++ */
++#define CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR, MEMBER, EXPR, NEXT_EXPR,  \
++                                     NEXT_COND)                               \
++    ((EXPR) ?                                                                 \
++     (((VAR) = OBJECT_CONTAINING(ITER_VAR(VAR), VAR, MEMBER)),                \
++      (NEXT_EXPR), ((NEXT_COND) ?                                             \
++       ((NEXT_VAR) =                                                          \
++        OBJECT_CONTAINING(ITER_VAR(NEXT_VAR), NEXT_VAR, MEMBER)) :            \
++       ((NEXT_VAR) = NULL)), 1) :                                             \
++     (((VAR) = NULL), ((NEXT_VAR) = NULL), 0))
++
++#define UPDATE_MULTIVAR_SAFE_LONG(VAR, NEXT_VAR)                              \
++    UPDATE_MULTIVAR(VAR, ITER_VAR(NEXT_VAR))
++
++/* Helpers to allow overloading the *_SAFE iterator macros and select either
++ * the LONG or the SHORT version depending on the number of arguments.
++ */
++#define GET_SAFE_MACRO2(_1, _2, NAME, ...) NAME
++#define GET_SAFE_MACRO3(_1, _2, _3, NAME, ...) NAME
++#define GET_SAFE_MACRO4(_1, _2, _3, _4, NAME, ...) NAME
++#define GET_SAFE_MACRO5(_1, _2, _3, _4, _5, NAME, ...) NAME
++#define GET_SAFE_MACRO6(_1, _2, _3, _4, _5, _6, NAME, ...) NAME
++#define GET_SAFE_MACRO(MAX_ARGS) GET_SAFE_MACRO ## MAX_ARGS
++
++/* MSVC treats __VA_ARGS__ as a simple token in argument lists. Introduce
++ * a level of indirection to work around that. */
++#define EXPAND_MACRO(name, args) name args
++
++/* Overload the LONG and the SHORT version of the macros. MAX_ARGS is the
++ * maximum number of arguments (i.e: the number of arguments of the LONG
++ * version). */
++#define OVERLOAD_SAFE_MACRO(LONG, SHORT, MAX_ARGS, ...) \
++        EXPAND_MACRO(GET_SAFE_MACRO(MAX_ARGS), \
++                     (__VA_ARGS__, LONG, SHORT))(__VA_ARGS__)
++
+ /* Returns the number of elements in ARRAY. */
+ #define ARRAY_SIZE(ARRAY) __ARRAY_SIZE(ARRAY)
+ 
 diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in
 index 89a36fe17b..a8b0705d9f 100755
 --- a/ipsec/ovs-monitor-ipsec.in
@@ -955,6 +1343,53 @@ index 3c965699ac..9698576d07 100644
      bfd_put_details(&ds, bfd);
      VLOG(level, "%s", ds_cstr(&ds));
      ds_destroy(&ds);
+diff --git a/lib/cmap.h b/lib/cmap.h
+index c502d23112..72e2ec5f71 100644
+--- a/lib/cmap.h
++++ b/lib/cmap.h
+@@ -108,6 +108,8 @@ size_t cmap_replace(struct cmap *, struct cmap_node *old_node,
+  *
+  * CMAP and HASH are evaluated only once.  NODE is evaluated many times.
+  *
++ * After a normal exit of the loop (not through a "break;" statement) NODE is
++ * NULL.
+  *
+  * Thread-safety
+  * =============
+@@ -128,15 +130,15 @@ size_t cmap_replace(struct cmap *, struct cmap_node *old_node,
+  * CMAP_FOR_EACH_WITH_HASH_PROTECTED may only be used if CMAP is guaranteed not
+  * to change during iteration.  It may be very slightly faster.
+  */
+-#define CMAP_NODE_FOR_EACH(NODE, MEMBER, CMAP_NODE)                     \
+-    for (INIT_CONTAINER(NODE, CMAP_NODE, MEMBER);                       \
+-         (NODE) != OBJECT_CONTAINING(NULL, NODE, MEMBER);               \
+-         ASSIGN_CONTAINER(NODE, cmap_node_next(&(NODE)->MEMBER), MEMBER))
+-#define CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, CMAP_NODE)           \
+-    for (INIT_CONTAINER(NODE, CMAP_NODE, MEMBER);                       \
+-         (NODE) != OBJECT_CONTAINING(NULL, NODE, MEMBER);               \
+-         ASSIGN_CONTAINER(NODE, cmap_node_next_protected(&(NODE)->MEMBER), \
+-                          MEMBER))
++#define CMAP_NODE_FOR_EACH(NODE, MEMBER, CMAP_NODE)                        \
++    for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node);         \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);         \
++         UPDATE_MULTIVAR(NODE, cmap_node_next(ITER_VAR(NODE))))
++#define CMAP_NODE_FOR_EACH_PROTECTED(NODE, MEMBER, CMAP_NODE)              \
++    for (INIT_MULTIVAR(NODE, MEMBER, CMAP_NODE, struct cmap_node);         \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);         \
++         UPDATE_MULTIVAR(NODE, cmap_node_next_protected(ITER_VAR(NODE))))
++
+ #define CMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, CMAP)   \
+     CMAP_NODE_FOR_EACH(NODE, MEMBER, cmap_find(CMAP, HASH))
+ #define CMAP_FOR_EACH_WITH_HASH_PROTECTED(NODE, MEMBER, HASH, CMAP)     \
+@@ -223,7 +225,7 @@ unsigned long cmap_find_batch(const struct cmap *cmap, unsigned long map,
+      ? (INIT_CONTAINER(NODE, (CURSOR)->node, MEMBER),   \
+         cmap_cursor_advance(CURSOR),                    \
+         true)                                           \
+-     : false)
++     : (NODE = NULL, false))
+ 
+ #define CMAP_CURSOR_FOR_EACH(NODE, MEMBER, CURSOR, CMAP)    \
+     for (*(CURSOR) = cmap_cursor_start(CMAP);               \
 diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c
 index 77cc76a9f6..7074561588 100644
 --- a/lib/db-ctl-base.c
@@ -1751,6 +2186,75 @@ index 89837de95d..a021bc0eba 100644
              }
          } else if (OVS_LIKELY(nw_proto == IPPROTO_UDP)) {
              if (OVS_LIKELY(size >= UDP_HEADER_LEN)) {
+diff --git a/lib/hindex.h b/lib/hindex.h
+index 876c5a9e39..f7a30d511a 100644
+--- a/lib/hindex.h
++++ b/lib/hindex.h
+@@ -128,18 +128,22 @@ void hindex_remove(struct hindex *, struct hindex_node *);
+  * Evaluates HASH only once.
+  */
+ #define HINDEX_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HINDEX)               \
+-    for (INIT_CONTAINER(NODE, hindex_node_with_hash(HINDEX, HASH), MEMBER); \
+-         NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER);                     \
+-         ASSIGN_CONTAINER(NODE, (NODE)->MEMBER.s, MEMBER))
++    for (INIT_MULTIVAR(NODE, MEMBER, hindex_node_with_hash(HINDEX, HASH),   \
++                       struct hindex_node);                                 \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);          \
++         UPDATE_MULTIVAR(NODE, ITER_VAR(NODE)->s))
+ 
+ /* Safe when NODE may be freed (not needed when NODE may be removed from the
+  * hash map but its members remain accessible and intact). */
+-#define HINDEX_FOR_EACH_WITH_HASH_SAFE(NODE, NEXT, MEMBER, HASH, HINDEX) \
+-    for (INIT_CONTAINER(NODE, hindex_node_with_hash(HINDEX, HASH), MEMBER); \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)                 \
+-          ? INIT_CONTAINER(NEXT, (NODE)->MEMBER.s, MEMBER), 1           \
+-          : 0);                                                         \
+-         (NODE) = (NEXT))
++#define HINDEX_FOR_EACH_WITH_HASH_SAFE(NODE, NEXT, MEMBER, HASH, HINDEX)    \
++    for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                        \
++                                hindex_node_with_hash(HINDEX, HASH),        \
++                                struct hindex_node);                        \
++         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                   \
++                                      ITER_VAR(NODE) != NULL,               \
++                                      ITER_VAR(NEXT) = ITER_VAR(NODE)->s,   \
++                                      ITER_VAR(NEXT) != NULL);              \
++         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
+ 
+ /* Returns the head node in 'hindex' with the given 'hash', or a null pointer
+  * if no nodes have that hash value. */
+@@ -157,19 +161,22 @@ hindex_node_with_hash(const struct hindex *hindex, size_t hash)
+ /* Iteration. */
+ 
+ /* Iterates through every node in HINDEX. */
+-#define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX)                           \
+-    for (INIT_CONTAINER(NODE, hindex_first(HINDEX), MEMBER);            \
+-         NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER);                 \
+-         ASSIGN_CONTAINER(NODE, hindex_next(HINDEX, &(NODE)->MEMBER), MEMBER))
++#define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX)                                 \
++    for (INIT_MULTIVAR(NODE, MEMBER, hindex_first(HINDEX),                    \
++                       struct hindex_node);                                   \
++         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
++         UPDATE_MULTIVAR(NODE, hindex_next(HINDEX, ITER_VAR(NODE))))
+ 
+ /* Safe when NODE may be freed (not needed when NODE may be removed from the
+  * hash index but its members remain accessible and intact). */
+-#define HINDEX_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HINDEX)              \
+-    for (INIT_CONTAINER(NODE, hindex_first(HINDEX), MEMBER);          \
+-         (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)                 \
+-          ? INIT_CONTAINER(NEXT, hindex_next(HINDEX, &(NODE)->MEMBER), MEMBER), 1 \
+-          : 0);                                                         \
+-         (NODE) = (NEXT))
++#define HINDEX_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HINDEX)                      \
++    for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, hindex_first(HINDEX),    \
++                                 struct hindex_node);                         \
++         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                     \
++                                      ITER_VAR(NODE) != NULL,                 \
++                        ITER_VAR(NEXT) = hindex_next(HINDEX, ITER_VAR(NODE)), \
++                                      ITER_VAR(NEXT) != NULL);                \
++         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
+ 
+ struct hindex_node *hindex_first(const struct hindex *);
+ struct hindex_node *hindex_next(const struct hindex *,
 diff --git a/lib/ipf.c b/lib/ipf.c
 index d9f781147a..507db2aea2 100644
 --- a/lib/ipf.c
@@ -2313,6 +2817,22 @@ index 4579548ee1..9485ddfc93 100644
              break;
           }
  
+diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h
+index ecc251a7ff..83bd10cca5 100644
+--- a/lib/ovs-numa.h
++++ b/lib/ovs-numa.h
+@@ -68,9 +68,9 @@ void ovs_numa_dump_destroy(struct ovs_numa_dump *);
+ int ovs_numa_thread_setaffinity_core(unsigned core_id);
+ 
+ #define FOR_EACH_CORE_ON_DUMP(ITER, DUMP)                    \
+-    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->cores)
++    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->cores)
+ 
+ #define FOR_EACH_NUMA_ON_DUMP(ITER, DUMP)                    \
+-    HMAP_FOR_EACH((ITER), hmap_node, &(DUMP)->numas)
++    HMAP_FOR_EACH (ITER, hmap_node, &(DUMP)->numas)
+ 
+ #endif /* ovs-numa.h */
 diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c
 index 659d49dbf7..dead31275d 100644
 --- a/lib/ovsdb-cs.c
@@ -3121,6 +3641,98 @@ index b30a11c24b..41835f6f4d 100644
          return NULL;
      }
  
+diff --git a/lib/rculist.h b/lib/rculist.h
+index 1072b87af2..c0d77acf94 100644
+--- a/lib/rculist.h
++++ b/lib/rculist.h
+@@ -365,35 +365,57 @@ rculist_is_singleton_protected(const struct rculist *list)
+     return list_next == list->prev && list_next != list;
+ }
+ 
+-#define RCULIST_FOR_EACH(ITER, MEMBER, RCULIST)                         \
+-    for (INIT_CONTAINER(ITER, rculist_next(RCULIST), MEMBER);           \
+-         &(ITER)->MEMBER != (RCULIST);                                  \
+-         ASSIGN_CONTAINER(ITER, rculist_next(&(ITER)->MEMBER), MEMBER))
+-#define RCULIST_FOR_EACH_CONTINUE(ITER, MEMBER, RCULIST)                \
+-    for (ASSIGN_CONTAINER(ITER, rculist_next(&(ITER)->MEMBER), MEMBER); \
+-         &(ITER)->MEMBER != (RCULIST);                                  \
+-         ASSIGN_CONTAINER(ITER, rculist_next(&(ITER)->MEMBER), MEMBER))
+-
+-#define RCULIST_FOR_EACH_REVERSE_PROTECTED(ITER, MEMBER, RCULIST)       \
+-    for (INIT_CONTAINER(ITER, (RCULIST)->prev, MEMBER);                 \
+-         &(ITER)->MEMBER != (RCULIST);                                  \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+-#define RCULIST_FOR_EACH_REVERSE_PROTECTED_CONTINUE(ITER, MEMBER, RCULIST) \
+-    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER);           \
+-         &(ITER)->MEMBER != (RCULIST);                                  \
+-         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+-
+-#define RCULIST_FOR_EACH_PROTECTED(ITER, MEMBER, RCULIST)               \
+-    for (INIT_CONTAINER(ITER, rculist_next_protected(RCULIST), MEMBER); \
+-         &(ITER)->MEMBER != (RCULIST);                                  \
+-         ASSIGN_CONTAINER(ITER, rculist_next_protected(&(ITER)->MEMBER), \
+-                          MEMBER))
+-
+-#define RCULIST_FOR_EACH_SAFE_PROTECTED(ITER, NEXT, MEMBER, RCULIST)    \
+-    for (INIT_CONTAINER(ITER, rculist_next_protected(RCULIST), MEMBER); \
+-         (&(ITER)->MEMBER != (RCULIST)                                  \
+-          ? INIT_CONTAINER(NEXT, rculist_next_protected(&(ITER)->MEMBER), \
+-                           MEMBER), 1 : 0);                             \
+-         (ITER) = (NEXT))
++#define RCULIST_FOR_EACH(ITER, MEMBER, RCULIST)                               \
++    for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(RCULIST),                   \
++                       const struct rculist);                                 \
++         CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST));       \
++         UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER))))
++
++#define RCULIST_FOR_EACH_CONTINUE(ITER, MEMBER, RCULIST)                      \
++    for (INIT_MULTIVAR(ITER, MEMBER, rculist_next(&(ITER)->MEMBER),           \
++                       const struct rculist);                                 \
++         CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST));       \
++         UPDATE_MULTIVAR(ITER, rculist_next(ITER_VAR(ITER))))
++
++#define RCULIST_FOR_EACH_REVERSE_PROTECTED(ITER, MEMBER, RCULIST)             \
++    for (INIT_MULTIVAR(ITER, MEMBER, (RCULIST)->prev, struct rculist);        \
++         CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST));       \
++         UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev))
++
++#define RCULIST_FOR_EACH_REVERSE_PROTECTED_CONTINUE(ITER, MEMBER, RCULIST)    \
++    for (INIT_MULTIVAR(ITER, MEMBER, (ITER)->MEMBER.prev, struct rculist);    \
++         CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST));       \
++         UPDATE_MULTIVAR(ITER, ITER_VAR(VAR).prev))
++
++#define RCULIST_FOR_EACH_PROTECTED(ITER, MEMBER, RCULIST)                     \
++    for (INIT_MULTIVAR(ITER, MEMBER, rculist_next_protected(RCULIST),         \
++                       struct rculist);                                       \
++         CONDITION_MULTIVAR(ITER, MEMBER, ITER_VAR(ITER) != (RCULIST));       \
++         UPDATE_MULTIVAR(ITER, rculist_next_protected(ITER_VAR(ITER)))        \
++
++#define RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED(ITER, MEMBER, RCULIST)          \
++    for (INIT_MULTIVAR_SAFE_SHORT(ITER, MEMBER,                               \
++                                  rculist_next_protected(RCULIST),            \
++                                  struct rculist);                            \
++         CONDITION_MULTIVAR_SAFE_SHORT(ITER, MEMBER,                          \
++                                       ITER_VAR(ITER) != (RCULIST),           \
++             ITER_NEXT_VAR(ITER) = rculist_next_protected(ITER_VAR(VAR)));    \
++        UPDATE_MULTIVAR_SHORT(ITER))
++
++#define RCULIST_FOR_EACH_SAFE_LONG_PROTECTED(ITER, NEXT, MEMBER, RCULIST)     \
++    for (INIT_MULTIVAR_SAFE_LONG(ITER, NEXT, MEMBER,                          \
++                                 rculist_next_protected(RCULIST)              \
++                                 struct rculist);                             \
++         CONDITION_MULTIVAR_SAFE_LONG(VAR, NEXT, MEMBER                       \
++                                      ITER_VAR(ITER) != (RCULIST),            \
++             ITER_VAR(NEXT) = rculist_next_protected(ITER_VAR(VAR)),          \
++                                      ITER_VAR(NEXT) != (RCULIST));           \
++        UPDATE_MULTIVAR_LONG(ITER))
++
++#define RCULIST_FOR_EACH_SAFE_PROTECTED(...)                                  \
++    OVERLOAD_SAFE_MACRO(RCULIST_FOR_EACH_SAFE_LONG_PROTECTED,                 \
++                        RCULIST_FOR_EACH_SAFE_SHORT_PROTECTED,                \
++                        4, __VA_ARGS__)
++
+ 
+ #endif /* rculist.h */
 diff --git a/lib/reconnect.c b/lib/reconnect.c
 index a929ddfd2d..89a0bcaf95 100644
 --- a/lib/reconnect.c
@@ -4112,6 +4724,19 @@ index e4b42b0594..877bca3127 100644
  int tnl_neigh_lookup(const char dev_name[IFNAMSIZ], const struct in6_addr *dst,
                       struct eth_addr *mac);
  void tnl_neigh_cache_init(void);
+diff --git a/ofproto/bond.c b/ofproto/bond.c
+index a4116588f4..2c0ad5ef84 100644
+--- a/ofproto/bond.c
++++ b/ofproto/bond.c
+@@ -1253,7 +1253,7 @@ insert_bal(struct ovs_list *bals, struct bond_member *member)
+             break;
+         }
+     }
+-    ovs_list_insert(&pos->bal_node, &member->bal_node);
++    ovs_list_insert(pos ? &pos->bal_node : bals, &member->bal_node);
+ }
+ 
+ /* Removes 'member' from its current list and then inserts it into 'bals' so
 diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
 index 864c136b5d..0f4a61ac6b 100644
 --- a/ofproto/ofproto-dpif-sflow.c
@@ -8688,6 +9313,107 @@ index 406334f3e0..1a80047619 100644
  )
 +
 +m4_define([CHECK_SYSTEM_TSO], [])
+diff --git a/tests/test-cmap.c b/tests/test-cmap.c
+index 0705475606..f8cc4dd80a 100644
+--- a/tests/test-cmap.c
++++ b/tests/test-cmap.c
+@@ -74,6 +74,7 @@ check_cmap(struct cmap *cmap, const int values[], size_t n,
+         cmap_values[i++] = e->value;
+     }
+     assert(i == n);
++    assert(e == NULL);
+ 
+     /* Here we test iteration with cmap_next_position() */
+     i = 0;
+@@ -107,6 +108,7 @@ check_cmap(struct cmap *cmap, const int values[], size_t n,
+             count += e->value == values[i];
+         }
+         assert(count == 1);
++        assert(e == NULL);
+     }
+ 
+     /* Check that all the values are there in batched lookup. */
+@@ -130,6 +132,7 @@ check_cmap(struct cmap *cmap, const int values[], size_t n,
+             CMAP_NODE_FOR_EACH (e, node, nodes[k]) {
+                 count += e->value == values[i + k];
+             }
++            assert(e == NULL);
+         }
+         assert(count == j); /* j elements in a batch. */
+     }
+diff --git a/tests/test-hindex.c b/tests/test-hindex.c
+index af06be5fcc..95e49284ee 100644
+--- a/tests/test-hindex.c
++++ b/tests/test-hindex.c
+@@ -265,6 +265,11 @@ test_hindex_for_each_safe(hash_func *hash)
+             i = 0;
+             n_remaining = n;
+             HINDEX_FOR_EACH_SAFE (e, next, node, &hindex) {
++                if (hindex_next(&hindex, &e->node) == NULL) {
++                    assert(next == NULL);
++                } else {
++                    assert(&next->node == hindex_next(&hindex, &e->node));
++                }
+                 assert(i < n);
+                 if (pattern & (1ul << e->value)) {
+                     size_t j;
+@@ -281,6 +286,7 @@ test_hindex_for_each_safe(hash_func *hash)
+                 i++;
+             }
+             assert(i == n);
++            assert(next == NULL);
+ 
+             for (i = 0; i < n; i++) {
+                 if (pattern & (1ul << i)) {
+diff --git a/tests/test-hmap.c b/tests/test-hmap.c
+index 9259b0b3fc..47b4755386 100644
+--- a/tests/test-hmap.c
++++ b/tests/test-hmap.c
+@@ -62,6 +62,7 @@ check_hmap(struct hmap *hmap, const int values[], size_t n,
+         hmap_values[i++] = e->value;
+     }
+     assert(i == n);
++    assert(e == NULL);
+ 
+     memcpy(sort_values, values, sizeof *sort_values * n);
+     qsort(sort_values, n, sizeof *sort_values, compare_ints);
+@@ -82,6 +83,7 @@ check_hmap(struct hmap *hmap, const int values[], size_t n,
+             count += e->value == values[i];
+         }
+         assert(count == 1);
++        assert(e == NULL);
+     }
+ 
+     /* Check counters. */
+@@ -243,6 +245,11 @@ test_hmap_for_each_safe(hash_func *hash)
+             i = 0;
+             n_remaining = n;
+             HMAP_FOR_EACH_SAFE (e, next, node, &hmap) {
++                if (hmap_next(&hmap, &e->node) == NULL) {
++                    assert(next == NULL);
++                } else {
++                    assert(&next->node == hmap_next(&hmap, &e->node));
++                }
+                 assert(i < n);
+                 if (pattern & (1ul << e->value)) {
+                     size_t j;
+@@ -259,6 +266,8 @@ test_hmap_for_each_safe(hash_func *hash)
+                 i++;
+             }
+             assert(i == n);
++            assert(next == NULL);
++            assert(e == NULL);
+ 
+             for (i = 0; i < n; i++) {
+                 if (pattern & (1ul << i)) {
+@@ -308,6 +317,7 @@ test_hmap_for_each_pop(hash_func *hash)
+             i++;
+         }
+         assert(i == n);
++        assert(e == NULL);
+ 
+         hmap_destroy(&hmap);
+     }
 diff --git a/tests/test-json.c b/tests/test-json.c
 index a7ee595e0b..072a537252 100644
 --- a/tests/test-json.c
@@ -8771,6 +9497,52 @@ index a7ee595e0b..072a537252 100644
 +}
 +
 +OVSTEST_REGISTER("json-string-benchmark", json_string_benchmark_main);
+diff --git a/tests/test-list.c b/tests/test-list.c
+index 6f1fb059bc..648e02a5e2 100644
+--- a/tests/test-list.c
++++ b/tests/test-list.c
+@@ -61,7 +61,7 @@ check_list(struct ovs_list *list, const int values[], size_t n)
+         assert(e->value == values[i]);
+         i++;
+     }
+-    assert(&e->node == list);
++    assert(e == NULL);
+     assert(i == n);
+ 
+     i = 0;
+@@ -70,7 +70,7 @@ check_list(struct ovs_list *list, const int values[], size_t n)
+         assert(e->value == values[n - i - 1]);
+         i++;
+     }
+-    assert(&e->node == list);
++    assert(e == NULL);
+     assert(i == n);
+ 
+     assert(ovs_list_is_empty(list) == !n);
+@@ -135,6 +135,13 @@ test_list_for_each_safe(void)
+             values_idx = 0;
+             n_remaining = n;
+             LIST_FOR_EACH_SAFE (e, next, node, &list) {
++                /* "next" is valid as long as it's not pointing to &list. */
++                if (&e->node == list.prev) {
++                    assert(next == NULL);
++                } else {
++                    assert(&next->node == e->node.next);
++                }
++
+                 assert(i < n);
+                 if (pattern & (1ul << i)) {
+                     ovs_list_remove(&e->node);
+@@ -148,7 +155,8 @@ test_list_for_each_safe(void)
+                 i++;
+             }
+             assert(i == n);
+-            assert(&e->node == &list);
++            assert(e == NULL);
++            assert(next == NULL);
+ 
+             for (i = 0; i < n; i++) {
+                 if (pattern & (1ul << i)) {
 diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
 index daa55dab7b..57572cd3ed 100644
 --- a/tests/test-ovsdb.c
diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec
index efba37d..7c886c3 100644
--- a/SPECS/openvswitch2.16.spec
+++ b/SPECS/openvswitch2.16.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.16.0
-Release: 64%{?dist}
+Release: 65%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -699,6 +699,21 @@ exit 0
 %endif
 
 %changelog
+* Wed Mar 30 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-65
+- Merging upstream branch-2.16 [RH git: b4c45acc47]
+    Commit list:
+    7644c924e8 sparse: bump recommended version and include headers.
+    20b87feba9 rculist: use multi-variable helpers for loop macros.
+    05a440fafb hindex: use multi-variable iterators.
+    04dca15004 cmap: use multi-variable iterators.
+    80e64f712d hmap: implement UB-safe hmap pop iterator.
+    3b4b0af690 hmap: use multi-variable helpers for hmap loops.
+    05e899ea8f list: use multi-variable helpers for list loops.
+    d2406399ae util: add helpers to overload SAFE macro.
+    f22f9d947a util: add safe multi-variable iterators.
+    72c3e8627c util: add multi-variable loop iterator macros.
+
+
 * Wed Mar 30 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-64
 - Merging upstream branch-2.16 [RH git: 32008eb008]
     Commit list: