[Openvpn-devel] [S] Change in openvpn[master]: oob: Measure probe RTT for candidate-band selection

"stipa \(Code Review\) via Openvpn-devel" <[email protected]> Wed, 29 Jul 2026 12:22:54 +0000
Newsgroups net.sourceforge.lists.openvpn-devel
Message-ID <125f554c078a9afb9e42997ee1e050258b25f25d-EmailReplacePatchSet-HTML@gerrit.openvpn.net>
--===============6969258336492862994==
Content-Transfer-Encoding: 8bit
Content-Disposition: inline
Content-Type: multipart/alternative; boundary="R46sRr4DW4w="; charset=UTF-8

--R46sRr4DW4w=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Attention is currently required from: plaisthos=2E

Hello plaisthos, 

I'd =
like you to reexamine a change=2E Please visit

    http://gerrit=2Eopenvpn=
=2Enet/c/openvpn/+/1748?usp=3Demail

to look at the new patch set (#14)=2E
=


Change subject: oob: Measure probe RTT for candidate-band selection
=2E=
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=
=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E=2E

oob: Measure pro=
be RTT for candidate-band selection

Record each probe's round-trip time (p=
er-target send timestamp vs reply
arrival) and feed it to oob_rank_probe_re=
sults(), where RTT forms the
candidate band: responders within the effectiv=
e margin of the fastest compete
on weight, slower ones fall behind=2E Log t=
he measured RTT and the effective
margin (with its source: client / server-=
advertised / default) at verb 4=2E

Before this the client never measured R=
TT, so every responder sat in the band
and selection was purely weighted-ra=
ndom; with real measurements the
latency-based candidate selection takes ef=
fect=2E

Change-Id: I375a41749060b7d006647bc27002c55436c8a8bb
Signed-off-by=
: Lev Stipakov <lev@openvpn=2Enet>
---
M doc/man-sections/client-options=2E=
rst
M src/openvpn/oob_client=2Ec
2 files changed, 28 insertions(+), 5 delet=
ions(-)


  git pull ssh://gerrit=2Eopenvpn=2Enet:29418/openvpn refs/change=
s/48/1748/14

diff --git a/doc/man-sections/client-options=2Erst b/doc/man-=
sections/client-options=2Erst
index 82e7b22=2E=2E10ca808 100644
--- a/doc/m=
an-sections/client-options=2Erst
+++ b/doc/man-sections/client-options=2Ers=
t
@@ -608,9 +608,13 @@
   remote, and each answering server replies with it=
s advertised priority
   and weight=2E Remotes are then reordered following=
 DNS SRV (RFC 2782)
   semantics: servers that answered are tried before th=
ose that did not,
-  grouped by priority (lowest first); within a priority =
group, servers are
-  picked by weighted-random selection=2E Round-trip tim=
e is not yet taken
-  into account, so ``max-latency-diff`` has no effect f=
or now=2E
+  grouped by priority (lowest first); within a priority group, s=
ervers
+  whose measured round-trip time is within ``max-latency-diff``
+  =
milliseconds of the fastest one are picked by weighted-random
+  selection,=
 the others follow in round-trip-time order=2E When
+  ``max-latency-diff``=
 is not given, the margin advertised by the
+  answering server is used, fa=
lling back to a built-in default of
+  :code:`10` ms=2E
 
   The probe is c=
urrently sent without control-channel wrapping, so it only
   works against=
 a server configured without ``--tls-auth``,
diff --git a/src/openvpn/oob_c=
lient=2Ec b/src/openvpn/oob_client=2Ec
index 4b8c576=2E=2E3de791f 100644
--=
- a/src/openvpn/oob_client=2Ec
+++ b/src/openvpn/oob_client=2Ec
@@ -56,6 +5=
6,7 @@
     struct sockaddr_storage dest;
     socklen_t destlen;
     bool=
 sent;
+    struct timeval sent_at; /* when the probe was sent, for RTT mea=
surement */
 };
 
 /* The probe uses one native socket per address family, =
so every remote is probed
@@ -177,7 +178,13 @@
             && addr_port_ma=
tch((const struct openvpn_sockaddr *)(const void *)from,
                  =
              (const struct openvpn_sockaddr *)(const void *)&targets[i]=2E=
dest))
         {
+            struct timeval rcv;
+            openvpn_get=
timeofday(&rcv, NULL);
+            long ms =3D (long)(rcv=2Etv_sec - targe=
ts[i]=2Esent_at=2Etv_sec) * 1000
+                      + (rcv=2Etv_usec - =
targets[i]=2Esent_at=2Etv_usec) / 1000;
+
             results[i]=2Erespond=
ed =3D true;
+            results[i]=2Ertt_ms =3D (ms > 0) ? (unsigned int)=
ms : 0;
             results[i]=2Ereply =3D reply;
             break;
    =
     }
@@ -432,6 +439,7 @@
             }
             else
             {
=
+                openvpn_gettimeofday(&targets[i]=2Esent_at, NULL);
       =
          targets[i]=2Edestlen =3D destlen;
                 targets[i]=2Es=
ent =3D true;
                 sent_count++;
@@ -454,8 +462,19 @@
         =
if (results[i]=2Eresponded)
         {
             responded++;
-         =
   msg(D_LOW, "server-probe: %s:%s answered (priority %d, weight %d)", ce->=
remote,
-                ce->remote_port, results[i]=2Ereply=2Epriority, re=
sults[i]=2Ereply=2Eweight);
+            /* Effective candidate-band margin=
 and where it came from: the
+             * client's own setting wins, els=
e the server's advertised value,
+             * else the built-in default=
=2E */
+            int client_margin =3D c->options=2Eserver_probe_latency=
_margin;
+            int margin =3D oob_effective_margin(&results[i], clie=
nt_margin);
+            const char *margin_src =3D client_margin >=3D 0   =
                   ? "client"
+                                     : resul=
ts[i]=2Ereply=2Emax_latency_diff > 0 ? "server-advertised"
+               =
                                                              : "default";
=
+            msg(D_LOW,
+                "server-probe: %s:%s answered (pri=
ority %d, weight %d, rtt %u ms;"
+                " latency margin %d ms [%=
s])",
+                ce->remote, ce->remote_port, results[i]=2Ereply=2Epr=
iority, results[i]=2Ereply=2Eweight,
+                results[i]=2Ertt_ms, =
margin, margin_src);
         }
         else
         {

-- 
To view, visi=
t http://gerrit=2Eopenvpn=2Enet/c/openvpn/+/1748?usp=3Demail
To unsubscribe=
, or for help writing mail filters, visit http://gerrit=2Eopenvpn=2Enet/set=
tings?usp=3Demail

Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
=
Gerrit-Branch: master
Gerrit-Change-Id: I375a41749060b7d006647bc27002c55436=
c8a8bb
Gerrit-Change-Number: 1748
Gerrit-PatchSet: 14
Gerrit-Owner: stipa <=
lstipakov@gmail=2Ecom>
Gerrit-Reviewer: plaisthos <arne-openvpn@rfc2549=2Eo=
rg>
Gerrit-CC: openvpn-devel <openvpn-devel@lists=2Esourceforge=2Enet>
Gerr=
it-Attention: plaisthos <arne-openvpn@rfc2549=2Eorg>

--R46sRr4DW4w=
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html><html><head><style></style></head><body><p> Attention is cur=
rently required from: plaisthos=2E </p>
<p>stipa <strong>uploaded patch set=
 #14</strong> to this change=2E</p><p><a href=3D"http://gerrit=2Eopenvpn=2E=
net/c/openvpn/+/1748?usp=3Demail">View Change</a></p><pre class=3D"blocks" =
style=3D"font-family: monospace,monospace; white-space: pre-wrap;">oob: Mea=
sure probe RTT for candidate-band selection<br><br>Record each probe&#39;s =
round-trip time (per-target send timestamp vs reply<br>arrival) and feed it=
 to oob_rank_probe_results(), where RTT forms the<br>candidate band: respon=
ders within the effective margin of the fastest compete<br>on weight, slowe=
r ones fall behind=2E Log the measured RTT and the effective<br>margin (wit=
h its source: client / server-advertised / default) at verb 4=2E<br><br>Bef=
ore this the client never measured RTT, so every responder sat in the band<=
br>and selection was purely weighted-random; with real measurements the<br>=
latency-based candidate selection takes effect=2E<br><br>Change-Id: I375a41=
749060b7d006647bc27002c55436c8a8bb<br>Signed-off-by: Lev Stipakov &lt;lev@o=
penvpn=2Enet&gt;<br>---<br>M doc/man-sections/client-options=2Erst<br>M src=
/openvpn/oob_client=2Ec<br>2 files changed, 28 insertions(+), 5 deletions(-=
)<br><br></pre><pre class=3D"blocks" style=3D"font-family: monospace,monosp=
ace; white-space: pre-wrap;">git pull ssh://gerrit=2Eopenvpn=2Enet:29418/op=
envpn refs/changes/48/1748/14</pre><pre style=3D"font-family: monospace,mon=
ospace; white-space: pre-wrap;"><span>diff --git a/doc/man-sections/client-=
options=2Erst b/doc/man-sections/client-options=2Erst</span><br><span>index=
 82e7b22=2E=2E10ca808 100644</span><br><span>--- a/doc/man-sections/client-=
options=2Erst</span><br><span>+++ b/doc/man-sections/client-options=2Erst</=
span><br><span>@@ -608,9 +608,13 @@</span><br><span>   remote, and each ans=
wering server replies with its advertised priority</span><br><span>   and w=
eight=2E Remotes are then reordered following DNS SRV (RFC 2782)</span><br>=
<span>   semantics: servers that answered are tried before those that did n=
ot,</span><br><span style=3D"color: hsl(0, 100%, 40%);">-  grouped by prior=
ity (lowest first); within a priority group, servers are</span><br><span st=
yle=3D"color: hsl(0, 100%, 40%);">-  picked by weighted-random selection=2E=
 Round-trip time is not yet taken</span><br><span style=3D"color: hsl(0, 10=
0%, 40%);">-  into account, so ``max-latency-diff`` has no effect for now=
=2E</span><br><span style=3D"color: hsl(120, 100%, 40%);">+  grouped by pri=
ority (lowest first); within a priority group, servers</span><br><span styl=
e=3D"color: hsl(120, 100%, 40%);">+  whose measured round-trip time is with=
in ``max-latency-diff``</span><br><span style=3D"color: hsl(120, 100%, 40%)=
;">+  milliseconds of the fastest one are picked by weighted-random</span><=
br><span style=3D"color: hsl(120, 100%, 40%);">+  selection, the others fol=
low in round-trip-time order=2E When</span><br><span style=3D"color: hsl(12=
0, 100%, 40%);">+  ``max-latency-diff`` is not given, the margin advertised=
 by the</span><br><span style=3D"color: hsl(120, 100%, 40%);">+  answering =
server is used, falling back to a built-in default of</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+  :code:`10` ms=2E</span><br><span> </spa=
n><br><span>   The probe is currently sent without control-channel wrapping=
, so it only</span><br><span>   works against a server configured without `=
`--tls-auth``,</span><br><span>diff --git a/src/openvpn/oob_client=2Ec b/sr=
c/openvpn/oob_client=2Ec</span><br><span>index 4b8c576=2E=2E3de791f 100644<=
/span><br><span>--- a/src/openvpn/oob_client=2Ec</span><br><span>+++ b/src/=
openvpn/oob_client=2Ec</span><br><span>@@ -56,6 +56,7 @@</span><br><span>  =
   struct sockaddr_storage dest;</span><br><span>     socklen_t destlen;</s=
pan><br><span>     bool sent;</span><br><span style=3D"color: hsl(120, 100%=
, 40%);">+    struct timeval sent_at; /* when the probe was sent, for RTT m=
easurement */</span><br><span> };</span><br><span> </span><br><span> /* The=
 probe uses one native socket per address family, so every remote is probed=
</span><br><span>@@ -177,7 +178,13 @@</span><br><span>             &amp;&am=
p; addr_port_match((const struct openvpn_sockaddr *)(const void *)from,</sp=
an><br><span>                                (const struct openvpn_sockaddr=
 *)(const void *)&amp;targets[i]=2Edest))</span><br><span>         {</span>=
<br><span style=3D"color: hsl(120, 100%, 40%);">+            struct timeval=
 rcv;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+            op=
envpn_gettimeofday(&amp;rcv, NULL);</span><br><span style=3D"color: hsl(120=
, 100%, 40%);">+            long ms =3D (long)(rcv=2Etv_sec - targets[i]=2E=
sent_at=2Etv_sec) * 1000</span><br><span style=3D"color: hsl(120, 100%, 40%=
);">+                      + (rcv=2Etv_usec - targets[i]=2Esent_at=2Etv_use=
c) / 1000;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+</span><b=
r><span>             results[i]=2Eresponded =3D true;</span><br><span style=
=3D"color: hsl(120, 100%, 40%);">+            results[i]=2Ertt_ms =3D (ms &=
gt; 0) ? (unsigned int)ms : 0;</span><br><span>             results[i]=2Ere=
ply =3D reply;</span><br><span>             break;</span><br><span>        =
 }</span><br><span>@@ -432,6 +439,7 @@</span><br><span>             }</span=
><br><span>             else</span><br><span>             {</span><br><span=
 style=3D"color: hsl(120, 100%, 40%);">+                openvpn_gettimeofda=
y(&amp;targets[i]=2Esent_at, NULL);</span><br><span>                 target=
s[i]=2Edestlen =3D destlen;</span><br><span>                 targets[i]=2Es=
ent =3D true;</span><br><span>                 sent_count++;</span><br><spa=
n>@@ -454,8 +462,19 @@</span><br><span>         if (results[i]=2Eresponded)=
</span><br><span>         {</span><br><span>             responded++;</span=
><br><span style=3D"color: hsl(0, 100%, 40%);">-            msg(D_LOW, &quo=
t;server-probe: %s:%s answered (priority %d, weight %d)&quot;, ce-&gt;remot=
e,</span><br><span style=3D"color: hsl(0, 100%, 40%);">-                ce-=
&gt;remote_port, results[i]=2Ereply=2Epriority, results[i]=2Ereply=2Eweight=
);</span><br><span style=3D"color: hsl(120, 100%, 40%);">+            /* Ef=
fective candidate-band margin and where it came from: the</span><br><span s=
tyle=3D"color: hsl(120, 100%, 40%);">+             * client&#39;s own setti=
ng wins, else the server&#39;s advertised value,</span><br><span style=3D"c=
olor: hsl(120, 100%, 40%);">+             * else the built-in default=2E */=
</span><br><span style=3D"color: hsl(120, 100%, 40%);">+            int cli=
ent_margin =3D c-&gt;options=2Eserver_probe_latency_margin;</span><br><span=
 style=3D"color: hsl(120, 100%, 40%);">+            int margin =3D oob_effe=
ctive_margin(&amp;results[i], client_margin);</span><br><span style=3D"colo=
r: hsl(120, 100%, 40%);">+            const char *margin_src =3D client_mar=
gin &gt;=3D 0                      ? &quot;client&quot;</span><br><span sty=
le=3D"color: hsl(120, 100%, 40%);">+                                     : =
results[i]=2Ereply=2Emax_latency_diff &gt; 0 ? &quot;server-advertised&quot=
;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+                  =
                                                           : &quot;default&=
quot;;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+            m=
sg(D_LOW,</span><br><span style=3D"color: hsl(120, 100%, 40%);">+          =
      &quot;server-probe: %s:%s answered (priority %d, weight %d, rtt %u ms=
;&quot;</span><br><span style=3D"color: hsl(120, 100%, 40%);">+            =
    &quot; latency margin %d ms [%s])&quot;,</span><br><span style=3D"color=
: hsl(120, 100%, 40%);">+                ce-&gt;remote, ce-&gt;remote_port,=
 results[i]=2Ereply=2Epriority, results[i]=2Ereply=2Eweight,</span><br><spa=
n style=3D"color: hsl(120, 100%, 40%);">+                results[i]=2Ertt_m=
s, margin, margin_src);</span><br><span>         }</span><br><span>        =
 else</span><br><span>         {</span><br><span></span><br></pre><p>To vie=
w, visit <a href=3D"http://gerrit=2Eopenvpn=2Enet/c/openvpn/+/1748?usp=3Dem=
ail">change 1748</a>=2E To unsubscribe, or for help writing mail filters, v=
isit <a href=3D"http://gerrit=2Eopenvpn=2Enet/settings?usp=3Demail">setting=
s</a>=2E</p><div itemscope itemtype=3D"http://schema=2Eorg/EmailMessage"><d=
iv itemscope itemprop=3D"action" itemtype=3D"http://schema=2Eorg/ViewAction=
"><link itemprop=3D"url" href=3D"http://gerrit=2Eopenvpn=2Enet/c/openvpn/+/=
1748?usp=3Demail"/><meta itemprop=3D"name" content=3D"View Change"/></div><=
/div>

<div style=3D"display:none"> Gerrit-MessageType: newpatchset </div>
=
<div style=3D"display:none"> Gerrit-Project: openvpn </div>
<div style=3D"d=
isplay:none"> Gerrit-Branch: master </div>
<div style=3D"display:none"> Ger=
rit-Change-Id: I375a41749060b7d006647bc27002c55436c8a8bb </div>
<div style=
=3D"display:none"> Gerrit-Change-Number: 1748 </div>
<div style=3D"display:=
none"> Gerrit-PatchSet: 14 </div>
<div style=3D"display:none"> Gerrit-Owner=
: stipa &lt;lstipakov@gmail=2Ecom&gt; </div>
<div style=3D"display:none"> G=
errit-Reviewer: plaisthos &lt;arne-openvpn@rfc2549=2Eorg&gt; </div>
<div st=
yle=3D"display:none"> Gerrit-CC: openvpn-devel &lt;openvpn-devel@lists=2Eso=
urceforge=2Enet&gt; </div>
<div style=3D"display:none"> Gerrit-Attention: p=
laisthos &lt;arne-openvpn@rfc2549=2Eorg&gt; </div>

</body></html>
--R46sRr4DW4w=--


--===============6969258336492862994==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


--===============6969258336492862994==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

--===============6969258336492862994==--