package orchestrator import ( "fmt" "os/exec" "strings" ) // setupBridge creates the host bridge + enables NAT if it doesn't exist. func (o *Orchestrator) setupBridge() error { if o.cfg.Bridge == "none" { return nil } // check if bridge already exists if err := run("ip", "link", "show", o.cfg.Bridge); err == nil { return nil // already up } if err := run("ip", "link", "add", o.cfg.Bridge, "type", "bridge"); err != nil { return fmt.Errorf("create bridge: %w", err) } if err := run("ip", "addr", "add", o.cfg.BridgeCIDR, "dev", o.cfg.Bridge); err != nil { return fmt.Errorf("add bridge addr: %w", err) } if err := run("ip", "link", "set", o.cfg.Bridge, "up"); err != nil { return fmt.Errorf("bring bridge up: %w", err) } // find default route interface for NAT out, err := exec.Command("ip", "-4", "route", "show", "default").Output() if err == nil { fields := strings.Fields(string(out)) for i, f := range fields { if f == "dev" && i+1 < len(fields) { iface := fields[i+1] _ = run("sysctl", "-qw", "net.ipv4.ip_forward=1") // idempotent: ignore error if rule exists _ = run("iptables", "-t", "nat", "-A", "POSTROUTING", "-o", iface, "-j", "MASQUERADE") break } } } o.log.Infof("bridge %s up on %s", o.cfg.Bridge, o.cfg.BridgeCIDR) return nil } // createTap creates a tap device and attaches it to the bridge. func (o *Orchestrator) createTap(name string) error { if err := run("ip", "tuntap", "add", "dev", name, "mode", "tap"); err != nil { return fmt.Errorf("create tap %s: %w", name, err) } if err := run("ip", "link", "set", name, "up"); err != nil { return fmt.Errorf("bring tap %s up: %w", name, err) } if o.cfg.Bridge != "none" { if err := run("ip", "link", "set", name, "master", o.cfg.Bridge); err != nil { return fmt.Errorf("attach tap %s to bridge: %w", name, err) } } return nil } func destroyTap(name string) { _ = run("ip", "link", "del", name) } // run executes a command, returning an error if it fails. func run(name string, args ...string) error { return exec.Command(name, args...).Run() }