fea: remove qos download limit (#45)

* fea: remove qos download limit
* fix: crash when qos config missing
* fea: update inSpeed unit to Mbit
This commit is contained in:
Teddy_Zhu
2024-03-28 16:56:14 +08:00
committed by GitHub
parent ffce18224b
commit 2fa0ed3e19
9 changed files with 72 additions and 150 deletions

View File

@@ -37,9 +37,8 @@ func (qr QosRule) Add(c *cli.Context) error {
url := qr.Url(c.String("url"), name) url := qr.Url(c.String("url"), name)
rule := &schema.Qos{ rule := &schema.Qos{
Name: c.String("clientname"), Name: c.String("client"),
InSpeed: c.Int64("inspeed"), InSpeed: c.Float64("inspeed"),
OutSpeed: c.Int64("outspeed"),
} }
clt := qr.NewHttp(c.String("token")) clt := qr.NewHttp(c.String("token"))
@@ -55,7 +54,7 @@ func (qr QosRule) Remove(c *cli.Context) error {
url := qr.Url(c.String("url"), name) url := qr.Url(c.String("url"), name)
rule := &schema.Qos{ rule := &schema.Qos{
Name: c.String("clientname"), Name: c.String("client"),
} }
clt := qr.NewHttp(c.String("token")) clt := qr.NewHttp(c.String("token"))
@@ -68,9 +67,9 @@ func (qr QosRule) Remove(c *cli.Context) error {
func (qr QosRule) Tmpl() string { func (qr QosRule) Tmpl() string {
return `# total {{ len . }} return `# total {{ len . }}
{{ps -15 "Name"}} {{ps -15 "Device"}} {{ps -15 "ip"}} {{ps -8 "InSpeed"}} {{ps -8 "OutSpeed"}} {{ps -15 "Name"}} {{ps -15 "Device"}} {{ps -15 "ip"}} {{ps -8 "InSpeed"}}
{{- range . }} {{- range . }}
{{ps -15 .Name}} {{ps -15 .Device}} {{ps -15 .Ip}} {{pi -8 .InSpeed}} {{pi -8 .OutSpeed}} {{ps -15 .Name}} {{ps -15 .Device}} {{ps -15 .Ip}} {{pi -8 .InSpeed}}
{{- end }} {{- end }}
` `
} }
@@ -110,9 +109,8 @@ func (qr QosRule) Commands() *cli.Command {
Name: "add", Name: "add",
Usage: "Add a new qos rule for client", Usage: "Add a new qos rule for client",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{Name: "clientname", Aliases: []string{"cn"}}, &cli.StringFlag{Name: "client", Aliases: []string{"c"}},
&cli.StringFlag{Name: "inspeed", Aliases: []string{"is"}}, &cli.Float64Flag{Name: "inspeed", Aliases: []string{"is"}},
&cli.StringFlag{Name: "outspeed", Aliases: []string{"os"}},
}, },
Action: qr.Add, Action: qr.Add,
}, },
@@ -121,7 +119,7 @@ func (qr QosRule) Commands() *cli.Command {
Usage: "remove a qos rule", Usage: "remove a qos rule",
Aliases: []string{"rm"}, Aliases: []string{"rm"},
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{Name: "clientname", Aliases: []string{"cn"}}, &cli.StringFlag{Name: "client", Aliases: []string{"c"}},
}, },
Action: qr.Remove, Action: qr.Remove,
}, },

View File

@@ -2,8 +2,7 @@
"name": "example", "name": "example",
"qos":{ "qos":{
"hi@example": { "hi@example": {
"inSpeed": 125000, "inSpeed": 125000
"outSpeed":125000
} }
} }
} }

View File

@@ -48,8 +48,8 @@ type ZTruster interface {
} }
type Qoser interface { type Qoser interface {
AddQosUser(name string, inSpeed int64, outSpeed int64) error AddQosUser(name string, inSpeed float64) error
UpdateQosUser(name string, inSpeed int64, outSpeed int64) error UpdateQosUser(name string, inSpeed float64) error
DelQosUser(name string) error DelQosUser(name string) error
ListQosUsers(call func(obj schema.Qos)) ListQosUsers(call func(obj schema.Qos))
Save() Save()

View File

@@ -54,7 +54,7 @@ func (h QosApi) Add(w http.ResponseWriter, r *http.Request) {
} }
if qos != nil { if qos != nil {
if err := worker.Qoser().AddQosUser(qos.Name, qos.InSpeed, qos.OutSpeed); err != nil { if err := worker.Qoser().AddQosUser(qos.Name, qos.InSpeed); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }

View File

@@ -8,6 +8,15 @@ type Qos struct {
Config map[string]*QosLimit `json:"qos,omitempty"` Config map[string]*QosLimit `json:"qos,omitempty"`
} }
func (q *Qos) Correct(sw *Switch) {
for _, rule := range q.Config {
rule.Correct()
}
if q.File == "" {
q.File = sw.Dir("qos", q.Name+".json")
}
}
func (q *Qos) Save() { func (q *Qos) Save() {
if err := libol.MarshalSave(q, q.File, true); err != nil { if err := libol.MarshalSave(q, q.File, true); err != nil {
libol.Error("Switch.Save.Qos %s %s", q.Name, err) libol.Error("Switch.Save.Qos %s %s", q.Name, err)
@@ -15,8 +24,7 @@ func (q *Qos) Save() {
} }
type QosLimit struct { type QosLimit struct {
InSpeed int64 `json:"inSpeed,omitempty"` InSpeed float64 `json:"inSpeed,omitempty"`
OutSpeed int64 `json:"outSpeed,omitempty"`
} }
func (ql *QosLimit) Correct() { func (ql *QosLimit) Correct() {

View File

@@ -206,6 +206,13 @@ func (s *Switch) LoadNetwork() {
obj.Correct(s) obj.Correct(s)
s.Acl[obj.Name] = obj s.Acl[obj.Name] = obj
} }
if _, ok := s.Qos[obj.Name]; !ok {
obj := &Qos{
Name: obj.Name,
}
obj.Correct(s)
s.Qos[obj.Name] = obj
}
} }
} }

View File

@@ -1,9 +1,8 @@
package schema package schema
type Qos struct { type Qos struct {
Name string `json:"name"` Name string `json:"name"`
Device string `json:"device"` Device string `json:"device"`
Ip string `json:"ip"` Ip string `json:"ip"`
InSpeed int64 `json:"inSpeed"` InSpeed float64 `json:"inSpeed"`
OutSpeed int64 `json:"outSpeed"`
} }

View File

@@ -412,11 +412,6 @@ func (w *WorkerImpl) Start(v api.Switcher) {
Jump: w.qos.ChainIn(), Jump: w.qos.ChainIn(),
Comment: "Goto Qos ChainIn", Comment: "Goto Qos ChainIn",
}) })
fire.Mangle.Out.AddRule(cn.IPRule{
Output: vpn.Device,
Jump: w.qos.ChainOut(),
Comment: "Goto Qos ChainOut",
})
} }
} }

View File

@@ -16,13 +16,11 @@ import (
type QosUser struct { type QosUser struct {
QosChainName string QosChainName string
InSpeed int64 // bits InSpeed float64 // Mbit
OutSpeed int64 // bits
Name string Name string
Ip string Ip string
Device string Device string
qosChainIn *cn.FireWallChain qosChainIn *cn.FireWallChain
qosChainOut *cn.FireWallChain
out *libol.SubLogger out *libol.SubLogger
} }
@@ -32,74 +30,20 @@ func (qr *QosUser) RuleName(dir string) string {
} }
func (qr *QosUser) InLimitPacket() string { func (qr *QosUser) InLimitPacket() string {
//bytes / mtu //Mbit * 125000 / mtu
return strconv.Itoa(int(qr.InSpeed / 1500)) return strconv.Itoa(int((qr.InSpeed * 125000) / 1300))
}
func (qr *QosUser) OutLimitPacket() string {
//bytes / mtu
return strconv.Itoa(int(qr.OutSpeed / 1500))
} }
func (qr *QosUser) InLimitStr() string { func (qr *QosUser) InLimitStr() string {
//bytes / mtu
return qr.InLimitPacket() + "/s" return qr.InLimitPacket() + "/s"
} }
func (qr *QosUser) OutLimitStr() string {
//bytes / mtu
return qr.OutLimitPacket() + "/s"
}
func (qr *QosUser) InLimitRule() cn.IPRule { func (qr *QosUser) InLimitRule() cn.IPRule {
return cn.IPRule{ return cn.IPRule{
Limit: qr.InLimitStr(), Limit: qr.InLimitStr(),
//LimitBurst: qr.InLimitPacket(), LimitBurst: "100",
Comment: "Qos Limit In " + qr.Name, Comment: "Qos Limit In " + qr.Name,
Jump: "ACCEPT", Jump: "ACCEPT",
}
}
func (qr *QosUser) OutLimitRule() cn.IPRule {
return cn.IPRule{
Limit: qr.OutLimitStr(),
Comment: "Qos Limit Out " + qr.Name,
Jump: "ACCEPT",
}
}
func (qr *QosUser) BuildChainOut(chain *cn.FireWallChain) {
if qr.OutSpeed > 0 {
qr.qosChainOut = cn.NewFireWallChain(qr.RuleName("out"), cn.TMangle, "")
qr.qosChainOut.AddRule(qr.OutLimitRule())
qr.qosChainOut.AddRule(cn.IPRule{
Comment: "Qos Default Drop",
Jump: "DROP",
})
qr.qosChainOut.Install()
qr.BuildChainOutJump(chain)
}
}
func (qr *QosUser) BuildChainOutJump(chain *cn.FireWallChain) {
if qr.Ip != "" {
if err := chain.AddRuleX(cn.IPRule{
Comment: "Qos Jump",
Jump: qr.RuleName("out"),
Dest: qr.Ip,
}); err != nil {
qr.out.Warn("Qos.Add Out Rule: %s", err)
}
}
}
func (qr *QosUser) ClearChainOutJump(chain *cn.FireWallChain) {
if err := chain.DelRuleX(cn.IPRule{
Comment: "Qos Jump",
Jump: qr.RuleName("out"),
Dest: qr.Ip,
}); err != nil {
qr.out.Warn("Qos.Del Out Rule: %s", err)
} }
} }
@@ -139,14 +83,13 @@ func (qr *QosUser) ClearChainInJump(chain *cn.FireWallChain) {
} }
} }
func (qr *QosUser) Start(chainIn *cn.FireWallChain, chainOut *cn.FireWallChain) { func (qr *QosUser) Start(chainIn *cn.FireWallChain) {
qr.BuildChainIn(chainIn) qr.BuildChainIn(chainIn)
qr.BuildChainOut(chainOut)
} }
func (qr *QosUser) ReBuild(chainIn *cn.FireWallChain, chainOut *cn.FireWallChain) { func (qr *QosUser) ReBuild(chainIn *cn.FireWallChain) {
qr.Clear(chainIn, chainOut) qr.Clear(chainIn)
qr.Start(chainIn, chainOut) qr.Start(chainIn)
} }
func (qr *QosUser) ClearChainIn(chain *cn.FireWallChain) { func (qr *QosUser) ClearChainIn(chain *cn.FireWallChain) {
@@ -156,30 +99,22 @@ func (qr *QosUser) ClearChainIn(chain *cn.FireWallChain) {
qr.qosChainIn = nil qr.qosChainIn = nil
} }
} }
func (qr *QosUser) ClearChainOut(chain *cn.FireWallChain) {
if qr.qosChainOut != nil { func (qr *QosUser) Clear(chainIn *cn.FireWallChain) {
qr.ClearChainOutJump(chain)
qr.qosChainOut.Cancel()
qr.qosChainOut = nil
}
}
func (qr *QosUser) Clear(chainIn *cn.FireWallChain, chainOut *cn.FireWallChain) {
qr.ClearChainIn(chainIn) qr.ClearChainIn(chainIn)
qr.ClearChainOut(chainOut)
} }
func (qr *QosUser) Update(chainIn *cn.FireWallChain, chainOut *cn.FireWallChain, inSpeed int64, outSpeed int64, device string, ip string) { func (qr *QosUser) Update(chainIn *cn.FireWallChain, inSpeed float64, device string, ip string) {
ipChange := false changed := false
qr.Device = device
if qr.Ip != ip { if qr.Ip != ip {
ipChange = true changed = true
qr.Ip = ip qr.Ip = ip
} }
if ipChange { if changed {
qr.ClearChainInJump(chainIn) qr.ClearChainInJump(chainIn)
qr.ClearChainOutJump(chainOut)
qr.BuildChainOutJump(chainOut)
qr.BuildChainInJump(chainIn) qr.BuildChainInJump(chainIn)
} }
@@ -189,21 +124,14 @@ func (qr *QosUser) Update(chainIn *cn.FireWallChain, chainOut *cn.FireWallChain,
qr.BuildChainIn(chainIn) qr.BuildChainIn(chainIn)
} }
if qr.OutSpeed != outSpeed {
qr.OutSpeed = outSpeed
qr.ClearChainOut(chainOut)
qr.BuildChainOut(chainOut)
}
} }
type QosCtrl struct { type QosCtrl struct {
Name string Name string
Rules map[string]*QosUser Rules map[string]*QosUser
chainIn *cn.FireWallChain chainIn *cn.FireWallChain
chainOut *cn.FireWallChain out *libol.SubLogger
out *libol.SubLogger lock sync.Mutex
lock sync.Mutex
} }
func NewQosCtrl(name string) *QosCtrl { func NewQosCtrl(name string) *QosCtrl {
@@ -218,14 +146,9 @@ func (q *QosCtrl) ChainIn() string {
return "Qos_" + q.Name + "-in" return "Qos_" + q.Name + "-in"
} }
func (q *QosCtrl) ChainOut() string {
return "Qos_" + q.Name + "-out"
}
func (q *QosCtrl) Initialize() { func (q *QosCtrl) Initialize() {
//q.Start() //q.Start()
q.chainIn = cn.NewFireWallChain(q.ChainIn(), cn.TMangle, "") q.chainIn = cn.NewFireWallChain(q.ChainIn(), cn.TMangle, "")
q.chainOut = cn.NewFireWallChain(q.ChainOut(), cn.TMangle, "")
qosCfg := config.GetQos(q.Name) qosCfg := config.GetQos(q.Name)
@@ -235,7 +158,6 @@ func (q *QosCtrl) Initialize() {
QosChainName: q.Name, QosChainName: q.Name,
Name: name, Name: name,
InSpeed: limit.InSpeed, InSpeed: limit.InSpeed,
OutSpeed: limit.OutSpeed,
Ip: "", Ip: "",
out: libol.NewSubLogger("Qos_" + name), out: libol.NewSubLogger("Qos_" + name),
} }
@@ -248,11 +170,10 @@ func (q *QosCtrl) Initialize() {
func (q *QosCtrl) Start() { func (q *QosCtrl) Start() {
q.out.Info("Qos.Start") q.out.Info("Qos.Start")
q.chainIn.Install() q.chainIn.Install()
q.chainOut.Install()
if len(q.Rules) > 0 { if len(q.Rules) > 0 {
for _, rule := range q.Rules { for _, rule := range q.Rules {
rule.Start(q.chainIn, q.chainOut) rule.Start(q.chainIn)
} }
} }
@@ -263,19 +184,18 @@ func (q *QosCtrl) Stop() {
q.out.Info("Qos.Stop") q.out.Info("Qos.Stop")
if len(q.Rules) != 0 { if len(q.Rules) != 0 {
for _, rule := range q.Rules { for _, rule := range q.Rules {
rule.Clear(q.chainIn, q.chainOut) rule.Clear(q.chainIn)
} }
} }
q.chainIn.Cancel() q.chainIn.Cancel()
q.chainOut.Cancel()
} }
func (q *QosCtrl) DelUserRule(name string) { func (q *QosCtrl) DelUserRule(name string) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()
if rule, ok := q.Rules[name]; ok { if rule, ok := q.Rules[name]; ok {
rule.Clear(q.chainIn, q.chainOut) rule.Clear(q.chainIn)
delete(q.Rules, name) delete(q.Rules, name)
} }
} }
@@ -298,7 +218,7 @@ func (q *QosCtrl) FindClient(name string) *schema.VPNClient {
return nil return nil
} }
func (q *QosCtrl) AddOrUpdateQosUser(name string, inSpeed int64, outSpeed int64) { func (q *QosCtrl) AddOrUpdateQosUser(name string, inSpeed float64) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()
client := q.FindClient(name) client := q.FindClient(name)
@@ -311,18 +231,17 @@ func (q *QosCtrl) AddOrUpdateQosUser(name string, inSpeed int64, outSpeed int64)
if rule, ok := q.Rules[name]; ok { if rule, ok := q.Rules[name]; ok {
rule.Update(q.chainIn, q.chainOut, inSpeed, outSpeed, device, ip) rule.Update(q.chainIn, inSpeed, device, ip)
} else { } else {
rule = &QosUser{ rule = &QosUser{
QosChainName: q.Name, QosChainName: q.Name,
Name: name, Name: name,
InSpeed: inSpeed, InSpeed: inSpeed,
OutSpeed: outSpeed,
Ip: ip, Ip: ip,
out: libol.NewSubLogger("Qos_" + name), out: libol.NewSubLogger("Qos_" + name),
} }
rule.Start(q.chainIn, q.chainOut) rule.Start(q.chainIn)
q.Rules[name] = rule q.Rules[name] = rule
} }
@@ -350,11 +269,10 @@ func (q *QosCtrl) ClientUpdate() {
} }
} }
if existClient != nil { if existClient != nil {
rule.Update(q.chainIn, q.chainOut, rule.InSpeed, rule.OutSpeed, existClient.Device, existClient.Address) rule.Update(q.chainIn, rule.InSpeed, existClient.Device, existClient.Address)
} else { } else {
if rule.Ip != "" { if rule.Ip != "" {
rule.ClearChainInJump(q.chainIn) rule.ClearChainInJump(q.chainIn)
rule.ClearChainOutJump(q.chainOut)
rule.Ip = "" rule.Ip = ""
} }
} }
@@ -377,23 +295,22 @@ func (q *QosCtrl) Save() {
cfg.Config = make(map[string]*config.QosLimit, 1024) cfg.Config = make(map[string]*config.QosLimit, 1024)
for _, rule := range q.Rules { for _, rule := range q.Rules {
ql := &config.QosLimit{ ql := &config.QosLimit{
InSpeed: rule.InSpeed, InSpeed: rule.InSpeed,
OutSpeed: rule.OutSpeed,
} }
cfg.Config[rule.Name] = ql cfg.Config[rule.Name] = ql
} }
cfg.Save() cfg.Save()
} }
func (q *QosCtrl) AddQosUser(name string, inSpeed int64, outSpeed int64) error { func (q *QosCtrl) AddQosUser(name string, inSpeed float64) error {
q.AddOrUpdateQosUser(name, inSpeed, outSpeed) q.AddOrUpdateQosUser(name, inSpeed)
return nil return nil
} }
func (q *QosCtrl) UpdateQosUser(name string, inSpeed int64, outSpeed int64) error { func (q *QosCtrl) UpdateQosUser(name string, inSpeed float64) error {
q.AddOrUpdateQosUser(name, inSpeed, outSpeed) q.AddOrUpdateQosUser(name, inSpeed)
return nil return nil
} }
@@ -407,11 +324,10 @@ func (q *QosCtrl) ListQosUsers(call func(obj schema.Qos)) {
for _, rule := range q.Rules { for _, rule := range q.Rules {
obj := schema.Qos{ obj := schema.Qos{
Name: rule.Name, Name: rule.Name,
Device: rule.Device, Device: rule.Device,
InSpeed: rule.InSpeed, InSpeed: rule.InSpeed,
OutSpeed: rule.OutSpeed, Ip: rule.Ip,
Ip: rule.Ip,
} }
call(obj) call(obj)
} }