81 lines
1.9 KiB
Go
81 lines
1.9 KiB
Go
|
|
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
|
||
|
|
}
|