A python counterpart of the following commit:

  0b29edb5cbdc ("dns-resolve: Do not treat never accessed responses as 
expired.")

The same issue exists in the python code where we may never connect
to a remote server if our DNS TTL is lower than the backoff interval.

Fix it in the same way as we did in C implementation - allow using
the entry if it was never used after requesting for up to 5 minutes,
as this is not really caching, but a "transaction in progress" type
of situation.

More details in the commit message for the C version.

Signed-off-by: Ilya Maximets <[email protected]>
---
 python/ovs/dns_resolve.py | 29 ++++++++++++++++++++++++-----
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/python/ovs/dns_resolve.py b/python/ovs/dns_resolve.py
index 41546ad5c..d38e8a658 100644
--- a/python/ovs/dns_resolve.py
+++ b/python/ovs/dns_resolve.py
@@ -29,12 +29,15 @@ import ovs.vlog
 
 vlog = ovs.vlog.Vlog("dns_resolve")
 
+RESOLVE_UNUSED_TIMEOUT = 300  # Seconds.
+
 
 class ReqState(enum.Enum):
     INVALID = 0
     PENDING = 1
-    GOOD = 2
-    ERROR = 3
+    GOOD_UNUSED = 2
+    GOOD = 4
+    ERROR = 5
 
 
 class DNSRequest:
@@ -48,11 +51,27 @@ class DNSRequest:
 
     @property
     def expired(self):
-        return time.time() > self.time + self.ttl
+        ttl = self.ttl
+        # When we just sent a request, but didn't look at the response yet,
+        # it's not caching, but a "transaction in progress" situation, so we
+        # can use the response even with TTL of 0 and more than 1 second
+        # passed.  Allow such values to be accessed for at least
+        # RESOLVE_UNUSED_TIMEOUT seconds without considering them stale.
+        # This is necessary in case of large backoff intervals on connections
+        # or if the process is doing some other work not looking at the
+        # response for longer than TTL. */
+        if self.state == ReqState.GOOD_UNUSED:
+            ttl = max(ttl, RESOLVE_UNUSED_TIMEOUT)
+            # Not a "transaction in progress" anymore, normal caching rules
+            # should apply from this point forward.
+            self.state = ReqState.GOOD
+
+        return time.time() > self.time + ttl
 
     @property
     def is_valid(self):
-        return self.state == ReqState.GOOD and not self.expired
+        return (self.state in [ReqState.GOOD_UNUSED, ReqState.GOOD]
+                and not self.expired)
 
     def __str__(self):
         return (f"DNSRequest(name={self.name}, state={self.state}, "
@@ -184,7 +203,7 @@ class DNSResolver:
             # _callback causes a segfault. So just grab and store what we need.
             req.result = str(ip)
             req.ttl = result.ttl
-            req.state = ReqState.GOOD
+            req.state = ReqState.GOOD_UNUSED
             req.time = time.time()
         except (ValueError, StopIteration):
             req.state = ReqState.ERROR
-- 
2.52.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to