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,116 @@ 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 =
261+ SourceFilter :: Exclude ( sources_v4) ;
262+ group. bench_with_input (
263+ BenchmarkId :: new ( "exclude_miss_v4" , size) ,
264+ & filter_v4,
265+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v4) ) ) ) ,
266+ ) ;
267+ let src_in_list_v4 = make_src_v4 ( 0 ) ;
268+ group. bench_with_input (
269+ BenchmarkId :: new ( "exclude_hit_v4" , size) ,
270+ & filter_v4,
271+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v4) ) ) ) ,
272+ ) ;
273+
274+ let sources_v6: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v6) . collect ( ) ;
275+ let filter_v6 =
276+ SourceFilter :: Exclude ( sources_v6) ;
277+ group. bench_with_input (
278+ BenchmarkId :: new ( "exclude_miss_v6" , size) ,
279+ & filter_v6,
280+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v6) ) ) ) ,
281+ ) ;
282+ let src_in_list_v6 = make_src_v6 ( 0 ) ;
283+ group. bench_with_input (
284+ BenchmarkId :: new ( "exclude_hit_v6" , size) ,
285+ & filter_v6,
286+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v6) ) ) ) ,
287+ ) ;
288+ }
289+
290+ // INCLUDE with sources: "Hit" case where source is in inclusion list
291+ for size in [ 1 , 5 , 10 , 50 , 100 ] {
292+ let sources_v4: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v4) . collect ( ) ;
293+ let filter_v4 =
294+ SourceFilter :: Include ( sources_v4) ;
295+ let src_in_list_v4 = make_src_v4 ( 0 ) ;
296+ group. bench_with_input (
297+ BenchmarkId :: new ( "include_hit_v4" , size) ,
298+ & filter_v4,
299+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v4) ) ) ) ,
300+ ) ;
301+ group. bench_with_input (
302+ BenchmarkId :: new ( "include_miss_v4" , size) ,
303+ & filter_v4,
304+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v4) ) ) ) ,
305+ ) ;
306+
307+ let sources_v6: BTreeSet < _ > = ( 0 ..size) . map ( make_src_v6) . collect ( ) ;
308+ let filter_v6 =
309+ SourceFilter :: Include ( sources_v6) ;
310+ let src_in_list_v6 = make_src_v6 ( 0 ) ;
311+ group. bench_with_input (
312+ BenchmarkId :: new ( "include_hit_v6" , size) ,
313+ & filter_v6,
314+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_in_list_v6) ) ) ) ,
315+ ) ;
316+ group. bench_with_input (
317+ BenchmarkId :: new ( "include_miss_v6" , size) ,
318+ & filter_v6,
319+ |b, f| b. iter ( || black_box ( f. allows ( black_box ( src_v6) ) ) ) ,
320+ ) ;
321+ }
322+
323+ // INCLUDE() empty, rejecting all
324+ let filter_none =
325+ SourceFilter :: Include ( BTreeSet :: new ( ) ) ;
326+ group. bench_function ( "include_empty_v4" , |b| {
327+ b. iter ( || black_box ( filter_none. allows ( black_box ( src_v4) ) ) )
328+ } ) ;
329+ group. bench_function ( "include_empty_v6" , |b| {
330+ b. iter ( || black_box ( filter_none. allows ( black_box ( src_v6) ) ) )
331+ } ) ;
332+
333+ group. finish ( ) ;
334+ }
335+
336+ criterion_group ! ( wall, parse_and_process, source_filter_allows) ;
222337criterion_group ! (
223338 name = alloc;
224339 config = new_crit( Allocs ) ;
0 commit comments