Files

81 lines
1.9 KiB
Go
Raw Permalink Normal View History

2026-04-13 12:40:49 +03:00
package network
import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
)
// IsVLAN reports whether name is a VLAN interface (e.g. "eth0.100").
func IsVLAN(name string) bool {
idx := strings.LastIndex(name, ".")
if idx <= 0 {
return false
}
suffix := name[idx+1:]
if suffix == "" {
return false
}
_, err := strconv.Atoi(suffix)
return err == nil
}
// VLANParent returns the parent interface (e.g. "eth0.100" → "eth0").
func VLANParent(name string) string {
idx := strings.LastIndex(name, ".")
if idx < 0 {
return ""
}
return name[:idx]
}
// VLANId returns the VLAN ID (e.g. "eth0.100" → 100).
func VLANId(name string) int {
idx := strings.LastIndex(name, ".")
if idx < 0 {
return 0
}
id, _ := strconv.Atoi(name[idx+1:])
return id
}
// EnsureVLANExists creates the VLAN interface in the kernel if it doesn't exist.
func EnsureVLANExists(name string) error {
if _, err := os.Stat("/sys/class/net/" + name); err == nil {
return nil
}
parent := VLANParent(name)
id := VLANId(name)
if parent == "" || id == 0 {
return fmt.Errorf("invalid VLAN name: %s", name)
}
out, err := exec.Command("ip", "link", "add", "link", parent,
"name", name, "type", "vlan", "id", strconv.Itoa(id)).CombinedOutput()
if err != nil {
return fmt.Errorf("ip link add %s: %s", name, strings.TrimSpace(string(out)))
}
return nil
}
// DeleteVLAN brings down and removes a VLAN interface and its /etc/network/interfaces stanza.
func DeleteVLAN(name string) error {
_ = IfDown(name)
if _, err := os.Stat("/sys/class/net/" + name); err == nil {
out, err2 := exec.Command("ip", "link", "delete", name).CombinedOutput()
if err2 != nil {
return fmt.Errorf("ip link delete %s: %s", name, strings.TrimSpace(string(out)))
}
}
configs, err := ParseConfig()
if err != nil {
return err
}
if _, ok := configs[name]; ok {
delete(configs, name)
return WriteConfig(configs)
}
return nil
}