diff --git a/net-shaper/src/main.rs b/net-shaper/src/main.rs index 66f1990765..46e04c972a 100644 --- a/net-shaper/src/main.rs +++ b/net-shaper/src/main.rs @@ -34,7 +34,7 @@ impl NetworkTopology { } for x in self.interconnects.iter() { - if x.a as usize >= self.partitions.len() || x.b as usize >= self.partitions.len() { + if x.a as usize > self.partitions.len() || x.b as usize > self.partitions.len() { return false; } } @@ -43,12 +43,22 @@ impl NetworkTopology { } } -fn run(cmd: &str, args: &[&str], launch_err_msg: &str, status_err_msg: &str) -> bool { +fn run( + cmd: &str, + args: &[&str], + launch_err_msg: &str, + status_err_msg: &str, + ignore_err: bool, +) -> bool { let output = std::process::Command::new(cmd) .args(args) .output() .expect(launch_err_msg); + if ignore_err { + return true; + } + if !output.status.success() { eprintln!( "{} command failed with exit code: {}", @@ -83,6 +93,7 @@ fn insert_iptables_rule(my_partition: usize) -> bool { ], "Failed to add iptables rule", "iptables", + false, ) } @@ -92,6 +103,7 @@ fn flush_iptables_rule() { &["-F", "-t", "mangle"], "Failed to flush iptables", "iptables flush", + true, ); } @@ -104,6 +116,7 @@ fn insert_tc_root(interface: &str) -> bool { ], "Failed to add root qdisc", "tc add root qdisc", + false, ) } @@ -116,30 +129,33 @@ fn delete_tc_root(interface: &str) { ], "Failed to delete root qdisc", "tc qdisc delete root", + true, ); } -fn insert_tc_netem(interface: &str, class: &str, tos: &str, filter: &str) -> bool { +fn insert_tc_netem(interface: &str, class: &str, handle: &str, filter: &str) -> bool { + let mut filters: Vec<&str> = filter.split(' ').collect(); + let mut args = vec![ + "qdisc", "add", "dev", interface, "parent", class, "handle", handle, "netem", + ]; + args.append(&mut filters); // tc qdisc add dev parent 1: handle : netem - run( - "tc", - &[ - "qdisc", "add", "dev", interface, "parent", class, "handle", tos, "netem", filter, - ], - "Failed to add tc child", - "tc add child", - ) + run("tc", &args, "Failed to add tc child", "tc add child", false) } -fn delete_tc_netem(interface: &str, class: &str, tos: &str, filter: &str) { +fn delete_tc_netem(interface: &str, class: &str, handle: &str, filter: &str) { + let mut filters: Vec<&str> = filter.split(' ').collect(); + let mut args = vec![ + "qdisc", "delete", "dev", interface, "parent", class, "handle", handle, "netem", + ]; + args.append(&mut filters); // tc qdisc delete dev parent 1: handle : netem run( "tc", - &[ - "qdisc", "delete", "dev", interface, "parent", class, "handle", tos, "netem", filter, - ], + &args, "Failed to delete child qdisc", "tc delete child qdisc", + true, ); } @@ -153,6 +169,7 @@ fn insert_tos_filter(interface: &str, class: &str, tos: &str) -> bool { ], "Failed to add tos filter", "tc add filter", + false, ) } @@ -166,6 +183,7 @@ fn delete_tos_filter(interface: &str, class: &str, tos: &str) { ], "Failed to delete tos filter", "tc delete filter", + true, ); } @@ -180,7 +198,7 @@ fn identify_my_partition(partitions: &[u8], index: u64, size: u64) -> usize { } } - my_partition + my_partition + 1 } fn shape_network(matches: &ArgMatches) { @@ -216,12 +234,13 @@ fn shape_network(matches: &ArgMatches) { topology.interconnects.iter().for_each(|i| { if i.b as usize == my_partition { + let handle = (i.a + 1).to_string(); let tos_string = i.a.to_string(); let class = format!("1:{}", i.a); if !insert_tc_netem( interface.as_str(), class.as_str(), - tos_string.as_str(), + handle.as_str(), i.config.as_str(), ) { flush_iptables_rule(); @@ -229,12 +248,12 @@ fn shape_network(matches: &ArgMatches) { return; } - if !insert_tos_filter(interface.as_str(), tos_string.as_str(), class.as_str()) { + if !insert_tos_filter(interface.as_str(), class.as_str(), tos_string.as_str()) { flush_iptables_rule(); delete_tc_netem( interface.as_str(), class.as_str(), - tos_string.as_str(), + handle.as_str(), i.config.as_str(), ); delete_tc_root(interface.as_str()); @@ -265,13 +284,14 @@ fn cleanup_network(matches: &ArgMatches) { topology.interconnects.iter().for_each(|i| { if i.b as usize == my_partition { + let handle = (i.a + 1).to_string(); let tos_string = i.a.to_string(); let class = format!("1:{}", i.a); delete_tos_filter(interface.as_str(), class.as_str(), tos_string.as_str()); delete_tc_netem( interface.as_str(), class.as_str(), - tos_string.as_str(), + handle.as_str(), i.config.as_str(), ); } diff --git a/scripts/cargo-install-all.sh b/scripts/cargo-install-all.sh index 0a3ad89a08..ff1d523801 100755 --- a/scripts/cargo-install-all.sh +++ b/scripts/cargo-install-all.sh @@ -80,6 +80,7 @@ BINS=( solana-keygen solana-ledger-tool solana-log-analyzer + solana-net-shaper solana-archiver solana-validator ) diff --git a/scripts/net-shaper.sh b/scripts/net-shaper.sh new file mode 100755 index 0000000000..28b277a0a1 --- /dev/null +++ b/scripts/net-shaper.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Start/Stop network shaper +# +set -e + +[[ $(uname) == Linux ]] || exit 0 + +cd "$(dirname "$0")" + +sudo= +if sudo true; then + sudo="sudo -n" +fi + +set -x + +iface="$(ifconfig | grep mtu | grep -iv loopback | grep -i running | awk 'BEGIN { FS = ":" } ; {print $1}')" + +if [[ "$1" = cleanup ]]; then + $sudo ~solana/.cargo/bin/solana-net-shaper cleanup -f "$2" -s "$3" -p "$4" -i "$iface" +else + $sudo ~solana/.cargo/bin/solana-net-shaper shape -f "$2" -s "$3" -p "$4" -i "$iface" +fi