fea: switch: support router network

This commit is contained in:
Daniel Ding
2023-09-26 15:30:04 +08:00
parent baec14f05e
commit a15a737e2c
11 changed files with 356 additions and 158 deletions

View File

@@ -0,0 +1,20 @@
{
"name": "router",
"provider": "router",
"specifies": {
"link": "eth0",
"subnets": [
{
"cidr": "192.168.0.0/24"
},
{
"cidr": "192.168.1.0/24"
}
]
},
"routes": [
{
"prefix": "172.16.3.0/24"
}
]
}

View File

@@ -14,5 +14,6 @@ type FlowRule struct {
Match string `json:"match,omitempty"` Match string `json:"match,omitempty"`
DstPort string `json:"destPort,omitempty"` DstPort string `json:"destPort,omitempty"`
SrcPort string `json:"sourcePort,omitempty"` SrcPort string `json:"sourcePort,omitempty"`
CtState string `json:"ctState,omitempty"`
Jump string `json:"jump,omitempty"` // SNAT/RETURN/MASQUERADE Jump string `json:"jump,omitempty"` // SNAT/RETURN/MASQUERADE
} }

View File

@@ -1,9 +1,10 @@
package config package config
import ( import (
"github.com/luscis/openlan/pkg/libol"
"net" "net"
"path/filepath" "path/filepath"
"github.com/luscis/openlan/pkg/libol"
) )
type Network struct { type Network struct {
@@ -24,6 +25,22 @@ type Network struct {
Outputs []Output `json:"outputs"` Outputs []Output `json:"outputs"`
} }
func (n *Network) NewSpecifies() interface{} {
switch n.Provider {
case "esp":
n.Specifies = &ESPSpecifies{}
case "vxlan":
n.Specifies = &VxLANSpecifies{}
case "fabric":
n.Specifies = &FabricSpecifies{}
case "router":
n.Specifies = &RouterSpecifies{}
default:
n.Specifies = nil
}
return n.Specifies
}
func (n *Network) Correct() { func (n *Network) Correct() {
if n.Bridge == nil { if n.Bridge == nil {
n.Bridge = &Bridge{} n.Bridge = &Bridge{}
@@ -51,7 +68,13 @@ func (n *Network) Correct() {
obj.Correct() obj.Correct()
obj.Name = n.Name obj.Name = n.Name
} }
default: case "router":
spec := n.Specifies
if obj, ok := spec.(*RouterSpecifies); ok {
obj.Correct()
obj.Name = n.Name
}
}
if n.Subnet == nil { if n.Subnet == nil {
n.Subnet = &Subnet{} n.Subnet = &Subnet{}
} }
@@ -64,17 +87,7 @@ func (n *Network) Correct() {
if n.Subnet.Netmask == "" { if n.Subnet.Netmask == "" {
n.Subnet.Netmask = ipMask n.Subnet.Netmask = ipMask
} }
for i := range n.Routes { CorrectRoutes(n.Routes, ipAddr)
if n.Routes[i].Metric == 0 {
n.Routes[i].Metric = 660
}
if n.Routes[i].NextHop == "" {
n.Routes[i].NextHop = ipAddr
}
if n.Routes[i].Mode == "" {
n.Routes[i].Mode = "snat"
}
}
if n.OpenVPN != nil { if n.OpenVPN != nil {
n.OpenVPN.Network = n.Name n.OpenVPN.Network = n.Name
obj := DefaultOpenVPN() obj := DefaultOpenVPN()
@@ -82,7 +95,6 @@ func (n *Network) Correct() {
n.OpenVPN.Correct() n.OpenVPN.Correct()
} }
} }
}
func (n *Network) Dir(elem ...string) string { func (n *Network) Dir(elem ...string) string {
args := append([]string{n.ConfDir}, elem...) args := append([]string{n.ConfDir}, elem...)

11
pkg/config/router.go Normal file
View File

@@ -0,0 +1,11 @@
package config
type RouterSpecifies struct {
Mss int `json:"tcpMss,omitempty"`
Name string `json:"name,omitempty"`
Link string `json:"link,omitempty"`
Subnets []Subnet `json:"subnets"`
}
func (n *RouterSpecifies) Correct() {
}

View File

@@ -10,6 +10,7 @@ type Subnet struct {
Start string `json:"startAt,omitempty"` Start string `json:"startAt,omitempty"`
End string `json:"endAt,omitempty"` End string `json:"endAt,omitempty"`
Netmask string `json:"netmask,omitempty"` Netmask string `json:"netmask,omitempty"`
CIDR string `json:"cidr,omitempty"`
} }
type MultiPath struct { type MultiPath struct {
@@ -44,6 +45,20 @@ func (r *PrefixRoute) String() string {
return fmt.Sprintf("{%s}", strings.Join(elems, " ")) return fmt.Sprintf("{%s}", strings.Join(elems, " "))
} }
func CorrectRoutes(routes []PrefixRoute, nexthop string) {
for i := range routes {
if routes[i].Metric == 0 {
routes[i].Metric = 660
}
if routes[i].NextHop == "" {
routes[i].NextHop = nexthop
}
if routes[i].Mode == "" {
routes[i].Mode = "snat"
}
}
}
type HostLease struct { type HostLease struct {
Network string `json:"network,omitempty"` Network string `json:"network,omitempty"`
Hostname string `json:"hostname"` Hostname string `json:"hostname"`

View File

@@ -2,8 +2,9 @@ package config
import ( import (
"flag" "flag"
"github.com/luscis/openlan/pkg/libol"
"path/filepath" "path/filepath"
"github.com/luscis/openlan/pkg/libol"
) )
type Perf struct { type Perf struct {
@@ -150,22 +151,13 @@ func (s *Switch) Dir(elem ...string) string {
func (s *Switch) Format() { func (s *Switch) Format() {
for _, obj := range s.Network { for _, obj := range s.Network {
libol.Debug("Switch.Format %s", obj)
context := obj.Specifies context := obj.Specifies
switch obj.Provider { obj.NewSpecifies()
case "esp":
obj.Specifies = &ESPSpecifies{}
case "vxlan":
obj.Specifies = &VxLANSpecifies{}
case "fabric":
obj.Specifies = &FabricSpecifies{}
default:
obj.Specifies = nil
continue
}
if data, err := libol.Marshal(context, true); err == nil { if data, err := libol.Marshal(context, true); err == nil {
if err := libol.Unmarshal(obj.Specifies, data); err != nil { if err := libol.Unmarshal(obj.Specifies, data); err != nil {
libol.Warn("Switch.Format %s", err) libol.Warn("Switch.Format %s", err)
} else {
libol.Info("Switch.Format %v", obj.Specifies)
} }
} }
} }

View File

@@ -44,6 +44,7 @@ func NewFireWallGlobal(flows []config.FlowRule) *FireWallGlobal {
SrcPort: rule.SrcPort, SrcPort: rule.SrcPort,
Input: rule.Input, Input: rule.Input,
Output: rule.Output, Output: rule.Output,
CtState: rule.CtState,
}) })
} }
return f return f

View File

@@ -47,6 +47,7 @@ type IpRule struct {
SetMss int SetMss int
Order string Order string
Match string Match string
CtState string
TcpFlag []string TcpFlag []string
} }
@@ -81,6 +82,9 @@ func (ru IpRule) Args() []string {
args = append(args, "!") args = append(args, "!")
args = append(args, "-m", "set", "--match-set", ru.NoDestSet, "dst") args = append(args, "-m", "set", "--match-set", ru.NoDestSet, "dst")
} }
if ru.CtState != "" {
args = append(args, "-m", "conntrack", "--ctstate", ru.CtState)
}
if ru.Proto != "" { if ru.Proto != "" {
args = append(args, "-p", ru.Proto) args = append(args, "-p", ru.Proto)
} }

View File

@@ -36,6 +36,8 @@ func NewNetworker(c *co.Network) Networker {
obj = NewVxLANWorker(c) obj = NewVxLANWorker(c)
case "fabric": case "fabric":
obj = NewFabricWorker(c) obj = NewFabricWorker(c)
case "router":
obj = NewRouterWorker(c)
default: default:
obj = NewOpenLANWorker(c) obj = NewOpenLANWorker(c)
} }
@@ -66,12 +68,17 @@ type WorkerImpl struct {
dhcp *Dhcp dhcp *Dhcp
outputs []*LinuxPort outputs []*LinuxPort
fire *cn.FireWallTable fire *cn.FireWallTable
setR *cn.IPSet
setV *cn.IPSet
vpn *OpenVPN
} }
func NewWorkerApi(c *co.Network) *WorkerImpl { func NewWorkerApi(c *co.Network) *WorkerImpl {
return &WorkerImpl{ return &WorkerImpl{
cfg: c, cfg: c,
out: libol.NewSubLogger(c.Name), out: libol.NewSubLogger(c.Name),
setR: cn.NewIPSet(c.Name+"_r", "hash:net"),
setV: cn.NewIPSet(c.Name+"_v", "hash:net"),
} }
} }
@@ -88,6 +95,12 @@ func (w *WorkerImpl) Initialize() {
}) })
} }
w.fire = cn.NewFireWallTable(w.cfg.Name) w.fire = cn.NewFireWallTable(w.cfg.Name)
if out, err := w.setV.Clear(); err != nil {
w.out.Error("WorkImpl.Initialize: create ipset: %s %s", out, err)
}
if out, err := w.setR.Clear(); err != nil {
w.out.Error("WorkImpl.Initialize: create ipset: %s %s", out, err)
}
} }
func (w *WorkerImpl) AddPhysical(bridge string, vlan int, output string) { func (w *WorkerImpl) AddPhysical(bridge string, vlan int, output string) {
@@ -176,6 +189,7 @@ func (w *WorkerImpl) Start(v api.Switcher) {
cfg := w.cfg cfg := w.cfg
fire := w.fire fire := w.fire
w.out.Info("WorkerImpl.Start")
if cfg.Acl != "" { if cfg.Acl != "" {
fire.Raw.Pre.AddRule(cn.IpRule{ fire.Raw.Pre.AddRule(cn.IpRule{
Input: cfg.Bridge.Name, Input: cfg.Bridge.Name,
@@ -214,7 +228,7 @@ func (w *WorkerImpl) Start(v api.Switcher) {
w.AddOutput(cfg.Bridge.Name, port) w.AddOutput(cfg.Bridge.Name, port)
w.outputs = append(w.outputs, port) w.outputs = append(w.outputs, port)
} }
if w.dhcp != nil { if !(w.dhcp == nil) {
w.dhcp.Start() w.dhcp.Start()
fire.Nat.Post.AddRule(cn.IpRule{ fire.Nat.Post.AddRule(cn.IpRule{
Source: cfg.Bridge.Address, Source: cfg.Bridge.Address,
@@ -223,6 +237,10 @@ func (w *WorkerImpl) Start(v api.Switcher) {
Comment: "Default Gateway for DHCP", Comment: "Default Gateway for DHCP",
}) })
} }
if !(w.vpn == nil) {
w.vpn.Start()
}
w.fire.Start()
} }
func (w *WorkerImpl) DelPhysical(bridge string, vlan int, output string) { func (w *WorkerImpl) DelPhysical(bridge string, vlan int, output string) {
@@ -272,13 +290,20 @@ func (w *WorkerImpl) DelOutput(bridge string, port *LinuxPort) {
} }
func (w *WorkerImpl) Stop() { func (w *WorkerImpl) Stop() {
if w.dhcp != nil { w.out.Info("WorkerImpl.Stop")
w.fire.Stop()
if !(w.vpn == nil) {
w.vpn.Stop()
}
if !(w.dhcp == nil) {
w.dhcp.Stop() w.dhcp.Stop()
} }
for _, output := range w.outputs { for _, output := range w.outputs {
w.DelOutput(w.cfg.Bridge.Name, output) w.DelOutput(w.cfg.Bridge.Name, output)
} }
w.outputs = nil w.outputs = nil
w.setR.Destroy()
w.setV.Destroy()
} }
func (w *WorkerImpl) String() string { func (w *WorkerImpl) String() string {
@@ -303,3 +328,82 @@ func (w *WorkerImpl) Subnet() string {
func (w *WorkerImpl) Reload(v api.Switcher) { func (w *WorkerImpl) Reload(v api.Switcher) {
} }
func (w *WorkerImpl) toACL(acl, input string) {
if input == "" {
return
}
if acl != "" {
w.fire.Raw.Pre.AddRule(cn.IpRule{
Input: input,
Jump: acl,
})
}
}
func (w *WorkerImpl) openPort(protocol, port, comment string) {
w.out.Info("WorkerImpl.openPort %s %s", protocol, port)
// allowed forward between source and prefix.
w.fire.Filter.In.AddRule(cn.IpRule{
Proto: protocol,
Match: "multiport",
DstPort: port,
Comment: comment,
})
}
func (w *WorkerImpl) toForward_r(input, output, source, pfxSet, comment string) {
w.out.Debug("WorkerImpl.toForward %s:%s %s:%s", input, output, source, pfxSet)
// Allowed forward between source and prefix.
w.fire.Filter.For.AddRule(cn.IpRule{
Input: input,
Output: output,
Source: source,
DestSet: pfxSet,
Comment: comment,
})
}
func (w *WorkerImpl) toForward_s(input, output, srcSet, prefix, comment string) {
w.out.Debug("WorkerImpl.toForward %s:%s %s:%s", input, output, srcSet, prefix)
// Allowed forward between source and prefix.
w.fire.Filter.For.AddRule(cn.IpRule{
Input: input,
Output: output,
SrcSet: srcSet,
Dest: prefix,
Comment: comment,
})
}
func (w *WorkerImpl) toMasq_r(source, pfxSet, comment string) {
// Enable masquerade from source to prefix.
w.fire.Nat.Post.AddRule(cn.IpRule{
Source: source,
DestSet: pfxSet,
Jump: cn.CMasq,
Comment: comment,
})
}
func (w *WorkerImpl) toMasq_s(srcSet, prefix, comment string) {
// Enable masquerade from source to prefix.
w.fire.Nat.Post.AddRule(cn.IpRule{
SrcSet: srcSet,
Dest: prefix,
Jump: cn.CMasq,
Comment: comment,
})
}
func (w *WorkerImpl) toRelated(output, comment string) {
w.out.Debug("WorkerImpl.toRelated %s", output)
// Allowed forward between source and prefix.
w.fire.Filter.For.AddRule(cn.IpRule{
Output: output,
CtState: "RELATED,ESTABLISHED",
Comment: comment,
})
}

View File

@@ -11,8 +11,8 @@ import (
co "github.com/luscis/openlan/pkg/config" co "github.com/luscis/openlan/pkg/config"
"github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/libol"
"github.com/luscis/openlan/pkg/models" "github.com/luscis/openlan/pkg/models"
"github.com/luscis/openlan/pkg/network" cn "github.com/luscis/openlan/pkg/network"
"github.com/vishvananda/netlink" nl "github.com/vishvananda/netlink"
) )
func PeerName(name, prefix string) (string, string) { func PeerName(name, prefix string) (string, string) {
@@ -25,10 +25,7 @@ type OpenLANWorker struct {
newTime int64 newTime int64
startTime int64 startTime int64
links *Links links *Links
bridge network.Bridger bridge cn.Bridger
vpn *OpenVPN
setR *network.IPSet
setV *network.IPSet
} }
func NewOpenLANWorker(c *co.Network) *OpenLANWorker { func NewOpenLANWorker(c *co.Network) *OpenLANWorker {
@@ -38,80 +35,9 @@ func NewOpenLANWorker(c *co.Network) *OpenLANWorker {
newTime: time.Now().Unix(), newTime: time.Now().Unix(),
startTime: 0, startTime: 0,
links: NewLinks(), links: NewLinks(),
setR: network.NewIPSet(c.Name+"_r", "hash:net"),
setV: network.NewIPSet(c.Name+"_v", "hash:net"),
} }
} }
func (w *OpenLANWorker) toACL(acl, input string) {
if input == "" {
return
}
if acl != "" {
w.fire.Raw.Pre.AddRule(network.IpRule{
Input: input,
Jump: acl,
})
}
}
func (w *OpenLANWorker) openPort(protocol, port, comment string) {
w.out.Info("OpenLANWorker.openPort %s %s", protocol, port)
// allowed forward between source and prefix.
w.fire.Filter.In.AddRule(network.IpRule{
Proto: protocol,
Match: "multiport",
DstPort: port,
Comment: comment,
})
}
func (w *OpenLANWorker) toForward_r(input, output, source, pfxSet, comment string) {
w.out.Debug("OpenLANWorker.toForward %s:%s %s:%s", input, output, source, pfxSet)
// Allowed forward between source and prefix.
w.fire.Filter.For.AddRule(network.IpRule{
Input: input,
Output: output,
Source: source,
DestSet: pfxSet,
Comment: comment,
})
}
func (w *OpenLANWorker) toForward_s(input, output, srcSet, prefix, comment string) {
w.out.Debug("OpenLANWorker.toForward %s:%s %s:%s", input, output, srcSet, prefix)
// Allowed forward between source and prefix.
w.fire.Filter.For.AddRule(network.IpRule{
Input: input,
Output: output,
SrcSet: srcSet,
Dest: prefix,
Comment: comment,
})
}
func (w *OpenLANWorker) toMasq_r(source, pfxSet, comment string) {
// Enable masquerade from source to prefix.
w.fire.Nat.Post.AddRule(network.IpRule{
Source: source,
DestSet: pfxSet,
Jump: network.CMasq,
Comment: comment,
})
}
func (w *OpenLANWorker) toMast_s(srcSet, prefix, comment string) {
// Enable masquerade from source to prefix.
w.fire.Nat.Post.AddRule(network.IpRule{
SrcSet: srcSet,
Dest: prefix,
Jump: network.CMasq,
Comment: comment,
})
}
func (w *OpenLANWorker) updateVPN() { func (w *OpenLANWorker) updateVPN() {
cfg := w.Config() cfg := w.Config()
vCfg := cfg.OpenVPN vCfg := cfg.OpenVPN
@@ -152,6 +78,8 @@ func (w *OpenLANWorker) allowedVPN() {
} }
devName := vCfg.Device devName := vCfg.Device
// Enable MASQUERADE, and allowed forward.
w.toRelated(devName, "Accept related")
w.toACL(cfg.Acl, devName) w.toACL(cfg.Acl, devName)
for _, rt := range vCfg.Routes { for _, rt := range vCfg.Routes {
@@ -179,6 +107,7 @@ func (w *OpenLANWorker) allowedSubnet() {
subnet := w.Subnet() subnet := w.Subnet()
// Enable MASQUERADE, and allowed forward. // Enable MASQUERADE, and allowed forward.
w.toRelated(br.Name, "Accept related")
for _, rt := range cfg.Routes { for _, rt := range cfg.Routes {
if rt.MultiPath != nil { if rt.MultiPath != nil {
continue continue
@@ -193,7 +122,7 @@ func (w *OpenLANWorker) allowedSubnet() {
w.toForward_r(br.Name, "", subnet, w.setR.Name, "To route") w.toForward_r(br.Name, "", subnet, w.setR.Name, "To route")
w.toForward_s("", br.Name, w.setR.Name, subnet, "From route") w.toForward_s("", br.Name, w.setR.Name, subnet, "From route")
if vCfg != nil { if vCfg != nil {
w.toMast_s(w.setR.Name, vCfg.Subnet, "To VPN") w.toMasq_s(w.setR.Name, vCfg.Subnet, "To VPN")
} }
w.toMasq_r(subnet, w.setR.Name, "To Masq") w.toMasq_r(subnet, w.setR.Name, "To Masq")
} }
@@ -231,7 +160,7 @@ func (w *OpenLANWorker) Initialize() {
lease.Network = w.cfg.Name lease.Network = w.cfg.Name
} }
} }
w.bridge = network.NewBridger(brCfg.Provider, brCfg.Name, brCfg.IPMtu) w.bridge = cn.NewBridger(brCfg.Provider, brCfg.Name, brCfg.IPMtu)
w.updateVPN() w.updateVPN()
vCfg := w.cfg.OpenVPN vCfg := w.cfg.OpenVPN
@@ -241,12 +170,6 @@ func (w *OpenLANWorker) Initialize() {
w.vpn = obj w.vpn = obj
} }
w.WorkerImpl.Initialize() w.WorkerImpl.Initialize()
if out, err := w.setV.Clear(); err != nil {
w.out.Error("OpenLANWorker.Initialize: create ipset: %s %s", out, err)
}
if out, err := w.setR.Clear(); err != nil {
w.out.Error("OpenLANWorker.Initialize: create ipset: %s %s", out, err)
}
w.allowedSubnet() w.allowedSubnet()
w.allowedVPN() w.allowedVPN()
} }
@@ -282,9 +205,9 @@ func (w *OpenLANWorker) LoadRoutes() {
// route's next-hop is local not install again. // route's next-hop is local not install again.
continue continue
} }
nlrt := netlink.Route{Dst: dst} nlrt := nl.Route{Dst: dst}
for _, hop := range rt.MultiPath { for _, hop := range rt.MultiPath {
nxhe := &netlink.NexthopInfo{ nxhe := &nl.NexthopInfo{
Hops: hop.Weight, Hops: hop.Weight,
Gw: net.ParseIP(hop.NextHop), Gw: net.ParseIP(hop.NextHop),
} }
@@ -302,7 +225,7 @@ func (w *OpenLANWorker) LoadRoutes() {
} }
rt_c := rt rt_c := rt
promise.Go(func() error { promise.Go(func() error {
if err := netlink.RouteReplace(&nlrt); err != nil { if err := nl.RouteReplace(&nlrt); err != nil {
w.out.Warn("OpenLANWorker.LoadRoute: %v %s", nlrt, err) w.out.Warn("OpenLANWorker.LoadRoute: %v %s", nlrt, err)
return err return err
} }
@@ -319,13 +242,13 @@ func (w *OpenLANWorker) UnLoadRoutes() {
if err != nil { if err != nil {
continue continue
} }
nlRt := netlink.Route{Dst: dst} nlRt := nl.Route{Dst: dst}
if rt.MultiPath == nil { if rt.MultiPath == nil {
nlRt.Gw = net.ParseIP(rt.NextHop) nlRt.Gw = net.ParseIP(rt.NextHop)
nlRt.Priority = rt.Metric nlRt.Priority = rt.Metric
} }
w.out.Debug("OpenLANWorker.UnLoadRoute: %s", nlRt.String()) w.out.Debug("OpenLANWorker.UnLoadRoute: %s", nlRt.String())
if err := netlink.RouteDel(&nlRt); err != nil { if err := nl.RouteDel(&nlRt); err != nil {
w.out.Warn("OpenLANWorker.UnLoadRoute: %s", err) w.out.Warn("OpenLANWorker.UnLoadRoute: %s", err)
continue continue
} }
@@ -364,11 +287,11 @@ func (w *OpenLANWorker) connectPeer(cfg *co.Bridge) {
return return
} }
in, ex := PeerName(cfg.Network, "-e") in, ex := PeerName(cfg.Network, "-e")
link := &netlink.Veth{ link := &nl.Veth{
LinkAttrs: netlink.LinkAttrs{Name: in}, LinkAttrs: nl.LinkAttrs{Name: in},
PeerName: ex, PeerName: ex,
} }
br := network.NewBrCtl(cfg.Peer, cfg.IPMtu) br := cn.NewBrCtl(cfg.Peer, cfg.IPMtu)
promise := &libol.Promise{ promise := &libol.Promise{
First: time.Second * 2, First: time.Second * 2,
MaxInt: time.Minute, MaxInt: time.Minute,
@@ -379,16 +302,16 @@ func (w *OpenLANWorker) connectPeer(cfg *co.Bridge) {
w.out.Warn("%s notFound", br.Name) w.out.Warn("%s notFound", br.Name)
return libol.NewErr("%s notFound", br.Name) return libol.NewErr("%s notFound", br.Name)
} }
err := netlink.LinkAdd(link) err := nl.LinkAdd(link)
if err != nil { if err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err) w.out.Error("OpenLANWorker.connectPeer: %s", err)
return nil return nil
} }
br0 := network.NewBrCtl(cfg.Name, cfg.IPMtu) br0 := cn.NewBrCtl(cfg.Name, cfg.IPMtu)
if err := br0.AddPort(in); err != nil { if err := br0.AddPort(in); err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err) w.out.Error("OpenLANWorker.connectPeer: %s", err)
} }
br1 := network.NewBrCtl(cfg.Peer, cfg.IPMtu) br1 := cn.NewBrCtl(cfg.Peer, cfg.IPMtu)
if err := br1.AddPort(ex); err != nil { if err := br1.AddPort(ex); err != nil {
w.out.Error("OpenLANWorker.connectPeer: %s", err) w.out.Error("OpenLANWorker.connectPeer: %s", err)
} }
@@ -403,11 +326,7 @@ func (w *OpenLANWorker) Start(v api.Switcher) {
w.UpBridge(w.cfg.Bridge) w.UpBridge(w.cfg.Bridge)
w.LoadLinks() w.LoadLinks()
w.LoadRoutes() w.LoadRoutes()
if !(w.vpn == nil) {
w.vpn.Start()
}
w.WorkerImpl.Start(v) w.WorkerImpl.Start(v)
w.fire.Start()
} }
func (w *OpenLANWorker) downBridge(cfg *co.Bridge) { func (w *OpenLANWorker) downBridge(cfg *co.Bridge) {
@@ -420,11 +339,11 @@ func (w *OpenLANWorker) closePeer(cfg *co.Bridge) {
return return
} }
in, ex := PeerName(cfg.Network, "-e") in, ex := PeerName(cfg.Network, "-e")
link := &netlink.Veth{ link := &nl.Veth{
LinkAttrs: netlink.LinkAttrs{Name: in}, LinkAttrs: nl.LinkAttrs{Name: in},
PeerName: ex, PeerName: ex,
} }
err := netlink.LinkDel(link) err := nl.LinkDel(link)
if err != nil { if err != nil {
w.out.Error("OpenLANWorker.closePeer: %s", err) w.out.Error("OpenLANWorker.closePeer: %s", err)
return return
@@ -433,17 +352,11 @@ func (w *OpenLANWorker) closePeer(cfg *co.Bridge) {
func (w *OpenLANWorker) Stop() { func (w *OpenLANWorker) Stop() {
w.out.Info("OpenLANWorker.Close") w.out.Info("OpenLANWorker.Close")
w.fire.Stop()
w.WorkerImpl.Stop() w.WorkerImpl.Stop()
if !(w.vpn == nil) {
w.vpn.Stop()
}
w.UnLoadRoutes() w.UnLoadRoutes()
w.UnLoadLinks() w.UnLoadLinks()
w.startTime = 0 w.startTime = 0
w.downBridge(w.cfg.Bridge) w.downBridge(w.cfg.Bridge)
w.setR.Destroy()
w.setV.Destroy()
} }
func (w *OpenLANWorker) UpTime() int64 { func (w *OpenLANWorker) UpTime() int64 {
@@ -459,7 +372,7 @@ func (w *OpenLANWorker) AddLink(c co.Point) {
c.Alias = w.alias c.Alias = w.alias
c.Network = w.cfg.Name c.Network = w.cfg.Name
c.Interface.Name = network.Taps.GenName() c.Interface.Name = cn.Taps.GenName()
c.Interface.Bridge = br.Name c.Interface.Bridge = br.Name
c.Interface.Address = br.Address c.Interface.Address = br.Address
c.Interface.Provider = br.Provider c.Interface.Provider = br.Provider
@@ -501,7 +414,7 @@ func (w *OpenLANWorker) Subnet() string {
return "" return ""
} }
func (w *OpenLANWorker) Bridge() network.Bridger { func (w *OpenLANWorker) Bridge() cn.Bridger {
return w.bridge return w.bridge
} }

125
pkg/switch/router.go Executable file
View File

@@ -0,0 +1,125 @@
package _switch
import (
"net"
"time"
"github.com/luscis/openlan/pkg/api"
co "github.com/luscis/openlan/pkg/config"
"github.com/luscis/openlan/pkg/libol"
nl "github.com/vishvananda/netlink"
)
type RouterWorker struct {
*WorkerImpl
spec *co.RouterSpecifies
}
func NewRouterWorker(c *co.Network) *RouterWorker {
w := &RouterWorker{
WorkerImpl: NewWorkerApi(c),
}
w.spec, _ = c.Specifies.(*co.RouterSpecifies)
return w
}
func (w *RouterWorker) Initialize() {
w.WorkerImpl.Initialize()
}
func (w *RouterWorker) LoadRoutes() {
// install routes
cfg := w.cfg
w.out.Debug("RouterWorker.LoadRoute: %v", cfg.Routes)
for _, rt := range cfg.Routes {
_, dst, err := net.ParseCIDR(rt.Prefix)
if err != nil {
continue
}
if rt.NextHop == "" && rt.MultiPath == nil {
// route's next-hop is local not install again.
continue
}
nlrt := nl.Route{Dst: dst}
for _, hop := range rt.MultiPath {
nxhe := &nl.NexthopInfo{
Hops: hop.Weight,
Gw: net.ParseIP(hop.NextHop),
}
nlrt.MultiPath = append(nlrt.MultiPath, nxhe)
}
if rt.MultiPath == nil {
nlrt.Gw = net.ParseIP(rt.NextHop)
nlrt.Priority = rt.Metric
}
w.out.Debug("RouterWorker.LoadRoute: %s", nlrt.String())
promise := &libol.Promise{
First: time.Second * 2,
MaxInt: time.Minute,
MinInt: time.Second * 10,
}
rt_c := rt
promise.Go(func() error {
if err := nl.RouteReplace(&nlrt); err != nil {
w.out.Warn("RouterWorker.LoadRoute: %v %s", nlrt, err)
return err
}
w.out.Info("RouterWorker.LoadRoute: %v success", rt_c.String())
return nil
})
}
}
func (w *RouterWorker) UnLoadRoutes() {
cfg := w.cfg
for _, rt := range cfg.Routes {
_, dst, err := net.ParseCIDR(rt.Prefix)
if err != nil {
continue
}
nlRt := nl.Route{Dst: dst}
if rt.MultiPath == nil {
nlRt.Gw = net.ParseIP(rt.NextHop)
nlRt.Priority = rt.Metric
}
w.out.Debug("RouterWorker.UnLoadRoute: %s", nlRt.String())
if err := nl.RouteDel(&nlRt); err != nil {
w.out.Warn("RouterWorker.UnLoadRoute: %s", err)
continue
}
w.out.Info("RouterWorker.UnLoadRoute: %v", rt.String())
}
}
func (w *RouterWorker) Forward() {
spec := w.spec
// Enable MASQUERADE, and allowed forward.
w.out.Debug("RouterWorker.Forward %v", w.cfg)
for _, sub := range spec.Subnets {
if sub.CIDR == "" {
continue
}
w.setR.Add(sub.CIDR)
}
w.toRelated(spec.Link, "Accept related")
w.toForward_s(spec.Link, "", w.setR.Name, "", "From route")
w.toMasq_s(w.setR.Name, "", "To Masq")
}
func (w *RouterWorker) Start(v api.Switcher) {
w.uuid = v.UUID()
w.LoadRoutes()
w.Forward()
w.WorkerImpl.Start(v)
}
func (w *RouterWorker) Stop() {
w.WorkerImpl.Stop()
w.UnLoadRoutes()
}
func (w *RouterWorker) Reload(v api.Switcher) {
w.Stop()
w.Initialize()
w.Start(v)
}