Commit ab6a259233 for frr
commit ab6a259233add181a620feb0490d98a15d951d3a
Author: Amr Shadid <amr.shadid.2016@gmail.com>
Date: Tue Sep 15 06:48:59 2026 +0300
tests: isisd: cover trailing bytes in extended-reach sub-TLVs
Feed the unpacker a TLV 22 whose first item declares 8 sub-TLV bytes but
only 6 form an Admin Group sub-TLV, leaving 2 stray bytes, followed by a
second item. Before the fix the parser left those 2 bytes and read the
second neighbor from the wrong offset; the test checks that the second
neighbor still parses correctly.
Signed-off-by: Amr Shadid <amr.shadid.2016@gmail.com>
diff --git a/tests/isisd/subdir.am b/tests/isisd/subdir.am
index 74b6291cce..8daecf847c 100644
--- a/tests/isisd/subdir.am
+++ b/tests/isisd/subdir.am
@@ -74,3 +74,13 @@ tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD)
tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c tests/isisd/test_common.c
EXTRA_DIST += tests/isisd/test_isis_vertex_queue.py
+
+
+if ISISD
+check_PROGRAMS += tests/isisd/test_isis_tlv_ext_reach
+endif
+tests_isisd_test_isis_tlv_ext_reach_CFLAGS = $(TESTS_CFLAGS)
+tests_isisd_test_isis_tlv_ext_reach_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_isisd_test_isis_tlv_ext_reach_LDADD = $(ISISD_TEST_LDADD)
+tests_isisd_test_isis_tlv_ext_reach_SOURCES = tests/isisd/test_isis_tlv_ext_reach.c tests/isisd/test_common.c
+EXTRA_DIST += tests/isisd/test_isis_tlv_ext_reach.py
diff --git a/tests/isisd/test_isis_tlv_ext_reach.c b/tests/isisd/test_isis_tlv_ext_reach.c
new file mode 100644
index 0000000000..1cf812529a
--- /dev/null
+++ b/tests/isisd/test_isis_tlv_ext_reach.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <zebra.h>
+
+#include "memory.h"
+#include "sbuf.h"
+#include "stream.h"
+#include "frrevent.h"
+
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_tlvs.h"
+
+#include "test_common.h"
+
+/*
+ * #22820: a first extended-reach item whose sub-TLV area ends in two stray
+ * bytes must not shift the parse of the following item.
+ */
+/* clang-format off */
+static const uint8_t lsp_body[] = {
+ 0x16, 0x1e, /* TLV type 22 (Ext Reach), length 30 */
+
+ /* item 1 */
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, /* neighbor id */
+ 0x00, 0x00, 0x0a, /* metric 10 */
+ 0x08, /* 8 bytes of sub-TLVs */
+ 0x03, 0x04, 0xde, 0xad, 0xbe, 0xef, /* Admin Group sub-TLV (6 bytes) */
+ 0xff, 0xfe, /* 2 bytes declared but not a sub-TLV */
+
+ /* item 2 - must still parse as this exact neighbor */
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, /* neighbor id */
+ 0x00, 0x00, 0x14, /* metric 20 */
+ 0x00, /* no sub-TLVs */
+};
+/* clang-format on */
+
+int main(int argc, char **argv)
+{
+ static const uint8_t want_id[7] = {
+ 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00,
+ };
+ struct stream *s = stream_new(sizeof(lsp_body));
+ struct isis_extended_reach *first, *second;
+ struct isis_tlvs *tlvs;
+ const char *log;
+ int rv;
+
+ stream_put(s, lsp_body, sizeof(lsp_body));
+ stream_set_getp(s, 0);
+
+ rv = isis_unpack_tlvs(STREAM_READABLE(s), s, &tlvs, &log);
+ printf("unpack rv=%d\nlog:\n%s\n", rv, log);
+ assert(rv == 0);
+
+ assert(tlvs->extended_reach.count == 2);
+ first = (struct isis_extended_reach *)tlvs->extended_reach.head;
+ second = first->next;
+ printf("second neighbor id %02x%02x.%02x%02x.%02x%02x.%02x\n", second->id[0], second->id[1],
+ second->id[2], second->id[3], second->id[4], second->id[5], second->id[6]);
+ assert(memcmp(second->id, want_id, sizeof(want_id)) == 0);
+
+ isis_free_tlvs(tlvs);
+ stream_free(s);
+ printf("OK\n");
+ return 0;
+}
diff --git a/tests/isisd/test_isis_tlv_ext_reach.py b/tests/isisd/test_isis_tlv_ext_reach.py
new file mode 100644
index 0000000000..63bf7c5003
--- /dev/null
+++ b/tests/isisd/test_isis_tlv_ext_reach.py
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+import frrtest
+
+
+class TestIsisTlvExtReach(frrtest.TestMultiOut):
+ program = "./test_isis_tlv_ext_reach"
+
+
+TestIsisTlvExtReach.exit_cleanly()