1#![deny(missing_docs)]
146
147use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
148use packet_dissector_core::error::PacketError;
149use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue, FormatContext};
150use packet_dissector_core::packet::DissectBuffer;
151use packet_dissector_core::util::{
152 read_be_u16, read_be_u24, read_be_u32, read_ipv4_addr, read_ipv6_addr,
153};
154
155const HEADER_SIZE: usize = 19;
158
159const MARKER: [u8; 16] = [0xFF; 16];
161
162const MIN_OPEN_SIZE: usize = 29;
164
165const MIN_NOTIFICATION_SIZE: usize = 21;
167
168const MIN_UPDATE_SIZE: usize = 23;
170
171const ROUTE_REFRESH_SIZE: usize = 23;
173
174const MSG_OPEN: u8 = 1;
176const MSG_UPDATE: u8 = 2;
178const MSG_NOTIFICATION: u8 = 3;
180const MSG_KEEPALIVE: u8 = 4;
182const MSG_ROUTE_REFRESH: u8 = 5;
184
185fn msg_type_name(v: u8) -> Option<&'static str> {
190 match v {
191 MSG_OPEN => Some("OPEN"),
192 MSG_UPDATE => Some("UPDATE"),
193 MSG_NOTIFICATION => Some("NOTIFICATION"),
194 MSG_KEEPALIVE => Some("KEEPALIVE"),
195 MSG_ROUTE_REFRESH => Some("ROUTE-REFRESH"),
196 _ => None,
197 }
198}
199
200fn afi_name(v: u16) -> Option<&'static str> {
204 match v {
205 1 => Some("IPv4"),
206 2 => Some("IPv6"),
207 25 => Some("L2VPN"),
208 _ => None,
209 }
210}
211
212fn safi_name(v: u8) -> Option<&'static str> {
216 match v {
217 1 => Some("Unicast"),
218 2 => Some("Multicast"),
219 4 => Some("MPLS Labels"),
220 65 => Some("VPLS"),
221 70 => Some("EVPN"),
222 71 => Some("BGP-LS"),
223 73 => Some("SR Policy"),
224 85 => Some("BGP-MUP"),
225 128 => Some("MPLS-labeled VPN"),
226 129 => Some("Multicast VPN"),
227 132 => Some("Route Target Constraints"),
228 133 => Some("FlowSpec"),
229 134 => Some("L3VPN FlowSpec"),
230 _ => None,
231 }
232}
233
234fn parse_optional_parameters<'pkt>(
243 buf: &mut DissectBuffer<'pkt>,
244 params_data: &'pkt [u8],
245 base_offset: usize,
246 param_len_size: usize,
247) {
248 let mut pos = 0;
249 let hdr_size = 1 + param_len_size;
250
251 while pos + hdr_size <= params_data.len() {
252 let param_type = params_data[pos];
253 let param_len = if param_len_size == 1 {
254 params_data[pos + 1] as usize
255 } else {
256 ((params_data[pos + 1] as usize) << 8) | (params_data[pos + 2] as usize)
258 };
259 let param_start = base_offset + pos;
260
261 if pos + hdr_size + param_len > params_data.len() {
262 break;
263 }
264
265 if param_type == 2 {
267 let cap_data = ¶ms_data[pos + hdr_size..pos + hdr_size + param_len];
268 let mut cap_pos = 0;
269 while cap_pos + 2 <= cap_data.len() {
270 let cap_code = cap_data[cap_pos];
271 let cap_len = cap_data[cap_pos + 1] as usize;
272 let cap_abs = base_offset + pos + hdr_size + cap_pos;
273
274 if cap_pos + 2 + cap_len > cap_data.len() {
275 break;
276 }
277
278 let obj_idx = buf.begin_container(
279 &OPT_PARAM_OBJECT_DESCRIPTOR,
280 FieldValue::Object(0..0),
281 cap_abs..cap_abs + 2 + cap_len,
282 );
283 buf.push_field(
284 &OPT_PARAM_CHILDREN[FD_OPT_CODE],
285 FieldValue::U8(cap_code),
286 cap_abs..cap_abs + 1,
287 );
288 buf.push_field(
289 &OPT_PARAM_CHILDREN[FD_OPT_LENGTH],
290 FieldValue::U8(cap_data[cap_pos + 1]),
291 cap_abs + 1..cap_abs + 2,
292 );
293
294 if cap_len > 0 {
295 let cap_value = &cap_data[cap_pos + 2..cap_pos + 2 + cap_len];
296 buf.push_field(
297 &OPT_PARAM_CHILDREN[FD_OPT_VALUE],
298 FieldValue::Bytes(cap_value),
299 cap_abs + 2..cap_abs + 2 + cap_len,
300 );
301 }
302
303 buf.end_container(obj_idx);
304 cap_pos += 2 + cap_len;
305 }
306 } else {
307 let val = ¶ms_data[pos + hdr_size..pos + hdr_size + param_len];
309 let obj_idx = buf.begin_container(
310 &OPT_PARAM_OBJECT_DESCRIPTOR,
311 FieldValue::Object(0..0),
312 param_start..param_start + hdr_size + param_len,
313 );
314 buf.push_field(
315 &NON_CAP_PARAM_CHILDREN[FD_NCP_PARAM_TYPE],
316 FieldValue::U8(param_type),
317 param_start..param_start + 1,
318 );
319 buf.push_field(
320 &NON_CAP_PARAM_CHILDREN[FD_NCP_VALUE],
321 FieldValue::Bytes(val),
322 param_start + hdr_size..param_start + hdr_size + param_len,
323 );
324 buf.end_container(obj_idx);
325 }
326
327 pos += hdr_size + param_len;
328 }
329}
330
331fn parse_open<'pkt>(
337 buf: &mut DissectBuffer<'pkt>,
338 data: &'pkt [u8],
339 offset: usize,
340) -> Result<(), PacketError> {
341 if data.len() < MIN_OPEN_SIZE {
342 return Err(PacketError::Truncated {
343 expected: MIN_OPEN_SIZE,
344 actual: data.len(),
345 });
346 }
347
348 let version = data[19];
349 let my_as = read_be_u16(data, 20)?;
350 let hold_time = read_be_u16(data, 22)?;
351 let bgp_id = [data[24], data[25], data[26], data[27]];
352 let opt_params_len_byte = data[28];
353
354 buf.push_field(
355 &FIELD_DESCRIPTORS[FD_VERSION],
356 FieldValue::U8(version),
357 offset + 19..offset + 20,
358 );
359 buf.push_field(
360 &FIELD_DESCRIPTORS[FD_MY_AS],
361 FieldValue::U16(my_as),
362 offset + 20..offset + 22,
363 );
364 buf.push_field(
365 &FIELD_DESCRIPTORS[FD_HOLD_TIME],
366 FieldValue::U16(hold_time),
367 offset + 22..offset + 24,
368 );
369 buf.push_field(
370 &FIELD_DESCRIPTORS[FD_BGP_IDENTIFIER],
371 FieldValue::Ipv4Addr(bgp_id),
372 offset + 24..offset + 28,
373 );
374 buf.push_field(
375 &FIELD_DESCRIPTORS[FD_OPT_PARAMS_LENGTH],
376 FieldValue::U8(opt_params_len_byte),
377 offset + 28..offset + 29,
378 );
379
380 let extended = data.len() >= 32 && data[29] == 255;
386
387 let (params_offset, params_len, param_len_size) = if extended {
388 let ext_len = read_be_u16(data, 30)? as usize;
389 buf.push_field(
390 &FIELD_DESCRIPTORS[FD_EXT_OPT_PARAMS_LENGTH],
391 FieldValue::U16(ext_len as u16),
392 offset + 30..offset + 32,
393 );
394 (32usize, ext_len, 2usize)
395 } else {
396 (29usize, opt_params_len_byte as usize, 1usize)
397 };
398
399 if params_len > 0 {
400 let params_end = params_offset + params_len;
401 if data.len() < params_end {
402 return Err(PacketError::Truncated {
403 expected: params_end,
404 actual: data.len(),
405 });
406 }
407
408 let params_data = &data[params_offset..params_end];
409 let array_idx = buf.begin_container(
410 &FIELD_DESCRIPTORS[FD_OPTIONAL_PARAMETERS],
411 FieldValue::Array(0..0),
412 offset + params_offset..offset + params_end,
413 );
414 parse_optional_parameters(buf, params_data, offset + params_offset, param_len_size);
415 buf.end_container(array_idx);
416 }
417
418 Ok(())
419}
420
421fn error_code_name(v: u8) -> Option<&'static str> {
425 match v {
426 1 => Some("Message Header Error"),
427 2 => Some("OPEN Message Error"),
428 3 => Some("UPDATE Message Error"),
429 4 => Some("Hold Timer Expired"),
430 5 => Some("Finite State Machine Error"),
431 6 => Some("Cease"),
432 7 => Some("ROUTE-REFRESH Message Error"),
433 8 => Some("Send Hold Timer Expired"),
434 _ => None,
435 }
436}
437
438fn cease_subcode_name(v: u8) -> Option<&'static str> {
443 match v {
444 1 => Some("Maximum Number of Prefixes Reached"),
445 2 => Some("Administrative Shutdown"),
446 3 => Some("Peer De-configured"),
447 4 => Some("Administrative Reset"),
448 5 => Some("Connection Rejected"),
449 6 => Some("Other Configuration Change"),
450 7 => Some("Connection Collision Resolution"),
451 8 => Some("Out of Resources"),
452 9 => Some("Hard Reset"),
453 _ => None,
454 }
455}
456
457fn parse_notification<'pkt>(
461 buf: &mut DissectBuffer<'pkt>,
462 data: &'pkt [u8],
463 offset: usize,
464) -> Result<(), PacketError> {
465 if data.len() < MIN_NOTIFICATION_SIZE {
466 return Err(PacketError::Truncated {
467 expected: MIN_NOTIFICATION_SIZE,
468 actual: data.len(),
469 });
470 }
471
472 let error_code = data[19];
473 let error_subcode = data[20];
474
475 buf.push_field(
476 &FIELD_DESCRIPTORS[FD_ERROR_CODE],
477 FieldValue::U8(error_code),
478 offset + 19..offset + 20,
479 );
480 buf.push_field(
481 &FIELD_DESCRIPTORS[FD_ERROR_SUBCODE],
482 FieldValue::U8(error_subcode),
483 offset + 20..offset + 21,
484 );
485
486 if data.len() > MIN_NOTIFICATION_SIZE {
487 let data_bytes = &data[21..];
488 buf.push_field(
489 &FIELD_DESCRIPTORS[FD_DATA],
490 FieldValue::Bytes(data_bytes),
491 offset + 21..offset + data.len(),
492 );
493 }
494
495 Ok(())
496}
497
498fn route_refresh_subtype_name(v: u8) -> Option<&'static str> {
502 match v {
503 0 => Some("Route Refresh"),
504 1 => Some("BoRR"),
505 2 => Some("EoRR"),
506 _ => None,
507 }
508}
509
510fn parse_route_refresh<'pkt>(
515 buf: &mut DissectBuffer<'pkt>,
516 data: &'pkt [u8],
517 offset: usize,
518) -> Result<(), PacketError> {
519 if data.len() < ROUTE_REFRESH_SIZE {
520 return Err(PacketError::Truncated {
521 expected: ROUTE_REFRESH_SIZE,
522 actual: data.len(),
523 });
524 }
525
526 let afi = read_be_u16(data, 19)?;
527 let message_subtype = data[21];
530 let safi = data[22];
531
532 buf.push_field(
533 &FIELD_DESCRIPTORS[FD_AFI],
534 FieldValue::U16(afi),
535 offset + 19..offset + 21,
536 );
537 buf.push_field(
538 &FIELD_DESCRIPTORS[FD_MESSAGE_SUBTYPE],
539 FieldValue::U8(message_subtype),
540 offset + 21..offset + 22,
541 );
542 buf.push_field(
543 &FIELD_DESCRIPTORS[FD_SAFI],
544 FieldValue::U8(safi),
545 offset + 22..offset + 23,
546 );
547
548 Ok(())
549}
550
551fn parse_prefixes<'pkt>(
557 buf: &mut DissectBuffer<'pkt>,
558 data: &'pkt [u8],
559 base_offset: usize,
560 ipv6: bool,
561) {
562 let mut pos = 0;
563
564 let max_bits: usize = if ipv6 { 128 } else { 32 };
565 let descriptor = if ipv6 {
566 &PREFIX_ENTRY_IPV6_DESCRIPTOR
567 } else {
568 &PREFIX_ENTRY_IPV4_DESCRIPTOR
569 };
570
571 while pos < data.len() {
572 let prefix_bits = data[pos] as usize;
573
574 if prefix_bits > max_bits {
576 break;
577 }
578
579 let prefix_bytes = prefix_bits.div_ceil(8);
580
581 if pos + 1 + prefix_bytes > data.len() {
582 break;
583 }
584
585 let abs = base_offset + pos;
586 let entry_len = 1 + prefix_bytes;
587 buf.push_field(
588 descriptor,
589 FieldValue::Bytes(&data[pos..pos + entry_len]),
590 abs..abs + entry_len,
591 );
592
593 pos += entry_len;
594 }
595}
596
597fn path_attr_type_name(v: u8) -> Option<&'static str> {
601 match v {
602 1 => Some("ORIGIN"),
603 2 => Some("AS_PATH"),
604 3 => Some("NEXT_HOP"),
605 4 => Some("MULTI_EXIT_DISC"),
606 5 => Some("LOCAL_PREF"),
607 6 => Some("ATOMIC_AGGREGATE"),
608 7 => Some("AGGREGATOR"),
609 8 => Some("COMMUNITIES"),
610 9 => Some("ORIGINATOR_ID"),
611 10 => Some("CLUSTER_LIST"),
612 14 => Some("MP_REACH_NLRI"),
613 15 => Some("MP_UNREACH_NLRI"),
614 16 => Some("EXTENDED COMMUNITIES"),
615 17 => Some("AS4_PATH"),
616 18 => Some("AS4_AGGREGATOR"),
617 22 => Some("PMSI_TUNNEL"),
618 23 => Some("Tunnel Encapsulation"),
619 26 => Some("AIGP"),
620 29 => Some("BGP-LS Attribute"),
621 32 => Some("LARGE_COMMUNITY"),
622 33 => Some("BGPsec_Path"),
623 35 => Some("Only to Customer (OTC)"),
624 40 => Some("BGP Prefix-SID"),
625 _ => None,
626 }
627}
628
629fn parse_path_attribute<'pkt>(
634 buf: &mut DissectBuffer<'pkt>,
635 data: &'pkt [u8],
636 base_offset: usize,
637) -> Option<usize> {
638 if data.len() < 3 {
639 return None;
640 }
641
642 let flags = data[0];
643 let type_code = data[1];
644 let extended_length = flags & 0x10 != 0;
645
646 let (attr_len, header_len) = if extended_length {
647 if data.len() < 4 {
648 return None;
649 }
650 (read_be_u16(data, 2).unwrap_or_default() as usize, 4usize)
651 } else {
652 (data[2] as usize, 3usize)
653 };
654
655 let total_len = header_len + attr_len;
656 if data.len() < total_len {
657 return None;
658 }
659
660 let value_data = &data[header_len..total_len];
661
662 let obj_idx = buf.begin_container(
663 &PATH_ATTR_OBJECT_DESCRIPTOR,
664 FieldValue::Object(0..0),
665 base_offset..base_offset + total_len,
666 );
667
668 buf.push_field(
669 &PATH_ATTR_CHILDREN[FD_PA_FLAGS],
670 FieldValue::U8(flags),
671 base_offset..base_offset + 1,
672 );
673 buf.push_field(
674 &PATH_ATTR_CHILDREN[FD_PA_TYPE_CODE],
675 FieldValue::U8(type_code),
676 base_offset + 1..base_offset + 2,
677 );
678 buf.push_field(
679 &PATH_ATTR_CHILDREN[FD_PA_ATTR_LENGTH],
680 FieldValue::U16(attr_len as u16),
681 base_offset + 2..base_offset + header_len,
682 );
683
684 let val_offset = base_offset + header_len;
685 parse_attr_value(buf, type_code, value_data, val_offset);
686
687 buf.end_container(obj_idx);
688
689 Some(total_len)
690}
691
692fn origin_name(v: u8) -> Option<&'static str> {
696 match v {
697 0 => Some("IGP"),
698 1 => Some("EGP"),
699 2 => Some("INCOMPLETE"),
700 _ => None,
701 }
702}
703
704fn well_known_community_name(v: u32) -> Option<&'static str> {
709 match v {
710 0xFFFF_0000 => Some("GRACEFUL_SHUTDOWN"),
711 0xFFFF_0001 => Some("ACCEPT_OWN"),
712 0xFFFF_0002 => Some("ROUTE_FILTER_TRANSLATED_v4"),
713 0xFFFF_0003 => Some("ROUTE_FILTER_v4"),
714 0xFFFF_0004 => Some("ROUTE_FILTER_TRANSLATED_v6"),
715 0xFFFF_0005 => Some("ROUTE_FILTER_v6"),
716 0xFFFF_0006 => Some("LLGR_STALE"),
717 0xFFFF_0007 => Some("NO_LLGR"),
718 0xFFFF_029A => Some("BLACKHOLE"),
719 0xFFFF_FF01 => Some("NO_EXPORT"),
720 0xFFFF_FF02 => Some("NO_ADVERTISE"),
721 0xFFFF_FF03 => Some("NO_EXPORT_SUBCONFED"),
722 0xFFFF_FF04 => Some("NOPEER"),
723 _ => None,
724 }
725}
726
727fn extended_community_type_name(type_high: u8, sub_type: u8) -> Option<&'static str> {
732 let base_type = type_high & 0x3F;
733 match (base_type, sub_type) {
734 (0x00, 0x02) | (0x02, 0x02) => Some("Route Target"),
735 (0x01, 0x02) => Some("Route Target (IPv4)"),
736 (0x00, 0x03) | (0x02, 0x03) => Some("Route Origin"),
737 (0x01, 0x03) => Some("Route Origin (IPv4)"),
738 (0x03, 0x0B) => Some("Color"),
739 (0x06, _) => Some("EVPN"),
740 (0x0C, 0x00) => Some("MUP Direct Segment Identifier"),
741 _ => None,
742 }
743}
744
745fn as_path_segment_type_name(v: u8) -> Option<&'static str> {
750 match v {
751 1 => Some("AS_SET"),
752 2 => Some("AS_SEQUENCE"),
753 3 => Some("AS_CONFED_SEQUENCE"),
754 4 => Some("AS_CONFED_SET"),
755 _ => None,
756 }
757}
758
759fn parse_prefix_sid<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
765 let array_idx = buf.begin_container(
766 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
767 FieldValue::Array(0..0),
768 offset..offset + data.len(),
769 );
770 let mut pos = 0;
771 let mut count = 0;
772
773 while pos + 3 <= data.len() {
774 let tlv_type = data[pos];
775 let tlv_len = read_be_u16(data, pos + 1).unwrap_or_default() as usize;
776 let abs = offset + pos;
777
778 if pos + 3 + tlv_len > data.len() {
779 break;
780 }
781
782 let total = 3 + tlv_len;
783 let obj_idx = buf.begin_container(
784 &PREFIX_SID_TLV_OBJECT_DESCRIPTOR,
785 FieldValue::Object(0..0),
786 abs..abs + total,
787 );
788
789 buf.push_field(
790 &PREFIX_SID_TLV_CHILDREN[FD_PSID_TYPE],
791 FieldValue::U8(tlv_type),
792 abs..abs + 1,
793 );
794 buf.push_field(
795 &PREFIX_SID_TLV_CHILDREN[FD_PSID_LENGTH],
796 FieldValue::U16(tlv_len as u16),
797 abs + 1..abs + 3,
798 );
799
800 let val_data = &data[pos + 3..pos + 3 + tlv_len];
801 let val_offset = abs + 3;
802
803 match tlv_type {
804 1 => parse_label_index_tlv(buf, val_data, val_offset),
806 3 => parse_originator_srgb_tlv(buf, val_data, val_offset),
808 5 | 6 => parse_srv6_service_tlv(buf, val_data, val_offset),
811 _ => {
812 if !val_data.is_empty() {
813 buf.push_field(
814 &PREFIX_SID_TLV_CHILDREN[FD_PSID_VALUE],
815 FieldValue::Bytes(val_data),
816 val_offset..val_offset + val_data.len(),
817 );
818 }
819 }
820 }
821
822 buf.end_container(obj_idx);
823 count += 1;
824 pos += total;
825 }
826
827 if count == 0 {
828 buf.pop_field();
830 } else {
831 buf.end_container(array_idx);
832 }
833}
834
835fn parse_label_index_tlv<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
841 if data.len() < 7 {
842 if !data.is_empty() {
843 buf.push_field(
844 &PREFIX_SID_TLV_CHILDREN[FD_PSID_VALUE],
845 FieldValue::Bytes(data),
846 offset..offset + data.len(),
847 );
848 }
849 return;
850 }
851 let flags = read_be_u16(data, 1).unwrap_or_default();
853 let label_index = read_be_u32(data, 3).unwrap_or_default();
854
855 buf.push_field(
856 &PREFIX_SID_TLV_CHILDREN[FD_PSID_FLAGS],
857 FieldValue::U16(flags),
858 offset + 1..offset + 3,
859 );
860 buf.push_field(
861 &PREFIX_SID_TLV_CHILDREN[FD_PSID_LABEL_INDEX],
862 FieldValue::U32(label_index),
863 offset + 3..offset + 7,
864 );
865}
866
867fn parse_originator_srgb_tlv<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
873 if data.len() < 2 {
874 if !data.is_empty() {
875 buf.push_field(
876 &PREFIX_SID_TLV_CHILDREN[FD_PSID_VALUE],
877 FieldValue::Bytes(data),
878 offset..offset + data.len(),
879 );
880 }
881 return;
882 }
883
884 let flags = read_be_u16(data, 0).unwrap_or_default();
885 buf.push_field(
886 &PREFIX_SID_TLV_CHILDREN[FD_PSID_FLAGS],
887 FieldValue::U16(flags),
888 offset..offset + 2,
889 );
890
891 let array_idx = buf.begin_container(
892 &PREFIX_SID_TLV_CHILDREN[FD_PSID_SRGB_ENTRIES],
893 FieldValue::Array(0..0),
894 offset + 2..offset + data.len(),
895 );
896 let mut count = 0;
897 let mut pos = 2;
898 while pos + 6 <= data.len() {
899 let abs = offset + pos;
900 let base = read_be_u24(data, pos).unwrap_or_default();
901 let range = read_be_u24(data, pos + 3).unwrap_or_default();
902
903 let obj_idx = buf.begin_container(
904 &SRGB_ENTRY_OBJECT_DESCRIPTOR,
905 FieldValue::Object(0..0),
906 abs..abs + 6,
907 );
908 buf.push_field(
909 &SRGB_ENTRY_CHILDREN[FD_SRGB_BASE],
910 FieldValue::U32(base),
911 abs..abs + 3,
912 );
913 buf.push_field(
914 &SRGB_ENTRY_CHILDREN[FD_SRGB_RANGE],
915 FieldValue::U32(range),
916 abs + 3..abs + 6,
917 );
918 buf.end_container(obj_idx);
919
920 count += 1;
921 pos += 6;
922 }
923
924 if count == 0 {
925 buf.pop_field();
926 } else {
927 buf.end_container(array_idx);
928 }
929}
930
931fn parse_srv6_service_tlv<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
937 if data.is_empty() {
938 return;
939 }
940
941 let array_idx = buf.begin_container(
943 &PREFIX_SID_TLV_CHILDREN[FD_PSID_SUB_TLVS],
944 FieldValue::Array(0..0),
945 offset + 1..offset + data.len(),
946 );
947 let mut count = 0;
948 let mut pos = 1;
949
950 while pos + 3 <= data.len() {
951 let sub_type = data[pos];
952 let sub_len = read_be_u16(data, pos + 1).unwrap_or_default() as usize;
953 let abs = offset + pos;
954
955 if pos + 3 + sub_len > data.len() {
956 break;
957 }
958
959 let total = 3 + sub_len;
960 let obj_idx = buf.begin_container(
961 &SRV6_SID_INFO_OBJECT_DESCRIPTOR,
962 FieldValue::Object(0..0),
963 abs..abs + total,
964 );
965
966 buf.push_field(
967 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_TYPE],
968 FieldValue::U8(sub_type),
969 abs..abs + 1,
970 );
971 buf.push_field(
972 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_LENGTH],
973 FieldValue::U16(sub_len as u16),
974 abs + 1..abs + 3,
975 );
976
977 let val_data = &data[pos + 3..pos + 3 + sub_len];
978 let val_offset = abs + 3;
979
980 match sub_type {
981 1 => parse_srv6_sid_info_sub_tlv(buf, val_data, val_offset),
983 _ => {
984 if !val_data.is_empty() {
985 buf.push_field(
986 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_VALUE],
987 FieldValue::Bytes(val_data),
988 val_offset..val_offset + val_data.len(),
989 );
990 }
991 }
992 }
993
994 buf.end_container(obj_idx);
995 count += 1;
996 pos += total;
997 }
998
999 if count == 0 {
1000 buf.pop_field();
1001 } else {
1002 buf.end_container(array_idx);
1003 }
1004}
1005
1006fn parse_srv6_sid_info_sub_tlv<'pkt>(
1013 buf: &mut DissectBuffer<'pkt>,
1014 data: &'pkt [u8],
1015 offset: usize,
1016) {
1017 if data.len() < 21 {
1018 if !data.is_empty() {
1019 buf.push_field(
1020 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_VALUE],
1021 FieldValue::Bytes(data),
1022 offset..offset + data.len(),
1023 );
1024 }
1025 return;
1026 }
1027
1028 let sid = read_ipv6_addr(data, 1).unwrap_or_default();
1030 let sid_flags = data[17];
1031 let endpoint_behavior = read_be_u16(data, 18).unwrap_or_default();
1032 buf.push_field(
1035 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_SID],
1036 FieldValue::Ipv6Addr(sid),
1037 offset + 1..offset + 17,
1038 );
1039 buf.push_field(
1040 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_FLAGS],
1041 FieldValue::U8(sid_flags),
1042 offset + 17..offset + 18,
1043 );
1044 buf.push_field(
1045 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_ENDPOINT_BEHAVIOR],
1046 FieldValue::U16(endpoint_behavior),
1047 offset + 18..offset + 20,
1048 );
1049
1050 let mut pos = 21;
1052 while pos + 3 <= data.len() {
1053 let ss_type = data[pos];
1054 let ss_len = read_be_u16(data, pos + 1).unwrap_or_default() as usize;
1055
1056 if pos + 3 + ss_len > data.len() {
1057 break;
1058 }
1059
1060 if ss_type == 1 && ss_len == 6 {
1062 let ss_val = &data[pos + 3..pos + 3 + ss_len];
1063 let abs = offset + pos + 3;
1064 let obj_idx = buf.begin_container(
1065 &SRV6_SID_INFO_CHILDREN[FD_SRV6_SI_SID_STRUCTURE],
1066 FieldValue::Object(0..0),
1067 offset + pos..offset + pos + 3 + ss_len,
1068 );
1069 buf.push_field(
1070 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_LBL],
1071 FieldValue::U8(ss_val[0]),
1072 abs..abs + 1,
1073 );
1074 buf.push_field(
1075 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_LNL],
1076 FieldValue::U8(ss_val[1]),
1077 abs + 1..abs + 2,
1078 );
1079 buf.push_field(
1080 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_FL],
1081 FieldValue::U8(ss_val[2]),
1082 abs + 2..abs + 3,
1083 );
1084 buf.push_field(
1085 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_AL],
1086 FieldValue::U8(ss_val[3]),
1087 abs + 3..abs + 4,
1088 );
1089 buf.push_field(
1090 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_TL],
1091 FieldValue::U8(ss_val[4]),
1092 abs + 4..abs + 5,
1093 );
1094 buf.push_field(
1095 &SRV6_SID_STRUCTURE_CHILDREN[FD_SRV6_SS_TO],
1096 FieldValue::U8(ss_val[5]),
1097 abs + 5..abs + 6,
1098 );
1099 buf.end_container(obj_idx);
1100 }
1101
1102 pos += 3 + ss_len;
1103 }
1104}
1105
1106fn parse_as_path<'pkt>(
1111 buf: &mut DissectBuffer<'pkt>,
1112 data: &'pkt [u8],
1113 offset: usize,
1114 as_size: usize,
1115) {
1116 let mut pos = 0;
1117
1118 while pos + 2 <= data.len() {
1119 let seg_type = data[pos];
1120 let seg_len = data[pos + 1] as usize;
1121 let seg_abs = offset + pos;
1122
1123 let seg_data_len = seg_len * as_size;
1124 if pos + 2 + seg_data_len > data.len() {
1125 break;
1126 }
1127
1128 let seg_obj_idx = buf.begin_container(
1129 &AS_PATH_SEG_OBJECT_DESCRIPTOR,
1130 FieldValue::Object(0..0),
1131 seg_abs..seg_abs + 2 + seg_data_len,
1132 );
1133
1134 buf.push_field(
1135 &AS_PATH_SEG_CHILDREN[FD_APS_SEGMENT_TYPE],
1136 FieldValue::U8(seg_type),
1137 seg_abs..seg_abs + 1,
1138 );
1139
1140 let as_array_idx = buf.begin_container(
1141 &AS_PATH_SEG_CHILDREN[FD_APS_AS_NUMBERS],
1142 FieldValue::Array(0..0),
1143 seg_abs + 2..seg_abs + 2 + seg_data_len,
1144 );
1145 for i in 0..seg_len {
1146 let as_offset = pos + 2 + i * as_size;
1147 let as_abs = offset + as_offset;
1148 let asn = if as_size == 4 {
1149 read_be_u32(data, as_offset).unwrap_or_default()
1150 } else {
1151 read_be_u16(data, as_offset).unwrap_or_default() as u32
1152 };
1153 buf.push_field(
1154 &AS_NUMBER_DESCRIPTOR,
1155 FieldValue::U32(asn),
1156 as_abs..as_abs + as_size,
1157 );
1158 }
1159 buf.end_container(as_array_idx);
1160
1161 buf.end_container(seg_obj_idx);
1162
1163 pos += 2 + seg_data_len;
1164 }
1165}
1166
1167fn parse_attr_value<'pkt>(
1171 buf: &mut DissectBuffer<'pkt>,
1172 type_code: u8,
1173 data: &'pkt [u8],
1174 offset: usize,
1175) {
1176 match type_code {
1177 1 if data.len() == 1 => {
1179 buf.push_field(
1180 &FD_ORIGIN_VALUE,
1181 FieldValue::U8(data[0]),
1182 offset..offset + 1,
1183 );
1184 }
1185 2 => {
1187 let array_idx = buf.begin_container(
1188 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1189 FieldValue::Array(0..0),
1190 offset..offset + data.len(),
1191 );
1192 parse_as_path(buf, data, offset, 2);
1193 buf.end_container(array_idx);
1194 }
1195 3 if data.len() == 4 => {
1197 buf.push_field(
1198 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1199 FieldValue::Ipv4Addr(read_ipv4_addr(data, 0).unwrap_or_default()),
1200 offset..offset + 4,
1201 );
1202 }
1203 4 if data.len() == 4 => {
1205 let med = read_be_u32(data, 0).unwrap_or_default();
1206 buf.push_field(
1207 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1208 FieldValue::U32(med),
1209 offset..offset + 4,
1210 );
1211 }
1212 5 if data.len() == 4 => {
1214 let lp = read_be_u32(data, 0).unwrap_or_default();
1215 buf.push_field(
1216 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1217 FieldValue::U32(lp),
1218 offset..offset + 4,
1219 );
1220 }
1221 6 => {}
1223 7 if data.len() == 6 || data.len() == 8 => {
1226 buf.push_field(
1227 &FD_AGGREGATOR_VALUE,
1228 FieldValue::Bytes(data),
1229 offset..offset + data.len(),
1230 );
1231 }
1232 8 if data.len() % 4 == 0 => {
1234 let array_idx = buf.begin_container(
1235 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1236 FieldValue::Array(0..0),
1237 offset..offset + data.len(),
1238 );
1239 let mut pos = 0;
1240 while pos + 4 <= data.len() {
1241 let val = read_be_u32(data, pos).unwrap_or_default();
1242 buf.push_field(
1243 &COMMUNITY_ENTRY_DESCRIPTOR,
1244 FieldValue::U32(val),
1245 offset + pos..offset + pos + 4,
1246 );
1247 pos += 4;
1248 }
1249 buf.end_container(array_idx);
1250 }
1251 9 if data.len() == 4 => {
1253 buf.push_field(
1254 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1255 FieldValue::Ipv4Addr(read_ipv4_addr(data, 0).unwrap_or_default()),
1256 offset..offset + 4,
1257 );
1258 }
1259 10 if data.len() % 4 == 0 => {
1261 let array_idx = buf.begin_container(
1262 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1263 FieldValue::Array(0..0),
1264 offset..offset + data.len(),
1265 );
1266 let mut pos = 0;
1267 while pos + 4 <= data.len() {
1268 buf.push_field(
1269 &CLUSTER_ID_DESCRIPTOR,
1270 FieldValue::Ipv4Addr([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]),
1271 offset + pos..offset + pos + 4,
1272 );
1273 pos += 4;
1274 }
1275 buf.end_container(array_idx);
1276 }
1277 14 if data.len() >= 5 => {
1279 parse_mp_reach_nlri(buf, data, offset);
1280 }
1281 15 if data.len() >= 3 => {
1283 parse_mp_unreach_nlri(buf, data, offset);
1284 }
1285 16 if data.len() % 8 == 0 => {
1287 let array_idx = buf.begin_container(
1288 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1289 FieldValue::Array(0..0),
1290 offset..offset + data.len(),
1291 );
1292 let mut pos = 0;
1293 while pos + 8 <= data.len() {
1294 let abs = offset + pos;
1295 buf.push_field(
1296 &EXT_COMMUNITY_ENTRY_DESCRIPTOR,
1297 FieldValue::Bytes(&data[pos..pos + 8]),
1298 abs..abs + 8,
1299 );
1300 pos += 8;
1301 }
1302 buf.end_container(array_idx);
1303 }
1304 17 => {
1306 let array_idx = buf.begin_container(
1307 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1308 FieldValue::Array(0..0),
1309 offset..offset + data.len(),
1310 );
1311 parse_as_path(buf, data, offset, 4);
1312 buf.end_container(array_idx);
1313 }
1314 18 if data.len() == 8 => {
1316 buf.push_field(
1317 &FD_AS4_AGGREGATOR_VALUE,
1318 FieldValue::Bytes(data),
1319 offset..offset + 8,
1320 );
1321 }
1322 32 if data.len() % 12 == 0 => {
1324 let array_idx = buf.begin_container(
1325 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1326 FieldValue::Array(0..0),
1327 offset..offset + data.len(),
1328 );
1329 let mut pos = 0;
1330 while pos + 12 <= data.len() {
1331 buf.push_field(
1332 &LARGE_COMMUNITY_ENTRY_DESCRIPTOR,
1333 FieldValue::Bytes(&data[pos..pos + 12]),
1334 offset + pos..offset + pos + 12,
1335 );
1336 pos += 12;
1337 }
1338 buf.end_container(array_idx);
1339 }
1340 40 => {
1342 parse_prefix_sid(buf, data, offset);
1343 }
1344 _ => {
1345 if !data.is_empty() {
1347 buf.push_field(
1348 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1349 FieldValue::Bytes(data),
1350 offset..offset + data.len(),
1351 );
1352 }
1353 }
1354 }
1355}
1356
1357fn mup_route_type_name(v: u16) -> Option<&'static str> {
1362 match v {
1363 1 => Some("Interwork Segment Discovery"),
1364 2 => Some("Direct Segment Discovery"),
1365 3 => Some("Type 1 Session Transformed"),
1366 4 => Some("Type 2 Session Transformed"),
1367 _ => None,
1368 }
1369}
1370
1371fn mup_architecture_type_name(v: u8) -> Option<&'static str> {
1375 match v {
1376 1 => Some("3gpp-5g"),
1377 _ => None,
1378 }
1379}
1380
1381fn parse_mup_nlri<'pkt>(
1388 buf: &mut DissectBuffer<'pkt>,
1389 data: &'pkt [u8],
1390 base_offset: usize,
1391 ipv6: bool,
1392) {
1393 let mut pos = 0;
1394
1395 while pos + 4 <= data.len() {
1396 let arch_type = data[pos];
1397 let route_type = read_be_u16(data, pos + 1).unwrap_or_default();
1398 let rt_len = data[pos + 3] as usize;
1399 let header_len = 4;
1400
1401 if pos + header_len + rt_len > data.len() {
1402 break;
1403 }
1404
1405 let abs = base_offset + pos;
1406 let rt_data = &data[pos + header_len..pos + header_len + rt_len];
1407 let total = header_len + rt_len;
1408
1409 let obj_idx = buf.begin_container(
1410 &MUP_NLRI_OBJECT_DESCRIPTOR,
1411 FieldValue::Object(0..0),
1412 abs..abs + total,
1413 );
1414
1415 buf.push_field(
1416 &MUP_NLRI_CHILDREN[FD_MUP_ARCH_TYPE],
1417 FieldValue::U8(arch_type),
1418 abs..abs + 1,
1419 );
1420 buf.push_field(
1421 &MUP_NLRI_CHILDREN[FD_MUP_ROUTE_TYPE],
1422 FieldValue::U16(route_type),
1423 abs + 1..abs + 3,
1424 );
1425
1426 let rt_offset = abs + header_len;
1427 parse_mup_route_type_data(buf, route_type, rt_data, rt_offset, ipv6);
1428
1429 buf.end_container(obj_idx);
1430
1431 pos += total;
1432 }
1433}
1434
1435fn parse_mup_route_type_data<'pkt>(
1439 buf: &mut DissectBuffer<'pkt>,
1440 route_type: u16,
1441 data: &'pkt [u8],
1442 offset: usize,
1443 ipv6: bool,
1444) {
1445 if data.len() < 8 {
1447 if !data.is_empty() {
1448 buf.push_field(
1449 &MUP_NLRI_CHILDREN[FD_MUP_VALUE],
1450 FieldValue::Bytes(data),
1451 offset..offset + data.len(),
1452 );
1453 }
1454 return;
1455 }
1456
1457 buf.push_field(
1458 &MUP_NLRI_CHILDREN[FD_MUP_RD],
1459 FieldValue::Bytes(&data[..8]),
1460 offset..offset + 8,
1461 );
1462
1463 let rest = &data[8..];
1464 let rest_offset = offset + 8;
1465
1466 match route_type {
1467 1 => {
1469 if rest.is_empty() {
1470 return;
1471 }
1472 let prefix_len = rest[0] as usize;
1473 let prefix_bytes = prefix_len.div_ceil(8);
1474 if 1 + prefix_bytes > rest.len() {
1475 return;
1476 }
1477 let prefix_descriptor = if ipv6 {
1478 &PREFIX_ENTRY_IPV6_DESCRIPTOR
1479 } else {
1480 &PREFIX_ENTRY_IPV4_DESCRIPTOR
1481 };
1482 buf.push_field(
1483 prefix_descriptor,
1484 FieldValue::Bytes(&rest[..1 + prefix_bytes]),
1485 rest_offset..rest_offset + 1 + prefix_bytes,
1486 );
1487 }
1488 2 => {
1490 let addr_len = if ipv6 { 16 } else { 4 };
1491 if rest.len() < addr_len {
1492 return;
1493 }
1494 if ipv6 {
1495 let addr = read_ipv6_addr(rest, 0).unwrap_or_default();
1496 buf.push_field(
1497 &MUP_NLRI_CHILDREN[FD_MUP_ADDRESS],
1498 FieldValue::Ipv6Addr(addr),
1499 rest_offset..rest_offset + 16,
1500 );
1501 } else {
1502 buf.push_field(
1503 &MUP_NLRI_CHILDREN[FD_MUP_ADDRESS],
1504 FieldValue::Ipv4Addr([rest[0], rest[1], rest[2], rest[3]]),
1505 rest_offset..rest_offset + 4,
1506 );
1507 }
1508 }
1509 3 => {
1511 if rest.is_empty() {
1512 return;
1513 }
1514 let prefix_len = rest[0] as usize;
1515 let prefix_bytes = prefix_len.div_ceil(8);
1516 if 1 + prefix_bytes > rest.len() {
1517 return;
1518 }
1519 let prefix_descriptor = if ipv6 {
1520 &PREFIX_ENTRY_IPV6_DESCRIPTOR
1521 } else {
1522 &PREFIX_ENTRY_IPV4_DESCRIPTOR
1523 };
1524 buf.push_field(
1525 prefix_descriptor,
1526 FieldValue::Bytes(&rest[..1 + prefix_bytes]),
1527 rest_offset..rest_offset + 1 + prefix_bytes,
1528 );
1529
1530 let arch_start = 1 + prefix_bytes;
1532 let arch_data = &rest[arch_start..];
1533 let arch_offset = rest_offset + arch_start;
1534 if arch_data.len() >= 6 {
1536 buf.push_field(
1537 &MUP_NLRI_CHILDREN[FD_MUP_TEID],
1538 FieldValue::Bytes(&arch_data[..4]),
1539 arch_offset..arch_offset + 4,
1540 );
1541 buf.push_field(
1542 &MUP_NLRI_CHILDREN[FD_MUP_QFI],
1543 FieldValue::U8(arch_data[4]),
1544 arch_offset + 4..arch_offset + 5,
1545 );
1546
1547 let ep_addr_bits = arch_data[5] as usize;
1548 let ep_addr_bytes = ep_addr_bits / 8;
1549 let ep_start = 6;
1550 if ep_start + ep_addr_bytes <= arch_data.len() {
1551 let ep_val = format_address(
1552 &arch_data[ep_start..ep_start + ep_addr_bytes],
1553 ep_addr_bits == 128,
1554 );
1555 buf.push_field(
1556 &MUP_NLRI_CHILDREN[FD_MUP_ENDPOINT_ADDRESS],
1557 ep_val,
1558 arch_offset + ep_start..arch_offset + ep_start + ep_addr_bytes,
1559 );
1560
1561 let src_start = ep_start + ep_addr_bytes;
1563 if src_start < arch_data.len() {
1564 let src_addr_bits = arch_data[src_start] as usize;
1565 if src_addr_bits > 0 {
1566 let src_addr_bytes = src_addr_bits / 8;
1567 let src_data_start = src_start + 1;
1568 if src_data_start + src_addr_bytes <= arch_data.len() {
1569 let src_val = format_address(
1570 &arch_data[src_data_start..src_data_start + src_addr_bytes],
1571 src_addr_bits == 128,
1572 );
1573 buf.push_field(
1574 &MUP_NLRI_CHILDREN[FD_MUP_SOURCE_ADDRESS],
1575 src_val,
1576 arch_offset + src_data_start
1577 ..arch_offset + src_data_start + src_addr_bytes,
1578 );
1579 }
1580 }
1581 }
1582 }
1583 }
1584 }
1585 4 => {
1587 if rest.is_empty() {
1588 return;
1589 }
1590 let ep_len_bits = rest[0] as usize;
1591 let ep_total_bytes = ep_len_bits.div_ceil(8);
1593 if 1 + ep_total_bytes > rest.len() {
1594 return;
1595 }
1596 let addr_bits = ep_len_bits.saturating_sub(32);
1598 let addr_bytes = addr_bits.div_ceil(8);
1599 if addr_bytes > 0 {
1600 let addr_val = format_address(&rest[1..1 + addr_bytes], addr_bits == 128);
1601 buf.push_field(
1602 &MUP_NLRI_CHILDREN[FD_MUP_ENDPOINT_ADDRESS],
1603 addr_val,
1604 rest_offset + 1..rest_offset + 1 + addr_bytes,
1605 );
1606 }
1607 let teid_start = 1 + addr_bytes;
1608 if teid_start + 4 <= rest.len() {
1609 buf.push_field(
1610 &MUP_NLRI_CHILDREN[FD_MUP_TEID],
1611 FieldValue::Bytes(&rest[teid_start..teid_start + 4]),
1612 rest_offset + teid_start..rest_offset + teid_start + 4,
1613 );
1614 }
1615 }
1616 _ => {
1617 if !rest.is_empty() {
1618 buf.push_field(
1619 &MUP_NLRI_CHILDREN[FD_MUP_VALUE],
1620 FieldValue::Bytes(rest),
1621 rest_offset..rest_offset + rest.len(),
1622 );
1623 }
1624 }
1625 }
1626}
1627
1628fn format_nlri_ipv4_prefix(
1635 value: &FieldValue<'_>,
1636 _ctx: &FormatContext<'_>,
1637 w: &mut dyn std::io::Write,
1638) -> std::io::Result<()> {
1639 let bytes = match value {
1640 FieldValue::Bytes(b) => *b,
1641 _ => return w.write_all(b"\"\""),
1642 };
1643 if bytes.is_empty() {
1644 return w.write_all(b"\"\"");
1645 }
1646 let prefix_len = bytes[0];
1647 let mut octets = [0u8; 4];
1648 let available = (bytes.len() - 1).min(4);
1649 octets[..available].copy_from_slice(&bytes[1..1 + available]);
1650 write!(
1651 w,
1652 "\"{}.{}.{}.{}/{}\"",
1653 octets[0], octets[1], octets[2], octets[3], prefix_len
1654 )
1655}
1656
1657fn format_nlri_ipv6_prefix(
1664 value: &FieldValue<'_>,
1665 _ctx: &FormatContext<'_>,
1666 w: &mut dyn std::io::Write,
1667) -> std::io::Result<()> {
1668 let bytes = match value {
1669 FieldValue::Bytes(b) => *b,
1670 _ => return w.write_all(b"\"\""),
1671 };
1672 if bytes.is_empty() {
1673 return w.write_all(b"\"\"");
1674 }
1675 let prefix_len = bytes[0];
1676 let mut addr = [0u8; 16];
1677 let available = (bytes.len() - 1).min(16);
1678 addr[..available].copy_from_slice(&bytes[1..1 + available]);
1679 write!(w, "\"{}/{}\"", FieldValue::Ipv6Addr(addr), prefix_len)
1681}
1682
1683fn format_address(data: &[u8], ipv6: bool) -> FieldValue<'_> {
1685 if ipv6 && data.len() == 16 {
1686 FieldValue::Ipv6Addr(read_ipv6_addr(data, 0).unwrap_or_default())
1687 } else if !ipv6 && data.len() == 4 {
1688 FieldValue::Ipv4Addr(read_ipv4_addr(data, 0).unwrap_or_default())
1689 } else {
1690 FieldValue::Bytes(data)
1691 }
1692}
1693
1694fn format_aggregator(
1701 value: &FieldValue<'_>,
1702 _ctx: &FormatContext<'_>,
1703 w: &mut dyn std::io::Write,
1704) -> std::io::Result<()> {
1705 let bytes = match value {
1706 FieldValue::Bytes(b) => *b,
1707 _ => return w.write_all(b"\"\""),
1708 };
1709 match bytes.len() {
1710 6 => {
1711 let asn = u16::from_be_bytes([bytes[0], bytes[1]]) as u32;
1712 write!(
1713 w,
1714 "\"{} {}.{}.{}.{}\"",
1715 asn, bytes[2], bytes[3], bytes[4], bytes[5]
1716 )
1717 }
1718 8 => {
1719 let asn = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
1720 write!(
1721 w,
1722 "\"{} {}.{}.{}.{}\"",
1723 asn, bytes[4], bytes[5], bytes[6], bytes[7]
1724 )
1725 }
1726 _ => w.write_all(b"\"\""),
1727 }
1728}
1729
1730fn format_ext_community(
1740 value: &FieldValue<'_>,
1741 _ctx: &FormatContext<'_>,
1742 w: &mut dyn std::io::Write,
1743) -> std::io::Result<()> {
1744 let bytes = match value {
1745 FieldValue::Bytes(b) if b.len() == 8 => *b,
1746 _ => return w.write_all(b"\"\""),
1747 };
1748 let type_high = bytes[0];
1749 match type_high {
1750 0x00 | 0x40 => {
1752 let asn = u16::from_be_bytes([bytes[2], bytes[3]]) as u32;
1753 let val = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
1754 write!(w, "\"{}:{}\"", asn, val)
1755 }
1756 0x01 | 0x41 => {
1758 let val = u16::from_be_bytes([bytes[6], bytes[7]]);
1759 write!(
1760 w,
1761 "\"{}.{}.{}.{}:{}\"",
1762 bytes[2], bytes[3], bytes[4], bytes[5], val
1763 )
1764 }
1765 0x02 | 0x42 => {
1767 let asn = u32::from_be_bytes([bytes[2], bytes[3], bytes[4], bytes[5]]);
1768 let val = u16::from_be_bytes([bytes[6], bytes[7]]);
1769 write!(w, "\"{}:{}\"", asn, val)
1770 }
1771 _ => {
1772 write!(w, "\"0x")?;
1773 for b in bytes {
1774 write!(w, "{b:02x}")?;
1775 }
1776 write!(w, "\"")
1777 }
1778 }
1779}
1780
1781fn format_large_community(
1787 value: &FieldValue<'_>,
1788 _ctx: &FormatContext<'_>,
1789 w: &mut dyn std::io::Write,
1790) -> std::io::Result<()> {
1791 let bytes = match value {
1792 FieldValue::Bytes(b) if b.len() == 12 => *b,
1793 _ => return w.write_all(b"\"\""),
1794 };
1795 let global = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
1796 let local1 = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
1797 let local2 = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
1798 write!(w, "\"{}:{}:{}\"", global, local1, local2)
1799}
1800
1801fn format_route_distinguisher(
1810 value: &FieldValue<'_>,
1811 _ctx: &FormatContext<'_>,
1812 w: &mut dyn std::io::Write,
1813) -> std::io::Result<()> {
1814 let bytes = match value {
1815 FieldValue::Bytes(b) if b.len() == 8 => *b,
1816 _ => return w.write_all(b"\"\""),
1817 };
1818 let rd_type = u16::from_be_bytes([bytes[0], bytes[1]]);
1819 match rd_type {
1820 0 => {
1821 let asn = u16::from_be_bytes([bytes[2], bytes[3]]) as u32;
1822 let val = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
1823 write!(w, "\"0:{}:{}\"", asn, val)
1824 }
1825 1 => {
1826 let val = u16::from_be_bytes([bytes[6], bytes[7]]);
1827 write!(
1828 w,
1829 "\"1:{}.{}.{}.{}:{}\"",
1830 bytes[2], bytes[3], bytes[4], bytes[5], val
1831 )
1832 }
1833 2 => {
1834 let asn = u32::from_be_bytes([bytes[2], bytes[3], bytes[4], bytes[5]]);
1835 let val = u16::from_be_bytes([bytes[6], bytes[7]]);
1836 write!(w, "\"2:{}:{}\"", asn, val)
1837 }
1838 _ => {
1839 write!(w, "\"{rd_type}:0x")?;
1840 for b in &bytes[2..] {
1841 write!(w, "{b:02x}")?;
1842 }
1843 write!(w, "\"")
1844 }
1845 }
1846}
1847
1848fn format_teid(
1852 value: &FieldValue<'_>,
1853 _ctx: &FormatContext<'_>,
1854 w: &mut dyn std::io::Write,
1855) -> std::io::Result<()> {
1856 let bytes = match value {
1857 FieldValue::Bytes(b) if b.len() == 4 => *b,
1858 _ => return w.write_all(b"\"\""),
1859 };
1860 let val = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
1861 write!(w, "\"0x{val:08x}\"")
1862}
1863
1864fn parse_mp_reach_nlri<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
1868 let afi = read_be_u16(data, 0).unwrap_or_default();
1869 let safi = data[2];
1870 let nh_len = data[3] as usize;
1871
1872 let obj_idx = buf.begin_container(
1873 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1874 FieldValue::Object(0..0),
1875 offset..offset + data.len(),
1876 );
1877
1878 buf.push_field(
1879 &MP_CHILDREN[FD_MP_AFI],
1880 FieldValue::U16(afi),
1881 offset..offset + 2,
1882 );
1883 buf.push_field(
1884 &MP_CHILDREN[FD_MP_SAFI],
1885 FieldValue::U8(safi),
1886 offset + 2..offset + 3,
1887 );
1888
1889 let nh_start = 4;
1890 let nh_end = nh_start + nh_len;
1891 if nh_end > data.len() {
1892 buf.end_container(obj_idx);
1893 return;
1894 }
1895
1896 let nh_data = &data[nh_start..nh_end];
1898 if afi == 1 && nh_len == 4 {
1899 buf.push_field(
1901 &MP_CHILDREN[FD_MP_NEXT_HOP],
1902 FieldValue::Ipv4Addr([nh_data[0], nh_data[1], nh_data[2], nh_data[3]]),
1903 offset + nh_start..offset + nh_end,
1904 );
1905 } else if afi == 2 && (nh_len == 16 || nh_len == 32) {
1906 let addr = read_ipv6_addr(nh_data, 0).unwrap_or_default();
1908 buf.push_field(
1909 &MP_CHILDREN[FD_MP_NEXT_HOP],
1910 FieldValue::Ipv6Addr(addr),
1911 offset + nh_start..offset + nh_start + 16,
1912 );
1913 if nh_len == 32 {
1914 let ll_addr = read_ipv6_addr(nh_data, 16).unwrap_or_default();
1915 buf.push_field(
1916 &MP_CHILDREN[FD_MP_NEXT_HOP_LINK_LOCAL],
1917 FieldValue::Ipv6Addr(ll_addr),
1918 offset + nh_start + 16..offset + nh_end,
1919 );
1920 }
1921 } else {
1922 buf.push_field(
1923 &MP_CHILDREN[FD_MP_NEXT_HOP],
1924 FieldValue::Bytes(nh_data),
1925 offset + nh_start..offset + nh_end,
1926 );
1927 }
1928
1929 let nlri_start = nh_end + 1;
1931 if nlri_start < data.len() {
1932 let nlri_data = &data[nlri_start..];
1933 let is_mup = safi == 85;
1934 let is_ip = afi == 1 || afi == 2;
1935 if is_mup || is_ip {
1936 let array_idx = buf.begin_container(
1937 &MP_CHILDREN[FD_MP_NLRI],
1938 FieldValue::Array(0..0),
1939 offset + nlri_start..offset + data.len(),
1940 );
1941 let before = buf.field_count();
1942 if is_mup {
1943 parse_mup_nlri(buf, nlri_data, offset + nlri_start, afi == 2);
1944 } else {
1945 parse_prefixes(buf, nlri_data, offset + nlri_start, afi == 2);
1946 }
1947 if buf.field_count() == before {
1948 buf.pop_field(); } else {
1950 buf.end_container(array_idx);
1951 }
1952 }
1953 }
1954
1955 buf.end_container(obj_idx);
1956}
1957
1958fn parse_mp_unreach_nlri<'pkt>(buf: &mut DissectBuffer<'pkt>, data: &'pkt [u8], offset: usize) {
1962 let afi = read_be_u16(data, 0).unwrap_or_default();
1963 let safi = data[2];
1964
1965 let obj_idx = buf.begin_container(
1966 &PATH_ATTR_CHILDREN[FD_PA_VALUE],
1967 FieldValue::Object(0..0),
1968 offset..offset + data.len(),
1969 );
1970
1971 buf.push_field(
1972 &MP_CHILDREN[FD_MP_AFI],
1973 FieldValue::U16(afi),
1974 offset..offset + 2,
1975 );
1976 buf.push_field(
1977 &MP_CHILDREN[FD_MP_SAFI],
1978 FieldValue::U8(safi),
1979 offset + 2..offset + 3,
1980 );
1981
1982 let wr_start = 3;
1983 if wr_start < data.len() {
1984 let wr_data = &data[wr_start..];
1985 let is_mup = safi == 85;
1986 let is_ip = afi == 1 || afi == 2;
1987 if is_mup || is_ip {
1988 let array_idx = buf.begin_container(
1989 &MP_CHILDREN[FD_MP_WITHDRAWN_ROUTES],
1990 FieldValue::Array(0..0),
1991 offset + wr_start..offset + data.len(),
1992 );
1993 let before = buf.field_count();
1994 if is_mup {
1995 parse_mup_nlri(buf, wr_data, offset + wr_start, afi == 2);
1996 } else {
1997 parse_prefixes(buf, wr_data, offset + wr_start, afi == 2);
1998 }
1999 if buf.field_count() == before {
2000 buf.pop_field(); } else {
2002 buf.end_container(array_idx);
2003 }
2004 }
2005 }
2006
2007 buf.end_container(obj_idx);
2008}
2009
2010fn parse_update<'pkt>(
2014 buf: &mut DissectBuffer<'pkt>,
2015 data: &'pkt [u8],
2016 offset: usize,
2017) -> Result<(), PacketError> {
2018 if data.len() < MIN_UPDATE_SIZE {
2019 return Err(PacketError::Truncated {
2020 expected: MIN_UPDATE_SIZE,
2021 actual: data.len(),
2022 });
2023 }
2024
2025 let withdrawn_len = read_be_u16(data, 19)? as usize;
2026 buf.push_field(
2027 &FIELD_DESCRIPTORS[FD_WITHDRAWN_ROUTES_LENGTH],
2028 FieldValue::U16(withdrawn_len as u16),
2029 offset + 19..offset + 21,
2030 );
2031
2032 let wr_start = 21;
2033 let wr_end = wr_start + withdrawn_len;
2034
2035 if data.len() < wr_end + 2 {
2036 return Err(PacketError::Truncated {
2037 expected: wr_end + 2,
2038 actual: data.len(),
2039 });
2040 }
2041
2042 if withdrawn_len > 0 {
2044 let array_idx = buf.begin_container(
2045 &FIELD_DESCRIPTORS[FD_WITHDRAWN_ROUTES],
2046 FieldValue::Array(0..0),
2047 offset + wr_start..offset + wr_end,
2048 );
2049 let before = buf.field_count();
2050 parse_prefixes(buf, &data[wr_start..wr_end], offset + wr_start, false);
2051 if buf.field_count() == before {
2052 buf.pop_field();
2053 } else {
2054 buf.end_container(array_idx);
2055 }
2056 }
2057
2058 let path_attr_len = read_be_u16(data, wr_end)? as usize;
2059 buf.push_field(
2060 &FIELD_DESCRIPTORS[FD_TOTAL_PATH_ATTRIBUTE_LENGTH],
2061 FieldValue::U16(path_attr_len as u16),
2062 offset + wr_end..offset + wr_end + 2,
2063 );
2064
2065 let pa_start = wr_end + 2;
2066 let pa_end = pa_start + path_attr_len;
2067
2068 if data.len() < pa_end {
2069 return Err(PacketError::Truncated {
2070 expected: pa_end,
2071 actual: data.len(),
2072 });
2073 }
2074
2075 if path_attr_len > 0 {
2077 let array_idx = buf.begin_container(
2078 &FIELD_DESCRIPTORS[FD_PATH_ATTRIBUTES],
2079 FieldValue::Array(0..0),
2080 offset + pa_start..offset + pa_end,
2081 );
2082 let before = buf.field_count();
2083 let mut pos = 0;
2084 let attr_data = &data[pa_start..pa_end];
2085 while pos < attr_data.len() {
2086 if let Some(consumed) =
2087 parse_path_attribute(buf, &attr_data[pos..], offset + pa_start + pos)
2088 {
2089 pos += consumed;
2090 } else {
2091 break;
2092 }
2093 }
2094 if buf.field_count() == before {
2095 buf.pop_field();
2096 } else {
2097 buf.end_container(array_idx);
2098 }
2099 }
2100
2101 let nlri_start = pa_end;
2103 let nlri_end = data.len();
2104 if nlri_start < nlri_end {
2105 let array_idx = buf.begin_container(
2106 &FIELD_DESCRIPTORS[FD_NLRI],
2107 FieldValue::Array(0..0),
2108 offset + nlri_start..offset + nlri_end,
2109 );
2110 let before = buf.field_count();
2111 parse_prefixes(buf, &data[nlri_start..nlri_end], offset + nlri_start, false);
2112 if buf.field_count() == before {
2113 buf.pop_field();
2114 } else {
2115 buf.end_container(array_idx);
2116 }
2117 }
2118
2119 Ok(())
2120}
2121
2122static OPT_PARAM_OBJECT_DESCRIPTOR: FieldDescriptor =
2124 FieldDescriptor::new("capability", "Capability", FieldType::Object)
2125 .with_children(OPT_PARAM_CHILDREN);
2126
2127static PATH_ATTR_OBJECT_DESCRIPTOR: FieldDescriptor =
2129 FieldDescriptor::new("path_attribute", "Path Attribute", FieldType::Object)
2130 .with_children(PATH_ATTR_CHILDREN);
2131
2132static PREFIX_ENTRY_IPV4_DESCRIPTOR: FieldDescriptor =
2136 FieldDescriptor::new("prefix", "Prefix", FieldType::Bytes)
2137 .with_format_fn(format_nlri_ipv4_prefix);
2138
2139static PREFIX_ENTRY_IPV6_DESCRIPTOR: FieldDescriptor =
2143 FieldDescriptor::new("prefix", "Prefix", FieldType::Bytes)
2144 .with_format_fn(format_nlri_ipv6_prefix);
2145
2146static AS_PATH_SEG_OBJECT_DESCRIPTOR: FieldDescriptor =
2148 FieldDescriptor::new("segment", "Segment", FieldType::Object)
2149 .with_children(AS_PATH_SEG_CHILDREN);
2150
2151static AS_NUMBER_DESCRIPTOR: FieldDescriptor =
2153 FieldDescriptor::new("asn", "AS Number", FieldType::U32);
2154
2155static COMMUNITY_ENTRY_DESCRIPTOR: FieldDescriptor =
2157 FieldDescriptor::new("community", "Community", FieldType::U32).with_display_fn(
2158 |v, _| match v {
2159 FieldValue::U32(c) => well_known_community_name(*c),
2160 _ => None,
2161 },
2162 );
2163
2164static CLUSTER_ID_DESCRIPTOR: FieldDescriptor =
2166 FieldDescriptor::new("cluster_id", "Cluster ID", FieldType::Ipv4Addr);
2167
2168static EXT_COMMUNITY_ENTRY_DESCRIPTOR: FieldDescriptor =
2170 FieldDescriptor::new("ext_community", "Extended Community", FieldType::Bytes)
2171 .with_display_fn(|v, _| match v {
2172 FieldValue::Bytes(b) if b.len() >= 2 => extended_community_type_name(b[0], b[1]),
2173 _ => None,
2174 })
2175 .with_format_fn(format_ext_community);
2176
2177static LARGE_COMMUNITY_ENTRY_DESCRIPTOR: FieldDescriptor =
2179 FieldDescriptor::new("large_community", "Large Community", FieldType::Bytes)
2180 .with_format_fn(format_large_community);
2181
2182static MUP_NLRI_OBJECT_DESCRIPTOR: FieldDescriptor =
2184 FieldDescriptor::new("mup_entry", "MUP Entry", FieldType::Object)
2185 .with_children(MUP_NLRI_CHILDREN);
2186
2187static PREFIX_SID_TLV_OBJECT_DESCRIPTOR: FieldDescriptor =
2189 FieldDescriptor::new("tlv", "TLV", FieldType::Object).with_children(PREFIX_SID_TLV_CHILDREN);
2190
2191static SRGB_ENTRY_OBJECT_DESCRIPTOR: FieldDescriptor =
2193 FieldDescriptor::new("srgb_entry", "SRGB Entry", FieldType::Object)
2194 .with_children(SRGB_ENTRY_CHILDREN);
2195
2196static SRV6_SID_INFO_OBJECT_DESCRIPTOR: FieldDescriptor =
2198 FieldDescriptor::new("sub_tlv", "Sub-TLV", FieldType::Object)
2199 .with_children(SRV6_SID_INFO_CHILDREN);
2200
2201const FD_NCP_PARAM_TYPE: usize = 0;
2203const FD_NCP_VALUE: usize = 1;
2204
2205static NON_CAP_PARAM_CHILDREN: &[FieldDescriptor] = &[
2207 FieldDescriptor::new("param_type", "Parameter Type", FieldType::U8),
2208 FieldDescriptor::new("value", "Value", FieldType::Bytes),
2209];
2210
2211const FD_APS_SEGMENT_TYPE: usize = 0;
2213const FD_APS_AS_NUMBERS: usize = 1;
2214
2215static AS_PATH_SEG_CHILDREN: &[FieldDescriptor] = &[
2217 FieldDescriptor {
2218 name: "segment_type",
2219 display_name: "Segment Type",
2220 field_type: FieldType::U8,
2221 optional: false,
2222 children: None,
2223 display_fn: Some(|v, _siblings| match v {
2224 FieldValue::U8(t) => as_path_segment_type_name(*t),
2225 _ => None,
2226 }),
2227 format_fn: None,
2228 },
2229 FieldDescriptor::new("as_numbers", "AS Numbers", FieldType::Array),
2230];
2231
2232const FD_MUP_ARCH_TYPE: usize = 0;
2234const FD_MUP_ROUTE_TYPE: usize = 1;
2235const FD_MUP_VALUE: usize = 2;
2236const FD_MUP_RD: usize = 3;
2237const FD_MUP_ADDRESS: usize = 5;
2238const FD_MUP_TEID: usize = 6;
2239const FD_MUP_QFI: usize = 7;
2240const FD_MUP_ENDPOINT_ADDRESS: usize = 8;
2241const FD_MUP_SOURCE_ADDRESS: usize = 9;
2242
2243static MUP_NLRI_CHILDREN: &[FieldDescriptor] = &[
2245 FieldDescriptor {
2246 name: "architecture_type",
2247 display_name: "Architecture Type",
2248 field_type: FieldType::U8,
2249 optional: false,
2250 children: None,
2251 display_fn: Some(|v, _siblings| match v {
2252 FieldValue::U8(a) => mup_architecture_type_name(*a),
2253 _ => None,
2254 }),
2255 format_fn: None,
2256 },
2257 FieldDescriptor {
2258 name: "route_type",
2259 display_name: "Route Type",
2260 field_type: FieldType::U16,
2261 optional: false,
2262 children: None,
2263 display_fn: Some(|v, _siblings| match v {
2264 FieldValue::U16(r) => mup_route_type_name(*r),
2265 _ => None,
2266 }),
2267 format_fn: None,
2268 },
2269 FieldDescriptor::new("value", "Value", FieldType::Bytes).optional(),
2270 FieldDescriptor::new("rd", "Route Distinguisher", FieldType::Bytes)
2271 .optional()
2272 .with_format_fn(format_route_distinguisher),
2273 FieldDescriptor::new("prefix", "Prefix", FieldType::Bytes).optional(),
2274 FieldDescriptor::new("address", "Address", FieldType::Bytes).optional(),
2275 FieldDescriptor::new("teid", "TEID", FieldType::Bytes)
2276 .optional()
2277 .with_format_fn(format_teid),
2278 FieldDescriptor::new("qfi", "QFI", FieldType::U8).optional(),
2279 FieldDescriptor::new("endpoint_address", "Endpoint Address", FieldType::Bytes).optional(),
2280 FieldDescriptor::new("source_address", "Source Address", FieldType::Bytes).optional(),
2281];
2282
2283const FD_PSID_TYPE: usize = 0;
2285const FD_PSID_LENGTH: usize = 1;
2286const FD_PSID_FLAGS: usize = 2;
2287const FD_PSID_LABEL_INDEX: usize = 3;
2288const FD_PSID_SRGB_ENTRIES: usize = 4;
2289const FD_PSID_SUB_TLVS: usize = 5;
2290const FD_PSID_VALUE: usize = 6;
2291
2292static PREFIX_SID_TLV_CHILDREN: &[FieldDescriptor] = &[
2297 FieldDescriptor::new("type", "Type", FieldType::U8),
2298 FieldDescriptor::new("length", "Length", FieldType::U16),
2299 FieldDescriptor::new("flags", "Flags", FieldType::U16).optional(),
2300 FieldDescriptor::new("label_index", "Label Index", FieldType::U32).optional(),
2301 FieldDescriptor::new("srgb_entries", "SRGB Entries", FieldType::Array)
2302 .optional()
2303 .with_children(SRGB_ENTRY_CHILDREN),
2304 FieldDescriptor::new("sub_tlvs", "Sub-TLVs", FieldType::Array)
2305 .optional()
2306 .with_children(SRV6_SID_INFO_CHILDREN),
2307 FieldDescriptor::new("value", "Value", FieldType::Bytes).optional(),
2308];
2309
2310const FD_SRGB_BASE: usize = 0;
2312const FD_SRGB_RANGE: usize = 1;
2313
2314static SRGB_ENTRY_CHILDREN: &[FieldDescriptor] = &[
2318 FieldDescriptor::new("base", "SRGB Base", FieldType::U32),
2319 FieldDescriptor::new("range", "SRGB Range", FieldType::U32),
2320];
2321
2322const FD_SRV6_SI_TYPE: usize = 0;
2324const FD_SRV6_SI_LENGTH: usize = 1;
2325const FD_SRV6_SI_SID: usize = 2;
2326const FD_SRV6_SI_FLAGS: usize = 3;
2327const FD_SRV6_SI_ENDPOINT_BEHAVIOR: usize = 4;
2328const FD_SRV6_SI_SID_STRUCTURE: usize = 5;
2329const FD_SRV6_SI_VALUE: usize = 6;
2330
2331static SRV6_SID_INFO_CHILDREN: &[FieldDescriptor] = &[
2335 FieldDescriptor::new("type", "Type", FieldType::U8),
2336 FieldDescriptor::new("length", "Length", FieldType::U16),
2337 FieldDescriptor::new("srv6_sid", "SRv6 SID", FieldType::Ipv6Addr).optional(),
2338 FieldDescriptor::new("sid_flags", "Service SID Flags", FieldType::U8).optional(),
2339 FieldDescriptor::new("endpoint_behavior", "Endpoint Behavior", FieldType::U16).optional(),
2340 FieldDescriptor::new("sid_structure", "SID Structure", FieldType::Object)
2341 .optional()
2342 .with_children(SRV6_SID_STRUCTURE_CHILDREN),
2343 FieldDescriptor::new("value", "Value", FieldType::Bytes).optional(),
2344];
2345
2346const FD_SRV6_SS_LBL: usize = 0;
2348const FD_SRV6_SS_LNL: usize = 1;
2349const FD_SRV6_SS_FL: usize = 2;
2350const FD_SRV6_SS_AL: usize = 3;
2351const FD_SRV6_SS_TL: usize = 4;
2352const FD_SRV6_SS_TO: usize = 5;
2353
2354static SRV6_SID_STRUCTURE_CHILDREN: &[FieldDescriptor] = &[
2358 FieldDescriptor::new(
2359 "locator_block_length",
2360 "Locator Block Length",
2361 FieldType::U8,
2362 ),
2363 FieldDescriptor::new("locator_node_length", "Locator Node Length", FieldType::U8),
2364 FieldDescriptor::new("function_length", "Function Length", FieldType::U8),
2365 FieldDescriptor::new("argument_length", "Argument Length", FieldType::U8),
2366 FieldDescriptor::new(
2367 "transposition_length",
2368 "Transposition Length",
2369 FieldType::U8,
2370 ),
2371 FieldDescriptor::new(
2372 "transposition_offset",
2373 "Transposition Offset",
2374 FieldType::U8,
2375 ),
2376];
2377
2378const FD_MP_AFI: usize = 0;
2380const FD_MP_SAFI: usize = 1;
2381const FD_MP_NEXT_HOP: usize = 2;
2382const FD_MP_NEXT_HOP_LINK_LOCAL: usize = 3;
2383const FD_MP_NLRI: usize = 4;
2384const FD_MP_WITHDRAWN_ROUTES: usize = 5;
2385
2386static MP_CHILDREN: &[FieldDescriptor] = &[
2388 FieldDescriptor::new("afi", "AFI", FieldType::U16),
2389 FieldDescriptor::new("safi", "SAFI", FieldType::U8),
2390 FieldDescriptor::new("next_hop", "Next Hop", FieldType::Bytes).optional(),
2391 FieldDescriptor::new(
2392 "next_hop_link_local",
2393 "Next Hop Link-Local",
2394 FieldType::Bytes,
2395 )
2396 .optional(),
2397 FieldDescriptor::new("nlri", "NLRI", FieldType::Array).optional(),
2398 FieldDescriptor::new("withdrawn_routes", "Withdrawn Routes", FieldType::Array).optional(),
2399];
2400
2401const FD_OPT_CODE: usize = 0;
2403const FD_OPT_LENGTH: usize = 1;
2404const FD_OPT_VALUE: usize = 2;
2405
2406static OPT_PARAM_CHILDREN: &[FieldDescriptor] = &[
2408 FieldDescriptor::new("code", "Code", FieldType::U8),
2409 FieldDescriptor::new("length", "Length", FieldType::U8),
2410 FieldDescriptor::new("value", "Value", FieldType::Bytes).optional(),
2411];
2412
2413const FD_PA_FLAGS: usize = 0;
2415const FD_PA_TYPE_CODE: usize = 1;
2416const FD_PA_ATTR_LENGTH: usize = 2;
2417const FD_PA_VALUE: usize = 3;
2418
2419static FD_ORIGIN_VALUE: FieldDescriptor = FieldDescriptor::new("value", "Value", FieldType::U8)
2421 .with_display_fn(|v, _| match v {
2422 FieldValue::U8(o) => origin_name(*o),
2423 _ => None,
2424 });
2425
2426static FD_AGGREGATOR_VALUE: FieldDescriptor =
2430 FieldDescriptor::new("value", "Value", FieldType::Bytes)
2431 .optional()
2432 .with_format_fn(format_aggregator);
2433
2434static FD_AS4_AGGREGATOR_VALUE: FieldDescriptor =
2438 FieldDescriptor::new("value", "Value", FieldType::Bytes)
2439 .optional()
2440 .with_format_fn(format_aggregator);
2441
2442static PATH_ATTR_CHILDREN: &[FieldDescriptor] = &[
2444 FieldDescriptor::new("flags", "Flags", FieldType::U8),
2445 FieldDescriptor {
2446 name: "type_code",
2447 display_name: "Type Code",
2448 field_type: FieldType::U8,
2449 optional: false,
2450 children: None,
2451 display_fn: Some(|v, _siblings| match v {
2452 FieldValue::U8(t) => path_attr_type_name(*t),
2453 _ => None,
2454 }),
2455 format_fn: None,
2456 },
2457 FieldDescriptor::new("attr_length", "Attribute Length", FieldType::U16),
2458 FieldDescriptor::new("value", "Value", FieldType::Bytes).optional(),
2459];
2460
2461const FD_MARKER: usize = 0;
2463const FD_LENGTH: usize = 1;
2464const FD_TYPE: usize = 2;
2465const FD_VERSION: usize = 3;
2467const FD_MY_AS: usize = 4;
2468const FD_HOLD_TIME: usize = 5;
2469const FD_BGP_IDENTIFIER: usize = 6;
2470const FD_OPT_PARAMS_LENGTH: usize = 7;
2471const FD_EXT_OPT_PARAMS_LENGTH: usize = 8;
2472const FD_OPTIONAL_PARAMETERS: usize = 9;
2473const FD_ERROR_CODE: usize = 10;
2475const FD_ERROR_SUBCODE: usize = 11;
2476const FD_DATA: usize = 12;
2477const FD_AFI: usize = 13;
2479const FD_SAFI: usize = 14;
2480const FD_MESSAGE_SUBTYPE: usize = 15;
2481const FD_WITHDRAWN_ROUTES_LENGTH: usize = 16;
2483const FD_WITHDRAWN_ROUTES: usize = 17;
2484const FD_TOTAL_PATH_ATTRIBUTE_LENGTH: usize = 18;
2485const FD_PATH_ATTRIBUTES: usize = 19;
2486const FD_NLRI: usize = 20;
2487
2488static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
2490 FieldDescriptor::new("marker", "Marker", FieldType::Bytes),
2492 FieldDescriptor::new("length", "Length", FieldType::U16),
2493 FieldDescriptor {
2494 name: "type",
2495 display_name: "Type",
2496 field_type: FieldType::U8,
2497 optional: false,
2498 children: None,
2499 display_fn: Some(|v, _siblings| match v {
2500 FieldValue::U8(t) => msg_type_name(*t),
2501 _ => None,
2502 }),
2503 format_fn: None,
2504 },
2505 FieldDescriptor::new("version", "Version", FieldType::U8).optional(),
2507 FieldDescriptor::new("my_as", "My AS", FieldType::U16).optional(),
2508 FieldDescriptor::new("hold_time", "Hold Time", FieldType::U16).optional(),
2509 FieldDescriptor::new("bgp_identifier", "BGP Identifier", FieldType::Ipv4Addr).optional(),
2510 FieldDescriptor::new(
2511 "opt_params_length",
2512 "Optional Parameters Length",
2513 FieldType::U8,
2514 )
2515 .optional(),
2516 FieldDescriptor::new(
2519 "ext_opt_params_length",
2520 "Extended Optional Parameters Length",
2521 FieldType::U16,
2522 )
2523 .optional(),
2524 FieldDescriptor::new(
2525 "optional_parameters",
2526 "Optional Parameters",
2527 FieldType::Array,
2528 )
2529 .optional()
2530 .with_children(OPT_PARAM_CHILDREN),
2531 FieldDescriptor {
2533 name: "error_code",
2534 display_name: "Error Code",
2535 field_type: FieldType::U8,
2536 optional: true,
2537 children: None,
2538 display_fn: Some(|v, _siblings| match v {
2539 FieldValue::U8(c) => error_code_name(*c),
2540 _ => None,
2541 }),
2542 format_fn: None,
2543 },
2544 FieldDescriptor {
2548 name: "error_subcode",
2549 display_name: "Error Subcode",
2550 field_type: FieldType::U8,
2551 optional: true,
2552 children: None,
2553 display_fn: Some(|v, siblings| {
2554 let FieldValue::U8(subcode) = v else {
2555 return None;
2556 };
2557 let error_code = siblings
2558 .iter()
2559 .find(|f| f.name() == "error_code")
2560 .and_then(|f| f.value.as_u8())?;
2561 if error_code == 6 {
2562 cease_subcode_name(*subcode)
2563 } else {
2564 None
2565 }
2566 }),
2567 format_fn: None,
2568 },
2569 FieldDescriptor::new("data", "Data", FieldType::Bytes).optional(),
2570 FieldDescriptor {
2572 name: "afi",
2573 display_name: "AFI",
2574 field_type: FieldType::U16,
2575 optional: true,
2576 children: None,
2577 display_fn: Some(|v, _siblings| match v {
2578 FieldValue::U16(a) => afi_name(*a),
2579 _ => None,
2580 }),
2581 format_fn: None,
2582 },
2583 FieldDescriptor {
2584 name: "safi",
2585 display_name: "SAFI",
2586 field_type: FieldType::U8,
2587 optional: true,
2588 children: None,
2589 display_fn: Some(|v, _siblings| match v {
2590 FieldValue::U8(s) => safi_name(*s),
2591 _ => None,
2592 }),
2593 format_fn: None,
2594 },
2595 FieldDescriptor {
2597 name: "message_subtype",
2598 display_name: "Message Subtype",
2599 field_type: FieldType::U8,
2600 optional: true,
2601 children: None,
2602 display_fn: Some(|v, _siblings| match v {
2603 FieldValue::U8(s) => route_refresh_subtype_name(*s),
2604 _ => None,
2605 }),
2606 format_fn: None,
2607 },
2608 FieldDescriptor::new(
2610 "withdrawn_routes_length",
2611 "Withdrawn Routes Length",
2612 FieldType::U16,
2613 )
2614 .optional(),
2615 FieldDescriptor::new("withdrawn_routes", "Withdrawn Routes", FieldType::Array).optional(),
2616 FieldDescriptor::new(
2617 "total_path_attribute_length",
2618 "Total Path Attribute Length",
2619 FieldType::U16,
2620 )
2621 .optional(),
2622 FieldDescriptor::new("path_attributes", "Path Attributes", FieldType::Array)
2623 .optional()
2624 .with_children(PATH_ATTR_CHILDREN),
2625 FieldDescriptor::new("nlri", "NLRI", FieldType::Array).optional(),
2626];
2627
2628fn dissect_one_message<'pkt>(
2633 data: &'pkt [u8],
2634 buf: &mut DissectBuffer<'pkt>,
2635 offset: usize,
2636) -> Result<usize, PacketError> {
2637 if data.len() < HEADER_SIZE {
2638 return Err(PacketError::Truncated {
2639 expected: HEADER_SIZE,
2640 actual: data.len(),
2641 });
2642 }
2643
2644 if data[..16] != MARKER {
2646 return Err(PacketError::InvalidHeader("BGP marker must be all 0xFF"));
2647 }
2648
2649 let length = read_be_u16(data, 16)?;
2650
2651 if (length as usize) < HEADER_SIZE {
2654 return Err(PacketError::InvalidFieldValue {
2655 field: "length",
2656 value: length as u32,
2657 });
2658 }
2659 if length as usize > data.len() {
2660 return Err(PacketError::Truncated {
2661 expected: length as usize,
2662 actual: data.len(),
2663 });
2664 }
2665
2666 let msg_type = data[18];
2667 let msg_len = length as usize;
2668 let msg_data = &data[..msg_len];
2669 let consumed = msg_data.len();
2670
2671 buf.begin_layer("BGP", None, FIELD_DESCRIPTORS, offset..offset + consumed);
2672
2673 buf.push_field(
2674 &FIELD_DESCRIPTORS[FD_MARKER],
2675 FieldValue::Bytes(&data[..16]),
2676 offset..offset + 16,
2677 );
2678 buf.push_field(
2679 &FIELD_DESCRIPTORS[FD_LENGTH],
2680 FieldValue::U16(length),
2681 offset + 16..offset + 18,
2682 );
2683 buf.push_field(
2684 &FIELD_DESCRIPTORS[FD_TYPE],
2685 FieldValue::U8(msg_type),
2686 offset + 18..offset + 19,
2687 );
2688
2689 match msg_type {
2690 MSG_OPEN => parse_open(buf, msg_data, offset)?,
2691 MSG_UPDATE => parse_update(buf, msg_data, offset)?,
2692 MSG_NOTIFICATION => parse_notification(buf, msg_data, offset)?,
2693 MSG_ROUTE_REFRESH => parse_route_refresh(buf, msg_data, offset)?,
2694 _ => {}
2695 }
2696
2697 buf.end_layer();
2698
2699 Ok(consumed)
2700}
2701
2702pub struct BgpDissector;
2704
2705impl Dissector for BgpDissector {
2706 fn name(&self) -> &'static str {
2707 "Border Gateway Protocol"
2708 }
2709
2710 fn short_name(&self) -> &'static str {
2711 "BGP"
2712 }
2713
2714 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
2715 FIELD_DESCRIPTORS
2716 }
2717
2718 fn dissect<'pkt>(
2719 &self,
2720 data: &'pkt [u8],
2721 buf: &mut DissectBuffer<'pkt>,
2722 offset: usize,
2723 ) -> Result<DissectResult, PacketError> {
2724 let mut pos = 0;
2725
2726 while pos + HEADER_SIZE <= data.len() {
2729 let consumed = dissect_one_message(&data[pos..], buf, offset + pos)?;
2730 pos += consumed;
2731 }
2732
2733 if pos == 0 {
2734 return Err(PacketError::Truncated {
2735 expected: HEADER_SIZE,
2736 actual: data.len(),
2737 });
2738 }
2739
2740 Ok(DissectResult::new(pos, DispatchHint::End))
2741 }
2742}
2743
2744#[cfg(test)]
2745mod tests {
2746 use super::*;
2747 use packet_dissector_core::field::Field;
2748
2749 fn nested_field_by_name<'a, 'pkt>(
2750 buf: &'a DissectBuffer<'pkt>,
2751 range: &core::ops::Range<u32>,
2752 name: &str,
2753 ) -> &'a Field<'pkt> {
2754 buf.nested_fields(range)
2755 .iter()
2756 .find(|f| f.name() == name)
2757 .unwrap_or_else(|| panic!("field '{}' not found", name))
2758 }
2759
2760 fn build_keepalive() -> Vec<u8> {
2762 let mut raw = vec![0xFF; 16]; raw.extend_from_slice(&19u16.to_be_bytes()); raw.push(4); raw
2766 }
2767
2768 #[test]
2769 fn parse_bgp_keepalive() {
2770 let data = build_keepalive();
2771 let mut buf = DissectBuffer::new();
2772 let result = BgpDissector.dissect(&data, &mut buf, 0).unwrap();
2773
2774 assert_eq!(result.bytes_consumed, 19);
2775 assert!(matches!(result.next, DispatchHint::End));
2776 assert_eq!(buf.layers().len(), 1);
2777
2778 let layer = &buf.layers()[0];
2779 assert_eq!(layer.name, "BGP");
2780 assert_eq!(
2781 buf.field_by_name(layer, "length").unwrap().value,
2782 FieldValue::U16(19)
2783 );
2784 assert_eq!(
2785 buf.field_by_name(layer, "type").unwrap().value,
2786 FieldValue::U8(4)
2787 );
2788 assert_eq!(
2789 buf.resolve_display_name(layer, "type_name"),
2790 Some("KEEPALIVE")
2791 );
2792 }
2793
2794 fn build_open_basic() -> Vec<u8> {
2796 let mut raw = vec![0xFF; 16]; raw.extend_from_slice(&29u16.to_be_bytes()); raw.push(1); raw.push(4); raw.extend_from_slice(&65001u16.to_be_bytes()); raw.extend_from_slice(&180u16.to_be_bytes()); raw.extend_from_slice(&[10, 0, 0, 1]); raw.push(0); raw
2805 }
2806
2807 fn build_open_with_capabilities() -> Vec<u8> {
2809 let cap_mp = [1, 4, 0, 1, 0, 1]; let as4_bytes = 65582u32.to_be_bytes();
2812 let cap_as4 = [
2813 65,
2814 4,
2815 as4_bytes[0],
2816 as4_bytes[1],
2817 as4_bytes[2],
2818 as4_bytes[3],
2819 ];
2820
2821 let cap_param_len = cap_mp.len() + cap_as4.len();
2823 let opt_params_len = 2 + cap_param_len; let total_len = 29 + opt_params_len;
2826 let mut raw = vec![0xFF; 16];
2827 raw.extend_from_slice(&(total_len as u16).to_be_bytes());
2828 raw.push(1); raw.push(4); raw.extend_from_slice(&65001u16.to_be_bytes()); raw.extend_from_slice(&180u16.to_be_bytes()); raw.extend_from_slice(&[10, 0, 0, 1]); raw.push(opt_params_len as u8); raw.push(2); raw.push(cap_param_len as u8);
2836 raw.extend_from_slice(&cap_mp);
2837 raw.extend_from_slice(&cap_as4);
2838 raw
2839 }
2840
2841 #[test]
2842 fn parse_bgp_open_basic() {
2843 let data = build_open_basic();
2844 let mut buf = DissectBuffer::new();
2845 let result = BgpDissector.dissect(&data, &mut buf, 0).unwrap();
2846
2847 assert_eq!(result.bytes_consumed, 29);
2848 let layer = &buf.layers()[0];
2849 assert_eq!(buf.resolve_display_name(layer, "type_name"), Some("OPEN"));
2850 assert_eq!(
2851 buf.field_by_name(layer, "version").unwrap().value,
2852 FieldValue::U8(4)
2853 );
2854 assert_eq!(
2855 buf.field_by_name(layer, "my_as").unwrap().value,
2856 FieldValue::U16(65001)
2857 );
2858 assert_eq!(
2859 buf.field_by_name(layer, "hold_time").unwrap().value,
2860 FieldValue::U16(180)
2861 );
2862 assert_eq!(
2863 buf.field_by_name(layer, "bgp_identifier").unwrap().value,
2864 FieldValue::Ipv4Addr([10, 0, 0, 1])
2865 );
2866 assert_eq!(
2867 buf.field_by_name(layer, "opt_params_length").unwrap().value,
2868 FieldValue::U8(0)
2869 );
2870 assert!(buf.field_by_name(layer, "optional_parameters").is_none());
2871 }
2872
2873 #[test]
2874 fn parse_bgp_open_with_capabilities() {
2875 let data = build_open_with_capabilities();
2876 let mut buf = DissectBuffer::new();
2877 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
2878
2879 let layer = &buf.layers()[0];
2880 let params = buf.field_by_name(layer, "optional_parameters").unwrap();
2881 let FieldValue::Array(ref arr_range) = params.value else {
2882 panic!("expected Array");
2883 };
2884 let objects: Vec<_> = buf
2886 .nested_fields(arr_range)
2887 .iter()
2888 .filter(|f| f.value.is_object())
2889 .collect();
2890 assert_eq!(objects.len(), 2);
2891 let cap1_range = objects[0].value.as_container_range().unwrap();
2893 assert_eq!(
2894 *nested_field_value(&buf, cap1_range, "code"),
2895 FieldValue::U8(1)
2896 );
2897 let val = nested_field_value(&buf, cap1_range, "value");
2899 assert_eq!(*val, FieldValue::Bytes(&[0, 1, 0, 1]));
2900 let cap2_range = objects[1].value.as_container_range().unwrap();
2902 assert_eq!(
2903 *nested_field_value(&buf, cap2_range, "code"),
2904 FieldValue::U8(65)
2905 );
2906 let as4_val = nested_field_value(&buf, cap2_range, "value");
2908 assert_eq!(*as4_val, FieldValue::Bytes(&65582u32.to_be_bytes()));
2909 }
2910
2911 #[test]
2912 fn parse_bgp_open_extended_optional_parameters() {
2913 let cap_mp = [1u8, 4, 0, 1, 0, 1]; let cap_param_value = cap_mp;
2923 let ext_param_hdr_len = 1 + 2 ;
2924 let ext_param_total_len = ext_param_hdr_len + cap_param_value.len();
2925 let ext_opt_params_len = ext_param_total_len; let total_len = 29 + 1 + 2 + ext_opt_params_len;
2930
2931 let mut raw = vec![0xFF; 16];
2932 raw.extend_from_slice(&(total_len as u16).to_be_bytes());
2933 raw.push(1); raw.push(4); raw.extend_from_slice(&65001u16.to_be_bytes()); raw.extend_from_slice(&180u16.to_be_bytes()); raw.extend_from_slice(&[10, 0, 0, 1]); raw.push(255); raw.push(255); raw.extend_from_slice(&(ext_opt_params_len as u16).to_be_bytes()); raw.push(2); raw.extend_from_slice(&(cap_param_value.len() as u16).to_be_bytes());
2944 raw.extend_from_slice(&cap_param_value);
2945
2946 let mut buf = DissectBuffer::new();
2947 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
2948
2949 let layer = &buf.layers()[0];
2950 assert_eq!(buf.resolve_display_name(layer, "type_name"), Some("OPEN"));
2951 assert_eq!(
2953 buf.field_by_name(layer, "opt_params_length").unwrap().value,
2954 FieldValue::U8(255)
2955 );
2956 assert_eq!(
2958 buf.field_by_name(layer, "ext_opt_params_length")
2959 .unwrap()
2960 .value,
2961 FieldValue::U16(ext_opt_params_len as u16)
2962 );
2963 let params = buf.field_by_name(layer, "optional_parameters").unwrap();
2965 let FieldValue::Array(ref arr_range) = params.value else {
2966 panic!("expected Array");
2967 };
2968 let objects: Vec<_> = buf
2969 .nested_fields(arr_range)
2970 .iter()
2971 .filter(|f| f.value.is_object())
2972 .collect();
2973 assert_eq!(objects.len(), 1);
2974 let cap_range = objects[0].value.as_container_range().unwrap();
2975 assert_eq!(
2976 *nested_field_value(&buf, cap_range, "code"),
2977 FieldValue::U8(1)
2978 );
2979 assert_eq!(
2980 *nested_field_value(&buf, cap_range, "value"),
2981 FieldValue::Bytes(&[0, 1, 0, 1])
2982 );
2983 }
2984
2985 #[test]
2986 fn parse_bgp_notification() {
2987 let mut raw = vec![0xFF; 16];
2988 raw.extend_from_slice(&23u16.to_be_bytes()); raw.push(3); raw.push(6); raw.push(2); raw.extend_from_slice(&[0xDE, 0xAD]); let mut buf = DissectBuffer::new();
2995 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
2996
2997 let layer = &buf.layers()[0];
2998 assert_eq!(
2999 buf.resolve_display_name(layer, "type_name"),
3000 Some("NOTIFICATION")
3001 );
3002 assert_eq!(
3003 buf.field_by_name(layer, "error_code").unwrap().value,
3004 FieldValue::U8(6)
3005 );
3006 assert_eq!(
3007 buf.resolve_display_name(layer, "error_code_name"),
3008 Some("Cease")
3009 );
3010 assert_eq!(
3011 buf.field_by_name(layer, "error_subcode").unwrap().value,
3012 FieldValue::U8(2)
3013 );
3014 assert_eq!(
3017 buf.field_by_name(layer, "data").unwrap().value,
3018 FieldValue::Bytes(&[0xDE, 0xAD])
3019 );
3020 }
3021
3022 #[test]
3023 fn parse_bgp_notification_cease_subcode_name() {
3024 let mut raw = vec![0xFF; 16];
3026 raw.extend_from_slice(&21u16.to_be_bytes()); raw.push(3); raw.push(6); raw.push(2); let mut buf = DissectBuffer::new();
3032 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3033 let layer = &buf.layers()[0];
3034 assert_eq!(
3035 buf.resolve_display_name(layer, "error_subcode_name"),
3036 Some("Administrative Shutdown")
3037 );
3038
3039 let mut raw = vec![0xFF; 16];
3041 raw.extend_from_slice(&21u16.to_be_bytes());
3042 raw.push(3); raw.push(6); raw.push(9); let mut buf = DissectBuffer::new();
3047 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3048 let layer = &buf.layers()[0];
3049 assert_eq!(
3050 buf.resolve_display_name(layer, "error_subcode_name"),
3051 Some("Hard Reset")
3052 );
3053
3054 let mut raw = vec![0xFF; 16];
3057 raw.extend_from_slice(&21u16.to_be_bytes());
3058 raw.push(3); raw.push(1); raw.push(2); let mut buf = DissectBuffer::new();
3063 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3064 let layer = &buf.layers()[0];
3065 assert_eq!(buf.resolve_display_name(layer, "error_subcode_name"), None);
3066 }
3067
3068 #[test]
3069 fn parse_bgp_route_refresh() {
3070 let mut raw = vec![0xFF; 16];
3071 raw.extend_from_slice(&23u16.to_be_bytes()); raw.push(5); raw.extend_from_slice(&1u16.to_be_bytes()); raw.push(0); raw.push(1); let mut buf = DissectBuffer::new();
3078 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3079
3080 let layer = &buf.layers()[0];
3081 assert_eq!(
3082 buf.resolve_display_name(layer, "type_name"),
3083 Some("ROUTE-REFRESH")
3084 );
3085 assert_eq!(
3086 buf.field_by_name(layer, "afi").unwrap().value,
3087 FieldValue::U16(1)
3088 );
3089 assert_eq!(buf.resolve_display_name(layer, "afi_name"), Some("IPv4"));
3090 assert_eq!(
3091 buf.field_by_name(layer, "safi").unwrap().value,
3092 FieldValue::U8(1)
3093 );
3094 assert_eq!(
3095 buf.resolve_display_name(layer, "safi_name"),
3096 Some("Unicast")
3097 );
3098 }
3099
3100 #[test]
3101 fn parse_bgp_route_refresh_subtype_borr() {
3102 let mut raw = vec![0xFF; 16];
3105 raw.extend_from_slice(&23u16.to_be_bytes()); raw.push(5); raw.extend_from_slice(&1u16.to_be_bytes()); raw.push(1); raw.push(1); let mut buf = DissectBuffer::new();
3112 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3113
3114 let layer = &buf.layers()[0];
3115 assert_eq!(
3116 buf.field_by_name(layer, "message_subtype").unwrap().value,
3117 FieldValue::U8(1)
3118 );
3119 assert_eq!(
3120 buf.resolve_display_name(layer, "message_subtype_name"),
3121 Some("BoRR")
3122 );
3123 assert_eq!(
3124 buf.field_by_name(layer, "safi").unwrap().value,
3125 FieldValue::U8(1)
3126 );
3127 }
3128
3129 #[test]
3130 fn parse_bgp_update_withdraw() {
3131 let mut raw = vec![0xFF; 16];
3133 let withdrawn = [8, 10]; let total_len = 19 + 2 + withdrawn.len() + 2; raw.extend_from_slice(&(total_len as u16).to_be_bytes());
3136 raw.push(2); raw.extend_from_slice(&(withdrawn.len() as u16).to_be_bytes()); raw.extend_from_slice(&withdrawn);
3139 raw.extend_from_slice(&0u16.to_be_bytes()); let mut buf = DissectBuffer::new();
3142 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3143
3144 let layer = &buf.layers()[0];
3145 assert_eq!(
3146 buf.field_by_name(layer, "withdrawn_routes_length")
3147 .unwrap()
3148 .value,
3149 FieldValue::U16(2)
3150 );
3151 let wr = buf.field_by_name(layer, "withdrawn_routes").unwrap();
3152 let FieldValue::Array(ref arr_range) = wr.value else {
3153 panic!("expected Array");
3154 };
3155 let arr = buf.nested_fields(arr_range);
3156 assert_eq!(arr.len(), 1);
3157 assert_eq!(arr[0].value, FieldValue::Bytes(&[8, 10]));
3159 assert!(buf.field_by_name(layer, "nlri").is_none());
3160 }
3161
3162 #[test]
3163 fn parse_bgp_update_announce() {
3164 let mut raw = vec![0xFF; 16];
3166
3167 let attr = [0x40, 0x01, 0x01, 0x00]; let nlri = [24, 192, 168, 1]; let total_len = 19 + 2 + 2 + attr.len() + nlri.len();
3174 raw.extend_from_slice(&(total_len as u16).to_be_bytes());
3175 raw.push(2); raw.extend_from_slice(&0u16.to_be_bytes()); raw.extend_from_slice(&(attr.len() as u16).to_be_bytes()); raw.extend_from_slice(&attr);
3179 raw.extend_from_slice(&nlri);
3180
3181 let mut buf = DissectBuffer::new();
3182 BgpDissector.dissect(&raw, &mut buf, 0).unwrap();
3183
3184 let layer = &buf.layers()[0];
3185 assert_eq!(
3186 buf.field_by_name(layer, "total_path_attribute_length")
3187 .unwrap()
3188 .value,
3189 FieldValue::U16(attr.len() as u16)
3190 );
3191
3192 let pa = buf.field_by_name(layer, "path_attributes").unwrap();
3194 let FieldValue::Array(ref arr_range) = pa.value else {
3195 panic!("expected Array");
3196 };
3197 let pa_objects: Vec<_> = buf
3198 .nested_fields(arr_range)
3199 .iter()
3200 .filter(|f| f.value.is_object())
3201 .collect();
3202 assert_eq!(pa_objects.len(), 1);
3203
3204 let nlri_field = buf.field_by_name(layer, "nlri").unwrap();
3206 let FieldValue::Array(ref nlri_range) = nlri_field.value else {
3207 panic!("expected Array");
3208 };
3209 let nlri_entries = buf.nested_fields(nlri_range);
3210 assert_eq!(nlri_entries.len(), 1);
3211 assert_eq!(nlri_entries[0].value, FieldValue::Bytes(&[24, 192, 168, 1]));
3213 }
3214
3215 fn first_pa_obj_range(buf: &DissectBuffer<'_>) -> core::ops::Range<u32> {
3217 let layer = &buf.layers()[0];
3218 let pa = buf.field_by_name(layer, "path_attributes").unwrap();
3219 let FieldValue::Array(ref arr_range) = pa.value else {
3220 panic!("expected Array for path_attributes")
3221 };
3222 let nested = buf.nested_fields(arr_range);
3223 let FieldValue::Object(ref obj_range) = nested[0].value else {
3224 panic!("expected Object for first path_attribute")
3225 };
3226 obj_range.clone()
3227 }
3228
3229 fn nested_field_value<'a, 'pkt>(
3231 buf: &'a DissectBuffer<'pkt>,
3232 range: &core::ops::Range<u32>,
3233 name: &str,
3234 ) -> &'a FieldValue<'pkt> {
3235 &nested_field_by_name(buf, range, name).value
3236 }
3237
3238 fn build_update(attrs: &[u8], nlri: &[u8]) -> Vec<u8> {
3240 let total_len = 19 + 2 + 2 + attrs.len() + nlri.len();
3241 let mut raw = vec![0xFF; 16];
3242 raw.extend_from_slice(&(total_len as u16).to_be_bytes());
3243 raw.push(2); raw.extend_from_slice(&0u16.to_be_bytes()); raw.extend_from_slice(&(attrs.len() as u16).to_be_bytes());
3246 raw.extend_from_slice(attrs);
3247 raw.extend_from_slice(nlri);
3248 raw
3249 }
3250
3251 fn build_attr(flags: u8, type_code: u8, value: &[u8]) -> Vec<u8> {
3253 let mut raw = vec![flags, type_code];
3254 if flags & 0x10 != 0 {
3255 raw.extend_from_slice(&(value.len() as u16).to_be_bytes());
3256 } else {
3257 raw.push(value.len() as u8);
3258 }
3259 raw.extend_from_slice(value);
3260 raw
3261 }
3262
3263 #[test]
3264 fn parse_bgp_update_origin() {
3265 let attr = build_attr(0x40, 1, &[0]); let data = build_update(&attr, &[]);
3267 let mut buf = DissectBuffer::new();
3268 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3269
3270 let obj_range = first_pa_obj_range(&buf);
3271 assert_eq!(
3273 *nested_field_value(&buf, &obj_range, "value"),
3274 FieldValue::U8(0)
3275 );
3276 }
3277
3278 #[test]
3279 fn parse_bgp_update_as_path() {
3280 let mut as_path_value = vec![2, 2]; as_path_value.extend_from_slice(&65001u16.to_be_bytes());
3282 as_path_value.extend_from_slice(&65002u16.to_be_bytes());
3283 let attr = build_attr(0x40, 2, &as_path_value);
3284 let data = build_update(&attr, &[]);
3285 let mut buf = DissectBuffer::new();
3286 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3287
3288 let obj_range = first_pa_obj_range(&buf);
3289 let FieldValue::Array(ref segs_range) = *nested_field_value(&buf, &obj_range, "value")
3290 else {
3291 panic!("expected Array for AS_PATH");
3292 };
3293 let segs: Vec<_> = buf
3295 .nested_fields(segs_range)
3296 .iter()
3297 .filter(|f| f.value.is_object())
3298 .collect();
3299 assert_eq!(segs.len(), 1);
3300 let seg_range = segs[0].value.as_container_range().unwrap();
3301 assert_eq!(
3302 *nested_field_value(&buf, seg_range, "segment_type"),
3303 FieldValue::U8(2)
3304 ); let asns_field = nested_field_by_name(&buf, seg_range, "as_numbers");
3306 let asns_range = asns_field.value.as_container_range().unwrap();
3307 let asns = buf.nested_fields(asns_range);
3308 assert_eq!(asns.len(), 2);
3309 assert_eq!(asns[0].value, FieldValue::U32(65001));
3310 assert_eq!(asns[1].value, FieldValue::U32(65002));
3311 }
3312
3313 #[test]
3314 fn parse_bgp_update_next_hop() {
3315 let attr = build_attr(0x40, 3, &[10, 0, 0, 1]);
3316 let data = build_update(&attr, &[]);
3317 let mut buf = DissectBuffer::new();
3318 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3319
3320 let obj_range = first_pa_obj_range(&buf);
3321 assert_eq!(
3322 *nested_field_value(&buf, &obj_range, "value"),
3323 FieldValue::Ipv4Addr([10, 0, 0, 1])
3324 );
3325 }
3326
3327 #[test]
3328 fn parse_bgp_update_communities() {
3329 let mut val = Vec::new();
3330 val.extend_from_slice(&((65001u32 << 16) | 100).to_be_bytes());
3331 val.extend_from_slice(&0xFFFFFF01u32.to_be_bytes()); let attr = build_attr(0xC0, 8, &val);
3333 let data = build_update(&attr, &[]);
3334 let mut buf = DissectBuffer::new();
3335 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3336
3337 let obj_range = first_pa_obj_range(&buf);
3338 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
3339 else {
3340 panic!("expected Array for communities");
3341 };
3342 let comms = buf.nested_fields(comms_range);
3343 assert_eq!(comms.len(), 2);
3344 assert_eq!(comms[0].value, FieldValue::U32((65001 << 16) | 100));
3345 assert_eq!(comms[1].value, FieldValue::U32(0xFFFFFF01));
3346 }
3347
3348 #[test]
3349 fn parse_bgp_update_extended_communities() {
3350 let mut val = vec![0x00, 0x02];
3351 val.extend_from_slice(&65001u16.to_be_bytes());
3352 val.extend_from_slice(&100u32.to_be_bytes());
3353 val.extend_from_slice(&[0x03, 0x0B, 0x00, 0x00]);
3354 val.extend_from_slice(&1000u32.to_be_bytes());
3355 let attr = build_attr(0xC0, 16, &val);
3356 let data = build_update(&attr, &[]);
3357 let mut buf = DissectBuffer::new();
3358 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3359
3360 let obj_range = first_pa_obj_range(&buf);
3361 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
3362 else {
3363 panic!("expected Array for extended communities");
3364 };
3365 let comms = buf.nested_fields(comms_range);
3366 assert_eq!(comms.len(), 2);
3367 assert_eq!(comms[0].value, FieldValue::Bytes(&val[0..8]));
3369 assert_eq!(comms[1].value, FieldValue::Bytes(&val[8..16]));
3370 }
3371
3372 #[test]
3373 fn parse_bgp_update_large_community() {
3374 let mut val = Vec::new();
3375 val.extend_from_slice(&64496u32.to_be_bytes());
3376 val.extend_from_slice(&100u32.to_be_bytes());
3377 val.extend_from_slice(&200u32.to_be_bytes());
3378 let attr = build_attr(0xC0, 32, &val);
3379 let data = build_update(&attr, &[]);
3380 let mut buf = DissectBuffer::new();
3381 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3382
3383 let obj_range = first_pa_obj_range(&buf);
3384 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
3385 else {
3386 panic!("expected Array for large communities");
3387 };
3388 let comms = buf.nested_fields(comms_range);
3389 assert_eq!(comms.len(), 1);
3390 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
3391 }
3392
3393 #[test]
3394 fn parse_bgp_update_mp_reach_ipv6() {
3395 let mut val = Vec::new();
3396 val.extend_from_slice(&2u16.to_be_bytes());
3397 val.push(1);
3398 val.push(16);
3399 val.extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
3400 val.push(0);
3401 val.push(48);
3402 val.extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01]);
3403
3404 let attr = build_attr(0x80 | 0x10, 14, &val);
3405 let data = build_update(&attr, &[]);
3406 let mut buf = DissectBuffer::new();
3407 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3408
3409 let obj_range = first_pa_obj_range(&buf);
3410 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
3411 else {
3412 panic!("expected Object for MP_REACH");
3413 };
3414 assert_eq!(
3415 *nested_field_value(&buf, mp_range, "afi"),
3416 FieldValue::U16(2)
3417 );
3418 let expected_nh = [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
3419 assert_eq!(
3420 *nested_field_value(&buf, mp_range, "next_hop"),
3421 FieldValue::Ipv6Addr(expected_nh)
3422 );
3423 let FieldValue::Array(ref prefixes_range) = *nested_field_value(&buf, mp_range, "nlri")
3424 else {
3425 panic!("expected Array for NLRI");
3426 };
3427 let prefixes = buf.nested_fields(prefixes_range);
3428 assert_eq!(prefixes.len(), 1);
3429 assert_eq!(
3430 prefixes[0].value,
3431 FieldValue::Bytes(&[48, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01])
3432 );
3433 }
3434
3435 #[test]
3436 fn parse_bgp_truncated_open() {
3437 let mut data = vec![0xFF; 16];
3438 data.extend_from_slice(&29u16.to_be_bytes());
3439 data.push(1);
3440 data.extend_from_slice(&[4, 0, 1]);
3441 let mut buf = DissectBuffer::new();
3442 let err = BgpDissector.dissect(&data, &mut buf, 0).unwrap_err();
3443 assert!(matches!(err, PacketError::Truncated { .. }));
3444 }
3445
3446 #[test]
3447 fn parse_bgp_truncated_header() {
3448 let data = vec![0xFF; 10];
3449 let mut buf = DissectBuffer::new();
3450 let err = BgpDissector.dissect(&data, &mut buf, 0).unwrap_err();
3451 assert!(matches!(
3452 err,
3453 PacketError::Truncated {
3454 expected: 19,
3455 actual: 10
3456 }
3457 ));
3458 }
3459
3460 #[test]
3461 fn parse_bgp_invalid_marker() {
3462 let mut data = build_keepalive();
3463 data[0] = 0x00;
3464 let mut buf = DissectBuffer::new();
3465 let err = BgpDissector.dissect(&data, &mut buf, 0).unwrap_err();
3466 assert!(matches!(err, PacketError::InvalidHeader(_)));
3467 }
3468
3469 #[test]
3470 fn parse_bgp_multiple_messages() {
3471 let mut data = build_keepalive();
3472 data.extend_from_slice(&build_keepalive());
3473
3474 let mut buf = DissectBuffer::new();
3475 let result = BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3476
3477 assert_eq!(result.bytes_consumed, 38);
3478 assert_eq!(buf.layers().len(), 2);
3479 assert_eq!(buf.layers()[0].name, "BGP");
3480 assert_eq!(buf.layers()[1].name, "BGP");
3481 assert_eq!(
3482 buf.resolve_display_name(&buf.layers()[0], "type_name"),
3483 Some("KEEPALIVE")
3484 );
3485 assert_eq!(
3486 buf.resolve_display_name(&buf.layers()[1], "type_name"),
3487 Some("KEEPALIVE")
3488 );
3489 assert_eq!(buf.layers()[0].range, 0..19);
3490 assert_eq!(buf.layers()[1].range, 19..38);
3491 }
3492
3493 #[test]
3494 fn parse_bgp_open_followed_by_keepalive() {
3495 let mut data = build_open_basic();
3496 data.extend_from_slice(&build_keepalive());
3497
3498 let mut buf = DissectBuffer::new();
3499 let result = BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3500
3501 assert_eq!(result.bytes_consumed, 48);
3502 assert_eq!(buf.layers().len(), 2);
3503 assert_eq!(
3504 buf.resolve_display_name(&buf.layers()[0], "type_name"),
3505 Some("OPEN")
3506 );
3507 assert_eq!(
3508 buf.resolve_display_name(&buf.layers()[1], "type_name"),
3509 Some("KEEPALIVE")
3510 );
3511 }
3512
3513 #[test]
3514 fn parse_bgp_update_mup_interwork_segment_discovery() {
3515 let mut val = Vec::new();
3516 val.extend_from_slice(&1u16.to_be_bytes());
3517 val.push(85);
3518 val.push(4);
3519 val.extend_from_slice(&[10, 0, 0, 1]);
3520 val.push(0);
3521 val.push(1);
3522 val.extend_from_slice(&1u16.to_be_bytes());
3523 val.push(12);
3524 val.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 1]);
3525 val.push(24);
3526 val.extend_from_slice(&[192, 168, 1]);
3527
3528 let attr = build_attr(0x80 | 0x10, 14, &val);
3529 let data = build_update(&attr, &[]);
3530 let mut buf = DissectBuffer::new();
3531 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3532
3533 let obj_range = first_pa_obj_range(&buf);
3534 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
3535 else {
3536 panic!("expected Object for MP_REACH");
3537 };
3538 assert_eq!(
3539 *nested_field_value(&buf, mp_range, "safi"),
3540 FieldValue::U8(85)
3541 );
3542 let FieldValue::Array(ref entries_range) = *nested_field_value(&buf, mp_range, "nlri")
3543 else {
3544 panic!("expected Array for MUP NLRI");
3545 };
3546 let entries: Vec<_> = buf
3547 .nested_fields(entries_range)
3548 .iter()
3549 .filter(|f| f.value.is_object())
3550 .collect();
3551 assert_eq!(entries.len(), 1);
3552 let entry_range = entries[0].value.as_container_range().unwrap();
3553 assert_eq!(
3555 *nested_field_value(&buf, entry_range, "prefix"),
3556 FieldValue::Bytes(&[24, 192, 168, 1])
3557 );
3558 }
3559
3560 #[test]
3561 fn parse_bgp_update_mup_type1_st() {
3562 let mut val = Vec::new();
3563 val.extend_from_slice(&1u16.to_be_bytes());
3564 val.push(85);
3565 val.push(4);
3566 val.extend_from_slice(&[10, 0, 0, 1]);
3567 val.push(0);
3568 val.push(1);
3569 val.extend_from_slice(&3u16.to_be_bytes());
3570 let rt_len = 8 + 1 + 4 + 4 + 1 + 1 + 4;
3571 val.push(rt_len as u8);
3572 val.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 1]);
3573 val.push(32);
3574 val.extend_from_slice(&[10, 1, 1, 1]);
3575 val.extend_from_slice(&0x12345678u32.to_be_bytes());
3576 val.push(9);
3577 val.push(32);
3578 val.extend_from_slice(&[10, 0, 0, 2]);
3579
3580 let attr = build_attr(0x80 | 0x10, 14, &val);
3581 let data = build_update(&attr, &[]);
3582 let mut buf = DissectBuffer::new();
3583 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3584
3585 let obj_range = first_pa_obj_range(&buf);
3586 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
3587 else {
3588 panic!("expected Object for MP_REACH");
3589 };
3590 let FieldValue::Array(ref entries_range) = *nested_field_value(&buf, mp_range, "nlri")
3591 else {
3592 panic!("expected Array for MUP NLRI");
3593 };
3594 let entry_objs: Vec<_> = buf
3595 .nested_fields(entries_range)
3596 .iter()
3597 .filter(|f| f.value.is_object())
3598 .collect();
3599 let entry_range = entry_objs[0].value.as_container_range().unwrap();
3600 assert_eq!(
3601 *nested_field_value(&buf, entry_range, "prefix"),
3602 FieldValue::Bytes(&[32, 10, 1, 1, 1])
3603 );
3604 assert_eq!(
3606 *nested_field_value(&buf, entry_range, "teid"),
3607 FieldValue::Bytes(&0x12345678u32.to_be_bytes())
3608 );
3609 assert_eq!(
3610 *nested_field_value(&buf, entry_range, "qfi"),
3611 FieldValue::U8(9)
3612 );
3613 assert_eq!(
3614 *nested_field_value(&buf, entry_range, "endpoint_address"),
3615 FieldValue::Ipv4Addr([10, 0, 0, 2])
3616 );
3617 }
3618
3619 #[test]
3620 fn parse_bgp_update_mup_extended_community() {
3621 let mut val = vec![0x0C, 0x00];
3622 val.extend_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
3623 let attr = build_attr(0xC0, 16, &val);
3624 let data = build_update(&attr, &[]);
3625 let mut buf = DissectBuffer::new();
3626 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3627
3628 let obj_range = first_pa_obj_range(&buf);
3629 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
3630 else {
3631 panic!("expected Array for extended communities");
3632 };
3633 let comms = buf.nested_fields(comms_range);
3634 assert_eq!(comms.len(), 1);
3635 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
3636 }
3637
3638 fn build_psid_tlv(tlv_type: u8, value: &[u8]) -> Vec<u8> {
3641 let mut raw = vec![tlv_type];
3642 raw.extend_from_slice(&(value.len() as u16).to_be_bytes());
3643 raw.extend_from_slice(value);
3644 raw
3645 }
3646
3647 fn extract_pa_value<'a, 'pkt>(buf: &'a DissectBuffer<'pkt>) -> &'a FieldValue<'pkt> {
3649 let obj_range = first_pa_obj_range(buf);
3650 nested_field_value(buf, &obj_range, "value")
3651 }
3652
3653 #[test]
3654 fn parse_bgp_prefix_sid_label_index() {
3655 let mut val = vec![0x00];
3656 val.extend_from_slice(&0u16.to_be_bytes());
3657 val.extend_from_slice(&100u32.to_be_bytes());
3658 let tlv = build_psid_tlv(1, &val);
3659 let attr = build_attr(0xC0, 40, &tlv);
3660 let data = build_update(&attr, &[]);
3661 let mut buf = DissectBuffer::new();
3662 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3663
3664 let pa_value = extract_pa_value(&buf);
3665 let FieldValue::Array(tlvs_range) = pa_value else {
3666 panic!("expected Array");
3667 };
3668 let tlvs = buf.nested_fields(tlvs_range);
3669 assert!(tlvs[0].value.is_object());
3670 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3671 panic!("expected Object");
3672 };
3673 assert_eq!(
3674 *nested_field_value(&buf, obj_range, "type"),
3675 FieldValue::U8(1)
3676 );
3677 assert_eq!(
3678 *nested_field_value(&buf, obj_range, "label_index"),
3679 FieldValue::U32(100)
3680 );
3681 assert_eq!(
3682 *nested_field_value(&buf, obj_range, "flags"),
3683 FieldValue::U16(0)
3684 );
3685 }
3686
3687 #[test]
3688 fn parse_bgp_prefix_sid_originator_srgb() {
3689 let mut val = vec![0x00, 0x00];
3690 val.push(0x00);
3691 val.push(0x3E);
3692 val.push(0x80);
3693 val.push(0x00);
3694 val.push(0x1F);
3695 val.push(0x40);
3696 let tlv = build_psid_tlv(3, &val);
3697 let attr = build_attr(0xC0, 40, &tlv);
3698 let data = build_update(&attr, &[]);
3699 let mut buf = DissectBuffer::new();
3700 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3701
3702 let pa_value = extract_pa_value(&buf);
3703 let FieldValue::Array(tlvs_range) = pa_value else {
3704 panic!("expected Array");
3705 };
3706 let tlvs = buf.nested_fields(tlvs_range);
3707 assert!(tlvs[0].value.is_object());
3708 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3709 panic!("expected Object");
3710 };
3711 assert_eq!(
3712 *nested_field_value(&buf, obj_range, "type"),
3713 FieldValue::U8(3)
3714 );
3715 let entries_field = nested_field_by_name(&buf, obj_range, "srgb_entries");
3716 let FieldValue::Array(ref srgbs_range) = entries_field.value else {
3717 panic!("expected Array");
3718 };
3719 let srgbs = buf.nested_fields(srgbs_range);
3720 assert!(srgbs[0].value.is_object());
3721 let FieldValue::Object(ref entry_range) = srgbs[0].value else {
3722 panic!("expected Object");
3723 };
3724 assert_eq!(
3725 *nested_field_value(&buf, entry_range, "base"),
3726 FieldValue::U32(16000)
3727 );
3728 assert_eq!(
3729 *nested_field_value(&buf, entry_range, "range"),
3730 FieldValue::U32(8000)
3731 );
3732 }
3733
3734 #[test]
3735 fn parse_bgp_prefix_sid_srv6_l3_service() {
3736 let mut sid_info_val = vec![0x00];
3737 sid_info_val
3738 .extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
3739 sid_info_val.push(0x00);
3740 sid_info_val.extend_from_slice(&0x0029u16.to_be_bytes());
3741 sid_info_val.push(0x00);
3742 let sub_tlv = build_psid_tlv(1, &sid_info_val);
3743 let mut service_val = vec![0x00];
3744 service_val.extend_from_slice(&sub_tlv);
3745 let tlv = build_psid_tlv(5, &service_val);
3746 let attr = build_attr(0xC0 | 0x10, 40, &tlv);
3747 let data = build_update(&attr, &[]);
3748 let mut buf = DissectBuffer::new();
3749 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3750
3751 let pa_value = extract_pa_value(&buf);
3752 let FieldValue::Array(tlvs_range) = pa_value else {
3753 panic!("expected Array");
3754 };
3755 let tlvs = buf.nested_fields(tlvs_range);
3756 assert!(tlvs[0].value.is_object());
3757 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3758 panic!("expected Object");
3759 };
3760 let sub_tlvs_field = nested_field_by_name(&buf, obj_range, "sub_tlvs");
3761 let FieldValue::Array(ref subs_range) = sub_tlvs_field.value else {
3762 panic!("expected Array");
3763 };
3764 let subs = buf.nested_fields(subs_range);
3765 assert!(subs[0].value.is_object());
3766 let FieldValue::Object(ref si_range) = subs[0].value else {
3767 panic!("expected Object");
3768 };
3769 let expected_sid = [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
3770 assert_eq!(
3771 *nested_field_value(&buf, si_range, "srv6_sid"),
3772 FieldValue::Ipv6Addr(expected_sid)
3773 );
3774 assert_eq!(
3775 *nested_field_value(&buf, si_range, "endpoint_behavior"),
3776 FieldValue::U16(0x0029)
3777 );
3778 }
3779
3780 #[test]
3781 fn parse_bgp_prefix_sid_srv6_sid_structure() {
3782 let mut sid_info_val = vec![0x00];
3783 sid_info_val.extend_from_slice(&[
3784 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3785 ]);
3786 sid_info_val.push(0x00);
3787 sid_info_val.extend_from_slice(&0x003Eu16.to_be_bytes());
3788 sid_info_val.push(0x00);
3789 sid_info_val.push(0x01);
3790 sid_info_val.extend_from_slice(&6u16.to_be_bytes());
3791 sid_info_val.push(40);
3792 sid_info_val.push(24);
3793 sid_info_val.push(16);
3794 sid_info_val.push(0);
3795 sid_info_val.push(0);
3796 sid_info_val.push(0);
3797 let sub_tlv = build_psid_tlv(1, &sid_info_val);
3798 let mut service_val = vec![0x00];
3799 service_val.extend_from_slice(&sub_tlv);
3800 let tlv = build_psid_tlv(5, &service_val);
3801 let attr = build_attr(0xC0 | 0x10, 40, &tlv);
3802 let data = build_update(&attr, &[]);
3803 let mut buf = DissectBuffer::new();
3804 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3805
3806 let pa_value = extract_pa_value(&buf);
3807 let FieldValue::Array(tlvs_range) = pa_value else {
3808 panic!("expected Array");
3809 };
3810 let tlvs = buf.nested_fields(tlvs_range);
3811 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3812 panic!("expected Object");
3813 };
3814 let sub_tlvs_field = nested_field_by_name(&buf, obj_range, "sub_tlvs");
3815 let FieldValue::Array(ref subs_range) = sub_tlvs_field.value else {
3816 panic!("expected Array");
3817 };
3818 let subs = buf.nested_fields(subs_range);
3819 let FieldValue::Object(ref si_range) = subs[0].value else {
3820 panic!("expected Object");
3821 };
3822 let ss_field = nested_field_by_name(&buf, si_range, "sid_structure");
3823 let FieldValue::Object(ref ss_range) = ss_field.value else {
3824 panic!("expected Object");
3825 };
3826 assert_eq!(
3827 *nested_field_value(&buf, ss_range, "locator_block_length"),
3828 FieldValue::U8(40)
3829 );
3830 assert_eq!(
3831 *nested_field_value(&buf, ss_range, "locator_node_length"),
3832 FieldValue::U8(24)
3833 );
3834 assert_eq!(
3835 *nested_field_value(&buf, ss_range, "function_length"),
3836 FieldValue::U8(16)
3837 );
3838 assert_eq!(
3839 *nested_field_value(&buf, ss_range, "argument_length"),
3840 FieldValue::U8(0)
3841 );
3842 assert_eq!(
3843 *nested_field_value(&buf, ss_range, "transposition_length"),
3844 FieldValue::U8(0)
3845 );
3846 assert_eq!(
3847 *nested_field_value(&buf, ss_range, "transposition_offset"),
3848 FieldValue::U8(0)
3849 );
3850 }
3851
3852 #[test]
3853 fn parse_bgp_prefix_sid_multiple_tlvs() {
3854 let mut label_val = vec![0x00];
3855 label_val.extend_from_slice(&0u16.to_be_bytes());
3856 label_val.extend_from_slice(&200u32.to_be_bytes());
3857 let tlv1 = build_psid_tlv(1, &label_val);
3858 let mut srgb_val = vec![0x00, 0x00];
3859 srgb_val.extend_from_slice(&[0x00, 0x3E, 0x80]);
3860 srgb_val.extend_from_slice(&[0x00, 0x1F, 0x40]);
3861 let tlv2 = build_psid_tlv(3, &srgb_val);
3862 let mut attr_val = Vec::new();
3863 attr_val.extend_from_slice(&tlv1);
3864 attr_val.extend_from_slice(&tlv2);
3865 let attr = build_attr(0xC0, 40, &attr_val);
3866 let data = build_update(&attr, &[]);
3867 let mut buf = DissectBuffer::new();
3868 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3869
3870 let pa_value = extract_pa_value(&buf);
3871 let FieldValue::Array(tlvs_range) = pa_value else {
3872 panic!("expected Array");
3873 };
3874 let tlvs = buf.nested_fields(tlvs_range);
3875 assert!(tlvs[0].value.is_object());
3876 let FieldValue::Object(ref obj0) = tlvs[0].value else {
3877 panic!("expected Object");
3878 };
3879 assert_eq!(*nested_field_value(&buf, obj0, "type"), FieldValue::U8(1));
3880 assert_eq!(
3881 *nested_field_value(&buf, obj0, "label_index"),
3882 FieldValue::U32(200)
3883 );
3884 let second_start = (obj0.end - tlvs_range.start) as usize;
3886 let FieldValue::Object(ref obj1) = tlvs[second_start].value else {
3887 panic!("expected Object");
3888 };
3889 assert_eq!(*nested_field_value(&buf, obj1, "type"), FieldValue::U8(3));
3890 }
3891
3892 #[test]
3893 fn parse_bgp_prefix_sid_unknown_tlv() {
3894 let payload = vec![0xDE, 0xAD, 0xBE, 0xEF];
3895 let tlv = build_psid_tlv(99, &payload);
3896 let attr = build_attr(0xC0, 40, &tlv);
3897 let data = build_update(&attr, &[]);
3898 let mut buf = DissectBuffer::new();
3899 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3900
3901 let pa_value = extract_pa_value(&buf);
3902 let FieldValue::Array(tlvs_range) = pa_value else {
3903 panic!("expected Array");
3904 };
3905 let tlvs = buf.nested_fields(tlvs_range);
3906 assert!(tlvs[0].value.is_object());
3907 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3908 panic!("expected Object");
3909 };
3910 assert_eq!(
3911 *nested_field_value(&buf, obj_range, "type"),
3912 FieldValue::U8(99)
3913 );
3914 assert_eq!(
3915 *nested_field_value(&buf, obj_range, "value"),
3916 FieldValue::Bytes(&[0xDE, 0xAD, 0xBE, 0xEF])
3917 );
3918 }
3919
3920 #[test]
3921 fn parse_bgp_prefix_sid_truncated() {
3922 let mut label_val = vec![0x00];
3923 label_val.extend_from_slice(&0u16.to_be_bytes());
3924 label_val.extend_from_slice(&50u32.to_be_bytes());
3925 let tlv1 = build_psid_tlv(1, &label_val);
3926 let mut truncated = vec![0x01];
3927 truncated.extend_from_slice(&10u16.to_be_bytes());
3928 truncated.extend_from_slice(&[0xAA, 0xBB]);
3929 let mut attr_val = Vec::new();
3930 attr_val.extend_from_slice(&tlv1);
3931 attr_val.extend_from_slice(&truncated);
3932 let attr = build_attr(0xC0, 40, &attr_val);
3933 let data = build_update(&attr, &[]);
3934 let mut buf = DissectBuffer::new();
3935 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3936
3937 let pa_value = extract_pa_value(&buf);
3938 let FieldValue::Array(tlvs_range) = pa_value else {
3939 panic!("expected Array");
3940 };
3941 let tlvs = buf.nested_fields(tlvs_range);
3942 assert!(tlvs[0].value.is_object());
3943 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
3944 panic!("expected Object");
3945 };
3946 assert_eq!(
3947 *nested_field_value(&buf, obj_range, "label_index"),
3948 FieldValue::U32(50)
3949 );
3950 }
3951
3952 #[test]
3953 fn parse_bgp_update_mp_unreach_ipv6() {
3954 let mut val = Vec::new();
3955 val.extend_from_slice(&2u16.to_be_bytes());
3956 val.push(1);
3957 val.push(32);
3958 val.extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8]);
3959 let attr = build_attr(0x80 | 0x10, 15, &val);
3960 let data = build_update(&attr, &[]);
3961 let mut buf = DissectBuffer::new();
3962 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
3963
3964 let obj_range = first_pa_obj_range(&buf);
3965 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
3966 else {
3967 panic!("expected Object for MP_UNREACH");
3968 };
3969 assert_eq!(
3970 *nested_field_value(&buf, mp_range, "afi"),
3971 FieldValue::U16(2)
3972 );
3973 assert_eq!(
3974 *nested_field_value(&buf, mp_range, "safi"),
3975 FieldValue::U8(1)
3976 );
3977 let wr_field = nested_field_by_name(&buf, mp_range, "withdrawn_routes");
3978 let FieldValue::Array(ref wr_range) = wr_field.value else {
3979 panic!("expected Array");
3980 };
3981 let prefixes = buf.nested_fields(wr_range);
3982 assert_eq!(prefixes.len(), 1);
3983 assert_eq!(
3984 prefixes[0].value,
3985 FieldValue::Bytes(&[32, 0x20, 0x01, 0x0d, 0xb8])
3986 );
3987 }
3988
3989 #[test]
3990 fn parse_bgp_update_mp_unreach_ipv4() {
3991 let mut val = Vec::new();
3992 val.extend_from_slice(&1u16.to_be_bytes());
3993 val.push(1);
3994 val.push(8);
3995 val.push(10);
3996 let attr = build_attr(0x80 | 0x10, 15, &val);
3997 let data = build_update(&attr, &[]);
3998 let mut buf = DissectBuffer::new();
3999 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4000
4001 let obj_range = first_pa_obj_range(&buf);
4002 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
4003 else {
4004 panic!("expected Object for MP_UNREACH");
4005 };
4006 assert_eq!(
4007 *nested_field_value(&buf, mp_range, "afi"),
4008 FieldValue::U16(1)
4009 );
4010 let wr_field = nested_field_by_name(&buf, mp_range, "withdrawn_routes");
4011 let FieldValue::Array(ref wr_range) = wr_field.value else {
4012 panic!("expected Array");
4013 };
4014 let prefixes = buf.nested_fields(wr_range);
4015 assert_eq!(prefixes.len(), 1);
4016 assert_eq!(prefixes[0].value, FieldValue::Bytes(&[8, 10]));
4017 }
4018
4019 #[test]
4020 fn parse_bgp_update_aggregator_2byte_as() {
4021 let mut val = Vec::new();
4022 val.extend_from_slice(&65001u16.to_be_bytes());
4023 val.extend_from_slice(&[10, 0, 0, 1]);
4024 let attr = build_attr(0xC0, 7, &val);
4025 let data = build_update(&attr, &[]);
4026 let mut buf = DissectBuffer::new();
4027 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4028
4029 let obj_range = first_pa_obj_range(&buf);
4030 assert_eq!(
4031 *nested_field_value(&buf, &obj_range, "value"),
4032 FieldValue::Bytes(&val[..])
4033 );
4034 }
4035
4036 #[test]
4037 fn parse_bgp_update_aggregator_4byte_as() {
4038 let mut val = Vec::new();
4039 val.extend_from_slice(&131072u32.to_be_bytes());
4040 val.extend_from_slice(&[192, 168, 1, 1]);
4041 let attr = build_attr(0xC0 | 0x10, 7, &val);
4042 let data = build_update(&attr, &[]);
4043 let mut buf = DissectBuffer::new();
4044 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4045
4046 let obj_range = first_pa_obj_range(&buf);
4047 assert_eq!(
4048 *nested_field_value(&buf, &obj_range, "value"),
4049 FieldValue::Bytes(&val[..])
4050 );
4051 }
4052
4053 #[test]
4054 fn parse_bgp_update_as4_path() {
4055 let mut as4_path_value = vec![2, 2];
4056 as4_path_value.extend_from_slice(&200000u32.to_be_bytes());
4057 as4_path_value.extend_from_slice(&300000u32.to_be_bytes());
4058 let attr = build_attr(0xC0 | 0x10, 17, &as4_path_value);
4059 let data = build_update(&attr, &[]);
4060 let mut buf = DissectBuffer::new();
4061 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4062
4063 let obj_range = first_pa_obj_range(&buf);
4064 let FieldValue::Array(ref segs_range) = *nested_field_value(&buf, &obj_range, "value")
4065 else {
4066 panic!("expected Array for AS4_PATH");
4067 };
4068 let segs: Vec<_> = buf
4069 .nested_fields(segs_range)
4070 .iter()
4071 .filter(|f| f.value.is_object())
4072 .collect();
4073 assert_eq!(segs.len(), 1);
4074 let seg_range = segs[0].value.as_container_range().unwrap();
4075 assert_eq!(
4076 *nested_field_value(&buf, seg_range, "segment_type"),
4077 FieldValue::U8(2)
4078 );
4079 let asns_field = nested_field_by_name(&buf, seg_range, "as_numbers");
4080 let asns_range = asns_field.value.as_container_range().unwrap();
4081 let asns = buf.nested_fields(asns_range);
4082 assert_eq!(asns.len(), 2);
4083 assert_eq!(asns[0].value, FieldValue::U32(200000));
4084 assert_eq!(asns[1].value, FieldValue::U32(300000));
4085 }
4086
4087 #[test]
4088 fn parse_bgp_update_as4_aggregator() {
4089 let mut val = Vec::new();
4090 val.extend_from_slice(&200000u32.to_be_bytes());
4091 val.extend_from_slice(&[172, 16, 0, 1]);
4092 let attr = build_attr(0xC0 | 0x10, 18, &val);
4093 let data = build_update(&attr, &[]);
4094 let mut buf = DissectBuffer::new();
4095 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4096
4097 let obj_range = first_pa_obj_range(&buf);
4098 assert_eq!(
4099 *nested_field_value(&buf, &obj_range, "value"),
4100 FieldValue::Bytes(&val[..])
4101 );
4102 }
4103
4104 #[test]
4105 fn parse_bgp_update_cluster_list() {
4106 let mut val = Vec::new();
4107 val.extend_from_slice(&[10, 0, 0, 1]);
4108 val.extend_from_slice(&[10, 0, 0, 2]);
4109 let attr = build_attr(0x80, 10, &val);
4110 let data = build_update(&attr, &[]);
4111 let mut buf = DissectBuffer::new();
4112 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4113
4114 let obj_range = first_pa_obj_range(&buf);
4115 let FieldValue::Array(ref clusters_range) = *nested_field_value(&buf, &obj_range, "value")
4116 else {
4117 panic!("expected Array for CLUSTER_LIST");
4118 };
4119 let clusters = buf.nested_fields(clusters_range);
4120 assert_eq!(clusters.len(), 2);
4121 assert_eq!(clusters[0].value, FieldValue::Ipv4Addr([10, 0, 0, 1]));
4122 assert_eq!(clusters[1].value, FieldValue::Ipv4Addr([10, 0, 0, 2]));
4123 }
4124
4125 #[test]
4126 fn parse_bgp_update_originator_id() {
4127 let attr = build_attr(0x80, 9, &[10, 0, 0, 1]);
4128 let data = build_update(&attr, &[]);
4129 let mut buf = DissectBuffer::new();
4130 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4131
4132 let obj_range = first_pa_obj_range(&buf);
4133 assert_eq!(
4134 *nested_field_value(&buf, &obj_range, "value"),
4135 FieldValue::Ipv4Addr([10, 0, 0, 1])
4136 );
4137 }
4138
4139 #[test]
4140 fn parse_bgp_update_multi_exit_disc() {
4141 let attr = build_attr(0x80, 4, &100u32.to_be_bytes());
4142 let data = build_update(&attr, &[]);
4143 let mut buf = DissectBuffer::new();
4144 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4145
4146 let obj_range = first_pa_obj_range(&buf);
4147 assert_eq!(
4148 *nested_field_value(&buf, &obj_range, "value"),
4149 FieldValue::U32(100)
4150 );
4151 }
4152
4153 #[test]
4154 fn parse_bgp_update_local_pref() {
4155 let attr = build_attr(0x40, 5, &200u32.to_be_bytes());
4156 let data = build_update(&attr, &[]);
4157 let mut buf = DissectBuffer::new();
4158 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4159
4160 let obj_range = first_pa_obj_range(&buf);
4161 assert_eq!(
4162 *nested_field_value(&buf, &obj_range, "value"),
4163 FieldValue::U32(200)
4164 );
4165 }
4166
4167 #[test]
4168 fn parse_bgp_update_atomic_aggregate() {
4169 let attr = build_attr(0x40, 6, &[]);
4170 let data = build_update(&attr, &[]);
4171 let mut buf = DissectBuffer::new();
4172 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4173
4174 let obj_range = first_pa_obj_range(&buf);
4175 let fields = buf.nested_fields(&obj_range);
4176 assert!(!fields.iter().any(|f| f.name() == "value"));
4177 }
4178
4179 #[test]
4180 fn parse_bgp_update_extended_communities_ipv4_route_target() {
4181 let mut val = vec![0x01, 0x02];
4182 val.extend_from_slice(&[192, 168, 1, 1]);
4183 val.extend_from_slice(&100u16.to_be_bytes());
4184 let attr = build_attr(0xC0, 16, &val);
4185 let data = build_update(&attr, &[]);
4186 let mut buf = DissectBuffer::new();
4187 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4188
4189 let obj_range = first_pa_obj_range(&buf);
4190 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
4191 else {
4192 panic!("expected Array");
4193 };
4194 let comms = buf.nested_fields(comms_range);
4195 assert_eq!(comms.len(), 1);
4196 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
4197 }
4198
4199 #[test]
4200 fn parse_bgp_update_extended_communities_route_origin() {
4201 let mut val = vec![0x00, 0x03];
4202 val.extend_from_slice(&65001u16.to_be_bytes());
4203 val.extend_from_slice(&500u32.to_be_bytes());
4204 let attr = build_attr(0xC0, 16, &val);
4205 let data = build_update(&attr, &[]);
4206 let mut buf = DissectBuffer::new();
4207 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4208
4209 let obj_range = first_pa_obj_range(&buf);
4210 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
4211 else {
4212 panic!("expected Array");
4213 };
4214 let comms = buf.nested_fields(comms_range);
4215 assert_eq!(comms.len(), 1);
4216 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
4217 }
4218
4219 #[test]
4220 fn parse_bgp_update_extended_communities_evpn() {
4221 let mut val = vec![0x06, 0x00];
4222 val.extend_from_slice(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
4223 let attr = build_attr(0xC0, 16, &val);
4224 let data = build_update(&attr, &[]);
4225 let mut buf = DissectBuffer::new();
4226 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4227
4228 let obj_range = first_pa_obj_range(&buf);
4229 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
4230 else {
4231 panic!("expected Array");
4232 };
4233 let comms = buf.nested_fields(comms_range);
4234 assert_eq!(comms.len(), 1);
4235 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
4236 }
4237
4238 #[test]
4239 fn parse_bgp_update_extended_communities_unknown() {
4240 let val = vec![0x99, 0x99, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
4241 let attr = build_attr(0xC0, 16, &val);
4242 let data = build_update(&attr, &[]);
4243 let mut buf = DissectBuffer::new();
4244 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4245
4246 let obj_range = first_pa_obj_range(&buf);
4247 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
4248 else {
4249 panic!("expected Array");
4250 };
4251 let comms = buf.nested_fields(comms_range);
4252 assert_eq!(comms.len(), 1);
4253 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
4254 }
4255
4256 #[test]
4257 fn parse_bgp_update_unknown_attribute() {
4258 let attr = build_attr(0xC0, 99, &[0xDE, 0xAD]);
4259 let data = build_update(&attr, &[]);
4260 let mut buf = DissectBuffer::new();
4261 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4262
4263 let obj_range = first_pa_obj_range(&buf);
4264 let fields = buf.nested_fields(&obj_range);
4265 assert!(!fields.iter().any(|f| f.name() == "type_name"));
4266 assert_eq!(
4267 *nested_field_value(&buf, &obj_range, "value"),
4268 FieldValue::Bytes(&[0xDE, 0xAD])
4269 );
4270 }
4271
4272 #[test]
4273 fn parse_bgp_update_mp_reach_ipv6_link_local() {
4274 let mut val = Vec::new();
4275 val.extend_from_slice(&2u16.to_be_bytes());
4276 val.push(1);
4277 val.push(32);
4278 val.extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
4279 val.extend_from_slice(&[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
4280 val.push(0);
4281 val.push(48);
4282 val.extend_from_slice(&[0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01]);
4283 let attr = build_attr(0x80 | 0x10, 14, &val);
4284 let data = build_update(&attr, &[]);
4285 let mut buf = DissectBuffer::new();
4286 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4287
4288 let obj_range = first_pa_obj_range(&buf);
4289 let FieldValue::Object(ref mp_range) = *nested_field_value(&buf, &obj_range, "value")
4290 else {
4291 panic!("expected Object for MP_REACH");
4292 };
4293 assert_eq!(
4294 *nested_field_value(&buf, mp_range, "next_hop"),
4295 FieldValue::Ipv6Addr([0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
4296 );
4297 assert_eq!(
4298 *nested_field_value(&buf, mp_range, "next_hop_link_local"),
4299 FieldValue::Ipv6Addr([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
4300 );
4301 }
4302
4303 #[test]
4304 fn parse_bgp_update_extended_communities_ipv4_route_origin() {
4305 let mut val = vec![0x01, 0x03];
4306 val.extend_from_slice(&[10, 0, 0, 1]);
4307 val.extend_from_slice(&200u16.to_be_bytes());
4308 let attr = build_attr(0xC0, 16, &val);
4309 let data = build_update(&attr, &[]);
4310 let mut buf = DissectBuffer::new();
4311 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4312
4313 let obj_range = first_pa_obj_range(&buf);
4314 let FieldValue::Array(ref comms_range) = *nested_field_value(&buf, &obj_range, "value")
4315 else {
4316 panic!("expected Array");
4317 };
4318 let comms = buf.nested_fields(comms_range);
4319 assert_eq!(comms.len(), 1);
4320 assert_eq!(comms[0].value, FieldValue::Bytes(&val[..]));
4321 }
4322
4323 #[test]
4324 fn parse_bgp_prefix_sid_srv6_l2_service() {
4325 let mut sid_info_val = vec![0x00];
4326 sid_info_val.extend_from_slice(&[0xfd, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
4327 sid_info_val.push(0x00);
4328 sid_info_val.extend_from_slice(&0x0014u16.to_be_bytes());
4329 sid_info_val.push(0x00);
4330 let sub_tlv = build_psid_tlv(1, &sid_info_val);
4331 let mut service_val = vec![0x00];
4332 service_val.extend_from_slice(&sub_tlv);
4333 let tlv = build_psid_tlv(6, &service_val);
4334 let attr = build_attr(0xC0 | 0x10, 40, &tlv);
4335 let data = build_update(&attr, &[]);
4336 let mut buf = DissectBuffer::new();
4337 BgpDissector.dissect(&data, &mut buf, 0).unwrap();
4338
4339 let pa_value = extract_pa_value(&buf);
4340 let FieldValue::Array(tlvs_range) = pa_value else {
4341 panic!("expected Array");
4342 };
4343 let tlvs = buf.nested_fields(tlvs_range);
4344 assert!(tlvs[0].value.is_object());
4345 let FieldValue::Object(ref obj_range) = tlvs[0].value else {
4346 panic!("expected Object");
4347 };
4348 assert_eq!(
4349 *nested_field_value(&buf, obj_range, "type"),
4350 FieldValue::U8(6)
4351 );
4352 let sub_tlvs_field = nested_field_by_name(&buf, obj_range, "sub_tlvs");
4353 let FieldValue::Array(ref subs_range) = sub_tlvs_field.value else {
4354 panic!("expected Array");
4355 };
4356 let subs = buf.nested_fields(subs_range);
4357 assert!(subs[0].value.is_object());
4358 let FieldValue::Object(ref si_range) = subs[0].value else {
4359 panic!("expected Object");
4360 };
4361 assert_eq!(
4362 *nested_field_value(&buf, si_range, "endpoint_behavior"),
4363 FieldValue::U16(0x0014)
4364 );
4365 }
4366
4367 fn call_format_fn(
4369 f: fn(&FieldValue<'_>, &FormatContext<'_>, &mut dyn std::io::Write) -> std::io::Result<()>,
4370 value: &FieldValue<'_>,
4371 ) -> String {
4372 let ctx = FormatContext {
4373 packet_data: &[],
4374 scratch: &[],
4375 layer_range: 0..0,
4376 field_range: 0..0,
4377 };
4378 let mut out = Vec::new();
4379 f(value, &ctx, &mut out).unwrap();
4380 String::from_utf8(out).unwrap()
4381 }
4382
4383 #[test]
4384 fn format_nlri_ipv4_prefix_cidr() {
4385 assert_eq!(
4387 call_format_fn(
4388 format_nlri_ipv4_prefix,
4389 &FieldValue::Bytes(&[24, 192, 168, 1])
4390 ),
4391 "\"192.168.1.0/24\""
4392 );
4393 assert_eq!(
4395 call_format_fn(
4396 format_nlri_ipv4_prefix,
4397 &FieldValue::Bytes(&[32, 10, 0, 0, 1])
4398 ),
4399 "\"10.0.0.1/32\""
4400 );
4401 assert_eq!(
4403 call_format_fn(format_nlri_ipv4_prefix, &FieldValue::Bytes(&[0])),
4404 "\"0.0.0.0/0\""
4405 );
4406 assert_eq!(
4408 call_format_fn(format_nlri_ipv4_prefix, &FieldValue::Bytes(&[8, 10])),
4409 "\"10.0.0.0/8\""
4410 );
4411 assert_eq!(
4413 call_format_fn(format_nlri_ipv4_prefix, &FieldValue::Bytes(&[])),
4414 "\"\""
4415 );
4416 assert_eq!(
4418 call_format_fn(format_nlri_ipv4_prefix, &FieldValue::U8(0)),
4419 "\"\""
4420 );
4421 }
4422
4423 #[test]
4424 fn format_nlri_ipv6_prefix_cidr() {
4425 assert_eq!(
4427 call_format_fn(
4428 format_nlri_ipv6_prefix,
4429 &FieldValue::Bytes(&[48, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01])
4430 ),
4431 "\"2001:db8:1::/48\""
4432 );
4433 let mut full = vec![128];
4435 let mut addr = [0u8; 16];
4436 addr[0] = 0x20;
4437 addr[1] = 0x01;
4438 addr[2] = 0x0d;
4439 addr[3] = 0xb8;
4440 addr[15] = 0x01;
4441 full.extend_from_slice(&addr);
4442 assert_eq!(
4443 call_format_fn(format_nlri_ipv6_prefix, &FieldValue::Bytes(&full)),
4444 "\"2001:db8::1/128\""
4445 );
4446 assert_eq!(
4448 call_format_fn(format_nlri_ipv6_prefix, &FieldValue::Bytes(&[0])),
4449 "\"::/0\""
4450 );
4451 assert_eq!(
4453 call_format_fn(format_nlri_ipv6_prefix, &FieldValue::Bytes(&[])),
4454 "\"\""
4455 );
4456 assert_eq!(
4458 call_format_fn(format_nlri_ipv6_prefix, &FieldValue::U8(0)),
4459 "\"\""
4460 );
4461 }
4462
4463 #[test]
4464 fn format_aggregator_values() {
4465 assert_eq!(
4467 call_format_fn(
4468 format_aggregator,
4469 &FieldValue::Bytes(&[0xFD, 0xE9, 10, 0, 0, 1])
4470 ),
4471 "\"65001 10.0.0.1\""
4472 );
4473 assert_eq!(
4475 call_format_fn(
4476 format_aggregator,
4477 &FieldValue::Bytes(&[0, 0, 0xFD, 0xE9, 10, 0, 0, 1])
4478 ),
4479 "\"65001 10.0.0.1\""
4480 );
4481 assert_eq!(
4483 call_format_fn(format_aggregator, &FieldValue::Bytes(&[])),
4484 "\"\""
4485 );
4486 assert_eq!(
4488 call_format_fn(
4489 format_aggregator,
4490 &FieldValue::Bytes(&[0, 0, 0, 0, 0, 0, 0])
4491 ),
4492 "\"\""
4493 );
4494 assert_eq!(
4496 call_format_fn(format_aggregator, &FieldValue::U8(0)),
4497 "\"\""
4498 );
4499 }
4500
4501 #[test]
4502 fn format_ext_community_values() {
4503 assert_eq!(
4505 call_format_fn(
4506 format_ext_community,
4507 &FieldValue::Bytes(&[0x00, 0x02, 0xFD, 0xE9, 0, 0, 0, 100])
4508 ),
4509 "\"65001:100\""
4510 );
4511 assert_eq!(
4513 call_format_fn(
4514 format_ext_community,
4515 &FieldValue::Bytes(&[0x40, 0x02, 0xFD, 0xE9, 0, 0, 0, 100])
4516 ),
4517 "\"65001:100\""
4518 );
4519 assert_eq!(
4521 call_format_fn(
4522 format_ext_community,
4523 &FieldValue::Bytes(&[0x01, 0x02, 10, 0, 0, 1, 0, 100])
4524 ),
4525 "\"10.0.0.1:100\""
4526 );
4527 assert_eq!(
4529 call_format_fn(
4530 format_ext_community,
4531 &FieldValue::Bytes(&[0x41, 0x02, 10, 0, 0, 1, 0, 100])
4532 ),
4533 "\"10.0.0.1:100\""
4534 );
4535 assert_eq!(
4537 call_format_fn(
4538 format_ext_community,
4539 &FieldValue::Bytes(&[0x02, 0x02, 0, 0, 0xFD, 0xE9, 0, 100])
4540 ),
4541 "\"65001:100\""
4542 );
4543 assert_eq!(
4545 call_format_fn(
4546 format_ext_community,
4547 &FieldValue::Bytes(&[0x42, 0x02, 0, 0, 0xFD, 0xE9, 0, 100])
4548 ),
4549 "\"65001:100\""
4550 );
4551 assert_eq!(
4553 call_format_fn(
4554 format_ext_community,
4555 &FieldValue::Bytes(&[0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
4556 ),
4557 "\"0x0300010203040506\""
4558 );
4559 assert_eq!(
4561 call_format_fn(format_ext_community, &FieldValue::Bytes(&[])),
4562 "\"\""
4563 );
4564 assert_eq!(
4566 call_format_fn(format_ext_community, &FieldValue::U8(0)),
4567 "\"\""
4568 );
4569 }
4570
4571 #[test]
4572 fn format_large_community_values() {
4573 assert_eq!(
4575 call_format_fn(
4576 format_large_community,
4577 &FieldValue::Bytes(&[0, 0, 0xFD, 0xE9, 0, 0, 0, 100, 0, 0, 0, 200])
4578 ),
4579 "\"65001:100:200\""
4580 );
4581 assert_eq!(
4583 call_format_fn(
4584 format_large_community,
4585 &FieldValue::Bytes(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
4586 ),
4587 "\"0:0:0\""
4588 );
4589 assert_eq!(
4591 call_format_fn(format_large_community, &FieldValue::Bytes(&[])),
4592 "\"\""
4593 );
4594 assert_eq!(
4596 call_format_fn(
4597 format_large_community,
4598 &FieldValue::Bytes(&[0, 0, 0, 0, 0, 0, 0, 0])
4599 ),
4600 "\"\""
4601 );
4602 assert_eq!(
4604 call_format_fn(format_large_community, &FieldValue::U8(0)),
4605 "\"\""
4606 );
4607 }
4608
4609 #[test]
4610 fn format_route_distinguisher_values() {
4611 assert_eq!(
4613 call_format_fn(
4614 format_route_distinguisher,
4615 &FieldValue::Bytes(&[0, 0, 0xFD, 0xE9, 0, 0, 0, 100])
4616 ),
4617 "\"0:65001:100\""
4618 );
4619 assert_eq!(
4621 call_format_fn(
4622 format_route_distinguisher,
4623 &FieldValue::Bytes(&[0, 1, 10, 0, 0, 1, 0, 100])
4624 ),
4625 "\"1:10.0.0.1:100\""
4626 );
4627 assert_eq!(
4629 call_format_fn(
4630 format_route_distinguisher,
4631 &FieldValue::Bytes(&[0, 2, 0, 0, 0xFD, 0xE9, 0, 100])
4632 ),
4633 "\"2:65001:100\""
4634 );
4635 assert_eq!(
4637 call_format_fn(
4638 format_route_distinguisher,
4639 &FieldValue::Bytes(&[0, 3, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06])
4640 ),
4641 "\"3:0x010203040506\""
4642 );
4643 assert_eq!(
4645 call_format_fn(format_route_distinguisher, &FieldValue::Bytes(&[])),
4646 "\"\""
4647 );
4648 assert_eq!(
4650 call_format_fn(format_route_distinguisher, &FieldValue::U8(0)),
4651 "\"\""
4652 );
4653 }
4654
4655 #[test]
4656 fn format_teid_values() {
4657 assert_eq!(
4659 call_format_fn(format_teid, &FieldValue::Bytes(&[0x12, 0x34, 0x56, 0x78])),
4660 "\"0x12345678\""
4661 );
4662 assert_eq!(
4664 call_format_fn(format_teid, &FieldValue::Bytes(&[0, 0, 0, 0])),
4665 "\"0x00000000\""
4666 );
4667 assert_eq!(call_format_fn(format_teid, &FieldValue::Bytes(&[])), "\"\"");
4669 assert_eq!(
4671 call_format_fn(format_teid, &FieldValue::Bytes(&[1, 2, 3])),
4672 "\"\""
4673 );
4674 assert_eq!(call_format_fn(format_teid, &FieldValue::U8(0)), "\"\"");
4676 }
4677}