fix: lease not update when switch restart #12

This commit is contained in:
Daniel Ding
2022-10-10 16:05:03 +08:00
parent afebb43dbe
commit c86cf5040d
10 changed files with 161 additions and 90 deletions

View File

@@ -184,16 +184,20 @@ test: ## execute unit test
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/access
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/libol
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/models
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/cache
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/config
go test -v -mod=vendor -bench=. github.com/luscis/openlan/pkg/network
## coverage
cover: env ## execute unit test and output coverage
@rm -rvf $(CD)
@mkdir -p $(CD)
go test -mod=vendor github.com/luscis/openlan/pkg/access -coverprofile=$(CD)/access.out -race -covermode=atomic
go test -mod=vendor github.com/luscis/openlan/pkg/libol -coverprofile=$(CD)/libol.out -race -covermode=atomic
go test -mod=vendor github.com/luscis/openlan/pkg/models -coverprofile=$(CD)/models.out -race -covermode=atomic
@rm -rvf $(CD) && mkdir -p $(CD)
@go test -mod=vendor github.com/luscis/openlan/pkg/access -coverprofile=$(CD)/0.out -race -covermode=atomic
@go test -mod=vendor github.com/luscis/openlan/pkg/libol -coverprofile=$(CD)/1.out -race -covermode=atomic
@go test -mod=vendor github.com/luscis/openlan/pkg/models -coverprofile=$(CD)/2.out -race -covermode=atomic
@go test -mod=vendor github.com/luscis/openlan/pkg/cache -coverprofile=$(CD)/3.out -race -covermode=atomic
@go test -mod=vendor github.com/luscis/openlan/pkg/config -coverprofile=$(CD)/4.out -race -covermode=atomic
@go test -mod=vendor github.com/luscis/openlan/pkg/network -coverprofile=$(CD)/5.out -race -covermode=atomic
echo 'mode: atomic' > $(SD)/coverage.out
@echo 'mode: atomic' > $(SD)/coverage.out && \
tail -q -n +2 $(CD)/*.out >> $(SD)/coverage.out
go tool cover -html=coverage.out -o coverage.html

View File

@@ -20,9 +20,9 @@ func (u Lease) Url(prefix, name string) string {
func (u Lease) Tmpl() string {
return `# total {{ len . }}
{{ps -16 "uuid"}} {{ps -16 "alias"}} {{ ps -16 "address" }} {{ps -22 "client"}} {{ps -8 "network"}} {{ ps -6 "type"}}
{{ps -16 "alias"}} {{ ps -16 "address" }} {{ps -22 "client"}} {{ps -8 "network"}} {{ ps -6 "type"}}
{{- range . }}
{{ps -16 .UUID}} {{ps -16 .Alias}} {{ ps -16 .Address}} {{ps -22 .Client}} {{ps -8 .Network}} {{ ps -6 .Type}}
{{ps -16 .Alias}} {{ ps -16 .Address}} {{ps -22 .Client}} {{ps -8 .Network}} {{ ps -6 .Type}}
{{- end }}
`
}

View File

@@ -12,14 +12,10 @@ func TestTapWrite(t *testing.T) {
t.Errorf("Tap.open %s", err)
return
}
//t.Logf("Tap.write: %s\n", dev.Name())
frame := make([]byte, 65)
for i := 0; i < 64; i++ {
frame[i] = uint8(i)
}
//t.Logf("Tap.write: %x", frame)
n, err := dev.Write(frame)
if err != nil {
t.Errorf("Tap.write: %s", err)

View File

@@ -65,35 +65,24 @@ func (r *Request) onNeighbor(client libol.SocketClient, data []byte) {
}
}
func (r *Request) getLease(ifAddr string, p *models.Point, n *models.Network) *schema.Lease {
func (r *Request) findLease(ifAddr string, p *models.Point, n *models.Network) *schema.Lease {
if n == nil {
return nil
}
uuid := p.UUID
alias := p.Alias
network := n.Name
lease := cache.Network.GetLeaseByAlias(alias) // try by alias firstly
lease := cache.Network.GetLease(alias, network) // try by alias firstly
if ifAddr == "" {
if lease == nil { // now to alloc it.
lease = cache.Network.NewLease(uuid, network)
if lease != nil {
lease.Alias = alias
}
} else {
lease.UUID = uuid
lease = cache.Network.NewLease(alias, network)
}
} else {
ipAddr := strings.SplitN(ifAddr, "/", 2)[0]
if lease != nil && lease.Address == ipAddr {
lease.UUID = uuid
}
if lease == nil || lease.Address != ipAddr {
lease = cache.Network.AddLease(uuid, ipAddr)
lease.Alias = alias
lease = cache.Network.AddLease(alias, ipAddr, network)
}
}
if lease != nil {
lease.Network = network
lease.Client = p.Client.String()
}
return lease
@@ -129,8 +118,7 @@ func (r *Request) onIpAddr(client libol.SocketClient, data []byte) {
Netmask: recv.Netmask,
Routes: n.Routes,
}
if recv.IfAddr == "" { // not interface address, and try to alloc it.
lease := r.getLease(recv.IfAddr, p, n)
lease := r.findLease(recv.IfAddr, p, n)
if lease != nil {
resp.IfAddr = lease.Address
resp.Netmask = n.Netmask
@@ -143,7 +131,6 @@ func (r *Request) onIpAddr(client libol.SocketClient, data []byte) {
}
resp.Routes = n.Routes
}
}
out.Cmd("Request.onIpAddr: resp %s", resp)
if respStr, err := json.Marshal(resp); err == nil {
m := libol.NewControlFrame(libol.IpAddrResp, respStr)

68
pkg/cache/network.go vendored
View File

@@ -10,8 +10,8 @@ import (
type network struct {
Networks *libol.SafeStrMap
UUID *libol.SafeStrMap // TODO with network
Addr *libol.SafeStrMap // TODO with network
UUID *libol.SafeStrMap
Addr *libol.SafeStrMap
}
func (w *network) Add(n *models.Network) {
@@ -57,7 +57,7 @@ func (w *network) ListLease() <-chan *schema.Lease {
return c
}
func (w *network) allocLease(sAddr, eAddr string) string {
func (w *network) allocLease(sAddr, eAddr, network string) string {
sIp := net.ParseIP(sAddr)
eIp := net.ParseIP(eAddr)
if sIp == nil || eIp == nil {
@@ -69,62 +69,67 @@ func (w *network) allocLease(sAddr, eAddr string) string {
tmp := make([]byte, 4)
binary.BigEndian.PutUint32(tmp[:4], i)
tmpStr := net.IP(tmp).String()
if _, ok := w.Addr.GetEx(tmpStr); !ok {
if ok := w.GetLeaseByAddr(tmpStr, network); ok == nil {
return tmpStr
}
}
return ""
}
func (w *network) NewLease(uuid, network string) *schema.Lease {
func (w *network) NewLease(alias, network string) *schema.Lease {
n := w.Get(network)
if n == nil || uuid == "" {
if n == nil || alias == "" {
return nil
}
uuid := alias + "@" + network
if obj, ok := w.UUID.GetEx(uuid); ok {
l := obj.(*schema.Lease)
return l // how to resolve conflict with new point?.
}
ipStr := w.allocLease(n.IpStart, n.IpEnd)
ipStr := w.allocLease(n.IpStart, n.IpEnd, network)
if ipStr == "" {
return nil
}
w.AddLease(uuid, ipStr)
return w.GetLease(uuid)
w.AddLease(alias, ipStr, network)
return w.GetLease(alias, network)
}
func (w *network) GetLease(uuid string) *schema.Lease {
func (w *network) GetLease(alias string, network string) *schema.Lease {
uuid := alias + "@" + network
if obj, ok := w.UUID.GetEx(uuid); ok {
return obj.(*schema.Lease)
}
return nil
}
func (w *network) GetLeaseByAlias(name string) *schema.Lease {
if obj, ok := w.UUID.GetEx(name); ok {
func (w *network) GetLeaseByAddr(addr string, network string) *schema.Lease {
ruid := addr + "@" + network
if obj, ok := w.Addr.GetEx(ruid); ok {
return obj.(*schema.Lease)
}
return nil
}
func (w *network) AddLease(uuid, ipStr string) *schema.Lease {
libol.Info("network.AddLease %s %s", uuid, ipStr)
if ipStr != "" {
l := &schema.Lease{
UUID: uuid,
Alias: uuid,
Address: ipStr,
}
_ = w.UUID.Set(uuid, l)
_ = w.Addr.Set(ipStr, l)
return l
}
func (w *network) AddLease(alias, ipStr, network string) *schema.Lease {
if ipStr == "" || alias == "" {
return nil
}
uuid := alias + "@" + network
libol.Info("network.AddLease %s %s", uuid, ipStr)
obj := &schema.Lease{
Alias: alias,
Address: ipStr,
Network: network,
}
_ = w.UUID.Set(uuid, obj)
ruid := ipStr + "@" + network
_ = w.Addr.Set(ruid, obj)
return obj
}
func (w *network) DelLease(uuid string) {
func (w *network) DelLease(alias string, network string) {
uuid := alias + "@" + network
libol.Debug("network.DelLease %s", uuid)
// TODO record free address for alias and wait timeout to release.
addr := ""
if obj, ok := w.UUID.GetEx(uuid); ok {
lease := obj.(*schema.Lease)
@@ -134,19 +139,18 @@ func (w *network) DelLease(uuid string) {
w.UUID.Del(uuid)
}
}
if obj, ok := w.Addr.GetEx(addr); ok {
ruid := addr + "@" + network
if obj, ok := w.Addr.GetEx(ruid); ok {
lease := obj.(*schema.Lease)
if lease.UUID == uuid { // avoid address conflict by different points.
libol.Info("network.DelLease (%s, %s) by Addr", uuid, addr)
libol.Info("network.DelLease (%s, %s) by Addr", ruid, alias)
if lease.Type != "static" {
w.Addr.Del(addr)
}
w.Addr.Del(ruid)
}
}
}
var Network = network{
Networks: libol.NewSafeStrMap(1024),
Networks: libol.NewSafeStrMap(128),
UUID: libol.NewSafeStrMap(1024),
Addr: libol.NewSafeStrMap(1024),
}

74
pkg/cache/network_test.go vendored Normal file
View File

@@ -0,0 +1,74 @@
package cache
import (
"github.com/luscis/openlan/pkg/models"
"github.com/luscis/openlan/pkg/schema"
"github.com/stretchr/testify/assert"
"testing"
)
func Test_Network_LeaseAdd(t *testing.T) {
// 0
Network.AddLease("fake-alias", "192.168.1.1", "fake-net")
{
leAddr := Network.GetLeaseByAddr("192.168.1.1", "fake-net")
assert.Equal(t, "fake-alias", leAddr.Alias, "MUST be found")
leAlias := Network.GetLease("fake-alias", "fake-net")
assert.Equal(t, "192.168.1.1", leAlias.Address, "MUST be found")
}
Network.DelLease("fake-alias", "fake-net")
{
leAddr := Network.GetLeaseByAddr("192.168.1.1", "fake-net")
assert.Equal(t, (*schema.Lease)(nil), leAddr, "MUST be not found")
leAlias := Network.GetLease("fake=alias", "fake-net")
assert.Equal(t, (*schema.Lease)(nil), leAlias, "MUST be not found")
}
Network.AddLease("fake-aa", "192.168.1.1", "fake-aa")
Network.AddLease("fake-cc", "192.168.1.1", "fake-aa")
Network.DelLease("fake-aa", "fake-net")
Network.DelLease("fake-cc", "fake-net")
{
leAddr := Network.GetLeaseByAddr("192.168.1.1", "fake-net")
assert.Equal(t, (*schema.Lease)(nil), leAddr, "MUST be not found")
leAlias := Network.GetLease("fake=alias", "fake-net")
assert.Equal(t, (*schema.Lease)(nil), leAlias, "MUST be not found")
}
// 1
Network.AddLease("fake-aa", "192.168.1.1", "fake-aa")
Network.AddLease("fake-aa", "192.168.1.1", "fake-cc")
{
lea := Network.GetLease("fake-aa", "fake-aa")
assert.Equal(t, "192.168.1.1", lea.Address, "MUST be found")
lec := Network.GetLease("fake-aa", "fake-cc")
assert.Equal(t, "192.168.1.1", lec.Address, "MUST be found")
}
n0 := &models.Network{
IpStart: "192.168.1.0",
IpEnd: "192.168.1.222",
Name: "fake-aa",
}
Network.Add(n0)
Network.NewLease("fake-vv", n0.Name)
Network.NewLease("fake-dd", n0.Name)
{
le1 := Network.GetLease("fake-vv", n0.Name)
assert.Equal(t, "192.168.1.0", le1.Address, "MUST be .0")
le2 := Network.GetLease("fake-dd", n0.Name)
assert.Equal(t, "192.168.1.2", le2.Address, "MUST be .2")
}
// 2
n1 := &models.Network{
IpStart: "192.168.1.0",
IpEnd: "192.168.1.222",
Name: "fake-dd",
}
Network.Add(n1)
Network.NewLease("fake-vv", n1.Name)
Network.NewLease("fake-dd", n1.Name)
{
le1 := Network.GetLease("fake-vv", n1.Name)
assert.Equal(t, "192.168.1.0", le1.Address, "MUST be .0")
le2 := Network.GetLease("fake-dd", n1.Name)
assert.Equal(t, "192.168.1.1", le2.Address, "MUST be .1")
}
}

View File

@@ -15,7 +15,7 @@ func TestBridgeWriteAndReadByTap(t *testing.T) {
//open tap kernel
dev01, err := NewKernelTap("true", TapConfig{Type: TAP})
if err != nil {
t.Errorf("Tap.Open %s", err)
t.Skipf("Tap.Open %s", err)
return
}
dev02, err := NewKernelTap("true", TapConfig{Type: TAP})

View File

@@ -2,7 +2,6 @@ package schema
type Lease struct {
Address string `json:"address"`
UUID string `json:"uuid"`
Alias string `json:"alias"`
Client string `json:"client"`
Type string `json:"type"`

View File

@@ -61,7 +61,7 @@ func (w *OpenLANWorker) Initialize() {
}
cache.Network.Add(&n)
for _, ht := range w.cfg.Hosts {
lease := cache.Network.AddLease(ht.Hostname, ht.Address)
lease := cache.Network.AddLease(ht.Hostname, ht.Address, n.Name)
if lease != nil {
lease.Type = "static"
lease.Network = w.cfg.Name

View File

@@ -492,6 +492,19 @@ func (v *Switch) SignIn(client libol.SocketClient) error {
return nil
}
func client2Point(client libol.SocketClient) (*models.Point, error) {
addr := client.RemoteAddr()
if private := client.Private(); private == nil {
return nil, libol.NewErr("point %s notFound.", addr)
} else {
obj, ok := private.(*models.Point)
if !ok {
return nil, libol.NewErr("point %s notRight.", addr)
}
return obj, nil
}
}
func (v *Switch) ReadClient(client libol.SocketClient, frame *libol.FrameMessage) error {
addr := client.RemoteAddr()
if v.out.Has(libol.LOG) {
@@ -510,16 +523,12 @@ func (v *Switch) ReadClient(client libol.SocketClient, frame *libol.FrameMessage
return nil
}
// process ethernet frame message.
private := client.Private()
if private == nil {
return libol.NewErr("point %s notFound.", addr)
obj, err := client2Point(client)
if err != nil {
return err
}
point, ok := private.(*models.Point)
if !ok {
return libol.NewErr("point %s notRight.", addr)
}
device := point.Device
if point == nil || device == nil {
device := obj.Device
if device == nil {
return libol.NewErr("Tap devices is nil")
}
if _, err := device.Write(frame.Frame()); err != nil {
@@ -532,10 +541,8 @@ func (v *Switch) ReadClient(client libol.SocketClient, frame *libol.FrameMessage
func (v *Switch) OnClose(client libol.SocketClient) error {
addr := client.RemoteAddr()
v.out.Info("Switch.OnClose: %s", addr)
// already not need support free list for device.
uuid := cache.Point.GetUUID(addr)
if cache.Point.GetAddr(uuid) == addr { // not has newer
cache.Network.DelLease(uuid)
if obj, err := client2Point(client); err == nil {
cache.Network.DelLease(obj.Alias, obj.Network)
}
cache.Point.Del(addr)
return nil