@@ -61,6 +61,101 @@ impl LibvirtOptions {
6161 }
6262}
6363
64+ /// Convert memory value with unit to megabytes (MiB)
65+ /// Handles libvirt-style units distinguishing between decimal (KB, MB, GB - powers of 1000)
66+ /// and binary (KiB, MiB, GiB - powers of 1024) units per libvirt specification
67+ pub ( crate ) fn convert_memory_to_mb ( value : u32 , unit : & str ) -> Option < u32 > {
68+ // Use u128 for calculations to prevent overflow with large units like TB
69+ let value_u128 = value as u128 ;
70+ let mib_u128 = 1024 * 1024 ;
71+
72+ let mb = match unit {
73+ // Binary prefixes (powers of 1024), converting to MiB
74+ "k" | "K" | "KiB" => value_u128 / 1024 ,
75+ "M" | "MiB" => value_u128,
76+ "G" | "GiB" => value_u128 * 1024 ,
77+ "T" | "TiB" => value_u128 * 1024 * 1024 ,
78+
79+ // Decimal prefixes (powers of 1000), converting to MiB
80+ "B" | "bytes" => value_u128 / mib_u128,
81+ "KB" => ( value_u128 * 1_000u128 . pow ( 1 ) ) / mib_u128,
82+ "MB" => ( value_u128 * 1_000u128 . pow ( 2 ) ) / mib_u128,
83+ "GB" => ( value_u128 * 1_000u128 . pow ( 3 ) ) / mib_u128,
84+ "TB" => ( value_u128 * 1_000u128 . pow ( 4 ) ) / mib_u128,
85+
86+ // Libvirt default is KiB for memory
87+ _ => value_u128 / 1024 ,
88+ } ;
89+ u32:: try_from ( mb) . ok ( )
90+ }
91+
92+ /// Parse memory value from a libvirt XML node with unit attribute
93+ /// Returns the value in megabytes (MiB)
94+ pub ( crate ) fn parse_memory_mb ( node : & crate :: xml_utils:: XmlNode ) -> Option < u32 > {
95+ let value = node. text_content ( ) . parse :: < u32 > ( ) . ok ( ) ?;
96+ // Convert to MB based on unit attribute (default is KiB per libvirt spec)
97+ let unit = node
98+ . attributes
99+ . get ( "unit" )
100+ . map ( |s| s. as_str ( ) )
101+ . unwrap_or ( "KiB" ) ;
102+ convert_memory_to_mb ( value, unit)
103+ }
104+
105+ #[ cfg( test) ]
106+ mod tests {
107+ use super :: * ;
108+
109+ #[ test]
110+ fn test_convert_memory_to_mb ( ) {
111+ // Test binary units (powers of 1024)
112+ assert_eq ! ( convert_memory_to_mb( 4194304 , "KiB" ) , Some ( 4096 ) ) ;
113+ assert_eq ! ( convert_memory_to_mb( 2097152 , "KiB" ) , Some ( 2048 ) ) ;
114+ assert_eq ! ( convert_memory_to_mb( 2048 , "MiB" ) , Some ( 2048 ) ) ;
115+ assert_eq ! ( convert_memory_to_mb( 4096 , "MiB" ) , Some ( 4096 ) ) ;
116+ assert_eq ! ( convert_memory_to_mb( 4 , "GiB" ) , Some ( 4096 ) ) ;
117+ assert_eq ! ( convert_memory_to_mb( 2 , "GiB" ) , Some ( 2048 ) ) ;
118+
119+ // Test short forms (binary)
120+ assert_eq ! ( convert_memory_to_mb( 4 , "G" ) , Some ( 4096 ) ) ;
121+ assert_eq ! ( convert_memory_to_mb( 2048 , "M" ) , Some ( 2048 ) ) ;
122+ assert_eq ! ( convert_memory_to_mb( 2097152 , "K" ) , Some ( 2048 ) ) ;
123+
124+ // Test decimal units (powers of 1000)
125+ assert_eq ! ( convert_memory_to_mb( 1048576 , "KB" ) , Some ( 1000 ) ) ;
126+ assert_eq ! ( convert_memory_to_mb( 1024 , "MB" ) , Some ( 976 ) ) ;
127+ assert_eq ! ( convert_memory_to_mb( 4 , "GB" ) , Some ( 3814 ) ) ;
128+
129+ // Test default/unknown unit (defaults to KiB)
130+ assert_eq ! ( convert_memory_to_mb( 4194304 , "unknown" ) , Some ( 4096 ) ) ;
131+ }
132+
133+ #[ test]
134+ fn test_parse_memory_mb ( ) {
135+ use crate :: xml_utils:: parse_xml_dom;
136+
137+ // Test KiB (default unit)
138+ let xml = r#"<memory>4194304</memory>"# ;
139+ let dom = parse_xml_dom ( xml) . unwrap ( ) ;
140+ assert_eq ! ( parse_memory_mb( & dom) , Some ( 4096 ) ) ;
141+
142+ // Test MiB
143+ let xml = r#"<memory unit='MiB'>2048</memory>"# ;
144+ let dom = parse_xml_dom ( xml) . unwrap ( ) ;
145+ assert_eq ! ( parse_memory_mb( & dom) , Some ( 2048 ) ) ;
146+
147+ // Test GiB
148+ let xml = r#"<memory unit='GiB'>4</memory>"# ;
149+ let dom = parse_xml_dom ( xml) . unwrap ( ) ;
150+ assert_eq ! ( parse_memory_mb( & dom) , Some ( 4096 ) ) ;
151+
152+ // Test KB (decimal unit: 1000-based)
153+ let xml = r#"<memory unit='KB'>1048576</memory>"# ;
154+ let dom = parse_xml_dom ( xml) . unwrap ( ) ;
155+ assert_eq ! ( parse_memory_mb( & dom) , Some ( 1000 ) ) ;
156+ }
157+ }
158+
64159/// libvirt subcommands for managing bootc disk images and domains
65160#[ derive( Debug , Subcommand ) ]
66161pub enum LibvirtSubcommands {
0 commit comments