88
99use criterion:: BenchmarkId ;
1010use criterion:: Criterion ;
11+ use criterion:: Throughput ;
1112use criterion:: criterion_group;
1213use criterion:: criterion_main;
1314use opte:: engine:: packet:: Packet ;
@@ -24,6 +25,11 @@ use opte_bench::packet::TestCase;
2425use opte_bench:: packet:: ULP_FAST_PATH ;
2526use opte_bench:: packet:: ULP_SLOW_PATH ;
2627use opte_test_utils:: * ;
28+ use oxide_vpc:: api:: IpAddr ;
29+ use oxide_vpc:: api:: Ipv4Addr ;
30+ use oxide_vpc:: api:: Ipv6Addr ;
31+ use oxide_vpc:: api:: SourceFilter ;
32+ use std:: collections:: BTreeSet ;
2733use std:: hint:: black_box;
2834
2935// Top level runner. Specifies packet classes.
@@ -218,7 +224,111 @@ pub fn test_handle<M: MeasurementInfo + 'static>(
218224 ) ;
219225}
220226
221- criterion_group ! ( wall, parse_and_process) ;
227+ /// Generate a source IP address for filter testing (10.0.0.x).
228+ fn make_src_v4 ( i : u32 ) -> IpAddr {
229+ IpAddr :: Ip4 ( Ipv4Addr :: from ( 0x0a000000u32 + i) )
230+ }
231+
232+ /// Generate a source IP address for filter testing (fd00::x).
233+ fn make_src_v6 ( i : u32 ) -> IpAddr {
234+ let mut bytes = [ 0u8 ; 16 ] ;
235+ bytes[ 0 ..4 ] . copy_from_slice ( & [ 0xfd , 0x00 , 0x00 , 0x00 ] ) ;
236+ bytes[ 12 ..16 ] . copy_from_slice ( & i. to_be_bytes ( ) ) ;
237+ IpAddr :: Ip6 ( Ipv6Addr :: from ( bytes) )
238+ }
239+
240+ /// Benchmark [`SourceFilter::allows`] for various filter configurations.
241+ fn source_filter_allows ( c : & mut Criterion ) {
242+ let mut group = c. benchmark_group ( "source_filter/allows" ) ;
243+ group. throughput ( Throughput :: Elements ( 1 ) ) ;
244+
245+ let src_v4 = make_src_v4 ( 100 ) ; // Not in any source list
246+ let src_v6 = make_src_v6 ( 100 ) ;
247+
248+ // Fast path: EXCLUDE() with empty sources (*, G)
249+ let filter_any = SourceFilter :: default ( ) ;
250+ group. bench_function ( "exclude_empty_v4" , |b| {
251+ b. iter ( || black_box ( filter_any. allows ( black_box ( src_v4) ) ) )
252+ } ) ;
253+ group. bench_function ( "exclude_empty_v6" , |b| {
254+ b. iter ( || black_box ( filter_any. allows ( black_box ( src_v6) ) ) )
255+ } ) ;
256+
257+ // EXCLUDE with sources: "Miss" case where source is not in exclusion list
258+ for size in [ 1 , 5 , 10 , 50 , 100 ] {
259+ let sources_v4: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v4) . collect ( ) ;
260+ let filter_v4 = SourceFilter :: Exclude ( sources_v4) ;
261+ group. bench_with_input (
262+ BenchmarkId :: new ( "exclude_miss_v4" , size) ,
263+ & filter_v4,
264+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v4) ) ) ) ,
265+ ) ;
266+ let src_in_list_v4 = make_src_v4 ( 0 ) ;
267+ group. bench_with_input (
268+ BenchmarkId :: new ( "exclude_hit_v4" , size) ,
269+ & filter_v4,
270+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v4) ) ) ) ,
271+ ) ;
272+
273+ let sources_v6: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v6) . collect ( ) ;
274+ let filter_v6 = SourceFilter :: Exclude ( sources_v6) ;
275+ group. bench_with_input (
276+ BenchmarkId :: new ( "exclude_miss_v6" , size) ,
277+ & filter_v6,
278+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v6) ) ) ) ,
279+ ) ;
280+ let src_in_list_v6 = make_src_v6 ( 0 ) ;
281+ group. bench_with_input (
282+ BenchmarkId :: new ( "exclude_hit_v6" , size) ,
283+ & filter_v6,
284+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v6) ) ) ) ,
285+ ) ;
286+ }
287+
288+ // INCLUDE with sources: "Hit" case where source is in inclusion list
289+ for size in [ 1 , 5 , 10 , 50 , 100 ] {
290+ let sources_v4: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v4) . collect ( ) ;
291+ let filter_v4 = SourceFilter :: Include ( sources_v4) ;
292+ let src_in_list_v4 = make_src_v4 ( 0 ) ;
293+ group. bench_with_input (
294+ BenchmarkId :: new ( "include_hit_v4" , size) ,
295+ & filter_v4,
296+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v4) ) ) ) ,
297+ ) ;
298+ group. bench_with_input (
299+ BenchmarkId :: new ( "include_miss_v4" , size) ,
300+ & filter_v4,
301+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v4) ) ) ) ,
302+ ) ;
303+
304+ let sources_v6: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v6) . collect ( ) ;
305+ let filter_v6 = SourceFilter :: Include ( sources_v6) ;
306+ let src_in_list_v6 = make_src_v6 ( 0 ) ;
307+ group. bench_with_input (
308+ BenchmarkId :: new ( "include_hit_v6" , size) ,
309+ & filter_v6,
310+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v6) ) ) ) ,
311+ ) ;
312+ group. bench_with_input (
313+ BenchmarkId :: new ( "include_miss_v6" , size) ,
314+ & filter_v6,
315+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v6) ) ) ) ,
316+ ) ;
317+ }
318+
319+ // INCLUDE() empty, rejecting all
320+ let filter_none = SourceFilter :: Include ( BTreeSet :: new ( ) ) ;
321+ group. bench_function ( "include_empty_v4" , |b| {
322+ b. iter ( || black_box ( filter_none. allows ( black_box ( src_v4) ) ) )
323+ } ) ;
324+ group. bench_function ( "include_empty_v6" , |b| {
325+ b. iter ( || black_box ( filter_none. allows ( black_box ( src_v6) ) ) )
326+ } ) ;
327+
328+ group. finish ( ) ;
329+ }
330+
331+ criterion_group ! ( wall, parse_and_process, source_filter_allows) ;
222332criterion_group ! (
223333 name = alloc;
224334 config = new_crit( Allocs ) ;
0 commit comments