mirror of
https://github.com/luscis/openlan.git
synced 2025-10-15 05:00:42 +08:00
fix: vrf not clear
This commit is contained in:
32
dist/rootfs/etc/openlan/switch/network/ipsec.json.example
vendored
Executable file
32
dist/rootfs/etc/openlan/switch/network/ipsec.json.example
vendored
Executable file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "ipsec",
|
||||
"provider": "ipsec",
|
||||
"specifies": {
|
||||
"tunnels": [
|
||||
{
|
||||
"remote": "3.3.2.1",
|
||||
"secret": "d7ecd73ccc25",
|
||||
"transport": "gre"
|
||||
},
|
||||
{
|
||||
"remote": "3.3.2.2",
|
||||
"secret": "d7ecd73ccc25",
|
||||
"transport": "gre"
|
||||
},
|
||||
{
|
||||
"localid": "@con1.ipsec.com",
|
||||
"remote": "3.3.3.1",
|
||||
"remoteport": "4501",
|
||||
"secret": "d7ecd73ccc25",
|
||||
"transport": "vxlan"
|
||||
},
|
||||
{
|
||||
"localport": "4501",
|
||||
"remote": "3.3.3.2",
|
||||
"remoteid": "@con1.ipsec.com",
|
||||
"secret": "d7ecd73ccc25",
|
||||
"transport": "vxlan"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "v1024",
|
||||
"provider": "vxlan",
|
||||
"specifies": {
|
||||
"vni": 1024,
|
||||
"fabric": "fabric"
|
||||
},
|
||||
"bridge": {
|
||||
"address": "192.168.55.1/24"
|
||||
},
|
||||
"subnet": {
|
||||
"startAt": "192.168.55.100",
|
||||
"endAt": "192.168.55.130"
|
||||
},
|
||||
"dhcp": "enable"
|
||||
}
|
4
dist/rootfs/var/openlan/script/ipsec.sh
vendored
4
dist/rootfs/var/openlan/script/ipsec.sh
vendored
@@ -14,3 +14,7 @@ set -ex
|
||||
|
||||
## Start pluto
|
||||
/usr/libexec/ipsec/pluto --leak-detective --config /etc/ipsec.conf --nofork
|
||||
|
||||
## Clear xfrm
|
||||
/sbin/ip xfrm policy flush
|
||||
/sbin/ip xfrm state flush
|
@@ -1,63 +0,0 @@
|
||||
package config
|
||||
|
||||
type FabricSpecifies struct {
|
||||
Mss int `json:"tcpMss,omitempty"`
|
||||
Fragment bool `json:"fragment"`
|
||||
Driver string `json:"driver,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Tunnels []*FabricTunnel `json:"tunnels"`
|
||||
}
|
||||
|
||||
func (n *FabricSpecifies) Correct() {
|
||||
for _, tun := range n.Tunnels {
|
||||
tun.Correct()
|
||||
if tun.DstPort == 0 {
|
||||
if n.Driver == "stt" {
|
||||
tun.DstPort = 7471
|
||||
} else {
|
||||
tun.DstPort = 4789 // 8472
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *FabricSpecifies) AddTunnel(obj *FabricTunnel) {
|
||||
found := -1
|
||||
for index, tun := range n.Tunnels {
|
||||
if tun.Remote != obj.Remote {
|
||||
continue
|
||||
}
|
||||
found = index
|
||||
n.Tunnels[index] = obj
|
||||
break
|
||||
}
|
||||
if found < 0 {
|
||||
n.Tunnels = append(n.Tunnels, obj)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *FabricSpecifies) DelTunnel(remote string) bool {
|
||||
found := -1
|
||||
for index, tun := range n.Tunnels {
|
||||
if tun.Remote != remote {
|
||||
continue
|
||||
}
|
||||
found = index
|
||||
break
|
||||
}
|
||||
if found >= 0 {
|
||||
copy(n.Tunnels[found:], n.Tunnels[found+1:])
|
||||
n.Tunnels = n.Tunnels[:len(n.Tunnels)-1]
|
||||
}
|
||||
return found >= 0
|
||||
}
|
||||
|
||||
type FabricTunnel struct {
|
||||
DstPort uint32 `json:"destPort"`
|
||||
Remote string `json:"remote"`
|
||||
Local string `json:"local,omitempty"`
|
||||
Mode string `json:"mode,omitempty"`
|
||||
}
|
||||
|
||||
func (c *FabricTunnel) Correct() {
|
||||
}
|
28
pkg/config/ipsec.go
Normal file
28
pkg/config/ipsec.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
type IPSecTunnel struct {
|
||||
Left string `json:"local"`
|
||||
LeftId string `json:"localid"`
|
||||
LeftPort string `json:"localport"`
|
||||
Right string `json:"remote"`
|
||||
RightId string `json:"remoteid"`
|
||||
RightPort string `json:"remoteport"`
|
||||
Transport string `json:"transport"`
|
||||
}
|
||||
|
||||
func (s *IPSecTunnel) Correct() {
|
||||
if s.Left == "" {
|
||||
s.Left = "%defaultroute"
|
||||
}
|
||||
}
|
||||
|
||||
type IPSecSpecifies struct {
|
||||
Name string `json:"name"`
|
||||
Tunnels []IPSecTunnel `json:"tunnels"`
|
||||
}
|
||||
|
||||
func (s *IPSecSpecifies) Correct() {
|
||||
for _, t := range s.Tunnels {
|
||||
t.Correct()
|
||||
}
|
||||
}
|
@@ -31,8 +31,8 @@ type Network struct {
|
||||
|
||||
func (n *Network) NewSpecifies() interface{} {
|
||||
switch n.Provider {
|
||||
case "vxlan":
|
||||
n.Specifies = &VxLANSpecifies{}
|
||||
case "ipsec":
|
||||
n.Specifies = &IPSecSpecifies{}
|
||||
case "router":
|
||||
n.Specifies = &RouterSpecifies{}
|
||||
default:
|
||||
@@ -55,6 +55,12 @@ func (n *Network) Correct(sw *Switch) {
|
||||
obj.Correct()
|
||||
obj.Name = n.Name
|
||||
}
|
||||
case "ipsec":
|
||||
spec := n.Specifies
|
||||
if obj, ok := spec.(*IPSecSpecifies); ok {
|
||||
obj.Correct()
|
||||
obj.Name = n.Name
|
||||
}
|
||||
}
|
||||
if n.Subnet == nil {
|
||||
n.Subnet = &Subnet{}
|
||||
|
@@ -1,6 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package models
|
||||
|
||||
func (l *EspState) Update() {
|
||||
}
|
@@ -1,510 +0,0 @@
|
||||
package cswitch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/danieldin95/go-openvswitch/ovs"
|
||||
"github.com/luscis/openlan/pkg/api"
|
||||
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"
|
||||
)
|
||||
|
||||
type Fabricer interface {
|
||||
AddNetwork(cfg *co.Network)
|
||||
DelNetwork(bridge string, vni uint32)
|
||||
TcpMss() int
|
||||
}
|
||||
|
||||
var fabrics = make(map[string]Fabricer)
|
||||
|
||||
func GetFabricer(name string) Fabricer {
|
||||
return fabrics[name]
|
||||
}
|
||||
|
||||
type OvsBridge struct {
|
||||
name string
|
||||
cli *ovs.Client
|
||||
out *libol.SubLogger
|
||||
}
|
||||
|
||||
func NewOvsBridge(name string) *OvsBridge {
|
||||
return &OvsBridge{
|
||||
name: name,
|
||||
cli: ovs.New(),
|
||||
out: libol.NewSubLogger(name),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OvsBridge) delFlow(flow *ovs.MatchFlow) error {
|
||||
if err := o.cli.OpenFlow.DelFlows(o.name, flow); err != nil {
|
||||
o.out.Warn("OvsBridge.addFlow %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) addFlow(flow *ovs.Flow) error {
|
||||
if err := o.cli.OpenFlow.AddFlow(o.name, flow); err != nil {
|
||||
o.out.Warn("OvsBridge.addFlow %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) setDown() error {
|
||||
if err := o.cli.VSwitch.DeleteBridge(o.name); err != nil {
|
||||
o.out.Error("OvsBridge.DeleteBridge %s %s", o.name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) setUp() error {
|
||||
if err := o.cli.VSwitch.AddBridge(o.name); err != nil {
|
||||
o.out.Error("OvsBridge.AddBridge %s %s", o.name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) setMode(mode ovs.FailMode) error {
|
||||
if err := o.cli.VSwitch.SetFailMode(o.name, mode); err != nil {
|
||||
o.out.Warn("OvsBridge.setMode %s %s", mode, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) addPort(name string, options *ovs.InterfaceOptions) error {
|
||||
if err := o.cli.VSwitch.AddPort(o.name, name); err != nil {
|
||||
o.out.Warn("OvsBridge.addPort %s %s", name, err)
|
||||
return err
|
||||
}
|
||||
if options == nil {
|
||||
return nil
|
||||
}
|
||||
if err := o.cli.VSwitch.Set.Interface(name, *options); err != nil {
|
||||
o.out.Warn("OvsBridge.addPort %s %s", name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) delPort(name string) error {
|
||||
if err := o.cli.VSwitch.DeletePort(o.name, name); err != nil {
|
||||
o.out.Warn("OvsBridge.delPort %s %s", name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) setPort(name string, options ovs.InterfaceOptions) error {
|
||||
if err := o.cli.VSwitch.Set.Interface(name, options); err != nil {
|
||||
o.out.Warn("OvsBridge.setPort %s %s", name, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OvsBridge) dumpPort(name string) *ovs.PortStats {
|
||||
if port, err := o.cli.OpenFlow.DumpPort(o.name, name); err != nil {
|
||||
o.out.Warn("OvsBridge.dumpPort %s %s", name, err)
|
||||
return nil
|
||||
} else {
|
||||
return port
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
TLsToTun = 2 // From a switch include border to tunnels.
|
||||
TTunToLs = 4 // From tunnels to a switch.
|
||||
TSourceLearn = 10 // Learning source mac.
|
||||
TUcastToTun = 20 // Forwarding by fdb.
|
||||
TFloodToTun = 30 // Flooding to tunnels or patch by flags.
|
||||
TFloodToBor = 31 // Flooding to border in a switch.
|
||||
TFloodLoop = 32 // Flooding to patch in a switch from border.
|
||||
)
|
||||
|
||||
const (
|
||||
FFromLs = 2 // In a logical switch.
|
||||
FFromTun = 4 // From peer tunnels.
|
||||
)
|
||||
|
||||
const (
|
||||
MatchRegFlag = "reg10"
|
||||
NxmRegFlag = "NXM_NX_REG10[0..31]"
|
||||
NxmRegEthDst = "NXM_OF_ETH_DST[]"
|
||||
NxmRegEthSrc = "NXM_OF_ETH_SRC[]"
|
||||
NxmRegTunId = "NXM_NX_TUN_ID[0..31]"
|
||||
NxmRegInPort = "NXM_OF_IN_PORT[]"
|
||||
)
|
||||
|
||||
type OvsPort struct {
|
||||
name string
|
||||
portId int
|
||||
options ovs.InterfaceOptions
|
||||
}
|
||||
|
||||
type FabricWorker struct {
|
||||
*WorkerImpl
|
||||
spec *co.FabricSpecifies
|
||||
ovs *OvsBridge
|
||||
cookie uint64
|
||||
tunnels map[string]*OvsPort
|
||||
borders map[string]*OvsPort
|
||||
bridge map[string]*cn.LinuxBridge
|
||||
}
|
||||
|
||||
func NewFabricWorker(c *co.Network) *FabricWorker {
|
||||
w := &FabricWorker{
|
||||
WorkerImpl: NewWorkerApi(c),
|
||||
ovs: NewOvsBridge(c.Bridge.Name),
|
||||
tunnels: make(map[string]*OvsPort, 1024),
|
||||
borders: make(map[string]*OvsPort, 1024),
|
||||
bridge: make(map[string]*cn.LinuxBridge, 1024),
|
||||
}
|
||||
w.spec, _ = c.Specifies.(*co.FabricSpecifies)
|
||||
fabrics[c.Name] = w
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *FabricWorker) upTables() {
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Actions: []ovs.Action{ovs.Drop()},
|
||||
})
|
||||
// Table 2: set flags from logical switch.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TLsToTun,
|
||||
Priority: 1,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Load(libol.Uint2S(FFromLs), NxmRegFlag),
|
||||
ovs.Resubmit(0, TSourceLearn),
|
||||
},
|
||||
})
|
||||
// Table 4: set flags from tunnels.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TTunToLs,
|
||||
Priority: 1,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Load(libol.Uint2S(FFromTun), NxmRegFlag),
|
||||
ovs.Resubmit(0, TSourceLearn),
|
||||
},
|
||||
})
|
||||
// Table 10: source learning
|
||||
w.addLearning()
|
||||
// Table 20: default to flood 30
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TUcastToTun,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Resubmit(0, TFloodToTun),
|
||||
},
|
||||
})
|
||||
// Table 30: default drop.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToTun,
|
||||
Actions: []ovs.Action{ovs.Drop()},
|
||||
})
|
||||
// Table 31: default drop.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToBor,
|
||||
Actions: []ovs.Action{ovs.Drop()},
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) Initialize() {
|
||||
w.WorkerImpl.Initialize()
|
||||
if err := w.ovs.setUp(); err != nil {
|
||||
return
|
||||
}
|
||||
_ = w.ovs.setMode("secure")
|
||||
w.upTables()
|
||||
api.ListWorker(func(n api.Networker) {
|
||||
if w.IsSlave(n) {
|
||||
n.Initialize()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) vni2peer(vni uint32) (string, string) {
|
||||
tunPort := fmt.Sprintf("vb-%08d", vni)
|
||||
brPort := fmt.Sprintf("vt-%08d", vni)
|
||||
return brPort, tunPort
|
||||
}
|
||||
|
||||
func (w *FabricWorker) UpLink(bridge string, vni uint32, addr string) *ovs.PortStats {
|
||||
brPort, tunPort := w.vni2peer(vni)
|
||||
link := &nl.Veth{
|
||||
LinkAttrs: nl.LinkAttrs{Name: tunPort},
|
||||
PeerName: brPort,
|
||||
}
|
||||
if err := nl.LinkAdd(link); err != nil {
|
||||
w.out.Warn("FabricWorker.addLink %s", err)
|
||||
}
|
||||
if err := nl.LinkSetUp(link); err != nil {
|
||||
w.out.Warn("FabricWorker.setLinkUp %s", err)
|
||||
}
|
||||
|
||||
// Setup linux bridge for outputs
|
||||
br := cn.NewLinuxBridge(bridge, 0)
|
||||
br.Open(addr)
|
||||
_ = br.AddSlave(brPort)
|
||||
if err := br.CallIptables(1); err != nil {
|
||||
w.out.Warn("FabricWorker.IpTables %s", err)
|
||||
}
|
||||
|
||||
w.bridge[bridge] = br
|
||||
// Add port to OvS tunnel bridge
|
||||
_ = w.ovs.addPort(tunPort, nil)
|
||||
if port := w.ovs.dumpPort(tunPort); port != nil {
|
||||
return port
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *FabricWorker) addLearning() {
|
||||
// Table 10: source mac learning
|
||||
learnSpecs := []ovs.Match{
|
||||
ovs.FieldMatch(NxmRegTunId, NxmRegTunId),
|
||||
ovs.FieldMatch(NxmRegEthDst, NxmRegEthSrc),
|
||||
}
|
||||
learnActions := []ovs.Action{
|
||||
ovs.OutputField(NxmRegInPort),
|
||||
}
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TSourceLearn,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Learn(&ovs.LearnedFlow{
|
||||
Table: TUcastToTun,
|
||||
Matches: learnSpecs,
|
||||
Priority: 1,
|
||||
HardTimeout: 300,
|
||||
Actions: learnActions,
|
||||
}),
|
||||
ovs.Resubmit(0, TUcastToTun),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) AddNetwork(cfg *co.Network) {
|
||||
spec, _ := cfg.Specifies.(*co.VxLANSpecifies)
|
||||
libol.Info("Fabric.AddNetwork %d", spec.Vni)
|
||||
patch := w.UpLink(cfg.Bridge.Name, spec.Vni, cfg.Bridge.Address)
|
||||
// Table 0: load tunnel id from patch port.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
InPort: patch.PortID,
|
||||
Priority: 1,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Load(libol.Uint2S(spec.Vni), NxmRegTunId),
|
||||
ovs.Resubmit(0, TLsToTun),
|
||||
},
|
||||
})
|
||||
// Table 30: flooding to patch from tunnels.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToTun,
|
||||
Priority: 2,
|
||||
Matches: []ovs.Match{
|
||||
ovs.FieldMatch(NxmRegTunId, libol.Uint2S(spec.Vni)),
|
||||
ovs.FieldMatch(MatchRegFlag, libol.Uint2S(FFromTun)),
|
||||
},
|
||||
Actions: []ovs.Action{
|
||||
ovs.Output(patch.PortID),
|
||||
ovs.Resubmit(0, TFloodToBor),
|
||||
},
|
||||
})
|
||||
// Table 32: flooding to patch from border.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodLoop,
|
||||
Priority: 2,
|
||||
Matches: []ovs.Match{
|
||||
ovs.FieldMatch(NxmRegTunId, libol.Uint2S(spec.Vni)),
|
||||
ovs.FieldMatch(MatchRegFlag, libol.Uint2S(FFromLs)),
|
||||
},
|
||||
Actions: []ovs.Action{
|
||||
ovs.Output(patch.PortID),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) Addr2Port(addr, pre string) string {
|
||||
name := pre + strings.ReplaceAll(addr, ".", "")
|
||||
return libol.IfName(name)
|
||||
}
|
||||
|
||||
func (w *FabricWorker) flood2Tunnel() {
|
||||
var actions []ovs.Action
|
||||
for _, tun := range w.tunnels {
|
||||
actions = append(actions, ovs.Output(tun.portId))
|
||||
}
|
||||
actions = append(actions, ovs.Resubmit(0, TFloodToBor))
|
||||
// Table 30: Flooding to tunnels from patch.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToTun,
|
||||
Priority: 1,
|
||||
Matches: []ovs.Match{
|
||||
ovs.FieldMatch(MatchRegFlag, libol.Uint2S(FFromLs)),
|
||||
},
|
||||
Actions: actions,
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) flood2Border() {
|
||||
var actions []ovs.Action
|
||||
for _, port := range w.borders {
|
||||
actions = append(actions, ovs.Output(port.portId))
|
||||
}
|
||||
// Table 31: flooding to border from tunnels.
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToBor,
|
||||
Priority: 1,
|
||||
Matches: []ovs.Match{
|
||||
ovs.FieldMatch(MatchRegFlag, libol.Uint2S(FFromTun)),
|
||||
},
|
||||
Actions: actions,
|
||||
})
|
||||
// Table 32: flooding to border from a border.
|
||||
actions = append(actions, ovs.Resubmit(0, TFloodLoop))
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
Table: TFloodToBor,
|
||||
Priority: 1,
|
||||
Matches: []ovs.Match{
|
||||
ovs.FieldMatch(MatchRegFlag, libol.Uint2S(FFromLs)),
|
||||
},
|
||||
Actions: actions,
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) tunnelType() ovs.InterfaceType {
|
||||
if w.spec.Driver == "stt" {
|
||||
return ovs.InterfaceTypeSTT
|
||||
}
|
||||
return ovs.InterfaceTypeVXLAN
|
||||
}
|
||||
|
||||
func (w *FabricWorker) AddTunnel(cfg co.FabricTunnel) {
|
||||
name := w.Addr2Port(cfg.Remote, "vx-")
|
||||
options := ovs.InterfaceOptions{
|
||||
Type: w.tunnelType(),
|
||||
BfdEnable: true,
|
||||
RemoteIP: cfg.Remote,
|
||||
Key: "flow",
|
||||
DstPort: cfg.DstPort,
|
||||
}
|
||||
if w.spec.Fragment {
|
||||
options.DfDefault = "false"
|
||||
} else {
|
||||
options.DfDefault = "true"
|
||||
}
|
||||
if err := w.ovs.addPort(name, &options); err != nil {
|
||||
return
|
||||
}
|
||||
port := w.ovs.dumpPort(name)
|
||||
if port == nil {
|
||||
return
|
||||
}
|
||||
if cfg.Mode == "border" {
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
InPort: port.PortID,
|
||||
Priority: 1,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Resubmit(0, TLsToTun),
|
||||
},
|
||||
})
|
||||
w.borders[name] = &OvsPort{
|
||||
name: name,
|
||||
portId: port.PortID,
|
||||
options: options,
|
||||
}
|
||||
// Update flow for flooding to border.
|
||||
w.flood2Border()
|
||||
} else {
|
||||
_ = w.ovs.addFlow(&ovs.Flow{
|
||||
InPort: port.PortID,
|
||||
Priority: 1,
|
||||
Actions: []ovs.Action{
|
||||
ovs.Resubmit(0, TTunToLs),
|
||||
},
|
||||
})
|
||||
w.tunnels[name] = &OvsPort{
|
||||
name: name,
|
||||
portId: port.PortID,
|
||||
options: options,
|
||||
}
|
||||
// Update flow for flooding to tunnels.
|
||||
w.flood2Tunnel()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *FabricWorker) Start(v api.Switcher) {
|
||||
w.out.Info("FabricWorker.Start")
|
||||
for _, tunnel := range w.spec.Tunnels {
|
||||
w.AddTunnel(*tunnel)
|
||||
}
|
||||
w.WorkerImpl.Start(v)
|
||||
api.ListWorker(func(n api.Networker) {
|
||||
if w.IsSlave(n) {
|
||||
n.Start(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (w *FabricWorker) downTables() {
|
||||
_ = w.ovs.delFlow(nil)
|
||||
}
|
||||
|
||||
func (w *FabricWorker) DelNetwork(bridge string, vni uint32) {
|
||||
brPort, tunPort := w.vni2peer(vni)
|
||||
if err := w.ovs.delPort(tunPort); err != nil {
|
||||
libol.Warn("FabricWorker.downNetwork %s", err)
|
||||
}
|
||||
link := &nl.Veth{
|
||||
LinkAttrs: nl.LinkAttrs{Name: tunPort},
|
||||
PeerName: brPort,
|
||||
}
|
||||
_ = nl.LinkDel(link)
|
||||
if br, ok := w.bridge[bridge]; ok {
|
||||
_ = br.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *FabricWorker) DelTunnel(name string) {
|
||||
_ = w.ovs.delPort(name)
|
||||
}
|
||||
|
||||
func (w *FabricWorker) IsSlave(n api.Networker) bool {
|
||||
cfg := n.Config()
|
||||
if cfg == nil || cfg.Specifies == nil {
|
||||
return false
|
||||
}
|
||||
spec, ok := cfg.Specifies.(*co.VxLANSpecifies)
|
||||
if !ok || spec.Fabric != w.cfg.Name {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *FabricWorker) Stop() {
|
||||
w.out.Info("FabricWorker.Stop")
|
||||
api.ListWorker(func(n api.Networker) {
|
||||
if w.IsSlave(n) {
|
||||
n.Stop()
|
||||
}
|
||||
})
|
||||
w.WorkerImpl.Stop()
|
||||
w.downTables()
|
||||
for _, tunnel := range w.tunnels {
|
||||
w.DelTunnel(tunnel.name)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *FabricWorker) Reload(v api.Switcher) {
|
||||
w.Stop()
|
||||
w.Initialize()
|
||||
w.Start(v)
|
||||
}
|
||||
|
||||
func (w *FabricWorker) TcpMss() int {
|
||||
return w.cfg.Bridge.Mss
|
||||
}
|
230
pkg/switch/ipsec.go
Normal file
230
pkg/switch/ipsec.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package cswitch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/luscis/openlan/pkg/api"
|
||||
co "github.com/luscis/openlan/pkg/config"
|
||||
"github.com/luscis/openlan/pkg/libol"
|
||||
)
|
||||
|
||||
type IPSecWorker struct {
|
||||
*WorkerImpl
|
||||
spec *co.IPSecSpecifies
|
||||
}
|
||||
|
||||
func NewIPSecWorker(c *co.Network) *IPSecWorker {
|
||||
w := &IPSecWorker{
|
||||
WorkerImpl: NewWorkerApi(c),
|
||||
}
|
||||
w.spec, _ = c.Specifies.(*co.IPSecSpecifies)
|
||||
return w
|
||||
}
|
||||
|
||||
// conn vxlan11252
|
||||
// keyexchange=ike
|
||||
// ikev2=no
|
||||
// type=transport
|
||||
// left=%defaultroute
|
||||
// right=45.135.117.235
|
||||
// rightikeport=4501
|
||||
// authby=secret
|
||||
|
||||
// conn vxlan11252-c2
|
||||
// auto=start
|
||||
// also=vxlan11252
|
||||
// leftid=@c2.vxlan11252.com
|
||||
// leftprotoport=udp/8472
|
||||
// rightprotoport=udp
|
||||
|
||||
// conn vxlan11252-c1
|
||||
// auto=start
|
||||
// also=vxlan11252
|
||||
// leftid=@c1.vxlan11252.com
|
||||
// leftprotoport=udp
|
||||
// rightprotoport=udp/8472
|
||||
|
||||
// conn vxlan11252
|
||||
// keyexchange=ike
|
||||
// ikev2=no
|
||||
// type=transport
|
||||
// left=%defaultroute
|
||||
// leftikeport=4501
|
||||
// right=218.94.118.90
|
||||
// authby=secret
|
||||
|
||||
// conn vxlan11252-c1
|
||||
// auto=start
|
||||
// also=vxlan11252
|
||||
// rightid=@c1.vxlan11252.com
|
||||
// leftprotoport=udp/8472
|
||||
// rightprotoport=udp
|
||||
|
||||
// conn vxlan11252-c2
|
||||
// auto=start
|
||||
// also=vxlan11252
|
||||
// rightid=@c2.vxlan11252.com
|
||||
// leftprotoport=udp
|
||||
// rightprotoport=udp/8472
|
||||
|
||||
const (
|
||||
vxlanTmpl = `
|
||||
conn {{ .Name }}
|
||||
keyexchange=ike
|
||||
ikev2=no
|
||||
type=transport
|
||||
left={{ .Left }}
|
||||
{{- if .LeftId }}
|
||||
leftid={{ .LeftId }}
|
||||
{{- end }}
|
||||
{{- if .LeftPort }}
|
||||
leftikeport={{ .LeftPort }}
|
||||
{{- end }}
|
||||
right={{ .Right }}
|
||||
{{- if .RightId }}
|
||||
rightid={{ .RightId }}
|
||||
{{- end }}
|
||||
{{- if .RightPort }}
|
||||
rightikeport={{ .RightPort }}
|
||||
{{- end }}
|
||||
authby=secret
|
||||
|
||||
conn {{ .Name }}-c1
|
||||
auto=start
|
||||
also={{ .Name }}
|
||||
leftprotoport=udp/8472
|
||||
rightprotoport=udp
|
||||
|
||||
conn {{ .Name }}-c2
|
||||
auto=start
|
||||
also={{ .Remote }}-{{ .Protocol }}
|
||||
leftprotoport=udp
|
||||
rightprotoport=udp/8472
|
||||
`
|
||||
greTmpl = `
|
||||
conn {{ .Name }}-c1
|
||||
auto=start
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left={{ .Left }}
|
||||
right={{ .Right }}
|
||||
authby=secret
|
||||
leftprotoport=gre
|
||||
rightprotoport=gre
|
||||
`
|
||||
secretTmpl = `
|
||||
%any {{ .Remote }} : PSK "{{ .Secret }}"
|
||||
`
|
||||
)
|
||||
|
||||
func (w *IPSecWorker) Initialize() {
|
||||
w.out.Info("IPSecWorker.Initialize")
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) saveSec(name, tmpl string, data interface{}) error {
|
||||
file := fmt.Sprintf("/etc/ipsec.d/%s", name)
|
||||
out, err := libol.CreateFile(file)
|
||||
if err != nil || out == nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if obj, err := template.New("main").Parse(tmpl); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := obj.Execute(out, data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) startConn(name string) {
|
||||
promise := libol.NewPromise()
|
||||
promise.Go(func() error {
|
||||
if out, err := libol.Exec("ipsec", "auto", "--start", "--asynchronous", name); err != nil {
|
||||
w.out.Warn("IPSecWorker.startConn: %v %s", out, err)
|
||||
return err
|
||||
}
|
||||
w.out.Info("IPSecWorker.startConn: %v success", name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) AddTunnel(tunnel *co.IPSecTunnel) error {
|
||||
connTmpl := ""
|
||||
secTmpl := ""
|
||||
|
||||
name := fmt.Sprintf("%s-%s", tunnel.Right, tunnel.Transport)
|
||||
if tunnel.Transport == "vxlan" {
|
||||
connTmpl = vxlanTmpl
|
||||
secTmpl = secretTmpl
|
||||
} else if tunnel.Transport == "gre" {
|
||||
connTmpl = greTmpl
|
||||
secTmpl = secretTmpl
|
||||
}
|
||||
|
||||
if secTmpl != "" {
|
||||
if err := w.saveSec(name+".secrets", secTmpl, tunnel); err != nil {
|
||||
w.out.Error("WorkerImpl.AddTunnel %s", err)
|
||||
return err
|
||||
}
|
||||
libol.Exec("ipsec", "auto", "--rereadsecrets")
|
||||
}
|
||||
if connTmpl != "" {
|
||||
if err := w.saveSec(name+".conf", connTmpl, tunnel); err != nil {
|
||||
w.out.Error("WorkerImpl.AddTunnel %s", err)
|
||||
return err
|
||||
}
|
||||
if tunnel.Transport == "vxlan" {
|
||||
w.startConn(name + "-c1")
|
||||
w.startConn(name + "-c2")
|
||||
} else if tunnel.Transport == "gre" {
|
||||
w.startConn(name + "-c1")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) Start(v api.Switcher) {
|
||||
w.uuid = v.UUID()
|
||||
w.out.Info("IPSecWorker.Start")
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) RemoveTunnel(tunnel *co.IPSecTunnel) error {
|
||||
|
||||
name := fmt.Sprintf("%s-%s", tunnel.Right, tunnel.Transport)
|
||||
if tunnel.Transport == "vxlan" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c1")
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c2")
|
||||
} else if tunnel.Transport == "gre" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-c1")
|
||||
}
|
||||
|
||||
cfile := fmt.Sprintf("/etc/ipsec.d/%s.conf", name)
|
||||
sfile := fmt.Sprintf("/etc/ipsec.d/%s.secrets", name)
|
||||
|
||||
if err := libol.FileExist(cfile); err == nil {
|
||||
if err := os.Remove(cfile); err != nil {
|
||||
w.out.Warn("IPSecWorker.RemoveTunnel %s", err)
|
||||
}
|
||||
}
|
||||
if err := libol.FileExist(sfile); err == nil {
|
||||
if err := os.Remove(sfile); err != nil {
|
||||
w.out.Warn("IPSecWorker.RemoveTunnel %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) Stop() {
|
||||
w.out.Info("IPSecWorker.Stop")
|
||||
}
|
||||
|
||||
func (w *IPSecWorker) Reload(v api.Switcher) {
|
||||
w.Stop()
|
||||
w.Initialize()
|
||||
w.Start(v)
|
||||
}
|
@@ -3,9 +3,7 @@ package cswitch
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/luscis/openlan/pkg/api"
|
||||
@@ -21,8 +19,8 @@ import (
|
||||
func NewNetworker(c *co.Network) api.Networker {
|
||||
var obj api.Networker
|
||||
switch c.Provider {
|
||||
case "vxlan":
|
||||
obj = NewVxLANWorker(c)
|
||||
case "ipsec":
|
||||
obj = NewIPSecWorker(c)
|
||||
case "router":
|
||||
obj = NewRouterWorker(c)
|
||||
default:
|
||||
@@ -185,12 +183,6 @@ func (w *WorkerImpl) AddPhysical(bridge string, output string) {
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) addOutput(bridge string, port *LinuxPort) {
|
||||
if port.output.Secret != "" {
|
||||
if err := w.addSecConn(port); err != nil {
|
||||
w.out.Error("WorkerImpl.addOutput %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := port.output
|
||||
mtu := 0
|
||||
if cfg.Protocol == "gre" {
|
||||
@@ -469,12 +461,6 @@ func (w *WorkerImpl) DelPhysical(bridge string, output string) {
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) delOutput(bridge string, port *LinuxPort) {
|
||||
if port.output.Secret != "" {
|
||||
if err := w.delSecConn(port); err != nil {
|
||||
w.out.Error("WorkerImpl.AddOutput %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := port.output
|
||||
w.out.Info("WorkerImpl.delOutput %s %s", port.link, port.String())
|
||||
|
||||
@@ -558,11 +544,9 @@ func (w *WorkerImpl) Stop() {
|
||||
w.out.Info("WorkerImpl.Stop")
|
||||
|
||||
w.fire.Stop()
|
||||
|
||||
w.nextgroup.Stop()
|
||||
|
||||
w.unloadRoutes()
|
||||
|
||||
if !(w.vpn == nil) {
|
||||
if !(w.ztrust == nil) {
|
||||
w.ztrust.Stop()
|
||||
@@ -570,14 +554,14 @@ func (w *WorkerImpl) Stop() {
|
||||
if !(w.qos == nil) {
|
||||
w.qos.Stop()
|
||||
}
|
||||
|
||||
w.vpn.Stop()
|
||||
|
||||
}
|
||||
|
||||
if !(w.dhcp == nil) {
|
||||
w.dhcp.Stop()
|
||||
}
|
||||
if !(w.vrf == nil) {
|
||||
w.vrf.Down()
|
||||
}
|
||||
|
||||
for _, output := range w.outputs {
|
||||
w.delOutput(w.cfg.Bridge.Name, output)
|
||||
@@ -588,7 +572,6 @@ func (w *WorkerImpl) Stop() {
|
||||
|
||||
w.setR.Destroy()
|
||||
w.setV.Destroy()
|
||||
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) String() string {
|
||||
@@ -1080,119 +1063,6 @@ func (w *WorkerImpl) ACLer() api.ACLer {
|
||||
return w.acl
|
||||
}
|
||||
|
||||
const (
|
||||
vxlanConn = `
|
||||
conn vxlan{{ .Segment }}-in
|
||||
keyingtries=%forever
|
||||
auto=start
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=udp/8472
|
||||
rightprotoport=udp
|
||||
|
||||
conn vxlan{{ .Segment }}-out
|
||||
keyingtries=%forever
|
||||
auto=start
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=udp
|
||||
rightprotoport=udp/8472
|
||||
`
|
||||
greConn = `
|
||||
conn gre{{ .Segment }}
|
||||
keyingtries=%forever
|
||||
auto=start
|
||||
ike=aes_gcm256-sha2_256
|
||||
esp=aes_gcm256
|
||||
ikev2=insist
|
||||
type=transport
|
||||
left=%defaultroute
|
||||
right={{ .Remote }}
|
||||
authby=secret
|
||||
leftprotoport=gre
|
||||
rightprotoport=gre
|
||||
`
|
||||
secretConn = `
|
||||
%any {{ .Remote }} : PSK "{{ .Secret }}"
|
||||
`
|
||||
)
|
||||
|
||||
func (w *WorkerImpl) saveSec(name, tmpl string, data interface{}) error {
|
||||
file := fmt.Sprintf("/etc/ipsec.d/%s", name)
|
||||
out, err := libol.CreateFile(file)
|
||||
if err != nil || out == nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if obj, err := template.New("main").Parse(tmpl); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if err := obj.Execute(out, data); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) startSecConn(name string) {
|
||||
promise := libol.NewPromise()
|
||||
promise.Go(func() error {
|
||||
if out, err := libol.Exec("ipsec", "auto", "--start", "--asynchronous", name); err != nil {
|
||||
w.out.Warn("WorkerImpl.startSecConn: %v %s", out, err)
|
||||
return err
|
||||
}
|
||||
w.out.Info("WorkerImpl.startSecConn: %v success", name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) addSecConn(port *LinuxPort) error {
|
||||
connTmpl := ""
|
||||
secTmpl := ""
|
||||
|
||||
name := port.link
|
||||
data := port.output
|
||||
if data.Protocol == "vxlan" {
|
||||
connTmpl = vxlanConn
|
||||
secTmpl = secretConn
|
||||
} else if data.Protocol == "gre" {
|
||||
connTmpl = vxlanConn
|
||||
secTmpl = secretConn
|
||||
}
|
||||
|
||||
if secTmpl != "" {
|
||||
if err := w.saveSec(name+".secrets", secTmpl, data); err != nil {
|
||||
w.out.Error("WorkerImpl.addSecConn %s", err)
|
||||
return err
|
||||
}
|
||||
libol.Exec("ipsec", "auto", "--rereadsecrets")
|
||||
}
|
||||
if connTmpl != "" {
|
||||
if err := w.saveSec(name+".conf", connTmpl, data); err != nil {
|
||||
w.out.Error("WorkerImpl.addSecConn %s", err)
|
||||
return err
|
||||
}
|
||||
if data.Protocol == "vxlan" {
|
||||
w.startSecConn(name + "-in")
|
||||
w.startSecConn(name + "-out")
|
||||
} else if data.Protocol == "gre" {
|
||||
w.startSecConn(name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) AddOutput(data schema.Output) {
|
||||
output := co.Output{
|
||||
Segment: data.Segment,
|
||||
@@ -1210,33 +1080,6 @@ func (w *WorkerImpl) AddOutput(data schema.Output) {
|
||||
w.outputs = append(w.outputs, port)
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) delSecConn(port *LinuxPort) error {
|
||||
data := port.output
|
||||
name := port.link
|
||||
|
||||
if data.Protocol == "vxlan" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-in")
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name+"-out")
|
||||
} else if data.Protocol == "gre" {
|
||||
libol.Exec("ipsec", "auto", "--delete", "--asynchronous", name)
|
||||
}
|
||||
|
||||
cfile := fmt.Sprintf("/etc/ipsec.d/%s.conf", name)
|
||||
sfile := fmt.Sprintf("/etc/ipsec.d/%s.secrets", name)
|
||||
|
||||
if err := libol.FileExist(cfile); err == nil {
|
||||
if err := os.Remove(cfile); err != nil {
|
||||
w.out.Warn("WorkerImpl.delSecConn %s", err)
|
||||
}
|
||||
}
|
||||
if err := libol.FileExist(sfile); err == nil {
|
||||
if err := os.Remove(sfile); err != nil {
|
||||
w.out.Warn("WorkerImpl.delSecConn %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WorkerImpl) DelOutput(device string) {
|
||||
var port *LinuxPort
|
||||
for _, v := range w.outputs {
|
||||
|
@@ -1,51 +0,0 @@
|
||||
package cswitch
|
||||
|
||||
import (
|
||||
"github.com/luscis/openlan/pkg/api"
|
||||
co "github.com/luscis/openlan/pkg/config"
|
||||
)
|
||||
|
||||
type VxLANWorker struct {
|
||||
*WorkerImpl
|
||||
spec *co.VxLANSpecifies
|
||||
}
|
||||
|
||||
func NewVxLANWorker(c *co.Network) *VxLANWorker {
|
||||
w := &VxLANWorker{
|
||||
WorkerImpl: NewWorkerApi(c),
|
||||
}
|
||||
w.spec, _ = c.Specifies.(*co.VxLANSpecifies)
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *VxLANWorker) Initialize() {
|
||||
w.WorkerImpl.Initialize()
|
||||
}
|
||||
|
||||
func (w *VxLANWorker) Start(v api.Switcher) {
|
||||
w.uuid = v.UUID()
|
||||
master := GetFabricer(w.spec.Fabric)
|
||||
if master == nil {
|
||||
w.out.Warn("VxLANWorker.Start %s not found", w.spec.Fabric)
|
||||
return
|
||||
}
|
||||
w.cfg.Bridge.Mss = master.TcpMss()
|
||||
master.AddNetwork(w.cfg)
|
||||
w.WorkerImpl.Start(v)
|
||||
}
|
||||
|
||||
func (w *VxLANWorker) Stop() {
|
||||
w.WorkerImpl.Stop()
|
||||
master := GetFabricer(w.spec.Fabric)
|
||||
if master == nil {
|
||||
w.out.Warn("VxLANWorker.Stop %s not found", w.spec.Fabric)
|
||||
return
|
||||
}
|
||||
master.DelNetwork(w.cfg.Bridge.Name, w.spec.Vni)
|
||||
}
|
||||
|
||||
func (w *VxLANWorker) Reload(v api.Switcher) {
|
||||
w.Stop()
|
||||
w.Initialize()
|
||||
w.Start(v)
|
||||
}
|
Reference in New Issue
Block a user