Files
openlan/pkg/switch/openlan_linux.go
2025-04-13 15:33:35 +08:00

208 lines
4.2 KiB
Go
Executable File

package cswitch
import (
"time"
"github.com/luscis/openlan/pkg/api"
"github.com/luscis/openlan/pkg/cache"
co "github.com/luscis/openlan/pkg/config"
"github.com/luscis/openlan/pkg/libol"
cn "github.com/luscis/openlan/pkg/network"
nl "github.com/vishvananda/netlink"
)
func PeerName(name, prefix string) (string, string) {
return name + prefix + "i", name + prefix + "o"
}
type OpenLANWorker struct {
*WorkerImpl
alias string
newTime int64
startTime int64
links *Links
}
func NewOpenLANWorker(c *co.Network) *OpenLANWorker {
return &OpenLANWorker{
WorkerImpl: NewWorkerApi(c),
alias: c.Alias,
newTime: time.Now().Unix(),
startTime: 0,
links: NewLinks(),
}
}
func (w *OpenLANWorker) Initialize() {
brCfg := w.cfg.Bridge
name := w.cfg.Name
w.br = cn.NewBridger(brCfg.Provider, brCfg.Name, brCfg.IPMtu)
for _, ht := range w.cfg.Hosts {
lease := cache.Network.AddLease(ht.Hostname, ht.Address, name)
if lease != nil {
lease.Type = "static"
lease.Network = name
}
}
w.WorkerImpl.Initialize()
}
func (w *OpenLANWorker) LoadLinks() {
if w.cfg.Links != nil {
for _, link := range w.cfg.Links {
link.Correct()
w.AddLink(link)
}
}
}
func (w *OpenLANWorker) UnLoadLinks() {
w.links.lock.RLock()
defer w.links.lock.RUnlock()
for _, l := range w.links.links {
l.Stop()
}
}
func (w *OpenLANWorker) UpBridge(cfg *co.Bridge) {
master := w.br
// new it and configure address
master.Open(cfg.Address)
// configure stp
if cfg.Stp == "enable" {
if err := master.Stp(true); err != nil {
w.out.Warn("OpenLANWorker.UpBridge: Stp %s", err)
}
} else {
_ = master.Stp(false)
}
// configure forward delay
if err := master.Delay(cfg.Delay); err != nil {
w.out.Warn("OpenLANWorker.UpBridge: Delay %s", err)
}
w.connectPeer(cfg)
if err := master.CallIptables(0); err != nil {
w.out.Warn("OpenLANWorker.Start: CallIptables %s", err)
}
}
func (w *OpenLANWorker) connectPeer(cfg *co.Bridge) {
if cfg.Peer == "" {
return
}
in, ex := PeerName(cfg.Network, "-e")
link := &nl.Veth{
LinkAttrs: nl.LinkAttrs{Name: in},
PeerName: ex,
}
br := cn.NewBrCtl(cfg.Peer, cfg.IPMtu)
promise := &libol.Promise{
First: time.Second * 2,
MaxInt: time.Minute,
MinInt: time.Second * 10,
}
promise.Go(func() error {
if !br.Has() {
w.out.Warn("%s notFound", br.Name)
return libol.NewErr("%s notFound", br.Name)
}
err := nl.LinkAdd(link)
if err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err)
return nil
}
br0 := cn.NewBrCtl(cfg.Name, cfg.IPMtu)
if err := br0.AddPort(in); err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err)
}
br1 := cn.NewBrCtl(cfg.Peer, cfg.IPMtu)
if err := br1.AddPort(ex); err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err)
}
return nil
})
}
func (w *OpenLANWorker) Start(v api.Switcher) {
w.uuid = v.UUID()
w.startTime = time.Now().Unix()
w.out.Info("OpenLANWorker.Start")
w.UpBridge(w.cfg.Bridge)
w.LoadLinks()
w.WorkerImpl.Start(v)
}
func (w *OpenLANWorker) downBridge(cfg *co.Bridge) {
w.closePeer(cfg)
_ = w.br.Close()
}
func (w *OpenLANWorker) closePeer(cfg *co.Bridge) {
if cfg.Peer == "" {
return
}
in, ex := PeerName(cfg.Network, "-e")
link := &nl.Veth{
LinkAttrs: nl.LinkAttrs{Name: in},
PeerName: ex,
}
err := nl.LinkDel(link)
if err != nil {
w.out.Error("OpenLANWorker.closePeer: %s", err)
return
}
}
func (w *OpenLANWorker) Stop() {
w.out.Info("OpenLANWorker.Close")
w.WorkerImpl.Stop()
w.UnLoadLinks()
w.startTime = 0
w.downBridge(w.cfg.Bridge)
}
func (w *OpenLANWorker) UpTime() int64 {
if w.startTime != 0 {
return time.Now().Unix() - w.startTime
}
return 0
}
func (w *OpenLANWorker) AddLink(c co.Point) {
br := w.cfg.Bridge
c.Alias = w.alias
c.Network = w.cfg.Name
c.RequestAddr = false
c.Interface.Name = cn.Taps.GenName()
c.Interface.Bridge = br.Name
c.Interface.Address = br.Address
c.Interface.Provider = br.Provider
c.Interface.IPMtu = br.IPMtu
c.Log.File = "/dev/null"
l := NewLink(&c)
l.Initialize()
cache.Link.Add(l.uuid, l.Model())
w.links.Add(l)
l.Start()
}
func (w *OpenLANWorker) DelLink(addr string) {
if l := w.links.Remove(addr); l != nil {
cache.Link.Del(l.uuid)
}
}
func (w *OpenLANWorker) Reload(v api.Switcher) {
w.Stop()
w.Initialize()
w.Start(v)
}