]> git.puffer.fish Git - mirror/frr.git/commitdiff
tests: add external RFC8781 receiver tool
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 9 Apr 2025 13:53:43 +0000 (15:53 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Tue, 15 Apr 2025 12:20:23 +0000 (14:20 +0200)
Otherwise pretty much impossible to test this within the current
limitations of topotests.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
tests/topotests/zebra_pref64/rx_ipv6_ra_8781.py [new file with mode: 0644]

diff --git a/tests/topotests/zebra_pref64/rx_ipv6_ra_8781.py b/tests/topotests/zebra_pref64/rx_ipv6_ra_8781.py
new file mode 100644 (file)
index 0000000..c466f64
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: ISC
+# Copyright (c) 2025 by David Lamparter for NetDEF, Inc.
+
+# minimal tool to receive IPv6 RAs and check for PREF64 option
+# usage:
+#   python3 rx_ipv6_ra_8781.py eth123 64:ff9b::/64 1200 5
+# LIFETIME (first number) is the value expected in the packet
+# TIMEOUT (second number) is how long to wait for a matching packet
+
+import sys
+import socket
+import time
+
+from scapy.config import conf
+from scapy.layers.inet6 import (
+    IPv6,
+    ICMPv6ND_RA,
+    ICMPv6NDOptPREF64,
+)
+
+assert len(sys.argv) == 5, "required arguments: IFNAME PREF64 LIFETIME TIMEOUT"
+
+sock = conf.L2socket(iface=sys.argv[1])
+
+pref64str, masklenstr = sys.argv[2].split("/")
+pref64 = socket.inet_pton(socket.AF_INET6, pref64str)
+masklen = int(masklenstr)
+# lifetime is 13 bits with a *8
+lifetime = int(sys.argv[3]) // 8
+
+timeout = float(sys.argv[4])
+
+deadline = time.time() + timeout
+
+while time.time() < deadline:
+    pkts = sock.sniff(timeout=min(deadline - time.time(), 0.25))
+    for pkt in pkts:
+        ra = pkt.getlayer(ICMPv6ND_RA)
+        if not ra:
+            continue
+
+        ra.show()
+
+        pl = ra.payload
+        while pl:
+            cur, pl = pl, pl.payload
+            if isinstance(cur, ICMPv6NDOptPREF64):
+                cmp_pref64 = socket.inet_pton(socket.AF_INET6, cur.prefix)
+                cmp_masklen = int(cur.sprintf("%plc%")[1:])
+                if pref64 != cmp_pref64:
+                    print(f"prefix mismatch {pref64!r} != {cmp_pref64!r}")
+                    continue
+                if masklen != cmp_masklen:
+                    print(f"prefixlen mismatch {masklen!r} != {cmp_masklen!r}")
+                    continue
+                if lifetime != cur.scaledlifetime:
+                    print(
+                        f"lifetime mismatch {lifetime*8!r} != {cur.scaledlifetime*8!r}"
+                    )
+                    continue
+
+                print("MATCH - exiting successfully")
+                sys.exit(0)
+
+print("no matching packet received - exiting with failure")
+sys.exit(1)