From d7da1002f2b89944868489bb0c60c4dfee0f57ab Mon Sep 17 00:00:00 2001 From: xiang Date: Thu, 9 Sep 2021 11:31:58 +0800 Subject: [PATCH 1/7] support limit network bandwidth Signed-off-by: xiang --- cmd/attack/network.go | 24 +++++++++++++++++++- pkg/core/network.go | 43 ++++++++++++++++++++++++++++++------ pkg/server/chaosd/network.go | 4 ++-- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/cmd/attack/network.go b/cmd/attack/network.go index dc2eff8b..e1909455 100644 --- a/cmd/attack/network.go +++ b/cmd/attack/network.go @@ -47,6 +47,7 @@ func NewNetworkAttackCommand(uid *string) *cobra.Command { NetworkDuplicateCommand(dep, options), NetworkDNSCommand(dep, options), NewNetworkPortOccupiedCommand(dep, options), + NewNetworkBandwidthCommand(dep, options), ) return cmd @@ -191,6 +192,27 @@ func NetworkDNSCommand(dep fx.Option, options *core.NetworkCommand) *cobra.Comma return cmd } +func NewNetworkBandwidthCommand(dep fx.Option, options *core.NetworkCommand) *cobra.Command { + cmd := &cobra.Command{ + Use: "bandwidth", + Short: "limit network bandwidth", + + Run: func(*cobra.Command, []string) { + options.Action = core.NetworkBandwidthAction + options.CompleteDefaults() + utils.FxNewAppWithoutLog(dep, fx.Invoke(commonNetworkAttackFunc)).Run() + }, + } + + cmd.Flags().StringVarP(&options.Rate, "rate", "r", "", "the speed knob, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second") + cmd.Flags().Uint32VarP(&options.Limit, "limit", "l", 0, "the number of bytes that can be queued waiting for tokens to become available") + cmd.Flags().Uint32VarP(&options.Buffer, "buffer", "b", 0, "the maximum amount of bytes that tokens can be available for instantaneously") + cmd.Flags().Uint64VarP(options.Peakrate, "peakrate", "p", 0, "the maximum depletion rate of the bucket") + cmd.Flags().Uint32VarP(options.Minburst, "minburst", "m", 0, "specifies the size of the peakrate bucket") + + return cmd +} + func commonNetworkAttackFunc(options *core.NetworkCommand, chaos *chaosd.Server) { if err := options.Validate(); err != nil { utils.ExitWithError(utils.ExitBadArgs, err) @@ -210,7 +232,7 @@ func NewNetworkPortOccupiedCommand(dep fx.Option, options *core.NetworkCommand) Short: "attack network port", Run: func(cmd *cobra.Command, args []string) { - options.Action = core.NetworkPortOccupied + options.Action = core.NetworkPortOccupiedAction options.CompleteDefaults() utils.FxNewAppWithoutLog(dep, fx.Invoke(commonNetworkAttackFunc)).Run() }, diff --git a/pkg/core/network.go b/pkg/core/network.go index 3bd0cc9b..704e0394 100644 --- a/pkg/core/network.go +++ b/pkg/core/network.go @@ -22,7 +22,9 @@ import ( "github.com/pingcap/errors" + "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb" + "github.com/chaos-mesh/chaos-mesh/pkg/netem" "github.com/chaos-mesh/chaosd/pkg/utils" ) @@ -47,17 +49,20 @@ type NetworkCommand struct { PortPid int32 DNSIp string DNSHost string + + *BandwidthSpec `json:",inline"` } var _ AttackConfig = &NetworkCommand{} const ( - NetworkDelayAction = "delay" - NetworkLossAction = "loss" - NetworkCorruptAction = "corrupt" - NetworkDuplicateAction = "duplicate" - NetworkDNSAction = "dns" - NetworkPortOccupied = "occupied" + NetworkDelayAction = "delay" + NetworkLossAction = "loss" + NetworkCorruptAction = "corrupt" + NetworkDuplicateAction = "duplicate" + NetworkDNSAction = "dns" + NetworkPortOccupiedAction = "occupied" + NetworkBandwidthAction = "bandwidth" ) func (n *NetworkCommand) Validate() error { @@ -71,7 +76,7 @@ func (n *NetworkCommand) Validate() error { return n.validNetworkCommon() case NetworkDNSAction: return n.validNetworkDNS() - case NetworkPortOccupied: + case NetworkPortOccupiedAction: return n.validNetworkOccupied() default: return errors.Errorf("network action %s not supported", n.Action) @@ -293,6 +298,26 @@ func (n *NetworkCommand) ToDuplicateNetem() (*pb.Netem, error) { } func (n *NetworkCommand) ToTC(ipset string) (*pb.Tc, error) { + if n.Action == NetworkBandwidthAction { + tbf, err := netem.FromBandwidth(&v1alpha1.BandwidthSpec{ + Rate: n.Rate, + Limit: n.Limit, + Buffer: n.Buffer, + Peakrate: n.Peakrate, + Minburst: n.Minburst, + }) + + if err != nil { + return nil, err + } + + return &pb.Tc{ + Type: pb.Tc_BANDWIDTH, + Tbf: tbf, + Ipset: ipset, + }, nil + } + tc := &pb.Tc{ Type: pb.Tc_NETEM, Ipset: ipset, @@ -399,5 +424,9 @@ func NewNetworkCommand() *NetworkCommand { CommonAttackConfig: CommonAttackConfig{ Kind: NetworkAttack, }, + BandwidthSpec: &BandwidthSpec{ + Peakrate: new(uint64), + Minburst: new(uint32), + }, } } diff --git a/pkg/server/chaosd/network.go b/pkg/server/chaosd/network.go index ae1f6572..f4f554f1 100644 --- a/pkg/server/chaosd/network.go +++ b/pkg/server/chaosd/network.go @@ -63,7 +63,7 @@ func (networkAttack) Attack(options core.AttackConfig, env Environment) (err err } } - case core.NetworkPortOccupied: + case core.NetworkPortOccupiedAction: return env.Chaos.applyPortOccupied(attack) case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction: @@ -323,7 +323,7 @@ func (networkAttack) Recover(exp core.Experiment, env Environment) error { } } return env.Chaos.recoverDNSServer(attack) - case core.NetworkPortOccupied: + case core.NetworkPortOccupiedAction: return env.Chaos.recoverPortOccupied(attack, env.AttackUid) case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction: if attack.NeedApplyIPSet() { From a9483ca9d25b99549c3ee8c83d4e78df32783b70 Mon Sep 17 00:00:00 2001 From: xiang Date: Thu, 9 Sep 2021 18:05:21 +0800 Subject: [PATCH 2/7] minor update Signed-off-by: xiang --- pkg/server/chaosd/network.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/server/chaosd/network.go b/pkg/server/chaosd/network.go index f4f554f1..d78a23cd 100644 --- a/pkg/server/chaosd/network.go +++ b/pkg/server/chaosd/network.go @@ -195,6 +195,15 @@ func (s *Server) applyTC(attack *core.NetworkCommand, ipset string, uid string) Duplicate: attack.Percent, Correlation: attack.Correlation, } + case core.NetworkBandwidthAction: + tc.Bandwidth = &core.BandwidthSpec { + Rate: attack.Rate, + Limit: attack.Limit, + Buffer: attack.Buffer, + Peakrate: attack.Peakrate, + Minburst: attack.Minburst, + } + // do nothing? default: return errors.Errorf("network %s attack not supported", attack.Action) } From 1a3a9eb8b4aa76a3bc308dc0731c817865559781 Mon Sep 17 00:00:00 2001 From: xiang Date: Thu, 9 Sep 2021 18:09:53 +0800 Subject: [PATCH 3/7] minor update Signed-off-by: xiang --- cmd/attack/network.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cmd/attack/network.go b/cmd/attack/network.go index e1909455..a13f55ba 100644 --- a/cmd/attack/network.go +++ b/cmd/attack/network.go @@ -209,6 +209,18 @@ func NewNetworkBandwidthCommand(dep fx.Option, options *core.NetworkCommand) *co cmd.Flags().Uint32VarP(&options.Buffer, "buffer", "b", 0, "the maximum amount of bytes that tokens can be available for instantaneously") cmd.Flags().Uint64VarP(options.Peakrate, "peakrate", "p", 0, "the maximum depletion rate of the bucket") cmd.Flags().Uint32VarP(options.Minburst, "minburst", "m", 0, "specifies the size of the peakrate bucket") + cmd.Flags().StringVarP(&options.Device, "device", "d", "", "the network interface to impact") + cmd.Flags().StringVarP(&options.EgressPort, "egress-port", "e", "", + "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. "+ + "It can only be used in conjunction with -p tcp or -p udp") + cmd.Flags().StringVarP(&options.SourcePort, "source-port", "s", "", + "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. "+ + "It can only be used in conjunction with -p tcp or -p udp") + cmd.Flags().StringVarP(&options.IPAddress, "ip", "i", "", "only impact egress traffic to these IP addresses") + cmd.Flags().StringVarP(&options.Hostname, "hostname", "H", "", "only impact traffic to these hostnames") + cmd.Flags().StringVarP(&options.IPProtocol, "protocol", "p", "", + "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all") + return cmd } From e6f7c1e8c97e74c683f3014e82afccec94c6d72f Mon Sep 17 00:00:00 2001 From: xiang Date: Tue, 14 Sep 2021 07:43:42 +0000 Subject: [PATCH 4/7] minor fix Signed-off-by: xiang --- cmd/attack/network.go | 2 +- cmd/main.go | 4 ++++ pkg/core/network.go | 4 +++- pkg/server/chaosd/network.go | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/attack/network.go b/cmd/attack/network.go index a13f55ba..8edde6d2 100644 --- a/cmd/attack/network.go +++ b/cmd/attack/network.go @@ -207,7 +207,7 @@ func NewNetworkBandwidthCommand(dep fx.Option, options *core.NetworkCommand) *co cmd.Flags().StringVarP(&options.Rate, "rate", "r", "", "the speed knob, allows bps, kbps, mbps, gbps, tbps unit. bps means bytes per second") cmd.Flags().Uint32VarP(&options.Limit, "limit", "l", 0, "the number of bytes that can be queued waiting for tokens to become available") cmd.Flags().Uint32VarP(&options.Buffer, "buffer", "b", 0, "the maximum amount of bytes that tokens can be available for instantaneously") - cmd.Flags().Uint64VarP(options.Peakrate, "peakrate", "p", 0, "the maximum depletion rate of the bucket") + cmd.Flags().Uint64VarP(options.Peakrate, "peakrate", "", 0, "the maximum depletion rate of the bucket") cmd.Flags().Uint32VarP(options.Minburst, "minburst", "m", 0, "specifies the size of the peakrate bucket") cmd.Flags().StringVarP(&options.Device, "device", "d", "", "the network interface to impact") cmd.Flags().StringVarP(&options.EgressPort, "egress-port", "e", "", diff --git a/cmd/main.go b/cmd/main.go index f23fa33f..3b2f3d94 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,6 +22,8 @@ import ( _ "github.com/swaggo/swag" "go.uber.org/zap" + ctrl "sigs.k8s.io/controller-runtime" + ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/chaos-mesh/chaosd/cmd/attack" "github.com/chaos-mesh/chaosd/cmd/recover" "github.com/chaos-mesh/chaosd/cmd/search" @@ -66,6 +68,8 @@ func setLogLevel() { if strings.ToLower(logLevel) == "debug" { utils.PrintFxLog = true } + + ctrl.SetLogger(ctrlzap.New(ctrlzap.UseDevMode(true))) } func main() { diff --git a/pkg/core/network.go b/pkg/core/network.go index 704e0394..91ddd08f 100644 --- a/pkg/core/network.go +++ b/pkg/core/network.go @@ -78,6 +78,8 @@ func (n *NetworkCommand) Validate() error { return n.validNetworkDNS() case NetworkPortOccupiedAction: return n.validNetworkOccupied() + case NetworkBandwidthAction: + return nil default: return errors.Errorf("network action %s not supported", n.Action) } @@ -396,7 +398,7 @@ func (n *NetworkCommand) NeedApplyIptables() bool { func (n *NetworkCommand) NeedApplyTC() bool { switch n.Action { - case NetworkDelayAction, NetworkLossAction, NetworkCorruptAction, NetworkDuplicateAction: + case NetworkDelayAction, NetworkLossAction, NetworkCorruptAction, NetworkDuplicateAction, NetworkBandwidthAction: return true default: return false diff --git a/pkg/server/chaosd/network.go b/pkg/server/chaosd/network.go index d78a23cd..ad4a20df 100644 --- a/pkg/server/chaosd/network.go +++ b/pkg/server/chaosd/network.go @@ -66,7 +66,7 @@ func (networkAttack) Attack(options core.AttackConfig, env Environment) (err err case core.NetworkPortOccupiedAction: return env.Chaos.applyPortOccupied(attack) - case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction: + case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction, core.NetworkBandwidthAction: if attack.NeedApplyIPSet() { ipsetName, err = env.Chaos.applyIPSet(attack, env.AttackUid) if err != nil { @@ -334,7 +334,7 @@ func (networkAttack) Recover(exp core.Experiment, env Environment) error { return env.Chaos.recoverDNSServer(attack) case core.NetworkPortOccupiedAction: return env.Chaos.recoverPortOccupied(attack, env.AttackUid) - case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction: + case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction, core.NetworkBandwidthAction: if attack.NeedApplyIPSet() { if err := env.Chaos.recoverIPSet(env.AttackUid); err != nil { return errors.WithStack(err) From e30a860b825319466bdd2627bb78e2253d0a5cc2 Mon Sep 17 00:00:00 2001 From: xiang Date: Wed, 15 Sep 2021 10:42:40 +0800 Subject: [PATCH 5/7] remove useless code && format Signed-off-by: xiang --- cmd/attack/network.go | 9 --------- cmd/main.go | 4 ---- pkg/server/chaosd/network.go | 9 ++++----- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/cmd/attack/network.go b/cmd/attack/network.go index 8edde6d2..68c12f52 100644 --- a/cmd/attack/network.go +++ b/cmd/attack/network.go @@ -210,17 +210,8 @@ func NewNetworkBandwidthCommand(dep fx.Option, options *core.NetworkCommand) *co cmd.Flags().Uint64VarP(options.Peakrate, "peakrate", "", 0, "the maximum depletion rate of the bucket") cmd.Flags().Uint32VarP(options.Minburst, "minburst", "m", 0, "specifies the size of the peakrate bucket") cmd.Flags().StringVarP(&options.Device, "device", "d", "", "the network interface to impact") - cmd.Flags().StringVarP(&options.EgressPort, "egress-port", "e", "", - "only impact egress traffic to these destination ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. "+ - "It can only be used in conjunction with -p tcp or -p udp") - cmd.Flags().StringVarP(&options.SourcePort, "source-port", "s", "", - "only impact egress traffic from these source ports, use a ',' to separate or to indicate the range, such as 80, 8001:8010. "+ - "It can only be used in conjunction with -p tcp or -p udp") cmd.Flags().StringVarP(&options.IPAddress, "ip", "i", "", "only impact egress traffic to these IP addresses") cmd.Flags().StringVarP(&options.Hostname, "hostname", "H", "", "only impact traffic to these hostnames") - cmd.Flags().StringVarP(&options.IPProtocol, "protocol", "p", "", - "only impact traffic using this IP protocol, supported: tcp, udp, icmp, all") - return cmd } diff --git a/cmd/main.go b/cmd/main.go index 3b2f3d94..f23fa33f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -22,8 +22,6 @@ import ( _ "github.com/swaggo/swag" "go.uber.org/zap" - ctrl "sigs.k8s.io/controller-runtime" - ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/chaos-mesh/chaosd/cmd/attack" "github.com/chaos-mesh/chaosd/cmd/recover" "github.com/chaos-mesh/chaosd/cmd/search" @@ -68,8 +66,6 @@ func setLogLevel() { if strings.ToLower(logLevel) == "debug" { utils.PrintFxLog = true } - - ctrl.SetLogger(ctrlzap.New(ctrlzap.UseDevMode(true))) } func main() { diff --git a/pkg/server/chaosd/network.go b/pkg/server/chaosd/network.go index ad4a20df..6e8dd42d 100644 --- a/pkg/server/chaosd/network.go +++ b/pkg/server/chaosd/network.go @@ -196,14 +196,13 @@ func (s *Server) applyTC(attack *core.NetworkCommand, ipset string, uid string) Correlation: attack.Correlation, } case core.NetworkBandwidthAction: - tc.Bandwidth = &core.BandwidthSpec { - Rate: attack.Rate, - Limit: attack.Limit, - Buffer: attack.Buffer, + tc.Bandwidth = &core.BandwidthSpec{ + Rate: attack.Rate, + Limit: attack.Limit, + Buffer: attack.Buffer, Peakrate: attack.Peakrate, Minburst: attack.Minburst, } - // do nothing? default: return errors.Errorf("network %s attack not supported", attack.Action) } From 475e4fde81bab34f0cb006b0e389ed290ea0f666 Mon Sep 17 00:00:00 2001 From: xiang Date: Wed, 15 Sep 2021 14:28:52 +0800 Subject: [PATCH 6/7] fix panic when set uid Signed-off-by: xiang --- pkg/server/chaosd/network.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/server/chaosd/network.go b/pkg/server/chaosd/network.go index 6e8dd42d..b270ccdc 100644 --- a/pkg/server/chaosd/network.go +++ b/pkg/server/chaosd/network.go @@ -91,7 +91,7 @@ func (networkAttack) Attack(options core.AttackConfig, env Environment) (err err } func (s *Server) applyIPSet(attack *core.NetworkCommand, uid string) (string, error) { - ipset, err := attack.ToIPSet(fmt.Sprintf("chaos-%s", uid[:16])) + ipset, err := attack.ToIPSet(fmt.Sprintf("chaos-%.16s", uid)) if err != nil { return "", errors.WithStack(err) } From af847ae8773c92ff7c007437fad68d7c421f111c Mon Sep 17 00:00:00 2001 From: xiang Date: Mon, 8 Nov 2021 15:47:08 +0800 Subject: [PATCH 7/7] validate value Signed-off-by: xiang --- pkg/core/network.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/core/network.go b/pkg/core/network.go index 91ddd08f..001d03f2 100644 --- a/pkg/core/network.go +++ b/pkg/core/network.go @@ -79,7 +79,7 @@ func (n *NetworkCommand) Validate() error { case NetworkPortOccupiedAction: return n.validNetworkOccupied() case NetworkBandwidthAction: - return nil + return n.validNetworkBandwidth() default: return errors.Errorf("network action %s not supported", n.Action) } @@ -115,6 +115,14 @@ func (n *NetworkCommand) validNetworkDelay() error { return checkProtocolAndPorts(n.IPProtocol, n.SourcePort, n.EgressPort) } +func (n *NetworkCommand) validNetworkBandwidth() error { + if len(n.Rate) == 0 || n.Limit == 0 || n.Buffer == 0 { + return errors.Errorf("rate, limit and buffer both are required when action is bandwidth") + } + + return nil +} + func (n *NetworkCommand) validNetworkCommon() error { if len(n.Percent) == 0 { return errors.New("percent is required")