fea: support rate limit.

This commit is contained in:
Daniel Ding
2024-09-06 22:54:46 +08:00
parent 8377782339
commit a0f3e13c9e
8 changed files with 162 additions and 23 deletions

View File

@@ -39,4 +39,5 @@ func Commands(app *api.App) {
Version{}.Commands(app)
Log{}.Commands(app)
ZTrust{}.Commands(app)
Rate{}.Commands(app)
}

92
cmd/api/v5/rate.go Executable file
View File

@@ -0,0 +1,92 @@
package v5
import (
"github.com/luscis/openlan/cmd/api"
"github.com/luscis/openlan/pkg/schema"
"github.com/urfave/cli/v2"
)
type Rate struct {
Cmd
}
func (u Rate) Url(prefix, name string) string {
return prefix + "/api/interface/" + name + "/rate"
}
func (u Rate) Tmpl() string {
return `# total {{ len . }}
{{ps -16 "device"}} {{ps -8 "speed"}}
{{- range . }}
{{ps -16 .Device}} {{pi .Speed}}
{{- end }}
`
}
func (u Rate) List(c *cli.Context) error {
url := u.Url(c.String("url"), "")
clt := u.NewHttp(c.String("token"))
var items []schema.Rate
if err := clt.GetJSON(url, &items); err != nil {
return err
}
return u.Out(items, c.String("format"), u.Tmpl())
}
func (u Rate) Add(c *cli.Context) error {
name := c.String("device")
rate := &schema.Rate{
Device: name,
Speed: c.Int("speed"),
}
url := u.Url(c.String("url"), name)
clt := u.NewHttp(c.String("token"))
if err := clt.PostJSON(url, rate, nil); err != nil {
return err
}
return nil
}
func (u Rate) Remove(c *cli.Context) error {
name := c.String("device")
url := u.Url(c.String("url"), name)
clt := u.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, nil, nil); err != nil {
return err
}
return nil
}
func (u Rate) Commands(app *api.App) {
app.Command(&cli.Command{
Name: "rate",
Usage: "Rate Limit",
Subcommands: []*cli.Command{
{
Name: "list",
Usage: "Display all rate limits",
Aliases: []string{"ls"},
Action: u.List,
},
{
Name: "add",
Usage: "Add a rate limit",
Flags: []cli.Flag{
&cli.StringFlag{Name: "device", Required: true},
&cli.StringFlag{Name: "speed", Required: true},
},
Action: u.Add,
},
{
Name: "remove",
Usage: "Remove a rate limit",
Aliases: []string{"rm"},
Flags: []cli.Flag{
&cli.StringFlag{Name: "device", Required: true},
},
Action: u.Remove,
},
},
})
}

View File

@@ -9,6 +9,11 @@ import (
"github.com/luscis/openlan/pkg/schema"
)
type Rater interface {
AddRate(device string, mbit int)
DelRate(device string)
}
type Switcher interface {
UUID() string
UpTime() int64
@@ -20,6 +25,7 @@ type Switcher interface {
AddNetwork(network string)
DelNetwork(network string)
SaveNetwork(network string)
Rater
}
func NewWorkerSchema(s Switcher) schema.Worker {
@@ -89,8 +95,6 @@ type Super interface {
Start(v Switcher)
Stop()
Reload(v Switcher)
DoZTrust()
UndoZTrust()
}
type Networker interface {
@@ -108,6 +112,8 @@ type Networker interface {
Qoser() Qoser
ACLer() ACLer
FindHoper() FindHoper
DoZTrust()
UndoZTrust()
}
type IPSecer interface {

35
pkg/api/rate.go Executable file
View File

@@ -0,0 +1,35 @@
package api
import (
"net/http"
"github.com/gorilla/mux"
"github.com/luscis/openlan/pkg/schema"
)
type Rate struct {
Switcher Switcher
}
func (h Rate) Router(router *mux.Router) {
router.HandleFunc("/api/interface/{id}/rate", h.Post).Methods("POST")
router.HandleFunc("/api/interface/{id}/rate", h.Delete).Methods("DELETE")
}
func (h Rate) Post(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
device := vars["id"]
rate := &schema.Rate{}
if err := GetData(r, rate); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
h.Switcher.AddRate(device, rate.Speed)
}
func (h Rate) Delete(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
device := vars["id"]
h.Switcher.DelRate(device)
}

View File

@@ -14,7 +14,6 @@ func Add(router *mux.Router, switcher Switcher) {
Device{}.Router(router)
VPNClient{}.Router(router)
PProf{}.Router(router)
VxLAN{}.Router(router)
Config{Switcher: switcher}.Router(router)
Version{}.Router(router)
Log{}.Router(router)
@@ -26,4 +25,5 @@ func Add(router *mux.Router, switcher Switcher) {
Route{Switcher: switcher}.Router(router)
IPSec{}.Router(router)
FindHop{}.Router(router)
Rate{Switcher: switcher}.Router(router)
}

View File

@@ -1,20 +0,0 @@
package api
import (
"net/http"
"github.com/gorilla/mux"
)
type VxLAN struct {
Switcher Switcher
}
func (l VxLAN) Router(router *mux.Router) {
router.HandleFunc("/api/vxlan", l.List).Methods("GET")
router.HandleFunc("/api/vxlan/{id}", l.List).Methods("GET")
}
func (l VxLAN) List(w http.ResponseWriter, r *http.Request) {
ResponseJson(w, nil)
}

6
pkg/schema/rate.go Normal file
View File

@@ -0,0 +1,6 @@
package schema
type Rate struct {
Device string `json:"device"`
Speed int `json:"speed"` // Mbit
}

View File

@@ -2,6 +2,7 @@ package cswitch
import (
"encoding/json"
"fmt"
"os"
"strings"
"sync"
@@ -599,3 +600,21 @@ func (v *Switch) Reload() {
func (v *Switch) Save() {
v.cfg.Save()
}
func (v *Switch) AddRate(device string, mbit int) {
kbits := fmt.Sprintf("%dMbit", mbit)
burst := "64Kb"
latency := "400ms"
out, err := libol.Exec("tc", "qdisc", "add", "dev", device, "root", "tbf", "rate", kbits, "burst", burst, "latency", latency)
if err != nil {
v.out.Warn("Switch.AddRate: %s %d %s", device, mbit, out)
}
}
func (v *Switch) DelRate(device string) {
out, err := libol.Exec("tc", "qdisc", "del", "dev", device, "root")
if err != nil {
v.out.Warn("Switch.AddRate: %s %s", device, out)
}
}