Prepare, configure, and manage Firecracker microVMs in seconds!
virtualization linux microvm firecracker
at main 125 lines 3.4 kB view raw
1use crate::{ 2 constants::{BRIDGE_IP, MASK_SHORT}, 3 types::VmOptions, 4}; 5use anyhow::{anyhow, Context, Result}; 6use serde_json::Value; 7 8use crate::command::run_command; 9 10fn check_tap_exists(config: &VmOptions) -> bool { 11 run_command("ip", &["link", "show", &config.tap], false) 12 .map(|output| output.status.success()) 13 .unwrap_or(false) 14} 15 16fn check_bridge_exists(config: &VmOptions) -> bool { 17 run_command("ip", &["link", "show", &config.bridge], false) 18 .map(|output| output.status.success()) 19 .unwrap_or(false) 20} 21 22fn create_new_tap(config: &VmOptions) -> Result<()> { 23 run_command( 24 "ip", 25 &["tuntap", "add", "dev", &config.tap, "mode", "tap"], 26 true, 27 )?; 28 run_command("ip", &["link", "set", "dev", &config.tap, "up"], true)?; 29 run_command( 30 "ip", 31 &["link", "set", &config.tap, "master", &config.bridge], 32 true, 33 )?; 34 Ok(()) 35} 36 37pub fn setup_network(config: &VmOptions) -> Result<()> { 38 if check_tap_exists(config) { 39 run_command("ip", &["addr", "flush", "dev", &config.tap], true)?; 40 } 41 42 if check_tap_exists(config) && check_bridge_exists(config) { 43 println!("[✓] Network already configured. Skipping setup."); 44 return Ok(()); 45 } 46 47 if !check_bridge_exists(config) { 48 println!("[+] Configuring {}...", config.bridge); 49 run_command( 50 "ip", 51 &["link", "add", "name", &config.bridge, "type", "bridge"], 52 true, 53 )?; 54 run_command("ip", &["link", "set", &config.bridge, "up"], true)?; 55 run_command( 56 "ip", 57 &[ 58 "addr", 59 "add", 60 &format!("{}{}", BRIDGE_IP, MASK_SHORT), 61 "dev", 62 &config.bridge, 63 ], 64 true, 65 )?; 66 } 67 68 if !check_tap_exists(config) { 69 println!("[+] Configuring {}...", &config.tap); 70 create_new_tap(config)?; 71 } 72 73 let ip_forward = run_command("cat", &["/proc/sys/net/ipv4/ip_forward"], false)?.stdout; 74 if String::from_utf8_lossy(&ip_forward).trim() != "1" { 75 println!("[+] Enabling IP forwarding..."); 76 run_command("sysctl", &["-w", "net.ipv4.ip_forward=1"], true)?; 77 } 78 79 let output = run_command("ip", &["-j", "route", "list", "default"], false)?; 80 let json: Value = 81 serde_json::from_slice(&output.stdout).with_context(|| "Failed to parse route JSON")?; 82 let host_iface = json[0]["dev"] 83 .as_str() 84 .ok_or_else(|| anyhow!("Failed to get host interface"))?; 85 86 println!("[+] Setting up NAT on {}...", host_iface); 87 88 let rule_exists = run_command( 89 "iptables", 90 &[ 91 "-t", 92 "nat", 93 "-C", 94 "POSTROUTING", 95 "-o", 96 host_iface, 97 "-j", 98 "MASQUERADE", 99 ], 100 true, 101 ) 102 .map(|output| output.status.success()) 103 .unwrap_or(false); 104 105 if !rule_exists { 106 run_command( 107 "iptables", 108 &[ 109 "-t", 110 "nat", 111 "-A", 112 "POSTROUTING", 113 "-o", 114 host_iface, 115 "-j", 116 "MASQUERADE", 117 ], 118 true, 119 )?; 120 } 121 122 run_command("iptables", &["-P", "FORWARD", "ACCEPT"], true)?; 123 124 Ok(()) 125}