Commit a3aeae00fb for frr
commit a3aeae00fbdf29d7aececce988edfe2237e38c8d
Author: Philippe Guibert <philippe.guibert@6wind.com>
Date: Tue Nov 10 09:52:16 2026 +0100
pceplib: ignore unknown TLVs
A PCEP message is silently dropped when one of its objects carries a TLV
that pceplib does not know, for instance a TLV of type 31 in the LSP
object of a PCInitiate message. The message is not counted in the
"show sr-te pcep session" statistics, and no PCEP error is sent back.
Since commit 4dafe228dc, pcep_decode_object() fails when
pcep_decode_tlv() returns NULL, and pcep_decode_message() then discards
the whole message. pcep_decode_tlv() returns NULL for a malformed TLV,
but also for a TLV type without decoder. Before that commit, the TLV
parsing stopped at the first unknown TLV and the object was kept.
RFC 5440, section 7.1, requires to ignore an unrecognized TLV.
Fix this by skipping the TLVs without decoder in pcep_decode_object().
A TLV with a decoder that fails to decode it still makes the object
decoding fail. A unit test reads a PCInitiate message with an unknown
TLV in the LSP object.
Fixes: 4dafe228dc ("pceplib: only parse tlvs if sufficient octets present")
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
diff --git a/pceplib/pcep_msg_encoding.h b/pceplib/pcep_msg_encoding.h
index aadf59a1b6..19843f14ae 100644
--- a/pceplib/pcep_msg_encoding.h
+++ b/pceplib/pcep_msg_encoding.h
@@ -119,6 +119,7 @@ uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr,
/* Decode the TLV in tlv_buf and return a pointer to the object */
struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf);
+bool pcep_tlv_has_decoder(uint16_t tlv_type);
/* Decode the TLV header in 'tlv_buf' */
void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
struct pcep_object_tlv_header *tlv_hdr);
diff --git a/pceplib/pcep_msg_objects_encoding.c b/pceplib/pcep_msg_objects_encoding.c
index 5724078759..6753097902 100644
--- a/pceplib/pcep_msg_objects_encoding.c
+++ b/pceplib/pcep_msg_objects_encoding.c
@@ -1065,6 +1065,15 @@ struct pcep_object_header *pcep_decode_object(const uint8_t *obj_buf, size_t buf
break;
}
+ /* RFC 5440, section 7.1: unrecognized TLVs are ignored */
+ if (!pcep_tlv_has_decoder(tlv_hdr.type)) {
+ pcep_log(LOG_DEBUG, "%s: Ignoring unknown TLV type [%d]", __func__,
+ tlv_hdr.type);
+ tlv_index += normalize_pcep_tlv_length(tlv_hdr.encoded_tlv_length +
+ TLV_HEADER_LENGTH);
+ continue;
+ }
+
struct pcep_object_tlv_header *tlv =
pcep_decode_tlv(obj_buf + tlv_index);
if (tlv == NULL) {
diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c
index 4efe03e9e7..b6220213a3 100644
--- a/pceplib/pcep_msg_tlvs_encoding.c
+++ b/pceplib/pcep_msg_tlvs_encoding.c
@@ -840,6 +840,14 @@ void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
tlv_hdr->encoded_tlv = tlv_buf;
}
+bool pcep_tlv_has_decoder(uint16_t tlv_type)
+{
+ if (tlv_type == PCEP_OBJ_TYPE_CISCO_BSID)
+ return true;
+
+ return tlv_type < MAX_TLV_ENCODER_INDEX && tlv_decoders[tlv_type] != NULL;
+}
+
struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf)
{
initialize_tlv_coders();
diff --git a/pceplib/test/pcep_msg_messages_tests.c b/pceplib/test/pcep_msg_messages_tests.c
index 38db910324..26bc02914c 100644
--- a/pceplib/test/pcep_msg_messages_tests.c
+++ b/pceplib/test/pcep_msg_messages_tests.c
@@ -194,6 +194,8 @@ int main(int argc, char **argv)
test_pcep_msg_read_pcep_initiate2);
CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_vendor_info",
test_pcep_msg_read_pcep_initiate_vendor_info);
+ CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_unknown_tlv",
+ test_pcep_msg_read_pcep_initiate_unknown_tlv);
CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update",
test_pcep_msg_read_pcep_update);
CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open",
diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c
index 9b0653fdb8..982d55d756 100644
--- a/pceplib/test/pcep_msg_tools_test.c
+++ b/pceplib/test/pcep_msg_tools_test.c
@@ -75,6 +75,20 @@ const char *pcep_initiate_vendor_info_hexbyte_strs[] = {
"00", "03", "00", "04", "00", "00", "00", "64"
};
+/* The PCEP INITIATE above, with a TLV of type 31 before the SYMBOLIC_PATH_NAME
+ * TLV of the LSP object. pceplib has no decoder for this TLV type. Its 5 octet
+ * value is followed by 3 padding octets.
+ */
+uint16_t pcep_initiate_unknown_tlv_hexbyte_strs_length = 80;
+const char *pcep_initiate_unknown_tlv_hexbyte_strs[] = {
+ "20", "0c", "00", "50", "21", "12", "00", "0c", "00", "00", "00", "00", "00", "00",
+ "00", "01", "20", "10", "00", "20", "00", "00", "00", "09", "00", "1f", "00", "05",
+ "01", "02", "03", "04", "05", "00", "00", "00", "00", "11", "00", "08", "66", "61",
+ "39", "33", "33", "39", "32", "39", "04", "10", "00", "0c", "7f", "00", "00", "01",
+ "28", "28", "28", "28", "07", "10", "00", "14", "01", "08", "0a", "00", "01", "01",
+ "18", "00", "01", "08", "0a", "00", "07", "04", "18", "00"
+};
+
uint16_t pcep_update_hexbyte_strs_length = 48;
const char *pcep_update_hexbyte_strs[] = {
"20", "0b", "00", "30", "21", "12", "00", "14", "00", "00", "00", "00",
@@ -447,6 +461,50 @@ void test_pcep_msg_read_pcep_initiate_vendor_info(void)
unlink(filename);
}
+void test_pcep_msg_read_pcep_initiate_unknown_tlv(void)
+{
+ char filename[BASE_TMPFILE_SIZE];
+ int fd = convert_hexstrs_to_binary(filename, pcep_initiate_unknown_tlv_hexbyte_strs,
+ pcep_initiate_unknown_tlv_hexbyte_strs_length);
+ double_linked_list *msg_list;
+ struct pcep_message *msg;
+ struct pcep_object_header *obj_hdr;
+ struct pcep_object_tlv_symbolic_path_name *sym_path_name;
+
+ if (fd == -1) {
+ CU_ASSERT_TRUE(fd >= 0);
+ return;
+ }
+ msg_list = pcep_msg_read(fd);
+ CU_ASSERT_PTR_NOT_NULL(msg_list);
+ assert(msg_list != NULL);
+ CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+ msg = (struct pcep_message *)msg_list->head->data;
+ CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+ CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+ CU_ASSERT_EQUAL(msg->encoded_message_length, pcep_initiate_unknown_tlv_hexbyte_strs_length);
+
+ obj_hdr = (struct pcep_object_header *)msg->obj_list->head->next_node->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+ CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 32);
+ CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+ CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+
+ sym_path_name = (struct pcep_object_tlv_symbolic_path_name *)obj_hdr->tlv_list->head->data;
+ CU_ASSERT_EQUAL(sym_path_name->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+ CU_ASSERT_EQUAL(sym_path_name->symbolic_path_name_length, 8);
+ CU_ASSERT_EQUAL(strncmp(sym_path_name->symbolic_path_name, "fa933929", 8), 0);
+
+ obj_hdr = (struct pcep_object_header *)msg->obj_list->tail->data;
+ CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+ CU_ASSERT_EQUAL(((struct pcep_object_ro *)obj_hdr)->sub_objects->num_entries, 2);
+
+ pcep_msg_free_message_list(msg_list);
+ close(fd);
+ unlink(filename);
+}
+
void test_pcep_msg_read_pcep_open(void)
{
char filename[BASE_TMPFILE_SIZE];
diff --git a/pceplib/test/pcep_msg_tools_test.h b/pceplib/test/pcep_msg_tools_test.h
index 5415b6e695..82a4b6164b 100644
--- a/pceplib/test/pcep_msg_tools_test.h
+++ b/pceplib/test/pcep_msg_tools_test.h
@@ -23,6 +23,7 @@ void pcep_tools_test_teardown(void);
void test_pcep_msg_read_pcep_initiate(void);
void test_pcep_msg_read_pcep_initiate2(void);
void test_pcep_msg_read_pcep_initiate_vendor_info(void);
+void test_pcep_msg_read_pcep_initiate_unknown_tlv(void);
void test_pcep_msg_read_pcep_update(void);
void test_pcep_msg_read_pcep_open(void);
void test_pcep_msg_read_pcep_open_initiate(void);