bandwidth_limit_mode

This commit is contained in:
Craig O'Donnell 2023-01-31 22:24:52 -05:00
parent de7771da54
commit 491ee8a8d5
9 changed files with 71 additions and 24 deletions

View File

@ -717,10 +717,13 @@ type = tcp
local_port = 22 local_port = 22
remote_port = 6000 remote_port = 6000
bandwidth_limit = 1MB bandwidth_limit = 1MB
bandwidth_limit_mode = server
``` ```
Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`. Set `bandwidth_limit` in each proxy's configure to enable this feature. Supported units are `MB` and `KB`.
Set `bandwidth_limit_mode` to `client` or `server` to limit bandwidth on the client or server side. Default is `client`.
### TCP Stream Multiplexing ### TCP Stream Multiplexing
frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection. frp supports tcp stream multiplexing since v0.10.0 like HTTP2 Multiplexing, in which case all logic connections to the same frpc are multiplexed into the same TCP connection.

View File

@ -54,7 +54,7 @@ type Proxy interface {
func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) { func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
var limiter *rate.Limiter var limiter *rate.Limiter
limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes()
if limitBytes > 0 { if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeClient {
limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
} }

View File

@ -154,6 +154,8 @@ local_ip = 127.0.0.1
local_port = 22 local_port = 22
# limit bandwidth for this proxy, unit is KB and MB # limit bandwidth for this proxy, unit is KB and MB
bandwidth_limit = 1MB bandwidth_limit = 1MB
# where to limit bandwidth, can be 'client' or 'server', default is 'client'
bandwidth_limit_mode = server
# true or false, if true, messages between frps and frpc will be encrypted, default is false # true or false, if true, messages between frps and frpc will be encrypted, default is false
use_encryption = false use_encryption = false
# if true, message will be compressed # if true, message will be compressed

View File

@ -74,6 +74,7 @@ var testClientBytesWithFull = []byte(`
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@ -309,13 +310,14 @@ func Test_LoadClientBasicConf(t *testing.T) {
proxyExpected := map[string]ProxyConf{ proxyExpected := map[string]ProxyConf{
testUser + ".ssh": &TCPProxyConf{ testUser + ".ssh": &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testUser + ".ssh", ProxyName: testUser + ".ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",

View File

@ -141,6 +141,10 @@ type BaseProxyConf struct {
// BandwidthLimit limit the bandwidth // BandwidthLimit limit the bandwidth
// 0 means no limit // 0 means no limit
BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"` BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"`
// BandwidthLimitMode specifies whether to limit the bandwidth on the
// client or server side. Valid values include "client" and "server".
// By default, this value is "client".
BandwidthLimitMode BandwidthLimitMode `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"`
// meta info for each proxy // meta info for each proxy
Metas map[string]string `ini:"-" json:"metas"` Metas map[string]string `ini:"-" json:"metas"`
@ -335,6 +339,7 @@ func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool {
cfg.GroupKey != cmp.GroupKey || cfg.GroupKey != cmp.GroupKey ||
cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion || cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion ||
!cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) || !cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) ||
cfg.BandwidthLimitMode != cmp.BandwidthLimitMode ||
!reflect.DeepEqual(cfg.Metas, cmp.Metas) { !reflect.DeepEqual(cfg.Metas, cmp.Metas) {
return false return false
} }
@ -365,6 +370,15 @@ func (cfg *BaseProxyConf) decorate(prefix string, name string, section *ini.Sect
} }
} }
if bandwidthMode, err := section.GetKey("bandwidth_limit_mode"); err == nil {
cfg.BandwidthLimitMode, err = NewBandwidthLimitMode(bandwidthMode.String())
if err != nil {
return err
}
} else {
cfg.BandwidthLimitMode = BandwidthLimitModeClient
}
// plugin_xxx // plugin_xxx
cfg.LocalSvrConf.PluginParams = GetMapByPrefix(section.KeysHash(), "plugin_") cfg.LocalSvrConf.PluginParams = GetMapByPrefix(section.KeysHash(), "plugin_")
@ -390,6 +404,7 @@ func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) {
pMsg.UseEncryption = cfg.UseEncryption pMsg.UseEncryption = cfg.UseEncryption
pMsg.UseCompression = cfg.UseCompression pMsg.UseCompression = cfg.UseCompression
pMsg.BandwidthLimit = cfg.BandwidthLimit.String() pMsg.BandwidthLimit = cfg.BandwidthLimit.String()
pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode.String()
pMsg.Group = cfg.Group pMsg.Group = cfg.Group
pMsg.GroupKey = cfg.GroupKey pMsg.GroupKey = cfg.GroupKey
pMsg.Metas = cfg.Metas pMsg.Metas = cfg.Metas
@ -401,6 +416,7 @@ func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) {
cfg.UseEncryption = pMsg.UseEncryption cfg.UseEncryption = pMsg.UseEncryption
cfg.UseCompression = pMsg.UseCompression cfg.UseCompression = pMsg.UseCompression
cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit) cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit)
cfg.BandwidthLimitMode, _ = NewBandwidthLimitMode(pMsg.BandwidthLimitMode)
cfg.Group = pMsg.Group cfg.Group = pMsg.Group
cfg.GroupKey = pMsg.GroupKey cfg.GroupKey = pMsg.GroupKey
cfg.Metas = pMsg.Metas cfg.Metas = pMsg.Metas

View File

@ -58,6 +58,7 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
local_ip = 127.0.0.9 local_ip = 127.0.0.9
local_port = 29 local_port = 29
bandwidth_limit = 19MB bandwidth_limit = 19MB
bandwidth_limit_mode = server
use_encryption use_encryption
use_compression use_compression
remote_port = 6009 remote_port = 6009
@ -71,13 +72,14 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
meta_var2 = 234`), meta_var2 = 234`),
expected: &TCPProxyConf{ expected: &TCPProxyConf{
BaseProxyConf: BaseProxyConf{ BaseProxyConf: BaseProxyConf{
ProxyName: testProxyPrefix + "ssh", ProxyName: testProxyPrefix + "ssh",
ProxyType: consts.TCPProxy, ProxyType: consts.TCPProxy,
UseCompression: true, UseCompression: true,
UseEncryption: true, UseEncryption: true,
Group: "test_group", Group: "test_group",
GroupKey: "123456", GroupKey: "123456",
BandwidthLimit: MustBandwidthQuantity("19MB"), BandwidthLimit: MustBandwidthQuantity("19MB"),
BandwidthLimitMode: BandwidthLimitModeServer,
Metas: map[string]string{ Metas: map[string]string{
"var1": "123", "var1": "123",
"var2": "234", "var2": "234",

View File

@ -120,3 +120,24 @@ func (q *BandwidthQuantity) MarshalJSON() ([]byte, error) {
func (q *BandwidthQuantity) Bytes() int64 { func (q *BandwidthQuantity) Bytes() int64 {
return q.i return q.i
} }
type BandwidthLimitMode string
const (
BandwidthLimitModeClient BandwidthLimitMode = "client"
BandwidthLimitModeServer BandwidthLimitMode = "server"
)
// Create a new BandwidthLimitMode from a string. Default to "client".
func NewBandwidthLimitMode(s string) (BandwidthLimitMode, error) {
switch BandwidthLimitMode(s) {
case BandwidthLimitModeClient, BandwidthLimitModeServer:
return BandwidthLimitMode(s), nil
default:
return BandwidthLimitModeClient, errors.New("invalid bandwidth_limit_mode")
}
}
func (m BandwidthLimitMode) String() string {
return string(m)
}

View File

@ -85,14 +85,15 @@ type LoginResp struct {
// When frpc login success, send this message to frps for running a new proxy. // When frpc login success, send this message to frps for running a new proxy.
type NewProxy struct { type NewProxy struct {
ProxyName string `json:"proxy_name,omitempty"` ProxyName string `json:"proxy_name,omitempty"`
ProxyType string `json:"proxy_type,omitempty"` ProxyType string `json:"proxy_type,omitempty"`
UseEncryption bool `json:"use_encryption,omitempty"` UseEncryption bool `json:"use_encryption,omitempty"`
UseCompression bool `json:"use_compression,omitempty"` UseCompression bool `json:"use_compression,omitempty"`
BandwidthLimit string `json:"bandwidth_limit,omitempty"` BandwidthLimit string `json:"bandwidth_limit,omitempty"`
Group string `json:"group,omitempty"` BandwidthLimitMode string `json:"bandwidth_limit_mode,omitempty"`
GroupKey string `json:"group_key,omitempty"` Group string `json:"group,omitempty"`
Metas map[string]string `json:"metas,omitempty"` GroupKey string `json:"group_key,omitempty"`
Metas map[string]string `json:"metas,omitempty"`
// tcp and udp only // tcp and udp only
RemotePort int `json:"remote_port,omitempty"` RemotePort int `json:"remote_port,omitempty"`

View File

@ -194,7 +194,7 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
var limiter *rate.Limiter var limiter *rate.Limiter
limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes() limitBytes := pxyConf.GetBaseInfo().BandwidthLimit.Bytes()
if limitBytes > 0 { if limitBytes > 0 && pxyConf.GetBaseInfo().BandwidthLimitMode == config.BandwidthLimitModeServer {
limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes)) limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
} }