ovn-lb-benchmark.py embedded the node index directly in the last
octet of VIP addresses (42.42.42.{i}).  When more than 255 nodes
are requested, this produces addresses like 42.42.42.256 which are
not valid IPv4 -- octets must be in the range 0-255.

Spread the node index across the third and fourth octets
(42.42.{i >> 8}.{i & 0xff}) to support up to 65535 nodes with
valid addresses.

This is the same design as ovn-benchmark.py.

Also make sure # of backends and VIPs is less than the max and greater
than 0.

Other housekeeping:
- Rename lr-X to gw-X to match ovn-benchmark.py.
- Use die() instead of sys.stderr.write() + sys.exit(1).
- Add missing import of ovs.jsonrpc.
- Remove unused seqno variable.

Fixes: 4eefb6359203 ("tutorial: Add scripts to simulate node-port ovn-k8s 
services.")
Assisted-by: Claude Sonnet 4.5, Claude Code
Signed-off-by: Rosemarie O'Riorden <[email protected]>
---
v1 -> v5:
 - Renamed gateway routers from lr-X to gw-X (and ports lr2j/j2lr to
   gw2j/j2gw) to match ovn-benchmark.py.
 - Made die() use sys.stderr.write() consistent with ovn-benchmark.py.
 - Replaced sys.stderr.write()/sys.exit(1) with die() for connection
   errors and argument validation.
 - Added minimum node count validation (>= 1), backends > 255
   validation (second IP octet overflow), and VIP bounds checking.
 - Added explicit import for ovs.jsonrpc.
 - Removed dead seqno variable.
---
 tutorial/ovn-lb-benchmark.py | 47 +++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 14 deletions(-)

diff --git a/tutorial/ovn-lb-benchmark.py b/tutorial/ovn-lb-benchmark.py
index 658beb94c..09cf1feac 100755
--- a/tutorial/ovn-lb-benchmark.py
+++ b/tutorial/ovn-lb-benchmark.py
@@ -3,6 +3,7 @@ import argparse
 import sys
 
 import ovs.db.idl
+import ovs.jsonrpc
 import ovs.poller
 import ovs.stream
 import ovs.vlog
@@ -16,10 +17,15 @@ SCHEMA = '../ovn-nb.ovsschema'
 
 
 def die(msg):
-    vlog.warn(f'Fatal error encountered: {msg}')
+    sys.stderr.write(f'\nError: {msg}\n')
     sys.exit(1)
 
 
+def ip_node(i):
+    """Convert node index to two IP octets, supporting up to 65535 nodes."""
+    return f'{i >> 8}.{i & 0xff}'
+
+
 def create_topology(idl, n):
     vlog.info('Creating topology')
     txn = ovs.db.idl.Transaction(idl)
@@ -50,18 +56,18 @@ def create_topology(idl, n):
         vlog.info(f'Provisioning node {i}')
         chassis = f'chassis-{i}'
         gwr = txn.insert(idl.tables['Logical_Router'])
-        gwr.name = f'lr-{i}'
+        gwr.name = f'gw-{i}'
         gwr.addvalue('load_balancer_group', lbg.uuid)
         gwr.setkey('options', 'chassis', chassis)
 
         gwr2join = txn.insert(idl.tables['Logical_Router_Port'])
-        gwr2join.name = f'lr2j-{i}'
+        gwr2join.name = f'gw2j-{i}'
         gwr2join.mac = '00:00:00:00:00:01'
         gwr2join.networks = ['10.0.0.1/8']
         gwr.addvalue('ports', gwr2join.uuid)
 
         join2gwr = txn.insert(idl.tables['Logical_Switch_Port'])
-        join2gwr.name = f'j2lr-{i}'
+        join2gwr.name = f'j2gw-{i}'
         join2gwr.type = 'router'
         join2gwr.addresses = ['router']
         join2gwr.setkey('options', 'router-port', gwr2join.name)
@@ -121,7 +127,7 @@ def add_chassis_template_vars(idl, n, n_vips, n_backends):
         txn = ovs.db.idl.Transaction(idl)
         tv = txn.insert(idl.tables['Chassis_Template_Var'])
         tv.chassis = f'chassis-{i}'
-        tv.setkey('variables', 'vip', f'42.42.42.{i}')
+        tv.setkey('variables', 'vip', f'42.42.{ip_node(i)}')
 
         for j in range(n_vips):
             port = j + 1
@@ -142,7 +148,7 @@ def find_by_name(idl, table, name):
 
 def add_explicit_lbs(idl, n, n_vips, n_backends):
     for i in range(n):
-        lr = find_by_name(idl, 'Logical_Router', f'lr-{i}')
+        lr = find_by_name(idl, 'Logical_Router', f'gw-{i}')
         ls = find_by_name(idl, 'Logical_Switch', f'ls-{i}')
         for j in range(n_vips):
             vlog.info(f'Adding LB {j} for node {i}')
@@ -154,7 +160,8 @@ def add_explicit_lbs(idl, n, n_vips, n_backends):
 
             lb = txn.insert(idl.tables['Load_Balancer'])
             lb.name = f'lb-{j}-{i}'
-            lb.setkey('vips', f'42.42.42.{i}:{port}', f'{",".join(backends)}')
+            lb.setkey('vips', f'42.42.{ip_node(i)}:{port}',
+                      f'{",".join(backends)}')
             lb.protocol = 'tcp'
             lr.addvalue('load_balancer', lb.uuid)
             ls.addvalue('load_balancer', lb.uuid)
@@ -167,21 +174,17 @@ def run(remote, n, n_vips, n_backends, templates):
     schema_helper.register_all()
     idl = ovs.db.idl.Idl(remote, schema_helper, leader_only=False)
 
-    seqno = 0
-
     error, stream = ovs.stream.Stream.open_block(
         ovs.stream.Stream.open(remote), 2000
     )
     if error:
-        sys.stderr.write(f'failed to connect to \"{remote}\"')
-        sys.exit(1)
+        die(f'failed to connect to "{remote}"')
 
     if not stream:
-        sys.stderr.write(f'failed to connect to \"{remote}\"')
-        sys.exit(1)
+        die(f'failed to connect to "{remote}"')
     rpc = ovs.jsonrpc.Connection(stream)
 
-    while idl.change_seqno == seqno and not idl.run():
+    while idl.change_seqno == 0 and not idl.run():
         rpc.run()
 
         poller = ovs.poller.Poller()
@@ -223,6 +226,22 @@ def main(argv):
     )
     parser.set_defaults(template=False)
     args = parser.parse_args()
+
+    if args.nodes < 1:
+        die('node count must be at least 1')
+    if args.nodes > 65535:
+        die('maximum supported node count is 65535')
+
+    if args.vips < 0:
+        die('VIP count must not be negative')
+    if args.vips > 63999:
+        die('maximum supported VIPs is 63999')
+
+    if args.backends < 0:
+        die('backend count must not be negative')
+    if args.backends > 255:
+        die('maximum supported backends is 255')
+
     run(args.remote, args.nodes, args.vips, args.backends, args.template)
 
 
-- 
2.56.0

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

Reply via email to