diff --git a/SOURCES/openvswitch-2.15.0.patch b/SOURCES/openvswitch-2.15.0.patch index b67f9aa..44c997c 100644 --- a/SOURCES/openvswitch-2.15.0.patch +++ b/SOURCES/openvswitch-2.15.0.patch @@ -19110,6 +19110,47 @@ index c20bcc0b33..9c83f1913a 100644 atomic_count_dec(&ipf->nfrag); ipf_list->last_sent_idx++; } +diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c +index 8c5126ffcb..df0396815a 100644 +--- a/lib/jsonrpc.c ++++ b/lib/jsonrpc.c +@@ -1261,6 +1261,24 @@ jsonrpc_session_force_reconnect(struct jsonrpc_session *s) + reconnect_force_reconnect(s->reconnect, time_msec()); + } + ++/* Resets the reconnect backoff for 's' by allowing as many free tries as the ++ * number of configured remotes. This is to be used by upper layers before ++ * calling jsonrpc_session_force_reconnect() if backoff is undesirable. ++ */ ++void ++jsonrpc_session_reset_backoff(struct jsonrpc_session *s) ++{ ++ unsigned int free_tries = s->remotes.n; ++ ++ if (jsonrpc_session_is_connected(s)) { ++ /* The extra free try will be consumed when the current remote ++ * is disconnected. ++ */ ++ free_tries++; ++ } ++ reconnect_set_backoff_free_tries(s->reconnect, free_tries); ++} ++ + /* Sets 'max_backoff' as the maximum time, in milliseconds, to wait after a + * connection attempt fails before attempting to connect again. */ + void +diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h +index d75d66b863..ba096dd0c8 100644 +--- a/lib/jsonrpc.h ++++ b/lib/jsonrpc.h +@@ -136,6 +136,7 @@ void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *, + + void jsonrpc_session_enable_reconnect(struct jsonrpc_session *); + void jsonrpc_session_force_reconnect(struct jsonrpc_session *); ++void jsonrpc_session_reset_backoff(struct jsonrpc_session *); + + void jsonrpc_session_set_max_backoff(struct jsonrpc_session *, + int max_backoff); diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 6be23dbeed..0ab511b60d 100644 --- a/lib/netdev-linux.c @@ -19686,10 +19727,27 @@ index a2778de4bc..3894cb3c33 100644 Open vSwitch 2.6 introduced nat. Linux 4.6 was the earliest upstream kernel that implemented ct support for diff --git a/lib/ovsdb-cs.c b/lib/ovsdb-cs.c -index ff8adaefb5..911b71dd4f 100644 +index ff8adaefb5..7c78056956 100644 --- a/lib/ovsdb-cs.c +++ b/lib/ovsdb-cs.c -@@ -903,8 +903,27 @@ ovsdb_cs_db_set_condition(struct ovsdb_cs_db *db, const char *table, +@@ -712,6 +712,16 @@ void + ovsdb_cs_force_reconnect(struct ovsdb_cs *cs) + { + if (cs->session) { ++ if (cs->state == CS_S_MONITORING) { ++ /* The ovsdb-cs was in MONITORING state, so we either had data ++ * inconsistency on this server, or it stopped being the cluster ++ * leader, or the user requested to re-connect. Avoiding backoff ++ * in these cases, as we need to re-connect as soon as possible. ++ * Connections that are not in MONITORING state should have their ++ * backoff to avoid constant flood of re-connection attempts in ++ * case there is no suitable database server. */ ++ jsonrpc_session_reset_backoff(cs->session); ++ } + jsonrpc_session_force_reconnect(cs->session); + } + } +@@ -903,8 +913,27 @@ ovsdb_cs_db_set_condition(struct ovsdb_cs_db *db, const char *table, } /* Conditions will be up to date when we receive replies for already @@ -19719,7 +19777,7 @@ index ff8adaefb5..911b71dd4f 100644 } /* Sets the replication condition for 'tc' in 'cs' to 'condition' and arranges -@@ -1367,7 +1386,7 @@ ovsdb_cs_send_transaction(struct ovsdb_cs *cs, struct json *operations) +@@ -1367,7 +1396,7 @@ ovsdb_cs_send_transaction(struct ovsdb_cs *cs, struct json *operations) sizeof *cs->txns); } cs->txns[cs->n_txns++] = request_id; @@ -19728,7 +19786,7 @@ index ff8adaefb5..911b71dd4f 100644 } /* Makes 'cs' drop its record of transaction 'request_id'. If a reply arrives -@@ -1380,6 +1399,7 @@ ovsdb_cs_forget_transaction(struct ovsdb_cs *cs, const struct json *request_id) +@@ -1380,6 +1409,7 @@ ovsdb_cs_forget_transaction(struct ovsdb_cs *cs, const struct json *request_id) { for (size_t i = 0; i < cs->n_txns; i++) { if (json_equal(request_id, cs->txns[i])) { @@ -20707,7 +20765,7 @@ index 8aec6bbac1..ba55566926 100644 from collections import Sequence, MutableSequence from functools import wraps diff --git a/python/ovs/db/idl.py b/python/ovs/db/idl.py -index 5850ac7abf..4cf79cf94e 100644 +index 5850ac7abf..6cb5bef10b 100644 --- a/python/ovs/db/idl.py +++ b/python/ovs/db/idl.py @@ -12,6 +12,7 @@ @@ -20729,7 +20787,15 @@ index 5850ac7abf..4cf79cf94e 100644 class Idl(object): """Open vSwitch Database Interface Definition Language (OVSDB IDL). -@@ -241,6 +246,7 @@ class Idl(object): +@@ -96,6 +101,7 @@ class Idl(object): + IDL_S_SERVER_MONITOR_REQUESTED = 2 + IDL_S_DATA_MONITOR_REQUESTED = 3 + IDL_S_DATA_MONITOR_COND_REQUESTED = 4 ++ IDL_S_MONITORING = 5 + + def __init__(self, remote, schema_helper, probe_interval=None, + leader_only=True): +@@ -241,6 +247,7 @@ class Idl(object): i = 0 while i < 50: i += 1 @@ -20737,7 +20803,7 @@ index 5850ac7abf..4cf79cf94e 100644 if not self._session.is_connected(): break -@@ -269,7 +275,7 @@ class Idl(object): +@@ -269,7 +276,7 @@ class Idl(object): if msg.params[0] == str(self.server_monitor_uuid): self.__parse_update(msg.params[1], OVSDB_UPDATE, tables=self.server_tables) @@ -20746,7 +20812,15 @@ index 5850ac7abf..4cf79cf94e 100644 if not self.__check_server_db(): self.force_reconnect() break -@@ -312,7 +318,7 @@ class Idl(object): +@@ -288,6 +295,7 @@ class Idl(object): + else: + assert self.state == self.IDL_S_DATA_MONITOR_REQUESTED + self.__parse_update(msg.result, OVSDB_UPDATE) ++ self.state = self.IDL_S_MONITORING + + except error.Error as e: + vlog.err("%s: parse error in received schema: %s" +@@ -312,7 +320,7 @@ class Idl(object): self.__error() break else: @@ -20755,7 +20829,7 @@ index 5850ac7abf..4cf79cf94e 100644 self.__send_monitor_request() elif (msg.type == ovs.jsonrpc.Message.T_REPLY and self._server_monitor_request_id is not None -@@ -322,7 +328,7 @@ class Idl(object): +@@ -322,7 +330,7 @@ class Idl(object): self._server_monitor_request_id = None self.__parse_update(msg.result, OVSDB_UPDATE, tables=self.server_tables) @@ -20764,7 +20838,7 @@ index 5850ac7abf..4cf79cf94e 100644 if self.__check_server_db(): self.__send_monitor_request() self.__send_db_change_aware() -@@ -336,7 +342,7 @@ class Idl(object): +@@ -336,7 +344,7 @@ class Idl(object): self.__error() break else: @@ -20773,7 +20847,7 @@ index 5850ac7abf..4cf79cf94e 100644 self.__send_monitor_request() elif (msg.type == ovs.jsonrpc.Message.T_REPLY and self._db_change_aware_request_id is not None -@@ -372,7 +378,7 @@ class Idl(object): +@@ -372,7 +380,7 @@ class Idl(object): self.force_reconnect() break else: @@ -20782,7 +20856,23 @@ index 5850ac7abf..4cf79cf94e 100644 self.__send_monitor_request() elif (msg.type in (ovs.jsonrpc.Message.T_ERROR, ovs.jsonrpc.Message.T_REPLY) -@@ -614,6 +620,7 @@ class Idl(object): +@@ -435,6 +443,15 @@ class Idl(object): + def force_reconnect(self): + """Forces the IDL to drop its connection to the database and reconnect. + In the meantime, the contents of the IDL will not change.""" ++ if self.state == self.IDL_S_MONITORING: ++ # The IDL was in MONITORING state, so we either had data ++ # inconsistency on this server, or it stopped being the cluster ++ # leader, or the user requested to re-connect. Avoiding backoff ++ # in these cases, as we need to re-connect as soon as possible. ++ # Connections that are not in MONITORING state should have their ++ # backoff to avoid constant flood of re-connection attempts in ++ # case there is no suitable database server. ++ self._session.reset_backoff() + self._session.force_reconnect() + + def session_name(self): +@@ -614,6 +631,7 @@ class Idl(object): raise error.Error(" is not an object", table_updates) @@ -20790,7 +20880,7 @@ index 5850ac7abf..4cf79cf94e 100644 for table_name, table_update in table_updates.items(): table = tables.get(table_name) if not table: -@@ -639,7 +646,9 @@ class Idl(object): +@@ -639,7 +657,9 @@ class Idl(object): % (table_name, uuid_string)) if version == OVSDB_UPDATE2: @@ -20801,7 +20891,7 @@ index 5850ac7abf..4cf79cf94e 100644 self.change_seqno += 1 continue -@@ -652,17 +661,20 @@ class Idl(object): +@@ -652,17 +672,20 @@ class Idl(object): raise error.Error(' missing "old" and ' '"new" members', row_update) @@ -20826,7 +20916,7 @@ index 5850ac7abf..4cf79cf94e 100644 else: # XXX rate-limit vlog.warn("cannot delete missing row %s from table" -@@ -681,29 +693,27 @@ class Idl(object): +@@ -681,29 +704,27 @@ class Idl(object): changed = self.__row_update(table, row, row_update) table.rows[uuid] = row if changed: @@ -20861,7 +20951,7 @@ index 5850ac7abf..4cf79cf94e 100644 else: # XXX rate-limit vlog.warn("cannot delete missing row %s from table %s" -@@ -723,7 +733,7 @@ class Idl(object): +@@ -723,7 +744,7 @@ class Idl(object): if op == ROW_CREATE: table.rows[uuid] = row if changed: @@ -20870,7 +20960,7 @@ index 5850ac7abf..4cf79cf94e 100644 else: op = ROW_UPDATE if not row: -@@ -737,8 +747,8 @@ class Idl(object): +@@ -737,8 +758,8 @@ class Idl(object): if op == ROW_CREATE: table.rows[uuid] = row if changed: @@ -20881,6 +20971,29 @@ index 5850ac7abf..4cf79cf94e 100644 def __check_server_db(self): """Returns True if this is a valid server database, False otherwise.""" +diff --git a/python/ovs/jsonrpc.py b/python/ovs/jsonrpc.py +index bf32f8c87c..d5127268aa 100644 +--- a/python/ovs/jsonrpc.py ++++ b/python/ovs/jsonrpc.py +@@ -612,5 +612,18 @@ class Session(object): + def force_reconnect(self): + self.reconnect.force_reconnect(ovs.timeval.msec()) + ++ def reset_backoff(self): ++ """ Resets the reconnect backoff by allowing as many free tries as the ++ number of configured remotes. This is to be used by upper layers ++ before calling force_reconnect() if backoff is undesirable.""" ++ free_tries = len(self.remotes) ++ ++ if self.is_connected(): ++ # The extra free try will be consumed when the current remote ++ # is disconnected. ++ free_tries += 1 ++ ++ self.reconnect.set_backoff_free_tries(free_tries) ++ + def get_num_of_remotes(self): + return len(self.remotes) diff --git a/python/ovstest/rpcserver.py b/python/ovstest/rpcserver.py index c4aab70207..05b6b1be20 100644 --- a/python/ovstest/rpcserver.py @@ -21521,7 +21634,7 @@ index 92aa427093..cf43e9cf86 100644 # Start collecting raft_is_connected logs for $target before shutting down # any servers. diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at -index 4b4791a7da..62181dd4de 100644 +index 4b4791a7da..d5cdf7e8b0 100644 --- a/tests/ovsdb-idl.at +++ b/tests/ovsdb-idl.at @@ -141,7 +141,7 @@ m4_define([OVSDB_CHECK_IDL_REGISTER_COLUMNS_PY], @@ -22631,7 +22744,78 @@ index 4b4791a7da..62181dd4de 100644 005: After delete 007: check simple4: empty 008: End test -@@ -1989,11 +2274,11 @@ OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect], +@@ -1942,11 +2227,29 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], + OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote']) + OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL reconnects to leader], 3, ['remote' '+remotestop' 'remote']) + +-# same as OVSDB_CHECK_IDL but uses C IDL implementation with tcp +-# with multiple remotes. ++# OVSDB_CHECK_CLUSTER_IDL_C(TITLE, N_SERVERS, [PRE-IDL-TXN], TRANSACTIONS, ++# OUTPUT, [KEYWORDS], [FILTER], [LOG_FILTER]) ++# ++# Creates a clustered database with a schema derived from idltest.ovsidl, runs ++# each PRE-IDL-TXN (if any), starts N_SERVERS ovsdb-server instances in RAFT, ++# on that database, and runs "test-ovsdb idl" passing each of the TRANSACTIONS ++# along. ++# ++# Checks that the overall output is OUTPUT. Before comparison, the ++# output is sorted (using "sort") and UUIDs in the output are replaced ++# by markers of the form where N is a number. The first unique ++# UUID is replaced by <0>, the next by <1>, and so on. If a given ++# UUID appears more than once it is always replaced by the same ++# marker. If FILTER is supplied then the output is also filtered ++# through the specified program. ++# ++# TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS. ++# ++# If LOG_FILTER is provided, checks that the contents of LOG_FILTER ++# are not matched by grep in the test-ovsdb logs. + m4_define([OVSDB_CHECK_CLUSTER_IDL_C], + [AT_SETUP([$1 - C - tcp]) +- AT_KEYWORDS([ovsdb server idl positive tcp socket $5]) ++ AT_KEYWORDS([ovsdb server idl tcp $6]) + m4_define([LPBK],[127.0.0.1]) + OVSDB_CLUSTER_START_IDLTEST([$2], ["ptcp:0:"LPBK]) + PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1]) +@@ -1957,11 +2260,36 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_C], + m4_if([$3], [], [], + [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])]) + AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl tcp:LPBK:$TCP_PORT_1 $4], +- [0], [stdout], [ignore]) ++ [0], [stdout], [stderr]) ++ AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]), ++ [0], [$5]) ++ m4_ifval([$8], [AT_CHECK([grep '$8' stderr], [1])], [], []) ++ AT_CLEANUP]) ++ ++# Same as OVSDB_CHECK_CLUSTER_IDL_C but uses the Python IDL implementation. ++m4_define([OVSDB_CHECK_CLUSTER_IDL_PY], ++ [AT_SETUP([$1 - Python3 - tcp]) ++ AT_KEYWORDS([ovsdb server idl tcp $6]) ++ m4_define([LPBK],[127.0.0.1]) ++ OVSDB_CLUSTER_START_IDLTEST([$2], ["ptcp:0:"LPBK]) ++ PARSE_LISTENING_PORT([s1.log], [TCP_PORT_1]) ++ PARSE_LISTENING_PORT([s2.log], [TCP_PORT_2]) ++ PARSE_LISTENING_PORT([s3.log], [TCP_PORT_3]) ++ remotes=tcp:LPBK:$TCP_PORT_1,tcp:LPBK:$TCP_PORT_2,tcp:LPBK:$TCP_PORT_3 ++ ++ m4_if([$3], [], [], ++ [AT_CHECK([ovsdb-client transact $remotes $3], [0], [ignore], [ignore])]) ++ AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py -t10 idl $srcdir/idltest.ovsschema tcp:LPBK:$TCP_PORT_1 $4], ++ [0], [stdout], [stderr]) + AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]), + [0], [$5]) ++ m4_if([$8], [AT_CHECK([grep '$8' stderr], [1])], [], []) + AT_CLEANUP]) + ++m4_define([OVSDB_CHECK_CLUSTER_IDL], ++ [OVSDB_CHECK_CLUSTER_IDL_C($@) ++ OVSDB_CHECK_CLUSTER_IDL_PY($@)]) ++ + # Checks that monitor_cond_since works fine when disconnects happen + # with cond_change requests in flight (i.e., IDL is properly updated). + OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect], +@@ -1989,11 +2317,34 @@ OVSDB_CHECK_CLUSTER_IDL_C([simple idl, monitor_cond_since, cluster disconnect], [[000: change conditions 001: empty 002: change conditions @@ -22646,6 +22830,29 @@ index 4b4791a7da..62181dd4de 100644 +008: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<2> 009: done ]]) ++ ++dnl This test checks that forceful reconnects triggered by the IDL ++dnl happen immediately (they should not use backoff). ++OVSDB_CHECK_CLUSTER_IDL([simple idl, initially empty, force reconnect], ++ 3, ++ [], ++ [['+reconnect' \ ++ 'reconnect' \ ++ 'reconnect' \ ++ 'reconnect']], ++ [[000: reconnect ++001: empty ++002: reconnect ++003: empty ++004: reconnect ++005: empty ++006: reconnect ++007: empty ++008: done ++]], ++[], ++[], ++reconnect.*waiting .* seconds before reconnect) diff --git a/tests/system-kmod-macros.at b/tests/system-kmod-macros.at index 15628a7c6f..86d633ac4f 100644 --- a/tests/system-kmod-macros.at diff --git a/SPECS/openvswitch2.15.spec b/SPECS/openvswitch2.15.spec index 03aeac2..6a365f4 100644 --- a/SPECS/openvswitch2.15.spec +++ b/SPECS/openvswitch2.15.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.15.0 -Release: 28%{?dist} +Release: 29%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -697,6 +697,12 @@ exit 0 %endif %changelog +* Fri Jul 23 2021 Open vSwitch CI - 2.15.0-29 +- Merging upstream branch-2.15 [RH gerrit: 60c8b2a15b] + Commit list: + 8aa0f03747 ovsdb-cs: Perform forced reconnects without a backoff. + + * Wed Jul 21 2021 Open vSwitch CI - 2.15.0-28 - Merging upstream branch-2.15 [RH gerrit: 48a90081e8] Commit list: