@@ -516,8 +516,8 @@ impl NextIpv4Address {
516516 let subnet = IpNetwork :: from ( subnet) ;
517517 let net = IpNetwork :: from ( first_available_address ( & subnet) ) ;
518518 let max_shift = i64:: from ( last_address_offset ( & subnet) ) ;
519- let generator =
520- DefaultShiftGenerator { base : net , max_shift , min_shift : 0 } ;
519+ let generator = DefaultShiftGenerator :: new ( net , max_shift , 0 )
520+ . expect ( "invalid min/max shift" ) ;
521521 Self { inner : NextItem :: new_scoped ( generator, subnet_id) }
522522 }
523523}
@@ -575,12 +575,13 @@ pub struct NextNicSlot {
575575
576576impl NextNicSlot {
577577 pub fn new ( parent_id : Uuid ) -> Self {
578- let generator = DefaultShiftGenerator {
579- base : 0 ,
580- max_shift : i64:: try_from ( MAX_NICS_PER_INSTANCE )
578+ let generator = DefaultShiftGenerator :: new (
579+ 0 ,
580+ i64:: try_from ( MAX_NICS_PER_INSTANCE )
581581 . expect ( "Too many network interfaces" ) ,
582- min_shift : 0 ,
583- } ;
582+ 0 ,
583+ )
584+ . expect ( "invalid min/max shift" ) ;
584585 Self { inner : NextItem :: new_scoped ( generator, parent_id) }
585586 }
586587}
@@ -607,25 +608,62 @@ pub struct NextMacAddress {
607608 > ,
608609}
609610
611+ // Helper to ensure we correctly compute the min/max shifts for a next MAC
612+ // query.
613+ #[ derive( Copy , Clone , Debug ) ]
614+ struct NextMacShifts {
615+ base : MacAddr ,
616+ min_shift : i64 ,
617+ max_shift : i64 ,
618+ }
619+
620+ impl NextMacShifts {
621+ fn for_guest ( ) -> Self {
622+ let base = MacAddr :: random_guest ( ) ;
623+ Self :: shifts_for ( base, MacAddr :: MIN_GUEST_ADDR , MacAddr :: MAX_GUEST_ADDR )
624+ }
625+
626+ fn for_system ( ) -> NextMacShifts {
627+ let base = MacAddr :: random_system ( ) ;
628+ Self :: shifts_for (
629+ base,
630+ MacAddr :: MIN_SYSTEM_ADDR ,
631+ MacAddr :: MAX_SYSTEM_ADDR ,
632+ )
633+ }
634+
635+ fn shifts_for ( base : MacAddr , min : i64 , max : i64 ) -> NextMacShifts {
636+ let x = base. to_i64 ( ) ;
637+
638+ // The max shift is the distance to the last value. This min shift is
639+ // always expressed as a negative number, giving the largest leftward
640+ // shift, i.e., the distance to the first value.
641+ let max_shift = max - x;
642+ let min_shift = min - x;
643+ Self { base, min_shift, max_shift }
644+ }
645+ }
646+
610647impl NextMacAddress {
611648 pub fn new ( vpc_id : Uuid , kind : NetworkInterfaceKind ) -> Self {
612649 let ( base, max_shift, min_shift) = match kind {
613650 NetworkInterfaceKind :: Instance => {
614- let base = MacAddr :: random_guest ( ) ;
615- let x = base. to_i64 ( ) ;
616- let max_shift = MacAddr :: MAX_GUEST_ADDR - x;
617- let min_shift = x - MacAddr :: MIN_GUEST_ADDR ;
651+ let NextMacShifts { base, min_shift, max_shift } =
652+ NextMacShifts :: for_guest ( ) ;
618653 ( base. into ( ) , max_shift, min_shift)
619654 }
620655 NetworkInterfaceKind :: Service => {
621- let base = MacAddr :: random_system ( ) ;
622- let x = base. to_i64 ( ) ;
623- let max_shift = MacAddr :: MAX_SYSTEM_ADDR - x;
624- let min_shift = x - MacAddr :: MAX_SYSTEM_ADDR ;
656+ let NextMacShifts { base, min_shift, max_shift } =
657+ NextMacShifts :: for_system ( ) ;
625658 ( base. into ( ) , max_shift, min_shift)
626659 }
627660 } ;
628- let generator = DefaultShiftGenerator { base, max_shift, min_shift } ;
661+ let generator = DefaultShiftGenerator :: new ( base, max_shift, min_shift)
662+ . unwrap_or_else ( || {
663+ panic ! (
664+ "invalid min shift ({min_shift}) or max_shift ({max_shift})"
665+ )
666+ } ) ;
629667 Self { inner : NextItem :: new_scoped ( generator, vpc_id) }
630668 }
631669}
@@ -1713,6 +1751,7 @@ mod tests {
17131751 use crate :: db:: model:: NetworkInterface ;
17141752 use crate :: db:: model:: Project ;
17151753 use crate :: db:: model:: VpcSubnet ;
1754+ use crate :: db:: queries:: network_interface:: NextMacShifts ;
17161755 use async_bb8_diesel:: AsyncRunQueryDsl ;
17171756 use dropshot:: test_util:: LogContext ;
17181757 use ipnetwork:: Ipv4Network ;
@@ -2801,4 +2840,37 @@ mod tests {
28012840 "fd00::5" . parse:: <IpAddr >( ) . unwrap( ) ,
28022841 ) ;
28032842 }
2843+
2844+ #[ test]
2845+ fn test_next_mac_shifts_for_system ( ) {
2846+ let NextMacShifts { base, min_shift, max_shift } =
2847+ NextMacShifts :: for_system ( ) ;
2848+ assert ! ( base. is_system( ) ) ;
2849+ assert ! (
2850+ min_shift <= 0 ,
2851+ "expected min shift to be negative, found {min_shift}"
2852+ ) ;
2853+ assert ! ( max_shift >= 0 , "found {max_shift}" ) ;
2854+ let x = base. to_i64 ( ) ;
2855+ assert_eq ! ( x + min_shift, MacAddr :: MIN_SYSTEM_ADDR ) ;
2856+ assert_eq ! ( x + max_shift, MacAddr :: MAX_SYSTEM_ADDR ) ;
2857+ }
2858+
2859+ #[ test]
2860+ fn test_next_mac_shifts_for_guest ( ) {
2861+ let NextMacShifts { base, min_shift, max_shift } =
2862+ NextMacShifts :: for_guest ( ) ;
2863+ assert ! ( base. is_guest( ) ) ;
2864+ assert ! (
2865+ min_shift <= 0 ,
2866+ "expected min shift to be negative, found {min_shift}"
2867+ ) ;
2868+ assert ! (
2869+ max_shift >= 0 ,
2870+ "expected max shift to be positive, found {max_shift}"
2871+ ) ;
2872+ let x = base. to_i64 ( ) ;
2873+ assert_eq ! ( x + min_shift, MacAddr :: MIN_GUEST_ADDR ) ;
2874+ assert_eq ! ( x + max_shift, MacAddr :: MAX_GUEST_ADDR ) ;
2875+ }
28042876}
0 commit comments