From cb082866ac6b4d691230d8f509ed2472ebbb4b67 Mon Sep 17 00:00:00 2001 From: Calvin Audier Date: Fri, 24 May 2024 10:08:23 +0200 Subject: [PATCH 1/3] Adding GetNetNs function to retrieve the netns ID. Replacing the nsenter command by ip netns exec Updating helper pod definition to mount the hostPath /var/run/netns Updating Dockerfile to add ip binary to experiments/helper pod. Signed-off-by: Calvin Audier --- build/Dockerfile | 1 + chaoslib/litmus/network-chaos/helper/netem.go | 51 ++++++++++++++----- .../litmus/network-chaos/lib/network-chaos.go | 12 +++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index e4ed59276..26401037f 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -35,6 +35,7 @@ COPY --from=dep /usr/bin/sudo /usr/bin/sudo COPY --from=dep /usr/lib/sudo /usr/lib/sudo COPY --from=dep /sbin/tc /sbin/ COPY --from=dep /sbin/iptables /sbin/ +COPY --from=dep /sbin/ip /sbin/ # Copying Necessary Files COPY ./pkg/cloud/aws/common/ssm-docs/LitmusChaos-AWS-SSM-Docs.yml . diff --git a/chaoslib/litmus/network-chaos/helper/netem.go b/chaoslib/litmus/network-chaos/helper/netem.go index 88b02ec6f..53826a719 100644 --- a/chaoslib/litmus/network-chaos/helper/netem.go +++ b/chaoslib/litmus/network-chaos/helper/netem.go @@ -1,6 +1,7 @@ package helper import ( + "bytes" "fmt" "github.com/litmuschaos/litmus-go/pkg/cerrors" "github.com/litmuschaos/litmus-go/pkg/events" @@ -76,6 +77,26 @@ func Helper(clients clients.ClientSets) { } +// Retrieve ID of the network namespace of the target container +func GetNetNS(pid int, source string) (string, error) { + + cmd := exec.Command("sudo", "ip", "netns", "identify", fmt.Sprintf("%d", pid)) + + var out, stdErr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stdErr + if err := cmd.Run(); err != nil { + return "", err + } + + netns := out.String() + // Removing trailing newline character + netnstrim := netns[:len(netns)-1] + log.Infof("[Info]: Process PID=%d has netns ID=%s", pid, netnstrim) + + return netnstrim, nil +} + // preparePodNetworkChaos contains the prepration steps before chaos injection func preparePodNetworkChaos(experimentsDetails *experimentTypes.ExperimentDetails, clients clients.ClientSets, eventsDetails *types.EventDetails, chaosDetails *types.ChaosDetails, resultDetails *types.ResultDetails) error { @@ -110,6 +131,11 @@ func preparePodNetworkChaos(experimentsDetails *experimentTypes.ExperimentDetail return stacktrace.Propagate(err, "could not get container pid") } + td.NetNS, err = GetNetNS(td.Pid, td.Source) + if err != nil { + return stacktrace.Propagate(err, "could not get netns id") + } + targets = append(targets, td) } @@ -171,14 +197,14 @@ func preparePodNetworkChaos(experimentsDetails *experimentTypes.ExperimentDetail } // injectChaos inject the network chaos in target container -// it is using nsenter command to enter into network namespace of target container +// it is using ip netns command to enter into network namespace of target container // and execute the netem command inside it. func injectChaos(netInterface string, target targetDetails) error { netemCommands := os.Getenv("NETEM_COMMAND") if len(target.DestinationIps) == 0 && len(sPorts) == 0 && len(dPorts) == 0 && len(whitelistDPorts) == 0 && len(whitelistSPorts) == 0 { - tc := fmt.Sprintf("sudo nsenter -t %d -n tc qdisc replace dev %s root netem %v", target.Pid, netInterface, netemCommands) + tc := fmt.Sprintf("sudo ip netns exec %s tc qdisc replace dev %s root netem %v", target.NetNS, netInterface, netemCommands) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create tc rules", target.Source); err != nil { return err @@ -187,7 +213,7 @@ func injectChaos(netInterface string, target targetDetails) error { // Create a priority-based queue // This instantly creates classes 1:1, 1:2, 1:3 - priority := fmt.Sprintf("sudo nsenter -t %v -n tc qdisc replace dev %v root handle 1: prio", target.Pid, netInterface) + priority := fmt.Sprintf("sudo ip netns exec %s tc qdisc replace dev %v root handle 1: prio", target.NetNS, netInterface) log.Info(priority) if err := common.RunBashCommand(priority, "failed to create priority-based queue", target.Source); err != nil { return err @@ -195,7 +221,7 @@ func injectChaos(netInterface string, target targetDetails) error { // Add queueing discipline for 1:3 class. // No traffic is going through 1:3 yet - traffic := fmt.Sprintf("sudo nsenter -t %v -n tc qdisc replace dev %v parent 1:3 netem %v", target.Pid, netInterface, netemCommands) + traffic := fmt.Sprintf("sudo ip netns exec %s tc qdisc replace dev %v parent 1:3 netem %v", target.NetNS, netInterface, netemCommands) log.Info(traffic) if err := common.RunBashCommand(traffic, "failed to create netem queueing discipline", target.Source); err != nil { return err @@ -204,7 +230,7 @@ func injectChaos(netInterface string, target targetDetails) error { if len(whitelistDPorts) != 0 || len(whitelistSPorts) != 0 { for _, port := range whitelistDPorts { //redirect traffic to specific dport through band 2 - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 2 u32 match ip dport %v 0xffff flowid 1:2", target.Pid, netInterface, port) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 2 u32 match ip dport %v 0xffff flowid 1:2", target.NetNS, netInterface, port) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create whitelist dport match filters", target.Source); err != nil { return err @@ -213,14 +239,14 @@ func injectChaos(netInterface string, target targetDetails) error { for _, port := range whitelistSPorts { //redirect traffic to specific sport through band 2 - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 2 u32 match ip sport %v 0xffff flowid 1:2", target.Pid, netInterface, port) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 2 u32 match ip sport %v 0xffff flowid 1:2", target.NetNS, netInterface, port) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create whitelist sport match filters", target.Source); err != nil { return err } } - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dst 0.0.0.0/0 flowid 1:3", target.Pid, netInterface) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dst 0.0.0.0/0 flowid 1:3", target.NetNS, netInterface) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create rule for all ports match filters", target.Source); err != nil { return err @@ -229,9 +255,9 @@ func injectChaos(netInterface string, target targetDetails) error { for _, ip := range target.DestinationIps { // redirect traffic to specific IP through band 3 - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dst %v flowid 1:3", target.Pid, netInterface, ip) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dst %v flowid 1:3", target.NetNS, netInterface, ip) if strings.Contains(ip, ":") { - tc = fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip6 dst %v flowid 1:3", target.Pid, netInterface, ip) + tc = fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip6 dst %v flowid 1:3", target.NetNS, netInterface, ip) } log.Info(tc) if err := common.RunBashCommand(tc, "failed to create destination ips match filters", target.Source); err != nil { @@ -241,7 +267,7 @@ func injectChaos(netInterface string, target targetDetails) error { for _, port := range sPorts { //redirect traffic to specific sport through band 3 - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip sport %v 0xffff flowid 1:3", target.Pid, netInterface, port) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip sport %v 0xffff flowid 1:3", target.NetNS, netInterface, port) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create source ports match filters", target.Source); err != nil { return err @@ -250,7 +276,7 @@ func injectChaos(netInterface string, target targetDetails) error { for _, port := range dPorts { //redirect traffic to specific dport through band 3 - tc := fmt.Sprintf("sudo nsenter -t %v -n tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dport %v 0xffff flowid 1:3", target.Pid, netInterface, port) + tc := fmt.Sprintf("sudo ip netns exec %s tc filter add dev %v protocol ip parent 1:0 prio 3 u32 match ip dport %v 0xffff flowid 1:3", target.NetNS, netInterface, port) log.Info(tc) if err := common.RunBashCommand(tc, "failed to create destination ports match filters", target.Source); err != nil { return err @@ -266,7 +292,7 @@ func injectChaos(netInterface string, target targetDetails) error { // killnetem kill the netem process for all the target containers func killnetem(target targetDetails, networkInterface string) (bool, error) { - tc := fmt.Sprintf("sudo nsenter -t %d -n tc qdisc delete dev %s root", target.Pid, networkInterface) + tc := fmt.Sprintf("sudo ip netns exec %s tc qdisc delete dev %s root", target.NetNS, networkInterface) cmd := exec.Command("/bin/bash", "-c", tc) out, err := cmd.CombinedOutput() @@ -292,6 +318,7 @@ type targetDetails struct { TargetContainer string ContainerId string Pid int + NetNS string Source string } diff --git a/chaoslib/litmus/network-chaos/lib/network-chaos.go b/chaoslib/litmus/network-chaos/lib/network-chaos.go index 2b302fc22..feb119ffb 100644 --- a/chaoslib/litmus/network-chaos/lib/network-chaos.go +++ b/chaoslib/litmus/network-chaos/lib/network-chaos.go @@ -224,6 +224,14 @@ func createHelperPod(experimentsDetails *experimentTypes.ExperimentDetails, clie }, }, }, + { + Name: "netns", + VolumeSource: apiv1.VolumeSource{ + HostPath: &apiv1.HostPathVolumeSource{ + Path: "/var/run/netns", + }, + }, + }, }, Containers: []apiv1.Container{ @@ -245,6 +253,10 @@ func createHelperPod(experimentsDetails *experimentTypes.ExperimentDetails, clie Name: "cri-socket", MountPath: experimentsDetails.SocketPath, }, + { + Name: "netns", + MountPath: "/var/run/netns", + }, }, SecurityContext: &apiv1.SecurityContext{ Privileged: &privilegedEnable, From e570b79492d740c456549b6c82527491e6527b04 Mon Sep 17 00:00:00 2001 From: Calvin Audier Date: Fri, 24 May 2024 15:05:49 +0200 Subject: [PATCH 2/3] Running gofmt to update netem.go Signed-off-by: Calvin Audier --- chaoslib/litmus/network-chaos/helper/netem.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaoslib/litmus/network-chaos/helper/netem.go b/chaoslib/litmus/network-chaos/helper/netem.go index 53826a719..855523b6e 100644 --- a/chaoslib/litmus/network-chaos/helper/netem.go +++ b/chaoslib/litmus/network-chaos/helper/netem.go @@ -88,7 +88,7 @@ func GetNetNS(pid int, source string) (string, error) { if err := cmd.Run(); err != nil { return "", err } - + netns := out.String() // Removing trailing newline character netnstrim := netns[:len(netns)-1] From 2bfd118a7cc97121039f3dc53d33f1512e891bba Mon Sep 17 00:00:00 2001 From: Calvin Audier Date: Mon, 27 May 2024 10:00:41 +0200 Subject: [PATCH 3/3] Remove unused source variable in GetNS function. Signed-off-by: Calvin Audier --- chaoslib/litmus/network-chaos/helper/netem.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chaoslib/litmus/network-chaos/helper/netem.go b/chaoslib/litmus/network-chaos/helper/netem.go index 855523b6e..b89488303 100644 --- a/chaoslib/litmus/network-chaos/helper/netem.go +++ b/chaoslib/litmus/network-chaos/helper/netem.go @@ -78,7 +78,7 @@ func Helper(clients clients.ClientSets) { } // Retrieve ID of the network namespace of the target container -func GetNetNS(pid int, source string) (string, error) { +func GetNetNS(pid int) (string, error) { cmd := exec.Command("sudo", "ip", "netns", "identify", fmt.Sprintf("%d", pid)) @@ -131,7 +131,7 @@ func preparePodNetworkChaos(experimentsDetails *experimentTypes.ExperimentDetail return stacktrace.Propagate(err, "could not get container pid") } - td.NetNS, err = GetNetNS(td.Pid, td.Source) + td.NetNS, err = GetNetNS(td.Pid) if err != nil { return stacktrace.Propagate(err, "could not get netns id") }