fea: support add findhop.

This commit is contained in:
Daniel Ding
2024-08-30 16:31:01 +08:00
parent 65a0ea5624
commit 1af859ed27
27 changed files with 504 additions and 160 deletions

122
cmd/api/v5/findhop.go Normal file
View File

@@ -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,
},
},
}
}

View File

@@ -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(),
},
})
}

View File

@@ -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,
},

View File

@@ -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")
}

View File

@@ -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 {

104
pkg/api/findhop.go Normal file
View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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
}
}

View File

@@ -21,3 +21,7 @@ func Update(obj *Switch) {
func Get() *Switch {
return switcher
}
func GetNetwork(name string) *Network {
return switcher.GetNetwork(name)
}

View File

@@ -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"`

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -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"`
}

View File

@@ -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 {

View File

@@ -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.name, cfg)
if driver == nil {
return libol.NewErr("FindHop.AddHop: don't support this driver %s", name)
}
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.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),

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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{

View File

@@ -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