From f144fb760f877435c38efb8b81e00a112563f6be Mon Sep 17 00:00:00 2001 From: Open vSwitch CI Date: Mar 31 2022 03:16:32 +0000 Subject: Import openvswitch2.13-2.13.0-171 from Fast DataPath --- diff --git a/SOURCES/openvswitch-2.13.0.patch b/SOURCES/openvswitch-2.13.0.patch index 5746669..c68b0a9 100644 --- a/SOURCES/openvswitch-2.13.0.patch +++ b/SOURCES/openvswitch-2.13.0.patch @@ -785,6 +785,19 @@ index dbf88ec43f..7acdaac06b 100644 Reporting Bugs -------------- +diff --git a/Documentation/intro/install/general.rst b/Documentation/intro/install/general.rst +index 09f2c13f16..6312f5879c 100644 +--- a/Documentation/intro/install/general.rst ++++ b/Documentation/intro/install/general.rst +@@ -167,7 +167,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/phy.rst b/Documentation/topics/dpdk/phy.rst index 38e52c8deb..55a98e2b0e 100644 --- a/Documentation/topics/dpdk/phy.rst @@ -1535,7 +1548,7 @@ index e06ddf2671..8e64d74aee 100644 :target: https://ci.appveyor.com/project/blp/ovs/history .. image:: https://api.cirrus-ci.com/github/openvswitch/ovs.svg diff --git a/acinclude.m4 b/acinclude.m4 -index c1470ccc6b..6401471494 100644 +index c1470ccc6b..106689493f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -192,10 +192,10 @@ dnl Configure Linux tc compat. @@ -1645,6 +1658,15 @@ index c1470ccc6b..6401471494 100644 OVS_FIND_PARAM_IFELSE([$KSRC/include/net/protocol.h], [udp_add_offload], [net], [OVS_DEFINE([HAVE_UDP_ADD_OFFLOAD_TAKES_NET])]) +@@ -1284,7 +1319,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], @@ -1294,11 +1329,11 @@ AC_DEFUN([OVS_ENABLE_SPARSE], dnl OVS_CTAGS_IDENTIFIERS @@ -80868,6 +80890,211 @@ index 5289a70f6e..cf009f8264 100644 #define OVS_LOCKABLE __attribute__((lockable)) #define OVS_REQ_RDLOCK(...) __attribute__((shared_locks_required(__VA_ARGS__))) #define OVS_ACQ_RDLOCK(...) __attribute__((shared_lock_function(__VA_ARGS__))) +diff --git a/include/openvswitch/hmap.h b/include/openvswitch/hmap.h +index 8aea9c22db..68c284cf14 100644 +--- a/include/openvswitch/hmap.h ++++ b/include/openvswitch/hmap.h +@@ -134,15 +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); \ +- 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); \ +- 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); +@@ -168,50 +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); \ +- 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) \ +- ? 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); \ +- 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);) ++#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/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 1f81d830e7..4b9893388b 100644 --- a/include/openvswitch/meta-flow.h @@ -80936,6 +81163,161 @@ index 0000000000..a49563f071 +#endif + +#endif /* usdt-probes.h */ +diff --git a/include/openvswitch/util.h b/include/openvswitch/util.h +index 9189e6480b..9a924719bf 100644 +--- a/include/openvswitch/util.h ++++ b/include/openvswitch/util.h +@@ -143,6 +143,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 37e3703245..41ef886194 100755 --- a/ipsec/ovs-monitor-ipsec.in @@ -81621,6 +82003,53 @@ index d1bd4aa12a..f646a8f742 100644 }; enum { +diff --git a/lib/cmap.h b/lib/cmap.h +index d9db3c915c..8655f76d92 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/conntrack-icmp.c b/lib/conntrack-icmp.c index 63246f0124..63ddd8038b 100644 --- a/lib/conntrack-icmp.c @@ -82980,6 +83409,75 @@ index 45bb96b543..f3f0358b36 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 446e89d13c..009f5d1e9b 100644 --- a/lib/ipf.c @@ -85419,6 +85917,22 @@ index ab8e08b84d..8f8c9041ac 100644

Open vSwitch 2.6 introduced nat. Linux 4.6 was the earliest upstream kernel that implemented ct support for +diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h +index 8f2ea34308..8d141b41e3 100644 +--- a/lib/ovs-numa.h ++++ b/lib/ovs-numa.h +@@ -66,9 +66,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/ovs-rcu.c b/lib/ovs-rcu.c index ebc8120f0f..cde1e925ba 100644 --- a/lib/ovs-rcu.c @@ -86373,6 +86887,98 @@ index b990ed9d59..0d3290dc37 100644 cursor.vector = impl->vector; cursor.entry_idx = -1; +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 c89abab889..a929ddfd2d 100644 --- a/lib/reconnect.c @@ -87587,6 +88193,19 @@ index add3aabcc2..391d6d8f7c 100644 dnl Checks for MSVC x64 compiler. AC_DEFUN([OVS_CHECK_WIN64], [AC_CACHE_CHECK( +diff --git a/ofproto/bond.c b/ofproto/bond.c +index 405202fb64..54e06211a6 100644 +--- a/ofproto/bond.c ++++ b/ofproto/bond.c +@@ -1165,7 +1165,7 @@ insert_bal(struct ovs_list *bals, struct bond_slave *slave) + break; + } + } +- ovs_list_insert(&pos->bal_node, &slave->bal_node); ++ ovs_list_insert(pos ? &pos->bal_node : bals, &slave->bal_node); + } + + /* Removes 'slave' from its current list and then inserts it into 'bals' so diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index 51d656cba9..fd926cbb82 100644 --- a/ofproto/connmgr.c @@ -94068,6 +94687,34 @@ index 6d53d016de..2d98fad485 100644 } assert(n_rules <= cls->n_rules); } +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-conntrack.c b/tests/test-conntrack.c index f77ee75e38..da1ac63b6c 100644 --- a/tests/test-conntrack.c @@ -94090,6 +94737,79 @@ index f77ee75e38..da1ac63b6c 100644 } ovs_barrier_block(&barrier); destroy_packets(pkt_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-jsonrpc.py b/tests/test-jsonrpc.py index 3eabcd78d5..1df5afa221 100644 --- a/tests/test-jsonrpc.py @@ -94115,6 +94835,52 @@ index d7854a1df3..32a77392c6 100755 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. +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 b1a4be36bb..c4845956ca 100644 --- a/tests/test-ovsdb.c diff --git a/SPECS/openvswitch2.13.spec b/SPECS/openvswitch2.13.spec index 121e9b8..1e52cae 100644 --- a/SPECS/openvswitch2.13.spec +++ b/SPECS/openvswitch2.13.spec @@ -59,7 +59,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.13.0 -Release: 170%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} +Release: 171%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -715,6 +715,22 @@ exit 0 %endif %changelog +* Wed Mar 30 2022 Open vSwitch CI - 2.13.0-171 +- Merging upstream branch-2.13 [RH git: 7763266297] + Commit list: + 3894437f6c sparse: bump recommended version and include headers. + c7f0d6113a rculist: use multi-variable helpers for loop macros. + 019895b832 hindex: use multi-variable iterators. + 9f176f7025 cmap: use multi-variable iterators. + e3e1e2045c hmap: implement UB-safe hmap pop iterator. + 6aa8de0291 hmap: use multi-variable helpers for hmap loops. + 72a9f2d75f hmap: Fix Coverity false positive + f7083afb85 list: use multi-variable helpers for list loops. + 57c44fa35e util: add helpers to overload SAFE macro. + 69acaa187b util: add safe multi-variable iterators. + 2c56295e27 util: add multi-variable loop iterator macros. + + * Wed Mar 30 2022 Open vSwitch CI - 2.13.0-170 - Merging upstream branch-2.13 [RH git: 7ec8e5d0e5] Commit list: