diff --git a/cmd/api/v5/findhop.go b/cmd/api/v5/findhop.go new file mode 100644 index 0000000..bc362c6 --- /dev/null +++ b/cmd/api/v5/findhop.go @@ -0,0 +1,122 @@ +package v5 + +import ( + "github.com/luscis/openlan/pkg/libol" + "github.com/luscis/openlan/pkg/schema" + "github.com/urfave/cli/v2" +) + +type FindHop struct { + Cmd +} + +func (r FindHop) Url(prefix, name string) string { + return prefix + "/api/network/" + name + "/findhop" +} + +func (r FindHop) Add(c *cli.Context) error { + network := c.String("name") + if len(network) == 0 { + return libol.NewErr("invalid network") + } + pr := &schema.FindHop{ + Name: c.String("findhop"), + Mode: c.String("mode"), + NextHop: c.String("nexthop"), + Check: c.String("check"), + } + url := r.Url(c.String("url"), network) + clt := r.NewHttp(c.String("token")) + if err := clt.PostJSON(url, pr, nil); err != nil { + return err + } + return nil +} + +func (r FindHop) Remove(c *cli.Context) error { + network := c.String("name") + if len(network) == 0 { + return libol.NewErr("invalid network") + } + pr := &schema.FindHop{ + Name: c.String("findhop"), + } + url := r.Url(c.String("url"), network) + clt := r.NewHttp(c.String("token")) + if err := clt.DeleteJSON(url, pr, nil); err != nil { + return err + } + return nil +} + +func (r FindHop) Save(c *cli.Context) error { + network := c.String("name") + url := r.Url(c.String("url"), network) + + clt := r.NewHttp(c.String("token")) + if err := clt.PutJSON(url, nil, nil); err != nil { + return err + } + + return nil +} + +func (r FindHop) Tmpl() string { + return `# total {{ len . }} +{{ps -25 "name"}} {{ps -8 "checker"}} {{ps -16 "mode"}} {{ps -25 "nexthop"}} {{ps -25 "available"}} +{{- range . }} +{{ps -25 .Name}} {{ps -8 .Check }} {{ps -16 .Mode}} {{ps -25 .NextHop}} {{ps -25 .Available}} +{{- end }} +` +} + +func (r FindHop) List(c *cli.Context) error { + url := r.Url(c.String("url"), c.String("name")) + clt := r.NewHttp(c.String("token")) + var items []schema.FindHop + if err := clt.GetJSON(url, &items); err != nil { + return err + } + return r.Out(items, c.String("format"), r.Tmpl()) +} + +func (r FindHop) Commands() *cli.Command { + return &cli.Command{ + Name: "findhop", + Usage: "FindHop configuration", + Subcommands: []*cli.Command{ + { + Name: "add", + Usage: "Add a findhop for the network", + Flags: []cli.Flag{ + &cli.StringFlag{Name: "findhop", Required: true}, + &cli.StringFlag{Name: "nexthop"}, + &cli.StringFlag{Name: "mode", Value: "active-backup"}, + &cli.StringFlag{Name: "check"}, + }, + Action: r.Add, + }, + { + Name: "remove", + Usage: "Remove a findhop from the network", + Aliases: []string{"rm"}, + Flags: []cli.Flag{ + &cli.StringFlag{Name: "findhop", Required: true}, + }, + Action: r.Remove, + }, + { + Name: "list", + Usage: "Display all findhop of the network", + Aliases: []string{"ls"}, + Action: r.List, + }, + { + Name: "save", + Usage: "Save all findhop", + Aliases: []string{"sa"}, + Action: r.Save, + }, + }, + } +} diff --git a/cmd/api/v5/network.go b/cmd/api/v5/network.go index 7f449cd..95b6e54 100755 --- a/cmd/api/v5/network.go +++ b/cmd/api/v5/network.go @@ -93,6 +93,7 @@ func (u Network) Commands(app *api.App) { openvpn := OpenVpn{} output := Output{} qos := Qos{} + findhop := FindHop{} app.Command(&cli.Command{ Name: "network", Aliases: []string{"net"}, @@ -134,6 +135,7 @@ func (u Network) Commands(app *api.App) { output.Commands(), route.Commands(), link.Commands(), + findhop.Commands(), }, }) } diff --git a/cmd/api/v5/route.go b/cmd/api/v5/route.go index 6443718..59e6cdd 100644 --- a/cmd/api/v5/route.go +++ b/cmd/api/v5/route.go @@ -109,7 +109,7 @@ func (r Route) Commands() *cli.Command { }, { Name: "list", - Usage: "Display all outputs of the network", + Usage: "Display all routes of the network", Aliases: []string{"ls"}, Action: r.List, }, diff --git a/pkg/api/acl.go b/pkg/api/acl.go index 5f06b7d..93a8b2b 100755 --- a/pkg/api/acl.go +++ b/pkg/api/acl.go @@ -24,7 +24,7 @@ func (h ACL) List(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } acl := worker.ACLer() @@ -43,21 +43,21 @@ func (h ACL) Add(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } acl := worker.ACLer() rule := &schema.ACLRule{} if err := GetData(r, rule); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if err := acl.AddRule(rule); err == nil { ResponseJson(w, "success") } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } } @@ -68,21 +68,21 @@ func (h ACL) Del(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } acl := worker.ACLer() rule := &schema.ACLRule{} if err := GetData(r, rule); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if err := acl.DelRule(rule); err == nil { ResponseJson(w, "success") } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } } @@ -93,11 +93,11 @@ func (h ACL) Save(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } acl := worker.ACLer() - acl.Save() + acl.SaveRule() ResponseJson(w, "success") } diff --git a/pkg/api/api.go b/pkg/api/api.go index d71cbaf..df2a485 100755 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -39,7 +39,7 @@ type ACLer interface { AddRule(rule *schema.ACLRule) error DelRule(rule *schema.ACLRule) error ListRules(call func(obj schema.ACLRule)) - Save() + SaveRule() } type ZTruster interface { @@ -62,11 +62,11 @@ type VPNer interface { } type Qoser interface { - AddQosUser(name string, inSpeed float64) error - UpdateQosUser(name string, inSpeed float64) error - DelQosUser(name string) error - ListQosUsers(call func(obj schema.Qos)) - Save() + AddQos(name string, inSpeed float64) error + UpdateQos(name string, inSpeed float64) error + DelQos(name string) error + ListQos(call func(obj schema.Qos)) + SaveQos() } type Outputer interface { @@ -75,25 +75,37 @@ type Outputer interface { SaveOutput() } -type Networker interface { +type FindHoper interface { + AddHop(data schema.FindHop) error + DelHop(data schema.FindHop) error + ListHop(call func(obj schema.FindHop)) + SaveHop() +} + +type Super interface { String() string ID() string Initialize() Start(v Switcher) Stop() - Bridge() cn.Bridger + Reload(v Switcher) +} + +type Networker interface { + Super Config() *co.Network Subnet() *net.IPNet - Reload(v Switcher) Provider() string - ZTruster() ZTruster - Qoser() Qoser IfAddr() string - ACLer() ACLer SetMss(mss int) Outputer Router VPNer + Bridger() cn.Bridger + ZTruster() ZTruster + Qoser() Qoser + ACLer() ACLer + FindHoper() FindHoper } type IPSecer interface { diff --git a/pkg/api/findhop.go b/pkg/api/findhop.go new file mode 100644 index 0000000..93dcd88 --- /dev/null +++ b/pkg/api/findhop.go @@ -0,0 +1,104 @@ +package api + +import ( + "net/http" + + "github.com/gorilla/mux" + "github.com/luscis/openlan/pkg/schema" +) + +type FindHop struct { + Switcher Switcher +} + +func (rt FindHop) Router(router *mux.Router) { + router.HandleFunc("/api/network/{id}/findhop", rt.List).Methods("GET") + router.HandleFunc("/api/network/{id}/findhop", rt.Add).Methods("POST") + router.HandleFunc("/api/network/{id}/findhop", rt.Del).Methods("DELETE") + router.HandleFunc("/api/network/{id}/findhop", rt.Save).Methods("PUT") +} + +func (rt FindHop) List(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + + worker := Call.GetWorker(id) + if worker == nil { + http.Error(w, "Network not found", http.StatusBadRequest) + return + } + routes := make([]schema.FindHop, 0, 1024) + hoper := worker.FindHoper() + + hoper.ListHop(func(obj schema.FindHop) { + routes = append(routes, obj) + }) + ResponseJson(w, routes) +} + +func (rt FindHop) Add(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + + worker := Call.GetWorker(id) + if worker == nil { + http.Error(w, "Network not found", http.StatusBadRequest) + return + } + + data := schema.FindHop{} + if err := GetData(r, &data); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + hoper := worker.FindHoper() + if err := hoper.AddHop(data); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ResponseJson(w, true) +} + +func (rt FindHop) Del(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + + worker := Call.GetWorker(id) + if worker == nil { + http.Error(w, "Network not found", http.StatusBadRequest) + return + } + + data := schema.FindHop{} + if err := GetData(r, &data); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + hoper := worker.FindHoper() + if err := hoper.DelHop(data); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + ResponseJson(w, true) +} + +func (rt FindHop) Save(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["id"] + + worker := Call.GetWorker(id) + if worker == nil { + http.Error(w, "Network not found", http.StatusBadRequest) + return + } + + hoper := worker.FindHoper() + hoper.SaveHop() + + ResponseJson(w, true) + +} diff --git a/pkg/api/ipsec.go b/pkg/api/ipsec.go index 8989bed..c7988f4 100755 --- a/pkg/api/ipsec.go +++ b/pkg/api/ipsec.go @@ -35,7 +35,7 @@ func (h IPSec) Get(w http.ResponseWriter, r *http.Request) { func (h IPSec) Post(w http.ResponseWriter, r *http.Request) { tun := &schema.IPSecTunnel{} if err := GetData(r, tun); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if Call.secer == nil { @@ -49,7 +49,7 @@ func (h IPSec) Post(w http.ResponseWriter, r *http.Request) { func (h IPSec) Delete(w http.ResponseWriter, r *http.Request) { tun := &schema.IPSecTunnel{} if err := GetData(r, tun); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if Call.secer == nil { @@ -63,7 +63,7 @@ func (h IPSec) Delete(w http.ResponseWriter, r *http.Request) { func (h IPSec) Restart(w http.ResponseWriter, r *http.Request) { tun := &schema.IPSecTunnel{} if err := GetData(r, tun); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if Call.secer == nil { diff --git a/pkg/api/log.go b/pkg/api/log.go index 68101a9..b1f5dcb 100755 --- a/pkg/api/log.go +++ b/pkg/api/log.go @@ -24,7 +24,7 @@ func (l Log) List(w http.ResponseWriter, r *http.Request) { func (l Log) Add(w http.ResponseWriter, r *http.Request) { log := &schema.Log{} if err := GetData(r, log); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } diff --git a/pkg/api/network.go b/pkg/api/network.go index 6b4b4c5..6e60fc9 100755 --- a/pkg/api/network.go +++ b/pkg/api/network.go @@ -49,7 +49,7 @@ func (h Network) Get(w http.ResponseWriter, r *http.Request) { func (h Network) Post(w http.ResponseWriter, r *http.Request) { network := &schema.Network{} if err := GetData(r, network); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } data, err := libol.Marshal(&network.Config, true) @@ -88,7 +88,7 @@ func (h Network) Delete(w http.ResponseWriter, r *http.Request) { func (h Network) Save(w http.ResponseWriter, r *http.Request) { network := &schema.Network{} if err := GetData(r, network); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } h.Switcher.SaveNetwork(network.Name) @@ -112,7 +112,7 @@ func (h Network) RestartVPN(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } diff --git a/pkg/api/output.go b/pkg/api/output.go index 791a504..7cc46c5 100755 --- a/pkg/api/output.go +++ b/pkg/api/output.go @@ -42,7 +42,7 @@ func (h Output) Post(w http.ResponseWriter, r *http.Request) { output := &schema.Output{} if err := GetData(r, output); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } cs := h.Switcher.Config() @@ -65,7 +65,7 @@ func (h Output) Delete(w http.ResponseWriter, r *http.Request) { output := &schema.Output{} if err := GetData(r, output); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } cs := h.Switcher.Config() diff --git a/pkg/api/pprof.go b/pkg/api/pprof.go index 2683495..971ad34 100755 --- a/pkg/api/pprof.go +++ b/pkg/api/pprof.go @@ -31,7 +31,7 @@ func (h PProf) Add(w http.ResponseWriter, r *http.Request) { pp := &schema.PProf{} if err := GetData(r, pp); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } diff --git a/pkg/api/qos.go b/pkg/api/qos.go index a5b6571..6cb271d 100644 --- a/pkg/api/qos.go +++ b/pkg/api/qos.go @@ -25,12 +25,12 @@ func (h QosApi) List(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } var qos = worker.Qoser() - qos.ListQosUsers(func(obj schema.Qos) { + qos.ListQos(func(obj schema.Qos) { qosList = append(qosList, obj) }) @@ -41,7 +41,7 @@ func (h QosApi) Add(w http.ResponseWriter, r *http.Request) { qos := &schema.Qos{} if err := GetData(r, qos); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -50,13 +50,13 @@ func (h QosApi) Add(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } if qos != nil { - if err := worker.Qoser().AddQosUser(qos.Name, qos.InSpeed); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + if err := worker.Qoser().AddQos(qos.Name, qos.InSpeed); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) return } ResponseJson(w, true) @@ -69,7 +69,7 @@ func (h QosApi) Del(w http.ResponseWriter, r *http.Request) { qos := &schema.Qos{} if err := GetData(r, qos); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -78,13 +78,13 @@ func (h QosApi) Del(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } if qos != nil { - if err := worker.Qoser().DelQosUser(qos.Name); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + if err := worker.Qoser().DelQos(qos.Name); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) return } ResponseJson(w, true) @@ -99,11 +99,11 @@ func (h QosApi) Save(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } qos := worker.Qoser() - qos.Save() + qos.SaveQos() ResponseJson(w, "success") } diff --git a/pkg/api/route.go b/pkg/api/route.go index a36661b..72e7909 100644 --- a/pkg/api/route.go +++ b/pkg/api/route.go @@ -26,7 +26,7 @@ func (rt Route) List(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } @@ -42,18 +42,18 @@ func (rt Route) Add(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } pr := &schema.PrefixRoute{} if err := GetData(r, pr); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if err := worker.AddRoute(pr, rt.Switcher); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -66,18 +66,18 @@ func (rt Route) Del(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } pr := &schema.PrefixRoute{} if err := GetData(r, pr); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if err := worker.DelRoute(pr, rt.Switcher); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -90,7 +90,7 @@ func (rt Route) Save(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } diff --git a/pkg/api/url.go b/pkg/api/url.go index 5dca04e..7cef71b 100755 --- a/pkg/api/url.go +++ b/pkg/api/url.go @@ -25,4 +25,5 @@ func Add(router *mux.Router, switcher Switcher) { ACL{}.Router(router) Route{Switcher: switcher}.Router(router) IPSec{}.Router(router) + FindHop{}.Router(router) } diff --git a/pkg/api/user.go b/pkg/api/user.go index e00a67e..ff9eb37 100755 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -50,7 +50,7 @@ func (h User) Get(w http.ResponseWriter, r *http.Request) { func (h User) Add(w http.ResponseWriter, r *http.Request) { user := &schema.User{} if err := GetData(r, user); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -87,7 +87,7 @@ func UserCheck(user, pass string) error { func (h User) Check(w http.ResponseWriter, r *http.Request) { user := &schema.User{} if err := GetData(r, user); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } if err := UserCheck(user.Name, user.Password); err == nil { diff --git a/pkg/api/ztrust.go b/pkg/api/ztrust.go index a90e912..8010796 100755 --- a/pkg/api/ztrust.go +++ b/pkg/api/ztrust.go @@ -48,12 +48,12 @@ func (h ZTrust) ListGuest(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } ztrust := worker.ZTruster() if ztrust == nil { - http.Error(w, "ZTrust disabled", http.StatusInternalServerError) + http.Error(w, "ZTrust disabled", http.StatusBadRequest) return } @@ -79,18 +79,18 @@ func (h ZTrust) AddGuest(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } ztrust := worker.ZTruster() if ztrust == nil { - http.Error(w, "ZTrust disabled", http.StatusInternalServerError) + http.Error(w, "ZTrust disabled", http.StatusBadRequest) return } guest := &schema.ZGuest{} if err := GetData(r, guest); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -118,7 +118,7 @@ func (h ZTrust) AddGuest(w http.ResponseWriter, r *http.Request) { if err := ztrust.AddGuest(guest.Name, guest.Address); err == nil { ResponseJson(w, "success") } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } } @@ -129,18 +129,18 @@ func (h ZTrust) DelGuest(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } ztrust := worker.ZTruster() if ztrust == nil { - http.Error(w, "ZTrust disabled", http.StatusInternalServerError) + http.Error(w, "ZTrust disabled", http.StatusBadRequest) return } guest := &schema.ZGuest{} if err := GetData(r, guest); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -156,7 +156,7 @@ func (h ZTrust) DelGuest(w http.ResponseWriter, r *http.Request) { if err := ztrust.DelGuest(guest.Name, guest.Address); err == nil { ResponseJson(w, "success") } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } } @@ -167,12 +167,12 @@ func (h ZTrust) ListKnock(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } ztrust := worker.ZTruster() if ztrust == nil { - http.Error(w, "ZTrust disabled", http.StatusInternalServerError) + http.Error(w, "ZTrust disabled", http.StatusBadRequest) return } @@ -197,18 +197,18 @@ func (h ZTrust) AddKnock(w http.ResponseWriter, r *http.Request) { worker := Call.GetWorker(id) if worker == nil { - http.Error(w, "Network not found", http.StatusInternalServerError) + http.Error(w, "Network not found", http.StatusBadRequest) return } ztrust := worker.ZTruster() if ztrust == nil { - http.Error(w, "ZTrust disabled", http.StatusInternalServerError) + http.Error(w, "ZTrust disabled", http.StatusBadRequest) return } rule := &schema.KnockRule{} if err := GetData(r, rule); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } @@ -223,7 +223,7 @@ func (h ZTrust) AddKnock(w http.ResponseWriter, r *http.Request) { if err := ztrust.Knock(user, rule.Protocol, rule.Dest, rule.Port, rule.Age); err == nil { ResponseJson(w, "success") } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusBadRequest) return } } diff --git a/pkg/config/config.go b/pkg/config/config.go index 599f5d9..829d683 100755 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -21,3 +21,7 @@ func Update(obj *Switch) { func Get() *Switch { return switcher } + +func GetNetwork(name string) *Network { + return switcher.GetNetwork(name) +} diff --git a/pkg/config/findhop.go b/pkg/config/findhop.go index 1e94ba4..cb0b40f 100644 --- a/pkg/config/findhop.go +++ b/pkg/config/findhop.go @@ -1,6 +1,7 @@ package config type FindHop struct { + Name string `json:"-"` Check string `json:"check"` Params PingParams `json:"params"` Mode string `json:"mode,omitempty"` diff --git a/pkg/config/network.go b/pkg/config/network.go index 19cc502..b7b39e7 100755 --- a/pkg/config/network.go +++ b/pkg/config/network.go @@ -237,3 +237,25 @@ func (n *Network) DelOutput(value *Output) (*Output, bool) { } return obj, index != -1 } + +func (n *Network) FindFindHop(value *FindHop) *FindHop { + return n.FindHop[value.Name] +} + +func (n *Network) AddFindHop(value *FindHop) bool { + older := n.FindFindHop(value) + if older == nil { + n.FindHop[value.Name] = value + return true + } + return false +} + +func (n *Network) DelFindHop(value *FindHop) (*FindHop, bool) { + older := n.FindFindHop(value) + if older != nil { + delete(n.FindHop, value.Name) + return older, true + } + return value, false +} diff --git a/pkg/config/subnet.go b/pkg/config/subnet.go index d0ca23d..da3d4e2 100755 --- a/pkg/config/subnet.go +++ b/pkg/config/subnet.go @@ -41,6 +41,9 @@ func (r *PrefixRoute) String() string { if len(r.NextHop) > 0 { elems = append(elems, fmt.Sprintf("Nexthop: %s", r.NextHop)) } + if len(r.FindHop) > 0 { + elems = append(elems, fmt.Sprintf("Findhop: %s", r.FindHop)) + } if len(r.Mode) > 0 { elems = append(elems, fmt.Sprintf("Forward: %s", r.Mode)) } diff --git a/pkg/schema/network.go b/pkg/schema/network.go index 88595fe..f48aacc 100755 --- a/pkg/schema/network.go +++ b/pkg/schema/network.go @@ -33,3 +33,11 @@ type Network struct { Name string `json:"name"` Config interface{} `json:"config"` } + +type FindHop struct { + Name string `json:"name"` + Mode string `json:"mode"` + Check string `json:"check"` + NextHop string `json:"nexthop"` + Available string `json:"available"` +} diff --git a/pkg/switch/acl.go b/pkg/switch/acl.go index 4c47829..cf4edcc 100644 --- a/pkg/switch/acl.go +++ b/pkg/switch/acl.go @@ -163,7 +163,7 @@ func (a *ACL) ListRules(call func(obj schema.ACLRule)) { } } -func (a *ACL) Save() { +func (a *ACL) SaveRule() { cfg := co.GetAcl(a.Name) cfg.Rules = nil for _, rule := range a.Rules { diff --git a/pkg/switch/findhop.go b/pkg/switch/findhop.go index c7f7bb7..5ed36c9 100644 --- a/pkg/switch/findhop.go +++ b/pkg/switch/findhop.go @@ -7,31 +7,35 @@ import ( "regexp" "sort" "strconv" + "strings" + "sync" "time" co "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/models" + "github.com/luscis/openlan/pkg/schema" nl "github.com/vishvananda/netlink" ) type FindHop struct { - Network string - cfg map[string]*co.FindHop + name string + cfg *co.Network drivers map[string]FindHopDriver out *libol.SubLogger + lock sync.RWMutex } -func NewFindHop(network string, cfg map[string]*co.FindHop) *FindHop { +func NewFindHop(name string, cfg *co.Network) *FindHop { drivers := make(map[string]FindHopDriver, 32) - for key, ng := range cfg { - drv := newCheckDriver(key, network, ng) + for key, ng := range cfg.FindHop { + drv := newCheckDriver(key, name, ng) if drv != nil { drivers[key] = drv } } return &FindHop{ - Network: network, + name: name, cfg: cfg, drivers: drivers, out: libol.NewSubLogger("findhop"), @@ -47,7 +51,7 @@ func newCheckDriver(name string, network string, cfg *co.FindHop) FindHopDriver } func (ng *FindHop) Start() { - ng.out.Info("FindHop.Start: findhop, drivers size: %d", len(ng.drivers)) + ng.out.Info("FindHop.Start: drivers size: %d", len(ng.drivers)) if len(ng.drivers) > 0 { for _, checker := range ng.drivers { checker.Start() @@ -64,53 +68,112 @@ func (ng *FindHop) Stop() { } // for add findhop dynamicly -func (ng *FindHop) AddFindHop(name string, cfg *co.FindHop) { +func (ng *FindHop) addHop(name string, cfg *co.FindHop) error { if _, ok := ng.drivers[name]; ok { - ng.out.Error("FindHop.addFindHop: checker already exists %s", name) - return + ng.out.Error("FindHop.addHop: checker already exists %s", name) + return nil } - driver := newCheckDriver(name, ng.Network, cfg) - if driver != nil { - ng.drivers[name] = driver - } else { - ng.out.Error("FindHop.AddFindHop: don't support this driver %s", name) + driver := newCheckDriver(name, ng.name, cfg) + if driver == nil { + return libol.NewErr("FindHop.AddHop: don't support this driver %s", name) } + ng.drivers[name] = driver driver.Start() + return nil } // for del findhop dynamicly -func (ng *FindHop) DelFindHop(name string, cfg co.FindHop) { +func (ng *FindHop) removeHop(name string) error { if driver, ok := ng.drivers[name]; !ok { - ng.out.Error("FindHop.addFindHop: checker not exists %s", name) - return + ng.out.Error("FindHop.addHop: checker not exists %s", name) + return nil } else { if driver.HasRoute() { - ng.out.Error("FindHop.delFindHop: checker has route %s", name) - return + return libol.NewErr("FindHop.delHop: checker has route %s", name) } driver.Stop() delete(ng.drivers, name) } + return nil } -func (ng *FindHop) LoadRoute(findhop string, nlr *nl.Route) { +func (ng *FindHop) LoadHop(findhop string, nlr *nl.Route) { + ng.lock.RLock() + defer ng.lock.RUnlock() if driver, ok := ng.drivers[findhop]; ok { - ng.out.Info("FindHop.loadRoute: %v", nlr) + ng.out.Info("FindHop.LoadHop: %s via %s", nlr.String(), findhop) driver.LoadRoute(nlr) } else { - ng.out.Error("FindHop.loadRoute: checker not found %s", findhop) + ng.out.Error("FindHop.LoadHop: checker not found %s", findhop) } } -func (ng *FindHop) UnloadRoute(findhop string, nlr *nl.Route) { +func (ng *FindHop) UnloadHop(findhop string, nlr *nl.Route) { + ng.lock.RLock() + defer ng.lock.RUnlock() if driver, ok := ng.drivers[findhop]; ok { - ng.out.Debug("FindHop.unloadRoute: %v", nlr) + ng.out.Info("FindHop.UnloadHop: %s via %s", nlr.String(), findhop) driver.UnloadRoute(nlr) } else { - ng.out.Error("FindHop.unloadRoute: checker not found %s", findhop) + ng.out.Error("FindHop.UnloadHop: checker not found %s", findhop) } } +func (ng *FindHop) AddHop(data schema.FindHop) error { + ng.lock.Lock() + defer ng.lock.Unlock() + cc := &co.FindHop{ + Name: data.Name, + Mode: data.Mode, + NextHop: strings.Split(data.NextHop, ","), + Check: data.Check, + } + cc.Correct() + if ng.cfg.AddFindHop(cc) { + return ng.addHop(data.Name, cc) + } + return nil +} + +func (ng *FindHop) DelHop(data schema.FindHop) error { + ng.lock.Lock() + defer ng.lock.Unlock() + cc := &co.FindHop{ + Name: data.Name, + } + if err := ng.removeHop(data.Name); err == nil { + ng.cfg.DelFindHop(cc) + return nil + } else { + return err + } +} + +func (ng *FindHop) ListHop(call func(obj schema.FindHop)) { + ng.lock.RLock() + defer ng.lock.RUnlock() + for name, drv := range ng.drivers { + cc := drv.Config() + avas := make([]string, 0) + for _, ava := range cc.Available { + avas = append(avas, ava.NextHop) + } + call(schema.FindHop{ + Name: name, + Mode: cc.Mode, + NextHop: strings.Join(cc.NextHop, ","), + Check: cc.Check, + Available: strings.Join(avas, ","), + }) + } +} + +func (ng *FindHop) SaveHop() { + ng.lock.RLock() + defer ng.lock.RUnlock() + ng.cfg.SaveFindHop() +} + type FindHopDriver interface { Name() string Check([]string) []co.MultiPath @@ -120,40 +183,39 @@ type FindHopDriver interface { LoadRoute(route *nl.Route) UnloadRoute(route *nl.Route) HasRoute() bool + Config() *co.FindHop } -type FindHopDriverImpl struct { +type FindHopImpl struct { Network string routes []*nl.Route cfg *co.FindHop out *libol.SubLogger } -func (c *FindHopDriverImpl) Name() string { +func (c *FindHopImpl) Name() string { return "common" } -func (c *FindHopDriverImpl) Start() { - +func (c *FindHopImpl) Start() { } -func (c *FindHopDriverImpl) Stop() { - +func (c *FindHopImpl) Stop() { } -func (c *FindHopDriverImpl) HasRoute() bool { +func (c *FindHopImpl) HasRoute() bool { return len(c.routes) > 0 } -func (c *FindHopDriverImpl) Check(ipList []string) []co.MultiPath { +func (c *FindHopImpl) Check(ipList []string) []co.MultiPath { return nil } -func (c *FindHopDriverImpl) UpdateAvailable(mp []co.MultiPath) bool { +func (c *FindHopImpl) UpdateAvailable(mp []co.MultiPath) bool { if c.cfg.Mode == "load-balance" { if !compareMultiPaths(mp, c.cfg.Available) { c.cfg.Available = mp - c.out.Info("FindHopDriverImpl.UpdateAvailable: available %v", c.cfg.Available) + c.out.Info("FindHopImpl.UpdateAvailable: available %v", c.cfg.Available) return true } } else { @@ -167,21 +229,21 @@ func (c *FindHopDriverImpl) UpdateAvailable(mp []co.MultiPath) bool { } if !newPath.CompareEqual(oldPath) { c.cfg.Available = []co.MultiPath{newPath} - c.out.Info("FindHopDriverImpl.UpdateAvailable: available %v", c.cfg.Available) + c.out.Info("FindHopImpl.UpdateAvailable: available %v", c.cfg.Available) return true } } return false } -func (c *FindHopDriverImpl) ReloadRoute() { - c.out.Debug("FindHopDriverImpl.ReloadRoute: route reload %d", len(c.routes)) +func (c *FindHopImpl) ReloadRoute() { + c.out.Debug("FindHopImpl.ReloadRoute: route reload %d", len(c.routes)) for _, rt := range c.routes { c.updateRoute(rt) } } -func (c *FindHopDriverImpl) modelMultiPath() []models.MultiPath { +func (c *FindHopImpl) modelMultiPath() []models.MultiPath { var modelMultiPath []models.MultiPath for _, mp := range c.cfg.Available { modelMultiPath = append(modelMultiPath, models.MultiPath{ @@ -192,7 +254,7 @@ func (c *FindHopDriverImpl) modelMultiPath() []models.MultiPath { return modelMultiPath } -func (c *FindHopDriverImpl) buildNexthopInfos() []*nl.NexthopInfo { +func (c *FindHopImpl) buildNexthopInfos() []*nl.NexthopInfo { multiPath := make([]*nl.NexthopInfo, 0, len(c.cfg.Available)) if len(c.cfg.Available) > 0 { for _, mr := range c.cfg.Available { @@ -206,8 +268,8 @@ func (c *FindHopDriverImpl) buildNexthopInfos() []*nl.NexthopInfo { return multiPath } -func (c *FindHopDriverImpl) updateRoute(nlr *nl.Route) { - c.out.Debug("FindHopDriverImpl.updateRoute: %v ", nlr) +func (c *FindHopImpl) updateRoute(nlr *nl.Route) { + c.out.Debug("FindHopImpl.updateRoute: %v ", nlr) multiPath := c.buildNexthopInfos() nlr.MultiPath = multiPath @@ -215,16 +277,16 @@ func (c *FindHopDriverImpl) updateRoute(nlr *nl.Route) { promise := libol.NewPromise() promise.Go(func() error { if err := nl.RouteReplace(nlr); err != nil { - c.out.Warn("FindHopDriverImpl.updateRoute: %v %s", nlr, err) + c.out.Warn("FindHopImpl.updateRoute: %s %s", nlr.String(), err) return err } - c.out.Info("FindHopDriverImpl.updateRoute: %s success", nlr.String()) + c.out.Info("FindHopImpl.updateRoute: %s success", nlr.String()) return nil }) } -func (c *FindHopDriverImpl) LoadRoute(nlr *nl.Route) { - c.out.Debug("FindHopDriverImpl.LoadRoute: %v", nlr) +func (c *FindHopImpl) LoadRoute(nlr *nl.Route) { + c.out.Debug("FindHopImpl.LoadRoute: %v", nlr) c.routes = append(c.routes, nlr) nlr.MultiPath = c.buildNexthopInfos() nlr.Gw = nil @@ -235,12 +297,12 @@ func (c *FindHopDriverImpl) LoadRoute(nlr *nl.Route) { } } -func (c *FindHopDriverImpl) UnloadRoute(rt *nl.Route) { - c.out.Debug("FindHopDriverImpl.UnLoadRoute: %v", rt) +func (c *FindHopImpl) UnloadRoute(rt *nl.Route) { + c.out.Debug("FindHopImpl.UnLoadRoute: %v", rt) //find route in routes var nlr *nl.Route for i, r := range c.routes { - if r.Dst == rt.Dst && r.Table == rt.Table { + if r.Dst.String() == rt.Dst.String() && r.Table == rt.Table { nlr = r c.routes = append(c.routes[:i], c.routes[i+1:]...) break @@ -249,12 +311,16 @@ func (c *FindHopDriverImpl) UnloadRoute(rt *nl.Route) { if nlr != nil { if err := nl.RouteDel(nlr); err != nil { - c.out.Warn("FindHopDriverImpl.UnLoadRoute: %s", err) + c.out.Warn("FindHopImpl.UnLoadRoute: %s", err) return } } } +func (c *FindHopImpl) Config() *co.FindHop { + return c.cfg +} + type PingResult struct { Ip string Latency float64 @@ -262,7 +328,7 @@ type PingResult struct { } type PingDriver struct { - *FindHopDriverImpl + *FindHopImpl CfgName string Running bool PingParams *co.PingParams @@ -271,7 +337,7 @@ type PingDriver struct { func NewPingDriver(name string, network string, cfg *co.FindHop) *PingDriver { return &PingDriver{ CfgName: name, - FindHopDriverImpl: &FindHopDriverImpl{ + FindHopImpl: &FindHopImpl{ Network: network, cfg: cfg, out: libol.NewSubLogger(cfg.Check + "_" + name), diff --git a/pkg/switch/network.go b/pkg/switch/network.go index 2c7b40e..bdf8aa7 100755 --- a/pkg/switch/network.go +++ b/pkg/switch/network.go @@ -98,7 +98,7 @@ func (w *WorkerImpl) Initialize() { w.acl = NewACL(cfg.Name) w.acl.Initialize() - w.findhop = NewFindHop(cfg.Name, cfg.FindHop) + w.findhop = NewFindHop(cfg.Name, cfg) if cfg.Subnet != nil { n := models.Network{ Name: cfg.Name, @@ -307,7 +307,7 @@ func (w *WorkerImpl) loadRoute(rt co.PrefixRoute) { nlr.Priority = rt.Metric } if rt.FindHop != "" { - w.findhop.LoadRoute(rt.FindHop, &nlr) + w.findhop.LoadHop(rt.FindHop, &nlr) return } w.out.Info("WorkerImpl.loadRoute: %s", nlr.String()) @@ -513,7 +513,7 @@ func (w *WorkerImpl) unloadRoute(rt co.PrefixRoute) { } if rt.FindHop != "" { - w.findhop.UnloadRoute(rt.FindHop, &nlr) + w.findhop.UnloadHop(rt.FindHop, &nlr) return } w.out.Debug("WorkerImpl.UnLoadRoute: %s", nlr.String()) @@ -578,7 +578,7 @@ func (w *WorkerImpl) ID() string { return w.uuid } -func (w *WorkerImpl) Bridge() cn.Bridger { +func (w *WorkerImpl) Bridger() cn.Bridger { return w.br } @@ -938,6 +938,7 @@ func (w *WorkerImpl) correctRoute(route *schema.PrefixRoute) co.PrefixRoute { rt := co.PrefixRoute{ Prefix: route.Prefix, NextHop: route.NextHop, + FindHop: route.FindHop, Mode: route.Mode, Metric: route.Metric, } @@ -965,7 +966,7 @@ func (w *WorkerImpl) AddRoute(route *schema.PrefixRoute, switcher api.Switcher) return nil } - w.out.Info("WorkerImpl.AddRoute: %v", rt) + w.out.Info("WorkerImpl.AddRoute: %s", rt.String()) w.addIpSet(rt) if inet, err := libol.ParseNet(rt.Prefix); err == nil { w.addVPNSet(inet.String()) @@ -996,14 +997,6 @@ func (w *WorkerImpl) SaveRoute() { w.cfg.SaveRoute() } -func (w *WorkerImpl) ZTruster() api.ZTruster { - return w.ztrust -} - -func (w *WorkerImpl) Qoser() api.Qoser { - return w.qos -} - func (w *WorkerImpl) Router() api.Router { return w } @@ -1013,10 +1006,6 @@ func (w *WorkerImpl) IfAddr() string { return strings.SplitN(br.Address, "/", 2)[0] } -func (w *WorkerImpl) ACLer() api.ACLer { - return w.acl -} - func (w *WorkerImpl) AddOutput(data schema.Output) { output := &co.Output{ Segment: data.Segment, @@ -1046,3 +1035,18 @@ func (w *WorkerImpl) DelOutput(data schema.Output) { func (w *WorkerImpl) SaveOutput() { w.cfg.SaveOutput() } +func (w *WorkerImpl) ZTruster() api.ZTruster { + return w.ztrust +} + +func (w *WorkerImpl) Qoser() api.Qoser { + return w.qos +} + +func (w *WorkerImpl) ACLer() api.ACLer { + return w.acl +} + +func (w *WorkerImpl) FindHoper() api.FindHoper { + return w.findhop +} diff --git a/pkg/switch/openlan.go b/pkg/switch/openlan.go index e356c94..4246b2e 100755 --- a/pkg/switch/openlan.go +++ b/pkg/switch/openlan.go @@ -200,10 +200,6 @@ func (w *OpenLANWorker) DelLink(addr string) { } } -func (w *OpenLANWorker) Bridge() cn.Bridger { - return w.br -} - func (w *OpenLANWorker) Reload(v api.Switcher) { w.Stop() w.Initialize() diff --git a/pkg/switch/qos.go b/pkg/switch/qos.go index 6aa81e3..2b8742d 100644 --- a/pkg/switch/qos.go +++ b/pkg/switch/qos.go @@ -1,14 +1,15 @@ package cswitch import ( + "strconv" + "sync" + "time" + "github.com/luscis/openlan/pkg/cache" "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" cn "github.com/luscis/openlan/pkg/network" "github.com/luscis/openlan/pkg/schema" - "strconv" - "sync" - "time" ) //125000 ~ 1Mb/s @@ -229,7 +230,7 @@ func (q *QosCtrl) FindClient(name string) *schema.VPNClient { return nil } -func (q *QosCtrl) AddOrUpdateQosUser(name string, inSpeed float64) { +func (q *QosCtrl) AddOrUpdateQos(name string, inSpeed float64) { q.lock.Lock() defer q.lock.Unlock() client := q.FindClient(name) @@ -293,16 +294,14 @@ func (q *QosCtrl) ClientUpdate() { } func (q *QosCtrl) Update() { - for { q.ClientUpdate() time.Sleep(time.Second * 5) } - } -func (q *QosCtrl) Save() { +func (q *QosCtrl) SaveQos() { cfg := config.GetQos(q.Name) cfg.Config = make(map[string]*config.QosLimit, 1024) for _, rule := range q.Rules { @@ -314,25 +313,25 @@ func (q *QosCtrl) Save() { cfg.Save() } -func (q *QosCtrl) AddQosUser(name string, inSpeed float64) error { +func (q *QosCtrl) AddQos(name string, inSpeed float64) error { - q.AddOrUpdateQosUser(name, inSpeed) + q.AddOrUpdateQos(name, inSpeed) return nil } -func (q *QosCtrl) UpdateQosUser(name string, inSpeed float64) error { +func (q *QosCtrl) UpdateQos(name string, inSpeed float64) error { - q.AddOrUpdateQosUser(name, inSpeed) + q.AddOrUpdateQos(name, inSpeed) return nil } -func (q *QosCtrl) DelQosUser(name string) error { +func (q *QosCtrl) DelQos(name string) error { q.DelUserRule(name) return nil } -func (q *QosCtrl) ListQosUsers(call func(obj schema.Qos)) { +func (q *QosCtrl) ListQos(call func(obj schema.Qos)) { for _, rule := range q.Rules { obj := schema.Qos{ diff --git a/pkg/switch/switch.go b/pkg/switch/switch.go index 3162829..9b08770 100755 --- a/pkg/switch/switch.go +++ b/pkg/switch/switch.go @@ -453,7 +453,7 @@ func (v *Switch) GetBridge(tenant string) (network.Bridger, error) { if !ok { return nil, libol.NewErr("bridge %s notFound", tenant) } - return w.Bridge(), nil + return w.Bridger(), nil } func (v *Switch) NewTap(tenant string) (network.Taper, error) { @@ -496,7 +496,7 @@ func (v *Switch) FreeTap(dev network.Taper) error { if !ok { return libol.NewErr("bridge %s notFound", tenant) } - br := w.Bridge() + br := w.Bridger() _ = br.DelSlave(dev.Name()) v.out.Info("Switch.FreeTap: %s", name) return nil