|
|
@@ -4,22 +4,28 @@ import (
|
|
|
"fmt"
|
|
|
"log"
|
|
|
"math"
|
|
|
+ "net"
|
|
|
"os/exec"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
+
|
|
|
+ "github.com/vishvananda/netlink"
|
|
|
)
|
|
|
|
|
|
-// KernelEngine manages routing tables, ip rules, and netfilter mangle rules for SD-WAN.
|
|
|
+// KernelEngine manages routing tables, ip rules, virtual devices, and netfilter mangle rules for SD-WAN.
|
|
|
type KernelEngine struct {
|
|
|
- mu sync.Mutex
|
|
|
+ mu sync.Mutex
|
|
|
+ virtualDevices map[string]bool
|
|
|
}
|
|
|
|
|
|
func NewKernelEngine() *KernelEngine {
|
|
|
- return &KernelEngine{}
|
|
|
+ return &KernelEngine{
|
|
|
+ virtualDevices: make(map[string]bool),
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// Sync applies the complete routing and iptables rules for all active SD-WAN groups.
|
|
|
+// Sync applies the complete routing, virtual devices, and iptables rules for all active SD-WAN groups.
|
|
|
func (e *KernelEngine) Sync(groups []*SDWANGroup) error {
|
|
|
e.mu.Lock()
|
|
|
defer e.mu.Unlock()
|
|
|
@@ -38,11 +44,26 @@ func (e *KernelEngine) Sync(groups []*SDWANGroup) error {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 3. Synchronize virtual dummy interfaces for active groups (e.g. "sdwan0")
|
|
|
+ activeDevices := make(map[string]bool)
|
|
|
+ for _, g := range groups {
|
|
|
+ if !g.Disabled && len(g.Members) > 0 && g.Name != "" {
|
|
|
+ activeDevices[g.Name] = true
|
|
|
+ e.ensureVirtualDevice(g.Name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for dev := range e.virtualDevices {
|
|
|
+ if !activeDevices[dev] {
|
|
|
+ e.removeVirtualDevice(dev)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ e.virtualDevices = activeDevices
|
|
|
+
|
|
|
if !hasActiveGroups {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
- // 3. Create fresh DEBTIK_SDWAN mangle chain
|
|
|
+ // 4. Create fresh DEBTIK_SDWAN mangle chain
|
|
|
_ = exec.Command("iptables", "-t", "mangle", "-N", "DEBTIK_SDWAN").Run()
|
|
|
_ = exec.Command("iptables", "-t", "mangle", "-F", "DEBTIK_SDWAN").Run()
|
|
|
|
|
|
@@ -352,3 +373,41 @@ func (e *KernelEngine) cleanupIPRules() {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func (e *KernelEngine) ensureVirtualDevice(name string) {
|
|
|
+ if name == "" {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ link, err := netlink.LinkByName(name)
|
|
|
+ if err == nil {
|
|
|
+ if link.Attrs().Flags&net.FlagUp == 0 {
|
|
|
+ _ = netlink.LinkSetUp(link)
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ dummy := &netlink.Dummy{
|
|
|
+ LinkAttrs: netlink.LinkAttrs{
|
|
|
+ Name: name,
|
|
|
+ MTU: 1500,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ if err := netlink.LinkAdd(dummy); err != nil {
|
|
|
+ _ = exec.Command("ip", "link", "add", name, "type", "dummy").Run()
|
|
|
+ _ = exec.Command("ip", "link", "set", name, "up", "mtu", "1500").Run()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ _ = netlink.LinkSetUp(dummy)
|
|
|
+}
|
|
|
+
|
|
|
+func (e *KernelEngine) removeVirtualDevice(name string) {
|
|
|
+ if name == "" {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ link, err := netlink.LinkByName(name)
|
|
|
+ if err == nil {
|
|
|
+ _ = netlink.LinkDel(link)
|
|
|
+ } else {
|
|
|
+ _ = exec.Command("ip", "link", "del", name).Run()
|
|
|
+ }
|
|
|
+}
|