@@ -599,7 +599,6 @@ async fn test_internal_ipv6_validation() {
599
599
assert_eq ! ( updated. tag, Some ( "updated_tag" . to_string( ) ) ) ;
600
600
assert_eq ! ( updated. ext_fwding. vlan_id, None ) ;
601
601
602
- // Cleanup
603
602
cleanup_test_group ( switch, created. group_ip ) . await ;
604
603
}
605
604
@@ -685,7 +684,6 @@ async fn test_vlan_propagation_to_internal() {
685
684
"Admin-scoped group bitmap should have VLAN 42 from external group"
686
685
) ;
687
686
688
- // Cleanup
689
687
cleanup_test_group ( switch, created_admin. group_ip ) . await ;
690
688
cleanup_test_group ( switch, created_external. group_ip ) . await ;
691
689
}
@@ -695,7 +693,6 @@ async fn test_vlan_propagation_to_internal() {
695
693
async fn test_group_api_lifecycle ( ) {
696
694
let switch = & * get_switch ( ) . await ;
697
695
698
- // Create admin-scoped IPv6 group for underlay replication infrastructure
699
696
let egress1 = PhysPort ( 28 ) ;
700
697
let internal_multicast_ip = IpAddr :: V6 ( MULTICAST_NAT_IP ) ;
701
698
let underlay_group = create_test_multicast_group (
@@ -1330,7 +1327,6 @@ async fn test_api_invalid_combinations() {
1330
1327
) ,
1331
1328
}
1332
1329
1333
- // Cleanup
1334
1330
cleanup_test_group ( switch, created_ipv4. group_ip ) . await ;
1335
1331
cleanup_test_group ( switch, created_non_admin. group_ip ) . await ;
1336
1332
cleanup_test_group ( switch, internal_multicast_ip) . await ;
@@ -2024,7 +2020,6 @@ async fn test_encapped_multicast_geneve_mcast_tag_to_external_members(
2024
2020
. await
2025
2021
. unwrap ( ) ;
2026
2022
2027
- // Run the test
2028
2023
let result = switch. packet_test ( vec ! [ test_pkt] , expected_pkts) ;
2029
2024
2030
2025
check_counter_incremented (
@@ -2163,7 +2158,6 @@ async fn test_encapped_multicast_geneve_mcast_tag_to_underlay_members(
2163
2158
. await
2164
2159
. unwrap ( ) ;
2165
2160
2166
- // Run the test
2167
2161
let result = switch. packet_test ( vec ! [ test_pkt] , expected_pkts) ;
2168
2162
2169
2163
check_counter_incremented (
@@ -2320,7 +2314,6 @@ async fn test_encapped_multicast_geneve_mcast_tag_to_underlay_and_external_membe
2320
2314
. await
2321
2315
. unwrap ( ) ;
2322
2316
2323
- // Run the test
2324
2317
let result = switch. packet_test ( vec ! [ test_pkt] , expected_pkts) ;
2325
2318
2326
2319
check_counter_incremented (
@@ -3844,6 +3837,288 @@ async fn test_multicast_reset_all_tables() -> TestResult {
3844
3837
Ok ( ( ) )
3845
3838
}
3846
3839
3840
+ #[ tokio:: test]
3841
+ #[ ignore]
3842
+ async fn test_multicast_group_id_recycling ( ) -> TestResult {
3843
+ let switch = & * get_switch ( ) . await ;
3844
+
3845
+ let egress = PhysPort ( 28 ) ;
3846
+ let internal_multicast_ip = IpAddr :: V6 ( MULTICAST_NAT_IP ) ;
3847
+ let underlay_group = create_test_multicast_group (
3848
+ switch,
3849
+ internal_multicast_ip,
3850
+ Some ( "recycling_test_underlay" ) ,
3851
+ & [ ( egress, types:: Direction :: Underlay ) ] ,
3852
+ None ,
3853
+ false ,
3854
+ None ,
3855
+ )
3856
+ . await ;
3857
+
3858
+ let group_ip1 = IpAddr :: V4 ( MULTICAST_TEST_IPV4 ) ;
3859
+ let nat_target = create_nat_target_ipv4 ( ) ;
3860
+ let external_create1 = types:: MulticastGroupCreateExternalEntry {
3861
+ group_ip : group_ip1,
3862
+ tag : Some ( "recycling_test_1" . to_string ( ) ) ,
3863
+ nat_target : nat_target. clone ( ) ,
3864
+ vlan_id : 10 ,
3865
+ sources : None ,
3866
+ ports : vec ! [ ] ,
3867
+ } ;
3868
+
3869
+ let created_group1 = switch
3870
+ . multicast_group_create_external ( & external_create1)
3871
+ . await ?;
3872
+
3873
+ let first_external_id = created_group1. external_group_id ;
3874
+ let first_underlay_id = created_group1. underlay_group_id ;
3875
+
3876
+ switch. multicast_group_delete ( & group_ip1) . await ?;
3877
+
3878
+ let group_ip2 = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 0 , 100 ) ) ;
3879
+ let external_create2 = types:: MulticastGroupCreateExternalEntry {
3880
+ group_ip : group_ip2,
3881
+ tag : Some ( "recycling_test_2" . to_string ( ) ) ,
3882
+ nat_target : nat_target. clone ( ) ,
3883
+ vlan_id : 10 ,
3884
+ sources : None ,
3885
+ ports : vec ! [ ] ,
3886
+ } ;
3887
+
3888
+ let created_group2 = switch
3889
+ . multicast_group_create_external ( & external_create2)
3890
+ . await ?;
3891
+
3892
+ assert ! (
3893
+ created_group2. external_group_id. is_some( ) ,
3894
+ "Second group should have external group ID"
3895
+ ) ;
3896
+ assert ! (
3897
+ created_group2. underlay_group_id. is_some( ) ,
3898
+ "Second group should have underlay group ID"
3899
+ ) ;
3900
+
3901
+ let group_ip3 = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 0 , 101 ) ) ;
3902
+ let external_create3 = types:: MulticastGroupCreateExternalEntry {
3903
+ group_ip : group_ip3,
3904
+ tag : Some ( "recycling_test_3" . to_string ( ) ) ,
3905
+ nat_target : nat_target. clone ( ) ,
3906
+ vlan_id : 10 ,
3907
+ sources : None ,
3908
+ ports : vec ! [ ] ,
3909
+ } ;
3910
+
3911
+ let created_group3 = switch
3912
+ . multicast_group_create_external ( & external_create3)
3913
+ . await ?;
3914
+
3915
+ assert ! (
3916
+ created_group3. external_group_id. is_some( ) ,
3917
+ "Third group should have external group ID"
3918
+ ) ;
3919
+ assert ! (
3920
+ created_group3. underlay_group_id. is_some( ) ,
3921
+ "Third group should have underlay group ID"
3922
+ ) ;
3923
+
3924
+ cleanup_test_group ( switch, group_ip2) . await ;
3925
+ cleanup_test_group ( switch, group_ip3) . await ;
3926
+ cleanup_test_group ( switch, internal_multicast_ip) . await ;
3927
+
3928
+ Ok ( ( ) )
3929
+ }
3930
+
3931
+ #[ tokio:: test]
3932
+ #[ ignore]
3933
+ async fn test_multicast_group_id_reuse ( ) -> TestResult {
3934
+ let switch = & * get_switch ( ) . await ;
3935
+
3936
+ let egress = PhysPort ( 29 ) ;
3937
+ let internal_multicast_ip = IpAddr :: V6 ( MULTICAST_NAT_IP ) ;
3938
+ let underlay_group = create_test_multicast_group (
3939
+ switch,
3940
+ internal_multicast_ip,
3941
+ Some ( "id_reuse_test_underlay" ) ,
3942
+ & [ ( egress, types:: Direction :: Underlay ) ] ,
3943
+ None ,
3944
+ false ,
3945
+ None ,
3946
+ )
3947
+ . await ;
3948
+
3949
+ let mut deleted_external_ids = Vec :: new ( ) ;
3950
+ let mut deleted_underlay_ids = Vec :: new ( ) ;
3951
+
3952
+ for i in 0 ..5 {
3953
+ let group_ip = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 0 , 50 + i) ) ;
3954
+ let nat_target = create_nat_target_ipv4 ( ) ;
3955
+ let external_create = types:: MulticastGroupCreateExternalEntry {
3956
+ group_ip,
3957
+ tag : Some ( format ! ( "id_reuse_test_{}" , i) ) ,
3958
+ nat_target,
3959
+ vlan_id : 10 ,
3960
+ sources : None ,
3961
+ ports : vec ! [ ] ,
3962
+ } ;
3963
+
3964
+ let created_group = switch
3965
+ . multicast_group_create_external ( & external_create)
3966
+ . await ?;
3967
+
3968
+ if let Some ( external_id) = created_group. external_group_id {
3969
+ deleted_external_ids. push ( external_id) ;
3970
+ }
3971
+ if let Some ( underlay_id) = created_group. underlay_group_id {
3972
+ deleted_underlay_ids. push ( underlay_id) ;
3973
+ }
3974
+
3975
+ switch. multicast_group_delete ( & group_ip) . await ?;
3976
+ }
3977
+
3978
+ let new_group_ip = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 0 , 200 ) ) ;
3979
+ let nat_target = create_nat_target_ipv4 ( ) ;
3980
+ let new_external_create = types:: MulticastGroupCreateExternalEntry {
3981
+ group_ip : new_group_ip,
3982
+ tag : Some ( "id_reuse_verification" . to_string ( ) ) ,
3983
+ nat_target,
3984
+ vlan_id : 10 ,
3985
+ sources : None ,
3986
+ ports : vec ! [ ] ,
3987
+ } ;
3988
+
3989
+ let new_created_group = switch
3990
+ . multicast_group_create_external ( & new_external_create)
3991
+ . await ?;
3992
+
3993
+ if let Some ( new_external_id) = new_created_group. external_group_id {
3994
+ assert ! (
3995
+ deleted_external_ids. contains( & new_external_id) ,
3996
+ "New group should reuse a deleted external group ID, got {}, expected one of {:?}" ,
3997
+ new_external_id,
3998
+ deleted_external_ids
3999
+ ) ;
4000
+ } else {
4001
+ panic ! ( "New group should have an external group ID" ) ;
4002
+ }
4003
+
4004
+ if let Some ( new_underlay_id) = new_created_group. underlay_group_id {
4005
+ assert ! (
4006
+ deleted_underlay_ids. contains( & new_underlay_id) ,
4007
+ "New group should reuse a deleted underlay group ID, got {}, expected one of {:?}" ,
4008
+ new_underlay_id,
4009
+ deleted_underlay_ids
4010
+ ) ;
4011
+ } else {
4012
+ panic ! ( "New group should have an underlay group ID" ) ;
4013
+ }
4014
+
4015
+ cleanup_test_group ( switch, new_group_ip) . await ;
4016
+ cleanup_test_group ( switch, internal_multicast_ip) . await ;
4017
+
4018
+ Ok ( ( ) )
4019
+ }
4020
+
4021
+ #[ tokio:: test]
4022
+ #[ ignore]
4023
+ async fn test_multicast_group_id_pool_exhaustion_recovery ( ) -> TestResult {
4024
+ let switch = & * get_switch ( ) . await ;
4025
+
4026
+ let egress = PhysPort ( 30 ) ;
4027
+ let internal_multicast_ip = IpAddr :: V6 ( MULTICAST_NAT_IP ) ;
4028
+ let underlay_group = create_test_multicast_group (
4029
+ switch,
4030
+ internal_multicast_ip,
4031
+ Some ( "pool_exhaustion_test_underlay" ) ,
4032
+ & [ ( egress, types:: Direction :: Underlay ) ] ,
4033
+ None ,
4034
+ false ,
4035
+ None ,
4036
+ )
4037
+ . await ;
4038
+
4039
+ let mut created_groups = Vec :: new ( ) ;
4040
+ let num_groups = 10 ;
4041
+
4042
+ for i in 0 ..num_groups {
4043
+ let group_ip = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 1 , i as u8 ) ) ;
4044
+ let nat_target = create_nat_target_ipv4 ( ) ;
4045
+ let external_create = types:: MulticastGroupCreateExternalEntry {
4046
+ group_ip,
4047
+ tag : Some ( format ! ( "pool_test_{}" , i) ) ,
4048
+ nat_target,
4049
+ vlan_id : 10 ,
4050
+ sources : None ,
4051
+ ports : vec ! [ ] ,
4052
+ } ;
4053
+
4054
+ let created_group = switch
4055
+ . multicast_group_create_external ( & external_create)
4056
+ . await ?;
4057
+
4058
+ created_groups. push ( ( group_ip, created_group) ) ;
4059
+ }
4060
+
4061
+ assert_eq ! (
4062
+ created_groups. len( ) ,
4063
+ num_groups,
4064
+ "Should have created {} groups" ,
4065
+ num_groups
4066
+ ) ;
4067
+
4068
+ let groups_to_delete = & created_groups[ 0 ..num_groups / 2 ] ;
4069
+ for ( group_ip, _) in groups_to_delete {
4070
+ switch. multicast_group_delete ( group_ip) . await ?;
4071
+ }
4072
+
4073
+ let mut new_groups = Vec :: new ( ) ;
4074
+ for i in 0 ..num_groups / 2 {
4075
+ let group_ip = IpAddr :: V4 ( Ipv4Addr :: new ( 224 , 0 , 2 , i as u8 ) ) ;
4076
+ let nat_target = create_nat_target_ipv4 ( ) ;
4077
+ let external_create = types:: MulticastGroupCreateExternalEntry {
4078
+ group_ip,
4079
+ tag : Some ( format ! ( "pool_recovery_test_{}" , i) ) ,
4080
+ nat_target,
4081
+ vlan_id : 10 ,
4082
+ sources : None ,
4083
+ ports : vec ! [ ] ,
4084
+ } ;
4085
+
4086
+ let created_group = switch
4087
+ . multicast_group_create_external ( & external_create)
4088
+ . await ?;
4089
+
4090
+ new_groups. push ( ( group_ip, created_group) ) ;
4091
+ }
4092
+
4093
+ assert_eq ! (
4094
+ new_groups. len( ) ,
4095
+ num_groups / 2 ,
4096
+ "Should have created {} new groups after pool recovery" ,
4097
+ num_groups / 2
4098
+ ) ;
4099
+
4100
+ for ( _, group) in & new_groups {
4101
+ assert ! (
4102
+ group. external_group_id. is_some( ) ,
4103
+ "New group should have external group ID"
4104
+ ) ;
4105
+ assert ! (
4106
+ group. underlay_group_id. is_some( ) ,
4107
+ "New group should have underlay group ID"
4108
+ ) ;
4109
+ }
4110
+
4111
+ for ( group_ip, _) in & created_groups[ num_groups / 2 ..] {
4112
+ cleanup_test_group ( switch, * group_ip) . await ;
4113
+ }
4114
+ for ( group_ip, _) in & new_groups {
4115
+ cleanup_test_group ( switch, * group_ip) . await ;
4116
+ }
4117
+ cleanup_test_group ( switch, internal_multicast_ip) . await ;
4118
+
4119
+ Ok ( ( ) )
4120
+ }
4121
+
3847
4122
#[ tokio:: test]
3848
4123
#[ ignore]
3849
4124
async fn test_multicast_vlan_translation_not_possible ( ) -> TestResult {
@@ -4335,7 +4610,6 @@ async fn test_external_group_nat_target_validation() {
4335
4610
"External group should have no members"
4336
4611
) ;
4337
4612
4338
- // Cleanup
4339
4613
cleanup_test_group ( switch, created_admin. group_ip ) . await ;
4340
4614
cleanup_test_group ( switch, created_external. group_ip ) . await ;
4341
4615
}
0 commit comments