Skip to content
Snippets Groups Projects
lib.rs 6.13 KiB
Newer Older
  • Learn to ignore specific revisions
  • use serde::{Deserialize, Serialize};
    use std::process::Command;
    
    const NETWORK_NAMESPACES: u32 = 1;
    
    const SRV_NS: &str = "srv_ns";
    const CLI_NS: &str = "cli_ns";
    const SRV_VE: &str = "srv_ve";
    const CLI_VE: &str = "cli_ve";
    
    #[derive(Clone, Debug, Serialize, Deserialize)]
    pub struct Message {
        pub id: u128,
        pub timestamp: u128,
        pub netem_parameters: Option<NetemParameters>,
    }
    
    #[derive(Clone, Debug, Serialize, Deserialize)]
    pub struct NetemParameters {
        pub srv_rate: u32,
        pub srv_delay: u32,
        pub srv_jitter: u32,
        pub srv_pkt_loss: u32,
        pub srv_duplicate: u32,
        pub srv_corrupt: u32,
        pub srv_reorder: u32,
        pub cli_rate: u32,
        pub cli_delay: u32,
        pub cli_jitter: u32,
        pub cli_pkt_loss: u32,
        pub cli_duplicate: u32,
        pub cli_corrupt: u32,
        pub cli_reorder: u32,
    }
    
    // impl NetemParameters {
    //     pub fn from_json(json_str: &str) -> Result<NetemParameters, serde_json::Error> {
    //         serde_json::from_str(json_str)
    //     }
    
    //     pub fn to_json(&self) -> Result<String, serde_json::Error> {
    //         serde_json::to_string(self)
    //     }
    // }
    
    impl NetemParameters {
        pub fn new() -> NetemParameters {
            NetemParameters {
                srv_rate: 1000,
                srv_delay: 0,
                srv_jitter: 0,
                srv_pkt_loss: 0,
                srv_duplicate: 0,
                srv_corrupt: 0,
                srv_reorder: 0,
                cli_rate: 1000,
                cli_delay: 0,
                cli_jitter: 0,
                cli_pkt_loss: 0,
                cli_duplicate: 0,
                cli_corrupt: 0,
                cli_reorder: 0,
            }
        }
    
        pub fn with_rate(mut self, rate: u32) -> NetemParameters {
            self.srv_rate = rate;
            self.cli_rate = rate;
            self
        }
    
        pub fn with_delay(mut self, delay: u32) -> NetemParameters {
            self.srv_delay = delay;
            self.cli_delay = delay;
            self
        }
    
        pub fn with_jitter(mut self, jitter: u32) -> NetemParameters {
            self.srv_jitter = jitter;
            self.cli_jitter = jitter;
            self
        }
    
        pub fn with_pkt_loss(mut self, pkt_loss: u32) -> NetemParameters {
            self.srv_pkt_loss = pkt_loss;
            self.cli_pkt_loss = pkt_loss;
            self
        }
    
        pub fn with_duplicate(mut self, duplicate: u32) -> NetemParameters {
            self.srv_duplicate = duplicate;
            self.cli_duplicate = duplicate;
            self
        }
    
        pub fn with_corrupt(mut self, corrupt: u32) -> NetemParameters {
            self.srv_corrupt = corrupt;
            self.cli_corrupt = corrupt;
            self
        }
    
        pub fn with_reorder(mut self, reorder: u32) -> NetemParameters {
            self.srv_reorder = reorder;
            self.cli_reorder = reorder;
            self
        }
    }
    
    pub fn set_network_parameters(parameters: NetemParameters) {
        for i in 1..(NETWORK_NAMESPACES + 1) {
            change_qdisc(
                format!("{SRV_NS}_{i}"),
                format!("{SRV_VE}"),
                parameters.srv_rate,
                parameters.srv_delay,
                parameters.srv_jitter,
                parameters.srv_pkt_loss,
                parameters.srv_duplicate,
                parameters.srv_corrupt,
                parameters.srv_reorder,
            );
            change_qdisc(
                format!("{CLI_NS}_{i}"),
                format!("{CLI_VE}"),
                parameters.cli_rate,
                parameters.cli_delay,
                parameters.cli_jitter,
                parameters.cli_pkt_loss,
                parameters.cli_duplicate,
                parameters.cli_corrupt,
                parameters.cli_reorder,
            );
        }
    }
    
    fn change_qdisc(
        ns: String,
        dev: String,
        rate: u32,
        delay: u32,
        jitter: u32,
        pkt_loss: u32,
        duplicate: u32,
        corrupt: u32,
        reorder: u32,
    ) {
        let rate = format!("{rate}mbit");
        let delay = format!("{delay}ms");
        let jitter = format!("{jitter}ms");
        let pkt_loss = format!("{pkt_loss}%");
        let duplicate = format!("{duplicate}%");
        let corrupt = format!("{corrupt}%");
        let reorder = format!("{reorder}%");
    
        let args = [
            "netns",
            "exec",
            &ns,
            "tc",
            "qdisc",
            "change",
            "dev",
            &dev,
            "root",
            "netem",
            "limit",
            "1000",
            "rate",
            &rate,
            "delay",
            &delay,
            &jitter,
            "loss",
            &pkt_loss,
            "duplicate",
            &duplicate,
            "corrupt",
            &corrupt,
            "reorder",
            &reorder,
        ];
        println!("> ip {args:?}");
    
        let output = Command::new("ip")
            .args(&args)
            .output()
            .expect("failed to execute command");
        println!("{output:?}");
    }
    
    pub fn create_qdiscs() {
        for i in 1..(NETWORK_NAMESPACES + 1) {
            create_qdisc(format!("{SRV_NS}_{i}"), format!("{SRV_VE}"));
            create_qdisc(format!("{CLI_NS}_{i}"), format!("{CLI_VE}"));
        }
        set_network_parameters(NetemParameters::new());
    }
    fn create_qdisc(ns: String, dev: String) {
        let args = [
            "netns", "exec", &ns, "tc", "qdisc", "add", "dev", &dev, "root", "netem",
        ];
        println!("> ip {args:?}");
    
        let output = Command::new("ip")
            .args(&args)
            .output()
            .expect("failed to execute command");
        println!("{output:?}");
    }
    
    pub fn remove_qdiscs() {
        for i in 1..(NETWORK_NAMESPACES + 1) {
            remove_qdisc(format!("{SRV_NS}_{i}"), format!("{SRV_VE}"));
            remove_qdisc(format!("{CLI_NS}_{i}"), format!("{CLI_VE}"));
        }
    }
    fn remove_qdisc(ns: String, dev: String) {
        let args = [
            "netns", "exec", &ns, "tc", "qdisc", "del", "dev", &dev, "root",
        ];
        println!("> ip {args:?}");
    
        let output = Command::new("ip")
            .args(&args)
            .output()
            .expect("failed to execute command");
        println!("{output:?}");
    }
    
    pub fn show_qdiscs() {
        for i in 1..(NETWORK_NAMESPACES + 1) {
            show_qdisc(format!("{SRV_NS}_{i}"), format!("{SRV_VE}"));
            show_qdisc(format!("{CLI_NS}_{i}"), format!("{CLI_VE}"));
        }
    }
    fn show_qdisc(ns: String, dev: String) {
        let args = ["netns", "exec", &ns, "tc", "qdisc", "show", "dev", &dev];
        println!("> ip {args:?}");
    
        let output = Command::new("ip")
            .args(&args)
            .output()
            .expect("failed to execute command");
        println!("{output:?}");
    }