diff --git a/Makefile b/Makefile index 8bdffbd..3c1b066 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ all: CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o target/gvn-Darwin-x86_64 main.go CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o target/gvn-Darwin-aarch64 main.go CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o target/gvn-Windows-x86_64.exe main.go - CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -o target/gvn-Freebsd-x86_64 main.go + CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -o target/gvn-Freebsd-amd64 main.go macOS: CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o target/gvn-Darwin-x86_64 main.go CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o target/gvn-Darwin-aarch64 main.go diff --git a/cmd/root.go b/cmd/root.go index ca15f9d..ed9cf25 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -26,6 +26,10 @@ import ( "github.com/spf13/viper" ) +const ( + INTERVAL = 30 +) + // rootCmd represents the base command when called without any subcommands var ( rootCmd = &cobra.Command{ @@ -55,6 +59,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.gvn.yaml)") rootCmd.PersistentFlags().BoolP("stdout", "", false, "logs to the stdout") + rootCmd.PersistentFlags().BoolP("debug", "", false, "debug log level") // Cobra also supports local flags, which will only run // when this action is called directly. @@ -76,6 +81,9 @@ func initConfig() { } else { logrus.SetOutput(file) } + if debug, _ := rootCmd.Flags().GetBool("debug"); debug { + logrus.SetLevel(logrus.DebugLevel) + } if cfgFile == "" { home, err := os.UserHomeDir() diff --git a/cmd/up.go b/cmd/up.go index c7456f2..119f372 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -118,50 +118,66 @@ func upCommand(cmd *cobra.Command) { // DHCP for client mode if MODE(viper.GetUint("mode")) == MODECLIENT { go func() { - ticker := time.NewTicker(10 * time.Second) - for _ = range ticker.C { - req := dhcp.Request{ - Id: viper.GetString("id"), - Name: viper.GetString("dev.name"), - Subnets: viper.GetStringSlice("dev.subnets"), + // HEARTBEAT + req := dhcp.Request{ + Id: viper.GetString("id"), + Name: viper.GetString("dev.name"), + Subnets: viper.GetStringSlice("dev.subnets"), + } + if client, res := dhcp.NewRPCClient(host, rpcZone, viper.GetString("server"), req); client != nil { + // ticker.Stop() + logrus.WithFields(logrus.Fields{ + "res": res, + "req": req, + }).Info("RPC - Client received data") + devChan <- tun.Device{ + Name: req.Name, + Ip: res.Ip, + Mtu: res.Mtu, + // ignore subnets because of self did't forward it to TUN + // Subnets: res.Subnets, + ServerVIP: res.ServerVIP, + Port: viper.GetUint("port"), } - if client, res := dhcp.NewRPCClient(host, rpcZone, viper.GetString("server"), req); client != nil { - ticker.Stop() - logrus.WithFields(logrus.Fields{ - "res": res, - "req": req, - }).Info("RPC - Client received data") - devChan <- tun.Device{ - Name: req.Name, - Ip: res.Ip, - Mtu: res.Mtu, - // ignore subnets because of self did't forward it to TUN - // Subnets: res.Subnets, - ServerVIP: res.ServerVIP, - } - // TODO: sleep or make sure call after tun.New - // refresh local VIP table - var ress []dhcp.Response - if err := dhcp.Call("DHCPService", "Clients", req, &ress); err == nil { - subnets := make([]string, 0) - for _, r := range ress { - logrus.WithFields(logrus.Fields{ - "VIP": r.Ip, - "ID": r.Id, - "Subnet": r.Subnets, - }).Info("Refresh local vip table") - route.Route.Add(strings.Split(r.Ip, "/")[0]+"/32", r.Id) - if r.Id != host.ID().Pretty() { - subnets = append(subnets, r.Subnets...) - } - } - logrus.WithFields(logrus.Fields{ - "subnets": subnets, - }).Info("Refresh subnets") - tun.RefreshRoute(subnets) + } + var ress []dhcp.Response + if err := dhcp.Call("DHCPService", "Clients", req, &ress); err == nil { + // subnets := make([]string, 0) + for _, r := range ress { + logrus.WithFields(logrus.Fields{ + "VIP": r.Ip, + "ID": r.Id, + "Subnet": r.Subnets, + }).Info("Refresh local vip table") + // route.Route.Add(strings.Split(r.Ip, "/")[0]+"/32", r.Id) + subnet := strings.Split(r.Ip, "/")[0] + "/32" + route.EventBus.Publish(route.ADD_ROUTE_TOPIC, route.RouteEvent{Id: r.Id, Subnets: []string{subnet}}) + if r.Id != host.ID().Pretty() { + // does not change route via local ethernet + // subnets = append(subnets, r.Subnets...) + route.EventBus.Publish(route.ADD_ROUTE_TOPIC, route.RouteEvent{Id: r.Id, Subnets: r.Subnets}) } } + // logrus.WithFields(logrus.Fields{ + // "subnets": subnets, + // }).Info("Refresh subnets") + // tun.RefreshRoute(subnets) + } else { + logrus.WithFields(logrus.Fields{ + "ERROR": err, + }).Error("Request clients error") + } + ticker := time.NewTicker(INTERVAL * time.Second) + for range ticker.C { + // TODO: sleep or make sure call after tun.New + // refresh local VIP table + if err := dhcp.Call("DHCPService", "Ping", req, nil); err != nil { + // TODO: log error + logrus.WithFields(logrus.Fields{ + "ERROR": err, + }).Error("RPC - Ping error") + } } }() } @@ -175,7 +191,7 @@ func upCommand(cmd *cobra.Command) { for sig := range c { switch sig { case syscall.SIGINT: - // exit when receive ctrl+c + // exit when receive ctrl+c and others signal logrus.WithFields(logrus.Fields{ "SIG": sig, "dev": mainDev, @@ -293,3 +309,45 @@ func readData(stream network.Stream) { } } } + +/* +func contains(elems []string, v string) bool { + for _, s := range elems { + if v == s { + return true + } + } + return false +} + +// check pre contains pos elements, eg: +// pre: [1, 3, 5, 6], pos: [1, 2, 3, 4] +// result should be: [2, 4] +func contains(left, right []string) []string { + sort.Strings(left) + sort.Strings(right) + tmp := make([]string, 0) + for _, item := range right { + if !contains(left, item) { + tmp = append(tmp, item) + } + } + return tmp +} + +func mins(left, right *[]string) { + for _, item := range *right { + left = remove(*left, item) + } +} + +func remove(items []string, item string) []string { + newitems := []string{} + for _, i := range items { + if i != item { + newitems = append(newitems, i) + } + } + return newitems +} +*/ diff --git a/conf/client-2.yaml b/conf/client-2.yaml index 3a614f2..0811770 100644 --- a/conf/client-2.yaml +++ b/conf/client-2.yaml @@ -1,5 +1,6 @@ id: QmZiwVDDPhByWJsk5tJqajnPFjvM15KV1NuasSb9WN3ZJq server: "/ip4/172.168.1.134/tcp/6543/p2p/QmSyYjoecj3aQ46TAWSEAmork3CRS51Y2SZCcEsiX8XeAx" +port: 6543 dev: name: utun4 mtu: 1420 diff --git a/dhcp/dhcpRPC.go b/dhcp/dhcpRPC.go index f6e520f..4ea67de 100644 --- a/dhcp/dhcpRPC.go +++ b/dhcp/dhcpRPC.go @@ -17,9 +17,11 @@ package dhcp import ( "context" + "errors" "net" "strings" "sync" + "time" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" @@ -44,6 +46,7 @@ type RPC struct { type Request struct { Id string + Mode int Name string Subnets []string } @@ -55,6 +58,9 @@ type Response struct { Mtu int Subnets []string ServerVIP string + Mode int + Ttl int64 + LoginTime int64 } type DHCPService struct { @@ -75,6 +81,9 @@ func (s *DHCPService) DHCP(ctx context.Context, req Request, res *Response) erro data.Id = req.Id data.Name = req.Name data.Subnets = req.Subnets + data.Mode = req.Mode + data.LoginTime = time.Now().Unix() + data.Ttl = 10 * 60 // 10 min if MaxCIDR == "" { MaxCIDR = s.Cidr @@ -106,12 +115,17 @@ func (s *DHCPService) DHCP(ctx context.Context, req Request, res *Response) erro res.Mtu = data.Mtu res.Subnets = data.Subnets res.ServerVIP = data.ServerVIP + res.Mode = data.Mode + res.LoginTime = data.LoginTime + res.Ttl = data.Ttl logrus.WithFields(logrus.Fields{ "res": res, }).Info("RPC - Client requested data") // vip/mask -> vip/32 - route.Route.Add(strings.Split(data.Ip, "/")[0]+"/32", data.Id) + // route.Route.Add(strings.Split(data.Ip, "/")[0]+"/32", data.Id) + subnet := strings.Split(data.Ip, "/")[0] + "/32" + route.EventBus.Publish(route.ADD_ROUTE_TOPIC, route.RouteEvent{Id: data.Id, Subnets: []string{subnet}}) mu.Unlock() return nil } @@ -119,11 +133,15 @@ func (s *DHCPService) DHCP(ctx context.Context, req Request, res *Response) erro func (s *DHCPService) Clients(ctx context.Context, req Request, res *[]Response) error { mu.Lock() for _, v := range s.KV { + if v.Mode != 1 && time.Now().Unix()-v.LoginTime > v.Ttl { + continue + } r := Response{ Id: v.Id, Name: v.Name, Ip: v.Ip, Mtu: v.Mtu, + Mode: v.Mode, Subnets: v.Subnets, ServerVIP: v.ServerVIP, } @@ -133,6 +151,20 @@ func (s *DHCPService) Clients(ctx context.Context, req Request, res *[]Response) return nil } +func (s *DHCPService) Ping(ctx context.Context, req Request, res *Response) error { + mu.Lock() + if v, ok := s.KV[req.Id]; ok { + v.Ttl = 10 * 60 // 10 min + v.LoginTime = time.Now().Unix() + s.KV[req.Id] = v + } else { + mu.Unlock() + return errors.New("not found") + } + mu.Unlock() + return nil +} + func NewRPCServer(host host.Host, zone string, cidr string, mtu int) { server := rpc.NewServer(host, protocol.ID(zone)) service := DHCPService{KV: map[string]Response{}, Cidr: cidr, Mtu: mtu} @@ -141,6 +173,21 @@ func NewRPCServer(host host.Host, zone string, cidr string, mtu int) { "ERROR": err, }).Panic("RPC - build RPC service error") } + // does not clean the zombie client + /* + go func() { + ticker := time.NewTicker(1 * time.Minute) + for range ticker.C { + for k, v := range service.KV { + if time.Now().Unix()-v.LoginTime > v.Ttl { + mu.Lock() + delete(service.KV, k) + mu.Unlock() + } + } + } + }() + */ // server register mu.Lock() service.KV[host.ID().Pretty()] = Response{ @@ -148,6 +195,9 @@ func NewRPCServer(host host.Host, zone string, cidr string, mtu int) { Ip: cidr, Mtu: mtu, ServerVIP: cidr, + Mode: 1, + LoginTime: time.Now().Unix(), + Ttl: 10 * 60, // 10 min } mu.Unlock() } @@ -161,7 +211,7 @@ func NewRPCClient(host host.Host, zone string, server string, req Request) (*rpc if err := client.Call(addr.ID, "DHCPService", "DHCP", req, &res); err != nil { logrus.WithFields(logrus.Fields{ "ERROR": err, - }).Error("RPC - call RPC serveice error") + }).Error("RPC - call DHCP RPC serveice error") } return client, res } @@ -172,7 +222,11 @@ func NewRPCClient(host host.Host, zone string, server string, req Request) (*rpc func Call(svcName string, svcMethod string, req Request, res interface{}) error { if err := client.Call(serverId, svcName, svcMethod, req, &res); err != nil { logrus.WithFields(logrus.Fields{ - "ERROR": err, + "ERROR": err, + "svcName": svcName, + "svcMethod": svcMethod, + "req": req, + "res": res, }).Error("RPC - call RPC serveice error") return err } diff --git a/eventbus/eventbus.go b/eventbus/eventbus.go new file mode 100644 index 0000000..a4c563f --- /dev/null +++ b/eventbus/eventbus.go @@ -0,0 +1,63 @@ +/* +Copyright © 2022 lilo + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package eventbus + +import ( + "sync" +) + +type DataEvent struct { + Data interface{} + Topic string +} + +// DataChannel is a channel which can accept an DataEvent +type DataChannel chan DataEvent + +// DataChannelSlice is a slice of DataChannels +type DataChannelSlice []DataChannel + +// EventBus stores the information about subscribers interested for a particular topic +type EventBus struct { + Subscribers map[string]DataChannelSlice + rm sync.RWMutex +} + +func (eb *EventBus) Publish(topic string, data interface{}) { + eb.rm.RLock() + if chans, found := eb.Subscribers[topic]; found { + // this is done because the slices refer to same array even though they are passed by value + // thus we are creating a new slice with our elements thus preserve locking correctly. + // special thanks for /u/freesid who pointed it out + channels := append(DataChannelSlice{}, chans...) + go func(data DataEvent, dataChannelSlices DataChannelSlice) { + for _, ch := range dataChannelSlices { + ch <- data + } + }(DataEvent{Data: data, Topic: topic}, channels) + } + eb.rm.RUnlock() +} + +func (eb *EventBus) Subscribe(topic string, ch DataChannel) { + eb.rm.Lock() + if prev, found := eb.Subscribers[topic]; found { + eb.Subscribers[topic] = append(prev, ch) + } else { + eb.Subscribers[topic] = append([]DataChannel{}, ch) + } + eb.rm.Unlock() +} diff --git a/p2p/dht.go b/p2p/dht.go index 4562c8c..aba1cfb 100644 --- a/p2p/dht.go +++ b/p2p/dht.go @@ -36,14 +36,11 @@ var ( routingDiscovery *discovery.RoutingDiscovery ) -// func NewDHT(host host.Host, bootstraps []multiaddr.Multiaddr) *dht.IpfsDHT { func NewDHT(host host.Host, zone string, bootstraps []string) *dht.IpfsDHT { ctx := context.Background() addrs := make([]peer.AddrInfo, 0) if len(bootstraps) > 0 { for _, bootstrap := range bootstraps { - // ids := strings.Split(bootstrap, "/") - // bs := peer.AddrInfo{ID: peer.ID(ids[len(ids)-1]), Addrs: addrs} addr, err := peer.AddrInfoFromString(bootstrap) if err != nil { continue @@ -51,10 +48,6 @@ func NewDHT(host host.Host, zone string, bootstraps []string) *dht.IpfsDHT { addrs = append(addrs, *addr) } - // var options []dht.Option - // options = append(options, dht.Mode(dht.ModeServer)) - // options = append(options, dht.BootstrapPeers(bs)) - dstore := dsync.MutexWrap(ds.NewMapDatastore()) kdht = dht.NewDHT(ctx, host, dstore) diff --git a/p2p/peer.go b/p2p/peer.go index ada6108..aa80d23 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -31,7 +31,6 @@ import ( pubsub "github.com/libp2p/go-libp2p-pubsub" "github.com/liloew/gvn/dhcp" "github.com/liloew/gvn/route" - "github.com/liloew/gvn/tun" "github.com/sirupsen/logrus" "github.com/songgao/water/waterutil" "github.com/spf13/viper" @@ -133,10 +132,11 @@ func NewPubSub(host host.Host, topic string) *Publisher { continue } // TODO: add MASQUERADE if self - tun.RefreshRoute(message.Subnets) + // tun.RefreshRoute(message.Subnets) for _, subnet := range message.Subnets { // Add will override the exist one - route.Route.Add(strings.TrimSpace(subnet), message.Id) + // route.Route.Add(strings.TrimSpace(subnet), message.Id) + route.EventBus.Publish(route.REFRESH_ROUTE_TOPIC, route.RouteEvent{Id: message.Id, Subnets: []string{subnet}}) } } else if message.MessageType == MessageTypeOnline { // refresh clients @@ -147,7 +147,7 @@ func NewPubSub(host host.Host, topic string) *Publisher { req := dhcp.Request{} var ress []dhcp.Response if err := dhcp.Call("DHCPService", "Clients", req, &ress); err == nil { - subnets := make([]string, 0) + // subnets := make([]string, 0) for _, r := range ress { if r.Id == host.ID().Pretty() { continue @@ -157,20 +157,25 @@ func NewPubSub(host host.Host, topic string) *Publisher { "ID": r.Id, "Subnet": r.Subnets, }).Info("Refresh local vip table") - route.Route.Add(strings.Split(r.Ip, "/")[0]+"/32", r.Id) + // route.Route.Add(strings.Split(r.Ip, "/")[0]+"/32", r.Id) + subnet := strings.Split(r.Ip, "/")[0] + "/32" + route.EventBus.Publish(route.REFRESH_ROUTE_TOPIC, route.RouteEvent{Id: r.Id, Subnets: []string{subnet}}) if r.Id != host.ID().Pretty() { - subnets = append(subnets, r.Subnets...) + // subnets = append(subnets, r.Subnets...) + route.EventBus.Publish(route.REFRESH_ROUTE_TOPIC, route.RouteEvent{Id: r.Id, Subnets: r.Subnets}) } } - logrus.WithFields(logrus.Fields{ - "subnets": subnets, - }).Info("Refresh subnets") - tun.RefreshRoute(subnets) + // logrus.WithFields(logrus.Fields{ + // "subnets": subnets, + // }).Info("Refresh subnets") + // tun.RefreshRoute(subnets) } } } else if message.MessageType == MessageTypeOffline { - route.Route.Remove(strings.Split(message.Vip, "/")[0] + "/32") + // route.Route.Remove(strings.Split(message.Vip, "/")[0] + "/32") + subnet := strings.Split(message.Vip, "/")[0] + "/32" + route.EventBus.Publish(route.REMOVE_ROUTE_TOPIC, route.RouteEvent{Subnets: []string{subnet}}) } } } else { diff --git a/route/route.go b/route/route.go new file mode 100644 index 0000000..d33adcb --- /dev/null +++ b/route/route.go @@ -0,0 +1,172 @@ +/* +Copyright © 2022 lilo + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package route + +import ( + "sync" + + "github.com/liloew/gvn/eventbus" + "github.com/liloew/gvn/tun" + "github.com/sirupsen/logrus" + "github.com/zmap/go-iptree/iptree" +) + +type RouteEvent struct { + Subnets []string + Id string + Vip string +} + +const ( + ADD_ROUTE_TOPIC = "ADD_ROUTE" + REMOVE_ROUTE_TOPIC = "REMOVE_ROUTE" + REFRESH_ROUTE_TOPIC = "REFRESH_ROUTE" + ONLINE_TOPIC = "ONLINE" + OFFLINE_TOPIC = "OFFLINE" +) + +var ( + Route = RouteTable{ + tree: iptree.New(), + } + EventBus = &eventbus.EventBus{ + Subscribers: map[string]eventbus.DataChannelSlice{}, + } + LocalRoute = make([]string, 0) +) + +func init() { + go func() { + addRouteCh := make(chan eventbus.DataEvent) + removeRouteCh := make(chan eventbus.DataEvent) + refreshRouteCh := make(chan eventbus.DataEvent) + onlineCh := make(chan eventbus.DataEvent) + // TODO: ofline channel + EventBus.Subscribe(ADD_ROUTE_TOPIC, addRouteCh) + EventBus.Subscribe(REMOVE_ROUTE_TOPIC, removeRouteCh) + EventBus.Subscribe(REFRESH_ROUTE_TOPIC, refreshRouteCh) + EventBus.Subscribe(ONLINE_TOPIC, onlineCh) + for { + select { + case data := <-addRouteCh: + logrus.WithFields(logrus.Fields{ + "Data": data.Data, + "Topic": data.Topic, + }).Debug("Add Route Channel") + for _, subnet := range data.Data.(RouteEvent).Subnets { + Route.add(subnet, data.Data.(RouteEvent).Id) + } + case data := <-removeRouteCh: + logrus.WithFields(logrus.Fields{ + "Data": data.Data, + "Topic": data.Topic, + }).Debug("Remove Route Channel") + for _, subnet := range data.Data.(RouteEvent).Subnets { + Route.remove(subnet) + } + case data := <-refreshRouteCh: + logrus.WithFields(logrus.Fields{ + "Data": data.Data, + "Topic": data.Topic, + }).Debug("Refresh Route Channel") + for _, subnet := range data.Data.(RouteEvent).Subnets { + Route.remove(subnet) + Route.add(subnet, data.Data.(RouteEvent).Id) + } + case data := <-onlineCh: + logrus.WithFields(logrus.Fields{ + "Data": data.Data, + "Topic": data.Topic, + }).Debug("Online Channel") + } + } + }() +} + +type RouteTable struct { + tree *iptree.IPTree + rm sync.RWMutex +} + +// subnet - 192.168.1.0/24 +// peerId - P2P node ID +func (r *RouteTable) refresh(subnet string, peerId string) { + r.remove(subnet) + r.add(subnet, peerId) +} + +func (r *RouteTable) remove(subnet string) { + // TODO: LocalRoute remove + r.rm.Lock() + r.tree.DeleteByString(subnet) + if err := tun.RemoveRoute([]string{subnet}); err == nil { + LocalRoute = remove(LocalRoute, subnet) + } else { + logrus.WithFields(logrus.Fields{ + "ERROR": err, + }).Error("Remove route error") + } + r.rm.Unlock() +} + +func (r *RouteTable) add(subnet string, peerId string) { + r.rm.Lock() + if contains(LocalRoute, subnet) { + logrus.WithFields(logrus.Fields{ + "LocalRoute": LocalRoute, + "Subnet": subnet, + }).Info("Ignore the subnet becuase of existence") + r.rm.Unlock() + return + } + r.tree.AddByString(subnet, peerId) + if err := tun.AddRoute([]string{subnet}); err == nil { + LocalRoute = append(LocalRoute, subnet) + } else { + logrus.WithFields(logrus.Fields{ + "ERROR": err, + }).Error("Add route error") + } + r.rm.Unlock() +} + +func (r *RouteTable) Get(ip string) (interface{}, bool, error) { + return r.tree.GetByString(ip) +} + +func (r *RouteTable) Clean() { + // TODO: + r.tree = iptree.New() +} + +func contains(elems []string, v string) bool { + for _, s := range elems { + if v == s { + return true + } + } + return false +} + +func remove(items []string, item string) []string { + newitems := []string{} + for _, i := range items { + if i != item { + newitems = append(newitems, i) + } + } + return newitems +} diff --git a/route/routeTable.go b/route/routeTable.go deleted file mode 100644 index f8aa2ec..0000000 --- a/route/routeTable.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright © 2022 lilo - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package route - -import ( - "github.com/zmap/go-iptree/iptree" -) - -var ( - Route = RouteTable{ - tree: iptree.New(), - } -) - -type RouteTable struct { - tree *iptree.IPTree -} - -// subnet - 192.168.1.0/24 -// peerId - P2P node ID -func (r *RouteTable) Refresh(subnet string, peerId string) { - r.Remove(subnet) - r.Add(subnet, peerId) -} - -func (r *RouteTable) Remove(subnet string) { - r.tree.DeleteByString(subnet) -} - -func (r *RouteTable) Add(subnet string, peerId string) { - r.tree.AddByString(subnet, peerId) -} - -func (r *RouteTable) Get(ip string) (interface{}, bool, error) { - return r.tree.GetByString(ip) -} - -func (r *RouteTable) Clean() { - // TODO: - r.tree = iptree.New() -}