usestd::net::Ipv4Addr;useaya::{include_bytes_aligned,maps::HashMap,programs::{tc,SchedClassifier,TcAttachType},Bpf,};useaya_log::BpfLogger;useclap::Parser;uselog::{info,warn};usetokio::signal;#[derive(Debug, Parser)]structOpt{#[clap(short, long, default_value = "eth0")]iface: String,}#[tokio::main]asyncfnmain()-> Result<(),anyhow::Error>{letopt=Opt::parse();env_logger::init();// This will include your eBPF object file as raw bytes at compile-time and load it at// runtime. This approach is recommended for most real-world use cases. If you would// like to specify the eBPF program at runtime rather than at compile-time, you can// reach for `Bpf::load_file` instead.#[cfg(debug_assertions)]letmutbpf=Bpf::load(include_bytes_aligned!("../../target/bpfel-unknown-none/debug/tc-egress"))?;#[cfg(not(debug_assertions))]letmutbpf=Bpf::load(include_bytes_aligned!("../../target/bpfel-unknown-none/release/tc-egress"))?;ifletErr(e)=BpfLogger::init(&mutbpf){// This can happen if you remove all log statements from your eBPF program.warn!("failed to initialize eBPF logger: {}",e);}// error adding clsact to the interface if it is already added is harmless// the full cleanup can be done with 'sudo tc qdisc del dev eth0 clsact'.let_=tc::qdisc_add_clsact(&opt.iface);letprogram: &mutSchedClassifier=bpf.program_mut("tc_egress").unwrap().try_into()?;program.load()?;program.attach(&opt.iface,TcAttachType::Egress)?;// (1)letmutblocklist: HashMap<_,u32,u32>=HashMap::try_from(bpf.map_mut("BLOCKLIST").unwrap())?;// (2)letblock_addr: u32=Ipv4Addr::new(1,1,1,1).try_into()?;// (3)blocklist.insert(block_addr,0,0)?;info!("Waiting for Ctrl-C...");signal::ctrl_c().await?;info!("Exiting...");Ok(())}