diff --git a/Makefile b/Makefile index ee1daeb..62ecef0 100755 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cmd/api/v5/lease.go b/cmd/api/v5/lease.go index 8decc7a..94e66ac 100755 --- a/cmd/api/v5/lease.go +++ b/cmd/api/v5/lease.go @@ -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 }} ` } diff --git a/pkg/access/tap_test.go b/pkg/access/tap_test.go index a072a20..ab56a48 100755 --- a/pkg/access/tap_test.go +++ b/pkg/access/tap_test.go @@ -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) diff --git a/pkg/app/request.go b/pkg/app/request.go index a5369e4..9587ca3 100755 --- a/pkg/app/request.go +++ b/pkg/app/request.go @@ -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,20 +118,18 @@ 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) - if lease != nil { - resp.IfAddr = lease.Address - resp.Netmask = n.Netmask - resp.Routes = n.Routes - } else { - resp.IfAddr = "169.254.0.0" - resp.Netmask = n.Netmask - if resp.Netmask == "" { - resp.Netmask = "255.255.0.0" - } - resp.Routes = n.Routes + lease := r.findLease(recv.IfAddr, p, n) + if lease != nil { + resp.IfAddr = lease.Address + resp.Netmask = n.Netmask + resp.Routes = n.Routes + } else { + resp.IfAddr = "169.254.0.0" + resp.Netmask = n.Netmask + if resp.Netmask == "" { + resp.Netmask = "255.255.0.0" } + resp.Routes = n.Routes } out.Cmd("Request.onIpAddr: resp %s", resp) if respStr, err := json.Marshal(resp); err == nil { diff --git a/pkg/cache/network.go b/pkg/cache/network.go index 5a74560..7912aa6 100755 --- a/pkg/cache/network.go +++ b/pkg/cache/network.go @@ -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 } - 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) - if lease.Type != "static" { - w.Addr.Del(addr) - } + libol.Info("network.DelLease (%s, %s) by Addr", ruid, alias) + if lease.Type != "static" { + w.Addr.Del(ruid) } } } var Network = network{ - Networks: libol.NewSafeStrMap(1024), + Networks: libol.NewSafeStrMap(128), UUID: libol.NewSafeStrMap(1024), Addr: libol.NewSafeStrMap(1024), } diff --git a/pkg/cache/network_test.go b/pkg/cache/network_test.go new file mode 100644 index 0000000..9823958 --- /dev/null +++ b/pkg/cache/network_test.go @@ -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") + } +} diff --git a/pkg/network/bridger_test.go b/pkg/network/bridger_test.go index 7210348..b09d8cf 100755 --- a/pkg/network/bridger_test.go +++ b/pkg/network/bridger_test.go @@ -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}) diff --git a/pkg/schema/network.go b/pkg/schema/network.go index 948ceae..f26ff24 100755 --- a/pkg/schema/network.go +++ b/pkg/schema/network.go @@ -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"` diff --git a/pkg/switch/openlan.go b/pkg/switch/openlan.go index 0b24ffe..1dccba8 100755 --- a/pkg/switch/openlan.go +++ b/pkg/switch/openlan.go @@ -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 diff --git a/pkg/switch/switch.go b/pkg/switch/switch.go index 4840f7c..559fd4b 100755 --- a/pkg/switch/switch.go +++ b/pkg/switch/switch.go @@ -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