Skip to content

Commit 32f0b55

Browse files
committed
test(flow-filter,nat): Re-add tests for prefixes overlapping
Following the recent re-introduction of support for overlapping prefixes when involved expose blocks use stateful NAT, re-introduce the relevant unit tests in the flow-filter and nat crates. This is a partial (rebased) reapply of commit 514646a ("chore(flow-filter): Remove code for exposed IP overlap support"). Signed-off-by: Quentin Monnet <qmo@qmon.net>
1 parent 755a08f commit 32f0b55

File tree

3 files changed

+1209
-2
lines changed

3 files changed

+1209
-2
lines changed

flow-filter/src/lib.rs

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,220 @@ mod tests {
447447
assert_eq!(packets[0].get_done(), Some(DoneReason::Filtered));
448448
}
449449

450+
#[test]
451+
fn test_flow_filter_multiple_matches_no_dst_vpcd() {
452+
// Setup table with overlapping destination prefixes from different VPCs
453+
let mut table = FlowFilterTable::new();
454+
let src_vpcd = vpcd(100);
455+
456+
// Manually set up a scenario where dst_vpcd lookup returns MultipleMatches
457+
// This happens when the same destination can be reached from multiple VPCs
458+
table
459+
.insert(
460+
src_vpcd,
461+
VpcdLookupResult::MultipleMatches,
462+
Prefix::from("10.0.0.0/24"),
463+
None,
464+
Prefix::from("20.0.0.0/24"),
465+
None,
466+
)
467+
.unwrap();
468+
469+
let mut writer = FlowFilterTableWriter::new();
470+
writer.update_flow_filter_table(table);
471+
472+
let mut flow_filter = FlowFilter::new("test-filter", writer.get_reader());
473+
474+
// Create test packet
475+
let packet = create_test_packet(
476+
Some(vpcd(100)),
477+
"10.0.0.5".parse().unwrap(),
478+
"20.0.0.10".parse().unwrap(),
479+
);
480+
481+
let packets = flow_filter
482+
.process([packet].into_iter())
483+
.collect::<Vec<_>>();
484+
485+
assert_eq!(packets.len(), 1);
486+
// Without table flow lookup we can't find the right dst_vpcd, so we should drop the packet
487+
assert!(packets[0].is_done());
488+
assert!(packets[0].meta().dst_vpcd.is_none());
489+
}
490+
491+
#[test]
492+
fn test_flow_filter_table_overlap_cases() {
493+
let vni1 = Vni::new_checked(100).unwrap();
494+
let vni2 = Vni::new_checked(200).unwrap();
495+
let vni3 = Vni::new_checked(300).unwrap();
496+
497+
let mut vpc_table = VpcTable::new();
498+
vpc_table
499+
.add(Vpc::new("vpc1", "VPC01", vni1.as_u32()).unwrap())
500+
.unwrap();
501+
vpc_table
502+
.add(Vpc::new("vpc2", "VPC02", vni2.as_u32()).unwrap())
503+
.unwrap();
504+
vpc_table
505+
.add(Vpc::new("vpc3", "VPC03", vni3.as_u32()).unwrap())
506+
.unwrap();
507+
508+
// - vpc1-to-vpc2:
509+
// VPC01:
510+
// prefixes:
511+
// - 1.0.0.0/24
512+
// VPC02:
513+
// prefixes:
514+
// - 5.0.0.0/24
515+
//
516+
// - vpc2-to-vpc3:
517+
// VPC02:
518+
// prefixes:
519+
// - 5.0.0.0/24
520+
// - 6.0.0.0/24
521+
// VPC03:
522+
// prefixes:
523+
// - 1.0.0.64/26 // 1.0.0.64 to 1.0.0.127
524+
let mut peering_table = VpcPeeringTable::new();
525+
peering_table
526+
.add(VpcPeering::new(
527+
"vpc1-to-vpc2",
528+
VpcManifest {
529+
name: "vpc1".to_string(),
530+
exposes: vec![VpcExpose::empty().ip("1.0.0.0/24".into())],
531+
},
532+
VpcManifest {
533+
name: "vpc2".to_string(),
534+
exposes: vec![VpcExpose::empty().ip("5.0.0.0/24".into())],
535+
},
536+
None,
537+
))
538+
.unwrap();
539+
540+
peering_table
541+
.add(VpcPeering::new(
542+
"vpc2-to-vpc3",
543+
VpcManifest {
544+
name: "vpc2".to_string(),
545+
exposes: vec![
546+
VpcExpose::empty().ip("5.0.0.0/24".into()),
547+
VpcExpose::empty().ip("6.0.0.0/24".into()),
548+
],
549+
},
550+
VpcManifest {
551+
name: "vpc3".to_string(),
552+
exposes: vec![VpcExpose::empty().ip("1.0.0.64/26".into())],
553+
},
554+
None,
555+
))
556+
.unwrap();
557+
558+
let mut overlay = Overlay::new(vpc_table, peering_table);
559+
// Build overlay.vpc_table's peerings from peering_table, with no validation.
560+
// We don't validate because overlapping prefixes actually make the config invalid; but it
561+
// doesn't matter for the test.
562+
overlay.collect_peerings();
563+
564+
let table = FlowFilterTable::build_from_overlay(&overlay).unwrap();
565+
566+
let mut writer = FlowFilterTableWriter::new();
567+
writer.update_flow_filter_table(table);
568+
569+
let mut flow_filter = FlowFilter::new("test-filter", writer.get_reader());
570+
571+
// Test with packets
572+
573+
// VPC-1 -> VPC-2: No ambiguity
574+
let packet = create_test_packet(
575+
Some(vpcd(100)),
576+
"1.0.0.5".parse().unwrap(),
577+
"5.0.0.10".parse().unwrap(),
578+
);
579+
580+
let packets = flow_filter
581+
.process([packet].into_iter())
582+
.collect::<Vec<_>>();
583+
584+
assert_eq!(packets.len(), 1);
585+
assert!(!packets[0].is_done(), "{:?}", packets[0].get_done());
586+
assert_eq!(packets[0].meta().dst_vpcd, Some(vpcd(vni2.into())));
587+
588+
// VPC-3 -> VPC-2: No ambiguity
589+
let packet = create_test_packet(
590+
Some(vpcd(300)),
591+
"1.0.0.70".parse().unwrap(),
592+
"5.0.0.10".parse().unwrap(),
593+
);
594+
595+
let packets = flow_filter
596+
.process([packet].into_iter())
597+
.collect::<Vec<_>>();
598+
599+
assert_eq!(packets.len(), 1);
600+
assert!(!packets[0].is_done(), "{:?}", packets[0].get_done());
601+
assert_eq!(packets[0].meta().dst_vpcd, Some(vpcd(vni2.into())));
602+
603+
// VPC-2 -> VPC-1 using lower non-overlapping destination prefix section
604+
let packet = create_test_packet(
605+
Some(vpcd(200)),
606+
"5.0.0.10".parse().unwrap(),
607+
"1.0.0.5".parse().unwrap(),
608+
);
609+
610+
let packets = flow_filter
611+
.process([packet].into_iter())
612+
.collect::<Vec<_>>();
613+
614+
assert_eq!(packets.len(), 1);
615+
assert!(!packets[0].is_done(), "{:?}", packets[0].get_done());
616+
assert_eq!(packets[0].meta().dst_vpcd, Some(vpcd(vni1.into())));
617+
618+
// VPC-2 -> VPC-1 using upper non-overlapping destination prefix section
619+
let packet = create_test_packet(
620+
Some(vpcd(200)),
621+
"5.0.0.10".parse().unwrap(),
622+
"1.0.0.205".parse().unwrap(),
623+
);
624+
625+
let packets = flow_filter
626+
.process([packet].into_iter())
627+
.collect::<Vec<_>>();
628+
629+
assert_eq!(packets.len(), 1);
630+
assert!(!packets[0].is_done(), "{:?}", packets[0].get_done());
631+
assert_eq!(packets[0].meta().dst_vpcd, Some(vpcd(vni1.into())));
632+
633+
// VPC-2 -> VPC-3 using non-overlapping source prefix
634+
let packet = create_test_packet(
635+
Some(vpcd(200)),
636+
"6.0.0.11".parse().unwrap(),
637+
"1.0.0.70".parse().unwrap(),
638+
);
639+
640+
let packets = flow_filter
641+
.process([packet].into_iter())
642+
.collect::<Vec<_>>();
643+
644+
assert_eq!(packets.len(), 1);
645+
assert!(!packets[0].is_done(), "{:?}", packets[0].get_done());
646+
assert_eq!(packets[0].meta().dst_vpcd, Some(vpcd(vni3.into())));
647+
648+
// VPC-2 -> VPC-??? using overlapping prefix sections: multiple matches
649+
let packet = create_test_packet(
650+
Some(vpcd(200)),
651+
"5.0.0.10".parse().unwrap(),
652+
"1.0.0.70".parse().unwrap(),
653+
);
654+
655+
let packets = flow_filter
656+
.process([packet].into_iter())
657+
.collect::<Vec<_>>();
658+
659+
assert_eq!(packets.len(), 1);
660+
assert!(packets[0].is_done(), "{:?}", packets[0].get_done());
661+
assert_eq!(packets[0].meta().dst_vpcd, None)
662+
}
663+
450664
#[test]
451665
fn test_flow_filter_ipv6() {
452666
// Setup table

0 commit comments

Comments
 (0)