<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: stevelatif</title>
    <description>The latest articles on DEV Community by stevelatif (@stevelatif).</description>
    <link>https://dev.to/stevelatif</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1346226%2Fac7361c7-65ac-4c20-bd7e-b89844186ba5.jpeg</url>
      <title>DEV Community: stevelatif</title>
      <link>https://dev.to/stevelatif</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stevelatif"/>
    <language>en</language>
    <item>
      <title>Simple Firewall with Rust and Aya</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Wed, 19 Jun 2024 06:03:54 +0000</pubDate>
      <link>https://dev.to/stevelatif/simple-firewall-with-rust-and-aa-4cam</link>
      <guid>https://dev.to/stevelatif/simple-firewall-with-rust-and-aa-4cam</guid>
      <description>&lt;h1&gt;Simple Firewall with Rust and Aya&lt;/h1&gt;

&lt;h1&gt;Other Parts in this Series&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/aya-rust-tutorial-part-5-using-maps-4d26c4a2fff8"&gt;Part 1 Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/aya-rust-tutorial-part-two-setting-up-33b1e489cb93"&gt;Part 2 Setting Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/aya-rust-tutorial-part-three-xdp-pass-c9b8e6e4baac"&gt;Part 3 XDP Pass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/aya-rust-tutorial-part-four-xdp-hello-world-c41abf76c353"&gt;Part 4 XDP Hello World&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/aya-rust-tutorial-part-5-using-maps-4d26c4a2fff8"&gt;Part 5 XDP Using Maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@stevelatif/simple-firewall-with-rust-and-aya-b56373c8bcc6"&gt;Part 6 Simple Firewall&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;Part 6 Creating a Simple Firewall&lt;/h1&gt;

&lt;p&gt;Welcome to Part 6. In this chapter we will extend the work we did in part 5
where we looked at a simple PerCpuArray map to count packets.&lt;/p&gt;

&lt;p&gt;Using eBPF we can create a simple firewall/router. With a small amount of code we can 
drop or redirect packets based on the source and destination addresses. 
We will implement this in several stages using a hashmap to store the 
configuration. 
The initial version will load the IP addresses from user space and to the eBPF kernel code,
and with each iteration we can add more functionality.&lt;/p&gt;

&lt;p&gt;As before, generate the code 
using `&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cargo generate https://github.com/aya-rs/aya-template
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I called the project &lt;code&gt;firewall-001&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;Modify the generated source code&lt;/h1&gt;

&lt;p&gt;Modify ebpf firewall-001-ebpf/Cargo.toml to include a dependency 
for the network-types crate:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[dependencies]
aya-ebpf = "0.1.0"
aya-log-ebpf = "0.1.0"
firewall-001-common = { path = "../firewall-001-common" }
network-types = "0.0.5"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then modify the ebpf code in &lt;code&gt;firewall-001-ebpf/src/main.rs&lt;/code&gt;
so we can add HashMap map &lt;/p&gt;

&lt;p&gt;In the eBPF code &lt;code&gt;firewall-001-ebpf/src/main.rs&lt;/code&gt;
the header section should look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    use aya&lt;em&gt;ebpf::{bindings::xdp&lt;/em&gt;action,
               macros::{xdp, 
               map }, // &amp;lt;---- added map macro
               programs::XdpContext,
               maps::HashMap // &amp;lt;--- added hashmaps
               };
    use aya&lt;em&gt;log&lt;/em&gt;ebpf::info;
    use core::mem;    // &amp;lt;--- added memory crate
    
    use network_types::{ // Added
        eth::{EthHdr, EtherType}, 
        ip::{IpProto, Ipv4Hdr},
        tcp::TcpHdr,
        udp::UdpHdr,
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add the map definition, as in Part 5 we define the map in the ebpf code in 
&lt;code&gt;firewall-001/firewall-001-ebpf/src/main.rs&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    #[map(name = "SRC&lt;em&gt;IP&lt;/em&gt;FILTER")]
    static mut SRC&lt;em&gt;IP&lt;/em&gt;FILTER: HashMap&amp;lt;u32, u8&amp;gt; =
        HashMap::&amp;lt;u32, u8&amp;gt;::with&lt;em&gt;max&lt;/em&gt;entries(1024, 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As we are working with the eBPF subsystem in the kernel we 
will need to work directly with raw pointers. This is where
will use the &lt;code&gt;core::mem crate&lt;/code&gt;. We need to check the size 
of data or the verifier will complain&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    fn ptr_at&amp;lt;T&amp;gt;(ctx: &amp;amp;XdpContext, offset: usize) -&amp;gt; Result&amp;lt;*const T, ()&amp;gt; {
        let start = ctx.data();
        let end = ctx.data_end();
        let len = mem::size_of::&amp;lt;T&amp;gt;();
        if start + offset + len &amp;gt; end {
            return Err(());
        }
        Ok((start + offset) as *const T)
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The packet parsing will be done in the try&lt;em&gt;firewall&lt;/em&gt;001 function. We will peel off 
the layers of each packet till we match the rules passed in by the map IP&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    let ethhdr: *const EthHdr = ptr_at(&amp;amp;ctx, 0)?; // 
    match unsafe { (*ethhdr).ether_type } {
        EtherType::Ipv4 =&amp;gt; {
            info!(&amp;amp;ctx, "received IPv4 packet");
        }
        EtherType::Ipv6 =&amp;gt; {
            info!(&amp;amp;ctx, "received IPv6 packet");
            return Ok(xdp&lt;em&gt;action::XDP&lt;/em&gt;DROP);
        }
    
        &lt;em&gt; =&amp;gt; return Ok(xdp_action::XDP&lt;/em&gt;PASS),
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We pass all IPv4 packets but drop any IPv6 packets, in the next section 
we start to unpack the IPv4 header, first we get the port &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    let source_port = match unsafe { (*ipv4hdr).proto } {
        IpProto::Tcp =&amp;gt; {
            let tcphdr: *const TcpHdr =
                ptr_at(&amp;amp;ctx, EthHdr::LEN + Ipv4Hdr::LEN)?;
            u16::from_be(unsafe { (*tcphdr).source })
        }
        IpProto::Udp =&amp;gt; {
            let udphdr: *const UdpHdr =
                ptr_at(&amp;amp;ctx, EthHdr::LEN + Ipv4Hdr::LEN)?;
            u16::from_be(unsafe { (*udphdr).source })
        }
        _ =&amp;gt; return Err(()),
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then we check if the ip address is one in our list of blocked ip addresses&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    if unsafe { SRC&lt;em&gt;IP_FILTER.get(&amp;amp;source_addr).is&lt;/em&gt;some() } {
        info!(&amp;amp;ctx, "dropping packet ...");
        return Ok(xdp&lt;em&gt;action::XDP&lt;/em&gt;DROP);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The user space code reads a YAML config file that contains a list of IP addresses and
an instruction as to what to do to the packets coming from that address. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ---
    "127.0.0.1" : "block"
    "10.0.0.1"  : "block"
    "10.0.0.2"  : "block"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We will use the figment crate to parse the YAML config file into a 
hashmap that can be loaded into the eBPF map. &lt;/p&gt;

&lt;p&gt;Modify the Cargo.toml file in firewall-001/Cargo.toml to include
the dependency:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    figment = { version = "0.10.18", features = ["yaml", "env"] }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then add the following to the user space rust code in firewall-001/src/main.rs&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    use std::net::Ipv4Addr;
    use figment::{Figment, providers::{Yaml, Format}};
    ...
    #[tokio::main]
    async fn main() -&amp;gt; Result&amp;lt;(), anyhow::Error&amp;gt; {
        let opt = Opt::parse();
        let config: HashMap&amp;lt;String,String&amp;gt; = Figment::new()
            .merge(Yaml::file("config.yaml"))
            .extract()?;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we extract the config file into a &lt;code&gt;HashMap&amp;lt;String,String&amp;gt;&lt;/code&gt;
Once we have the entries from our config file in the a HashMap 
we can load them into the hashmap created in the ebpf code. &lt;/p&gt;

&lt;p&gt;This is the opposite of what we did in the Part 5 where
we data was stored in the map on the eBPF side and passed 
to the user space program. Here we load the data from user space
and pass it to the eBPF using the map.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    let mut src&lt;em&gt;ip_filter : ayaHashMap&amp;lt;&lt;/em&gt;,  u32, u8&amp;gt; =
            ayaHashMap::try&lt;em&gt;from( bpf.map_mut("SRC_IP&lt;/em&gt;FILTER").unwrap())?;
    ...
        for (k, v)  in config {
            if v == "block" {
                let addr : Ipv4Addr  = k.parse().unwrap();
                println!("addr {:?}" , addr);
                let &lt;em&gt; = src_ip&lt;/em&gt;filter.insert(u32::from(addr), 1, 0);
            }
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The IP addresses get loaded into the map and are then visible in the
eBPF code running in the kernel.&lt;/p&gt;

&lt;p&gt;We can use the loopback address 127.0.0.1 to test whether the firewall works
First load the eBPF program and attach it to the loopback interface&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    RUST_LOG=info cargo xtask run -- -i lo 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can check that it is loaded using bpftool&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ sudo bpftool prog list | grep -A 5 firewall
    5118: xdp  name firewall_002  tag 64a3874abd9070d2  gpl
            loaded_at 2024-05-01T23:27:54-0700  uid 0
            xlated 7008B  jited 3759B  memlock 8192B  map_ids 1532,1534,1533,1535
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can use the netcat program to test it. 
In one terminal start a server listening on port 9090&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    nc -l 9090
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In another terminal send data to the server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    echo "the quick brown fox jumped over the lazy dog" |  nc 127.0.0.1 9090
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the terminal running the cargo command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    2024-05-02T06:37:27Z INFO  firewall_002] received IPv4 packet
    [2024-05-02T06:37:27Z INFO  firewall_002] dropping packet ...
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the netcat server window there will no output showing receipt of a packet&lt;/p&gt;

</description>
      <category>ebpf</category>
      <category>linux</category>
      <category>rust</category>
      <category>networking</category>
    </item>
    <item>
      <title>Aya Rust Tutorial part 5: Using Maps</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Wed, 19 Jun 2024 00:38:30 +0000</pubDate>
      <link>https://dev.to/stevelatif/aya-rust-tutorial-part-5-using-maps-1boe</link>
      <guid>https://dev.to/stevelatif/aya-rust-tutorial-part-5-using-maps-1boe</guid>
      <description>&lt;p&gt;© steve latif &lt;/p&gt;

&lt;p&gt;Welcome to part 5. So far we have created a basic hello world program in Part &lt;a href="https://dev.to/stevelatif/aya-rust-tutorial-part-four-xdp-hello-world-4c85"&gt;Four&lt;/a&gt;.
In this chapter we will start looking at how to pass data
between the kernel and user space using Maps.&lt;/p&gt;

&lt;h1&gt;Overview: What is a Map and why do we need them ?&lt;/h1&gt;

&lt;p&gt;The eBPF verifier enforces a 512 byte limit per stack frame,
if you need to handle more data you can store data using
&lt;a href="https://docs.kernel.org/bpf/maps.html"&gt;maps&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maps are created on the kernel code&lt;/li&gt;
&lt;li&gt;Maps are accessible from  user space using a system call and a key&lt;/li&gt;
&lt;li&gt;Maps allow persistence across program invocations&lt;/li&gt;
&lt;li&gt;Maps offer different storage types&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maps in eBPF are a basic building block and we will be using them extensively
in the next sections. Our first example will build on the previous
example and will be a packet counter using an array.&lt;/p&gt;

&lt;p&gt;Let's take a minute to look at the kernel code and
see the definitions there.
Maps are defined in &lt;a href="https://elixir.bootlin.com/linux/latest/source/tools/lib/bpf/libbpf.c#L511"&gt;libbpf.h&lt;/a&gt; &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;struct bpf&lt;em&gt;map&lt;/em&gt;def {
    unsigned int type;
    unsigned int key_size;
    unsigned int value_size;
    unsigned int max_entries;
    unsigned int map_flags;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The different map types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;ARRAY                &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_PERCPU&lt;/em&gt;ARRAY         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_PROG&lt;/em&gt;ARRAY           &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_PERF_EVENT&lt;/em&gt;ARRAY     &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_CGROUP&lt;/em&gt;ARRAY         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_CGROUP&lt;/em&gt;STORAGE         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_CGROUP&lt;/em&gt;STORAGE       &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_PERCPU_CGROUP&lt;/em&gt;STORAGE&lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;HASH                 &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_PERCPU&lt;/em&gt;HASH          &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_LRU&lt;/em&gt;HASH             &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_LRU_PERCPU&lt;/em&gt;HASH      &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_LPM&lt;/em&gt;TRIE             &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_STACK&lt;/em&gt;TRACE          &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_ARRAY_OF&lt;/em&gt;MAPS        &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_HASH_OF&lt;/em&gt;MAPS         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_INODE&lt;/em&gt;STORAGE        &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_TASK&lt;/em&gt;STORAGE         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;DEVMAP               &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_DEVMAP&lt;/em&gt;HASH          &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_SK&lt;/em&gt;STORAGE           &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;CPUMAP               &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;XSKMAP               &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;SOCKMAP              &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;SOCKHASH             &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_REUSEPORT&lt;/em&gt;SOCKARRAY  &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;QUEUE                &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;STACK                &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_STRUCT&lt;/em&gt;OPS           &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;RINGBUF              &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_BLOOM&lt;/em&gt;FILTER         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE_USER&lt;/em&gt;RINGBUF         &lt;/li&gt;
&lt;li&gt;BPF&lt;em&gt;MAP_TYPE&lt;/em&gt;ARENA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;are defined in &lt;a href="https://elixir.bootlin.com/linux/latest/source/include/linux/bpf_types.h#L87"&gt;map&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The corresponding aya definitions are documented &lt;a href="https://docs.aya-rs.dev/aya_ebpf/maps/"&gt;here&lt;/a&gt; 
for the kernel side. 
The corresponding user space entries are &lt;a href="https://docs.aya-rs.dev/aya/maps/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our initial example will be a simple per CPU packet counter that will print out 
from user space the number of packets arriving at an interface &lt;/p&gt;

&lt;p&gt;In the C API helper functions are used on both the kernel and user space side. 
The helpers have the same names on both sides.
The kernel side helper functions have access to a pointer to the map and key.&lt;/p&gt;

&lt;p&gt;On the user space side the helper functions use a syscall and file descriptor. &lt;/p&gt;

&lt;p&gt;In Aya on the kernel &lt;a href="https://docs.aya-rs.dev/aya_ebpf/maps/"&gt;side&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;array::Array&lt;/li&gt;
&lt;li&gt;bloom_filter::BloomFilter&lt;/li&gt;
&lt;li&gt;hash_map::HashMap&lt;/li&gt;
&lt;li&gt;hash_map::LruHashMap&lt;/li&gt;
&lt;li&gt;hash_map::LruPerCpuHashMap&lt;/li&gt;
&lt;li&gt;hash_map::PerCpuHashMap&lt;/li&gt;
&lt;li&gt;lpm_trie::LpmTrie&lt;/li&gt;
&lt;li&gt;per&lt;em&gt;cpu&lt;/em&gt;array::PerCpuArray&lt;/li&gt;
&lt;li&gt;perf::PerfEventArray&lt;/li&gt;
&lt;li&gt;perf::PerfEventByteArray&lt;/li&gt;
&lt;li&gt;program_array::ProgramArray&lt;/li&gt;
&lt;li&gt;queue::Queue&lt;/li&gt;
&lt;li&gt;ring_buf::RingBuf&lt;/li&gt;
&lt;li&gt;sock_hash::SockHash&lt;/li&gt;
&lt;li&gt;sock_map::SockMap&lt;/li&gt;
&lt;li&gt;stack::Stack&lt;/li&gt;
&lt;li&gt;stack_trace::StackTrace&lt;/li&gt;
&lt;li&gt;xdp::CpuMap&lt;/li&gt;
&lt;li&gt;xdp::DevMap&lt;/li&gt;
&lt;li&gt;xdp::DevMapHash&lt;/li&gt;
&lt;li&gt;xdp::XskMap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While on the user space &lt;a href="https://docs.aya-rs.dev/aya_ebpf/maps/"&gt;side&lt;/a&gt;
We have the same function list.&lt;/p&gt;

&lt;p&gt;As before generate the code from the template using the command&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; cargo generate https://github.com/aya-rs/aya-template
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I called the project &lt;code&gt;xdp-map-counter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lets set up the packet counter, on the eBPF side:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#![no_std]
#![no_main]
 
use aya&lt;em&gt;ebpf::{bindings::xdp&lt;/em&gt;action,
           macros::{xdp, map},
           programs::XdpContext,
           maps::PerCpuArray,
};
 
const CPU_CORES: u32 = 16;
 
#[map(name="PKT&lt;em&gt;CNT&lt;/em&gt;ARRAY")]
static mut PACKET&lt;em&gt;COUNTER: PERCPU&amp;lt;u32&amp;gt; = PerCpuArray::with_max_entries(CPU&lt;/em&gt;CORES , 0);
 
#[xdp]
pub fn xdp&lt;em&gt;map_counter(&lt;/em&gt;ctx: XdpContext) -&amp;gt; u32 {
    match try&lt;em&gt;xdp_map&lt;/em&gt;counter() {
        Ok(ret) =&amp;gt; ret,
        Err(&lt;em&gt;) =&amp;gt; xdp_action::XDP&lt;/em&gt;ABORTED,
    }
}
 
#[inline(always)] 
fn try&lt;em&gt;xdp_map&lt;/em&gt;counter() -&amp;gt; Result&amp;lt;u32, ()&amp;gt; {
    unsafe {
    let counter = PACKET_COUNTER
            .get&lt;em&gt;ptr&lt;/em&gt;mut(0)
             .ok_or(())? ;
    *counter += 1;
    }
    Ok(xdp&lt;em&gt;action::XDP&lt;/em&gt;PASS)
}
 
#[panic_handler]
fn panic(_info: &amp;amp;core::panic::PanicInfo) -&amp;gt; ! {
    unsafe { core::hint::unreachable_unchecked() }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The map will be created on the eBPF side. We will use a PerCpuArray in
this first example. Arrays are simple to work with. With the PerCpuArray
each CPU sees its own instance of the map, this means that it avoids
lock contention and is therefore the most performant way to get 
readings from eBPF to user land. The downside is that updating the 
values from user space can't be done safely.&lt;/p&gt;

&lt;p&gt;The size of array must be known at build time so we set a constant with an 
upper bound on the number of cores on the system
&lt;code&gt;const CPU_CORES: u32 = 16&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then we can define a PerCpuArray with &lt;code&gt;CPU_CORES&lt;/code&gt; entries initialized to 0.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#[map(name="PKT&lt;em&gt;CNT&lt;/em&gt;ARRAY")]
static mut PACKET&lt;em&gt;COUNTER: PerCpuArray&amp;lt;u32&amp;gt; = PerCpuArray::with_max_entries(CPU&lt;/em&gt;CORES, 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The main work is in the &lt;code&gt;try&lt;em&gt;xdp&lt;/em&gt;counter&lt;/code&gt; function.
We get a pointer to the map and then increment the value&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    unsafe {
    let counter = PACKET_COUNTER
            .get&lt;em&gt;ptr&lt;/em&gt;mut(0)
             .ok_or(())? ;
    *counter += 1;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the call to  &lt;code&gt;ok_or()&lt;/code&gt; is required, failing to have the check 
here will fail the eBPF verifier. &lt;/p&gt;

&lt;p&gt;The packet is then passed on to the networking stack.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    Ok(xdp&lt;em&gt;action::XDP&lt;/em&gt;PASS)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code on the user space side:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;use anyhow::Context;
use aya::programs::{Xdp, XdpFlags};
use aya::{include&lt;em&gt;bytes&lt;/em&gt;aligned, Bpf};
use aya::maps::PerCpuValues;
use aya::maps::PerCpuArray;
use aya_log::BpfLogger;
use clap::Parser;
use log::{warn, debug};
use aya::util::nr_cpus;
//use tokio::signal;
 
#[derive(Debug, Parser)]
struct Opt {
    #[clap(short, long, default_value = "eth0")]
    iface: String,
}
 
#[tokio::main]
async fn main() -&amp;gt; Result&amp;lt;(), anyhow::Error&amp;gt; {
    let opt = Opt::parse();
 
    env_logger::init();
    // Bump the memlock rlimit. This is needed for older kernels that don't use the
    // new memcg based accounting, see https://lwn.net/Articles/837122/
    let rlim = libc::rlimit {
        rlim&lt;em&gt;cur: libc::RLIM&lt;/em&gt;INFINITY,
        rlim&lt;em&gt;max: libc::RLIM&lt;/em&gt;INFINITY,
    };
    let ret = unsafe { libc::setrlimit(libc::RLIMIT_MEMLOCK, &amp;amp;rlim) };
    if ret != 0 {
        debug!("remove limit on locked memory failed, ret is: {}", ret);
    }
    // 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)]
    let mut bpf = Bpf::load(include&lt;em&gt;bytes&lt;/em&gt;aligned!(
        "../../target/bpfel-unknown-none/debug/xdp-map-counter"
    ))?;
    #[cfg(not(debug_assertions))]
    let mut bpf = Bpf::load(include&lt;em&gt;bytes&lt;/em&gt;aligned!(
        "../../target/bpfel-unknown-none/release/xdp-map-counter"
    ))?;
    if let Err(e) = BpfLogger::init(&amp;amp;mut bpf) {
        // This can happen if you remove all log statements from your eBPF program.
        warn!("failed to initialize eBPF logger: {}", e);
    }
    let program: &amp;amp;mut Xdp = bpf.program&lt;em&gt;mut("xdp_map_counter").unwrap().try&lt;/em&gt;into()?;
    program.load()?;
    program.attach(&amp;amp;opt.iface, XdpFlags::default())
        .context("failed to attach the XDP program with default flags - try changing XdpFlags::default() to XdpFlags::SKB_MODE")?;
 
    let array = PerCpuArray::try&lt;em&gt;from(bpf.map_mut("PKT_CNT&lt;/em&gt;ARRAY").unwrap())?;
 
    loop {
    let cc: PerCpuValues&amp;lt;u32&amp;gt; = array.get(&amp;amp;0, 0)?;
    let mut total : u32 =  0;
    //println!("{:?} packets",  cc);
    for ii in 1..nr_cpus().expect("failed to get number of cpus") {
        print!("{} ", cc[ii]);
        total += cc[ii];
    }
    println!("total: {} ", total);
    std::thread::sleep(std::time::Duration::from_secs(1));
    }
    //signal::ctrl_c().await?;    
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The array reference is created on the user space side here with name 
'PKT&lt;em&gt;CNT&lt;/em&gt;ARRAY'  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    let array = PerCpuArray::try&lt;em&gt;from(bpf.map_mut("PKT_CNT&lt;/em&gt;ARRAY").unwrap())?;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and must match the name declared in the eBPF code &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#[map(name="PKT&lt;em&gt;CNT&lt;/em&gt;ARRAY")]
static mut COUNTER: PerCpuArray&amp;lt;u32&amp;gt; = PerCpuArray::with&lt;em&gt;max_entries(CPU&lt;/em&gt;CORES , 0);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Most of the rest of the code is boilerplate except for the loop at the end which checks every 
second for the results from the kernel eBPF code and then prints out the stats.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; loop {
    let cc: PerCpuValues&amp;lt;u32&amp;gt; = array.get(&amp;amp;0, 0)?;
    let mut total : u32 =  0;
    for ii in 1..nr_cpus().expect("failed to get number of cpus") {
        print!("{} ", cc[ii]);
        total += cc[ii];
    }
    println!("total: {} ", total);
    std::thread::sleep(std::time::Duration::from_secs(1));
    }
   
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Testing&lt;/h2&gt;

&lt;p&gt;As we did before we can run it over the loopback interface.
Build as before&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cargo xtask build-ebpf
cargo build
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then run&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cargo xtask run -- -i lo
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In another terminal ping the loopback interface&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
ping 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the terminal where you are running the &lt;code&gt;cargo run&lt;/code&gt; command you should see &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 total: 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 total: 0 
0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 total: 2 
0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 total: 4 
0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 total: 6 
0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 total: 8 
0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 total: 10 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see packets arriving and being processed on one core. 
To run  a more stressful test, replace the ping with the 
following ssh command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; ssh 127.0.0.1 cat /dev/zero
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should see something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 total: 0 
0 7 6 2 0 0 0 0 0 0 0 5 0 0 0 total: 20 
0 7 6 2 0 0 0 0 0 0 0 6 0 0 0 total: 21 
0 7 6 2 0 0 0 0 0 0 0 6 0 0 0 total: 21 
0 7 6 2 0 0 0 0 0 0 0 6 0 0 0 total: 21 
0 7 6 2 0 0 0 0 0 0 0 6 0 0 0 total: 21 
0 48 12 2 0 16 0 0 0 0 0 8 0 702 0 total: 788 
0 48 133 12 0 527 0 0 0 5 0 8 94 1978 558 total: 3363 
0 48 133 243 0 527 0 17 0 5 0 8 94 1978 3179 total: 6232 
0 48 133 243 0 645 0 144 64 23 0 8 94 1978 5800 total: 9180 
0 48 133 243 0 733 0 201 64 203 2 8 94 1978 8406 total: 12113 
0 48 133 243 0 903 0 333 64 228 2 8 94 1978 11027 total: 15061 
0 48 133 243 0 1447 0 548 64 237 2 8 94 1978 13136 total: 17938 
0 368 133 243 0 3908 0 548 64 237 2 8 94 1978 13136 total: 20719 
0 595 133 416 0 6529 0 548 64 237 2 8 94 1978 13136 total: 23740 
0 683 133 674 0 9294 0 548 64 237 2 8 94 1978 13136 total: 26851 
0 854 133 927 0 11544 0 548 64 296 2 440 94 1978 13136 total: 30016 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run it for a few iterations before Ctrl-C ing it.&lt;/p&gt;

&lt;p&gt;As before lets take a minute to look at the eBPF byte code which corresponds to 
the code in the XDP section of &lt;code&gt;xdp-map-counter/xdp-map-counter-ebpf/src/main.rs&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fn try&lt;em&gt;xdp_map&lt;/em&gt;counter() -&amp;gt; Result&amp;lt;u32, ()&amp;gt; {
    unsafe {
    let counter = COUNTER
            .get&lt;em&gt;ptr&lt;/em&gt;mut(0)
             .ok_or(())? ;
    *counter += 1;
    }
    Ok(xdp&lt;em&gt;action::XDP&lt;/em&gt;PASS)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using &lt;code&gt;llvm-objdump&lt;/code&gt; as before&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ llvm-obj dump --section=xdp  -S target/bpfel-unknown-none/debug/xdp-map-counter
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;target/bpfel-unknown-none/debug/xdp-map-counter:    file format elf64-bpf
 
Disassembly of section xdp:
 
0000000000000000 &amp;lt;xdp&lt;em&gt;map&lt;/em&gt;counter&amp;gt;:
       0:   b7 06 00 00 00 00 00 00 r6 = 0
       1:   63 6a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r6
       2:   bf a2 00 00 00 00 00 00 r2 = r10
       3:   07 02 00 00 fc ff ff ff r2 += -4
       4:   18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       6:   85 00 00 00 01 00 00 00 call 1
       7:   15 00 04 00 00 00 00 00 if r0 == 0 goto +4 &amp;lt;LBB0_2&amp;gt;
       8:   61 01 00 00 00 00 00 00 r1 = *(u32 *)(r0 + 0)
       9:   07 01 00 00 01 00 00 00 r1 += 1
      10:   63 10 00 00 00 00 00 00 *(u32 *)(r0 + 0) = r1
      11:   b7 06 00 00 02 00 00 00 r6 = 2
 
0000000000000060 &amp;lt;LBB0_2&amp;gt;:
      12:   bf 60 00 00 00 00 00 00 r0 = r6
      13:   95 00 00 00 00 00 00 00 exit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We see that byte code maps closely to the rust code.
After setting up parameters in the first 4 lines, in line 6 we
have a &lt;code&gt;call 1&lt;/code&gt; that is a system call to the bpf helper 
&lt;code&gt;map&lt;em&gt;lookup&lt;/em&gt;elem&lt;/code&gt; 
That value gets assigned to r1 where it is incremented on
line 9
and is then assigned to a location in  memory.&lt;/p&gt;

</description>
      <category>ebpf</category>
      <category>networking</category>
      <category>linux</category>
      <category>rust</category>
    </item>
    <item>
      <title>Aya Rust tutorial Part Four XDP Hello World</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Sun, 09 Jun 2024 05:05:19 +0000</pubDate>
      <link>https://dev.to/stevelatif/aya-rust-tutorial-part-four-xdp-hello-world-4c85</link>
      <guid>https://dev.to/stevelatif/aya-rust-tutorial-part-four-xdp-hello-world-4c85</guid>
      <description>&lt;p&gt;© steve latif &lt;/p&gt;

&lt;h1&gt;
  
  
  Aya Rust Tutorial Part 4: XDP Hello World
&lt;/h1&gt;

&lt;p&gt;Welcome to part 4. So far we have installed the prerequisite in part 2,&lt;br&gt;
built eBPF code that loads into the kernel and passes the&lt;br&gt;
verifier. Let's continue on by building another XDP&lt;br&gt;
program that will print a message every time it receives a packet&lt;br&gt;
on an interface. As in part 3 we will use the loopback interface.&lt;br&gt;
This will show how to print a message from the kernel. This is analogous&lt;br&gt;
to using 'bpf_printk' in the eBPF programs in C, see [here](&lt;a href="https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/kprobe.bpf.c_ul"&gt;https://github.com/libbpf/libbpf-bootstrap/blob/master/examples/c/kprobe.bpf.c_ul&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will involve only a few more lines of code and &lt;br&gt;
will follow the same build and deployment process as in the previous chapter.&lt;/p&gt;

&lt;h1&gt;
  
  
  Generating the code
&lt;/h1&gt;

&lt;p&gt;As we did in part 3 &lt;br&gt;
generate the code using &lt;code&gt;cargo generate&lt;/code&gt;&lt;br&gt;
At the prompt select hello-world as the project name&lt;/p&gt;

&lt;p&gt;Using the template, generate the code in directory &lt;code&gt;hello-world\&lt;/code&gt;, select the xdp option.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo generate https://github.com/aya-rs/aya-template  
⚠️   Favorite `https://github.com/aya-rs/aya-template` not found in config, using it as a git repository: https://github.com/aya-rs/aya-template
🤷   Project Name: hello-world
🔧   Destination: /home/steve/articles/learning_ebpf_with_rust/xdp-tutorial/basic01-hello-world/hello-world ...
🔧   project-name: hello-world ...
🔧   Generating template ...
? 🤷   Which type of eBPF program? ›
  cgroup_skb
  cgroup_sockopt
  cgroup_sysctl
  classifier
  fentry
  fexit
  kprobe
  kretprobe
  lsm
  perf_event
  raw_tracepoint
  sk_msg
  sock_ops
  socket_filter
  tp_btf
  tracepoint
  uprobe
  uretprobe
❯ xdp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The generated code will if unaltered behave as a hello world program. In the&lt;br&gt;
first part of this note we will modify the generated code, but come back &lt;br&gt;
to it later &lt;br&gt;
Modify the generated code in the file &lt;code&gt;hello-world/hello-world-ebpf/src/main.rs&lt;/code&gt; &lt;br&gt;
so that it looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#![no_std]
#![no_main]

use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
use aya_ebpf::bpf_printk;

#[xdp]
pub fn hello_world(_ctx: XdpContext) -&amp;gt; u32 {
    unsafe {
        bpf_printk!(b"packet  received!");
    }
xdp_action::XDP_PASS
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This code uses the unsafe macro &lt;a href="https://docs.rs/aya-ebpf/latest/aya_ebpf/macro.bpf_printk.html"&gt;bpf_printk&lt;/a&gt; &lt;br&gt;
to print out a message every time a packet is received on the interface. &lt;br&gt;
It returns &lt;code&gt;XDP\_PASS\&lt;/code&gt;&lt;br&gt;
bpf_printk is a useful tool for debugging. It is globally shared in the kernel &lt;br&gt;
so other programs using it may disrupt its output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile the code
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo xtask build-ebpf
cargo build 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Looking into the BPF-ELF object
&lt;/h2&gt;

&lt;p&gt;As we did in the previous section, lets look at the generated eBPF byte code&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-readelf --sections target/bpfel-unknown-none/debug/hello-world
There are 7 section headers, starting at offset 0x2e0:

Section Headers:
    [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
    [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
    [ 1] .strtab           STRTAB          0000000000000000 000238 0000a2 00      0   0  1
    [ 2] .text             PROGBITS        0000000000000000 000040 000098 00  AX  0   0  8
    [ 3] xdp               PROGBITS        0000000000000000 0000d8 000030 00  AX  0   0  8
    [ 4] .relxdp           REL             0000000000000000 000228 000010 10   I  6   3  8
    [ 5] .rodata           PROGBITS        0000000000000000 000108 000013 00   A  0   0  1
    [ 6] .symtab           SYMTAB          0000000000000000 000120 000108 18      1   8  8
Key to Flags:
    W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
    L (link order), O (extra OS processing required), G (group), T (TLS),
    C (compressed), x (unknown), o (OS specific), E (exclude),
    R (retain), p (processor specific)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As before we have an xdp section, lets disassemble that:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-objdump --no-show-raw-insn --section=xdp  -S target/bpfel-unknown-none/debug/hello-world

target/bpfel-unknown-none/debug/hello-world:    file format elf64-bpf

Disassembly of section xdp:

0000000000000000 &amp;lt;hello_world&amp;gt;:
   0:       r1 = 0 ll
   2:       r2 = 19
   3:       call 6
   4:       r0 = 2
   5:       exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Recall that the registers for eBPF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;r0: Stores a return value of a function, and exit value for an eBPF program&lt;/li&gt;
&lt;li&gt;r1 - R5: Stores function arguments&lt;/li&gt;
&lt;li&gt;r6 - R9: For general purpose usage&lt;/li&gt;
&lt;li&gt;r10: Stores an address for stack frame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;line 0 zeroes out the r1 register&lt;br&gt;
line 2 sets r2 to 19 - the length of the output string&lt;br&gt;
line 3 makes a system call, the mysterious 6 is the index of &lt;br&gt;
bpf_helpers found in &lt;a href="https://elixir.bootlin.com/linux/v5.3.7/source/include/uapi/linux/bpf.h#L2724"&gt;bpf.h&lt;/a&gt;&lt;br&gt;
line 4 sets the exit value to 2 which corresponds to XDP_PASS&lt;/p&gt;

&lt;p&gt;To run this let's use cargo&lt;br&gt;
    $ cargo xtask build-ebpf&lt;br&gt;
    $ cargo build&lt;br&gt;
    $ cargo xtask run -- i lo&lt;/p&gt;

&lt;p&gt;To see output, open another terminal enable tracing:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then to see output&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cat /sys/kernel/debug/tracing/trace_pipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;From another terminal, ping the loopback interface &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ping 127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should see output being logged in the terminal where you ran the &lt;code&gt;trace_pipe&lt;/code&gt; command&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo cat /sys/kernel/debug/tracing/trace_pipe
 ping-75348   [000] ..s21 47214.233803: bpf_trace_printk: packet  received!
 ping-75348   [000] ..s21 47214.233815: bpf_trace_printk: packet  received!
 ping-75348   [007] ..s21 47215.236704: bpf_trace_printk: packet  received!
 ping-75348   [007] ..s21 47215.236737: bpf_trace_printk: packet  received!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's return to the previous step where we generated the code. Run the &lt;br&gt;
&lt;code&gt;cargo generate&lt;/code&gt; leave the generated code and don't change it&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#![no_std]
#![no_main]

use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};
use aya_log_ebpf::info;

#[xdp]
pub fn hello_world(ctx: XdpContext) -&amp;gt; u32 {
    match try_hello_world(ctx) {
        Ok(ret) =&amp;gt; ret,
        Err(_) =&amp;gt; xdp_action::XDP_ABORTED,
    }
}

fn try_hello_world(ctx: XdpContext) -&amp;gt; Result&amp;lt;u32, u32&amp;gt; {
    info!(&amp;amp;ctx, "received a packet");
    Ok(xdp_action::XDP_PASS)
}

#[panic_handler]
fn panic(_info: &amp;amp;core::panic::PanicInfo) -&amp;gt; ! {
    unsafe { core::hint::unreachable_unchecked() }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Build and running it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo xtask build-ebpf
cargo build
RUST_LOG=info cargo xtask run -- -i lo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then running ping in another terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ping 127.0.0.1 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should see this output in the window where you ran &lt;code&gt;cargo xtask run&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2024-06-08T04:24:17Z INFO  hello_world] Waiting for Ctrl-C...
[2024-06-08T04:24:21Z INFO  hello_world] received a packet
[2024-06-08T04:24:21Z INFO  hello_world] received a packet
[2024-06-08T04:24:22Z INFO  hello_world] received a packet
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This programs functions in the same way as the first one, but &lt;br&gt;
there are significant differences in the code. &lt;/p&gt;

&lt;p&gt;It looks more like idiomatic rust with only one unsafe block in &lt;br&gt;
the panic handler. &lt;/p&gt;

&lt;p&gt;However looking at a dump of the byte code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-objdump --section=xdp  -S target/bpfel-unknown-none/debug/hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;target/bpfel-unknown-none/debug/hello-world:    file format elf64-bpf&lt;/p&gt;

&lt;p&gt;Disassembly of section xdp:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0000000000000000 &amp;lt;hello_world&amp;gt;:
   0:   r6 = r1
   1:   r7 = 0
   2:   *(u32 *)(r10 - 4) = r7
   3:   r2 = r10
   4:   r2 += -4
   5:   r1 = 0 ll
   7:   call 1
   8:   if r0 == 0 goto +166 &amp;lt;LBB0_2&amp;gt;
   9:   *(u8 *)(r0 + 2) = r7
  10:   r2 = 11
  11:   *(u8 *)(r0 + 1) = r2
  12:   r1 = 1
  13:   *(u8 *)(r0 + 0) = r1
  14:   r3 = r0
  15:   r3 += 3
  16:   r4 = 0 ll
  18:   r5 = *(u8 *)(r4 + 0)
  19:   *(u8 *)(r3 + 0) = r5
  20:   r5 = *(u8 *)(r4 + 1)
  21:   *(u8 *)(r3 + 1) = r5
  22:   r5 = *(u8 *)(r4 + 2)
  23:   *(u8 *)(r3 + 2) = r5
  24:   r5 = *(u8 *)(r4 + 3)
  25:   *(u8 *)(r3 + 3) = r5
  26:   r5 = *(u8 *)(r4 + 4)
  27:   *(u8 *)(r3 + 4) = r5
  28:   r5 = *(u8 *)(r4 + 5)
  29:   *(u8 *)(r3 + 5) = r5
  30:   r5 = *(u8 *)(r4 + 6)
  31:   *(u8 *)(r3 + 6) = r5
  32:   r5 = *(u8 *)(r4 + 7)
  33:   *(u8 *)(r3 + 7) = r5
  34:   r5 = *(u8 *)(r4 + 8)
  35:   *(u8 *)(r3 + 8) = r5
  36:   r5 = *(u8 *)(r4 + 9)
  37:   *(u8 *)(r3 + 9) = r5
  38:   r5 = *(u8 *)(r4 + 10)
  39:   *(u8 *)(r3 + 10) = r5
  40:   r3 = 3
  41:   *(u8 *)(r0 + 18) = r3
  42:   *(u8 *)(r0 + 17) = r3
  43:   r3 = 2
  44:   *(u8 *)(r0 + 14) = r3
  45:   *(u8 *)(r0 + 20) = r7
  46:   *(u8 *)(r0 + 19) = r2
  47:   *(u8 *)(r0 + 16) = r7
  48:   *(u8 *)(r0 + 15) = r1
  49:   r3 = r0
  50:   r3 += 21
  51:   r5 = *(u8 *)(r4 + 0)
  52:   *(u8 *)(r3 + 0) = r5
  53:   r5 = *(u8 *)(r4 + 1)
  54:   *(u8 *)(r3 + 1) = r5
  55:   r5 = *(u8 *)(r4 + 2)
  56:   *(u8 *)(r3 + 2) = r5
  57:   r5 = *(u8 *)(r4 + 3)
  58:   *(u8 *)(r3 + 3) = r5
  59:   r5 = *(u8 *)(r4 + 4)
  60:   *(u8 *)(r3 + 4) = r5
  61:   r5 = *(u8 *)(r4 + 5)
  62:   *(u8 *)(r3 + 5) = r5
  63:   r5 = *(u8 *)(r4 + 6)
  64:   *(u8 *)(r3 + 6) = r5
  65:   r5 = *(u8 *)(r4 + 7)
  66:   *(u8 *)(r3 + 7) = r5
  67:   r5 = *(u8 *)(r4 + 8)
  68:   *(u8 *)(r3 + 8) = r5
  69:   r5 = *(u8 *)(r4 + 9)
  70:   *(u8 *)(r3 + 9) = r5
  71:   r5 = *(u8 *)(r4 + 10)
  72:   *(u8 *)(r3 + 10) = r5
  73:   *(u8 *)(r0 + 33) = r2
  74:   *(u8 *)(r0 + 34) = r7
  75:   r2 = 4
  76:   *(u8 *)(r0 + 32) = r2
  77:   r3 = r0
  78:   r3 += 35
  79:   r4 = 11 ll
  81:   r5 = *(u8 *)(r4 + 0)
  82:   *(u8 *)(r3 + 0) = r5
  83:   r5 = *(u8 *)(r4 + 1)
  84:   *(u8 *)(r3 + 1) = r5
  85:   r5 = *(u8 *)(r4 + 2)
  86:   *(u8 *)(r3 + 2) = r5
  87:   r5 = *(u8 *)(r4 + 3)
  88:   *(u8 *)(r3 + 3) = r5
  89:   r5 = *(u8 *)(r4 + 4)
  90:   *(u8 *)(r3 + 4) = r5
  91:   r5 = *(u8 *)(r4 + 5)
  92:   *(u8 *)(r3 + 5) = r5
  93:   r5 = *(u8 *)(r4 + 6)
  94:   *(u8 *)(r3 + 6) = r5
  95:   r5 = *(u8 *)(r4 + 7)
  96:   *(u8 *)(r3 + 7) = r5
  97:   r5 = *(u8 *)(r4 + 8)
  98:   *(u8 *)(r3 + 8) = r5
  99:   r5 = *(u8 *)(r4 + 9)
 100:   *(u8 *)(r3 + 9) = r5
 101:   r5 = *(u8 *)(r4 + 10)
 102:   *(u8 *)(r3 + 10) = r5
 103:   *(u8 *)(r0 + 56) = r1
 104:   r1 = 8
 105:   *(u8 *)(r0 + 54) = r1
 106:   r1 = 16
 107:   *(u8 *)(r0 + 49) = r1
 108:   *(u8 *)(r0 + 66) = r7
 109:   *(u8 *)(r0 + 63) = r7
 110:   *(u8 *)(r0 + 62) = r7
 111:   *(u8 *)(r0 + 61) = r7
 112:   *(u8 *)(r0 + 60) = r7
 113:   *(u8 *)(r0 + 59) = r7
 114:   *(u8 *)(r0 + 58) = r7
 115:   *(u8 *)(r0 + 57) = r7
 116:   *(u8 *)(r0 + 55) = r7
 117:   *(u8 *)(r0 + 52) = r7
 118:   *(u8 *)(r0 + 51) = r7
 119:   *(u8 *)(r0 + 50) = r7
 120:   *(u8 *)(r0 + 48) = r7
 121:   *(u8 *)(r0 + 47) = r2
 122:   r1 = 17
 123:   *(u8 *)(r0 + 65) = r1
 124:   *(u8 *)(r0 + 64) = r1
 125:   r1 = 6
 126:   *(u8 *)(r0 + 53) = r1
 127:   r1 = 5
 128:   *(u8 *)(r0 + 46) = r1
 129:   r1 = r0
 130:   r1 += 67
 131:   r2 = 22 ll
 133:   r3 = *(u8 *)(r2 + 0)
 134:   *(u8 *)(r1 + 0) = r3
 135:   r3 = *(u8 *)(r2 + 1)
 136:   *(u8 *)(r1 + 1) = r3
 137:   r3 = *(u8 *)(r2 + 2)
 138:   *(u8 *)(r1 + 2) = r3
 139:   r3 = *(u8 *)(r2 + 3)
 140:   *(u8 *)(r1 + 3) = r3
 141:   r3 = *(u8 *)(r2 + 4)
 142:   *(u8 *)(r1 + 4) = r3
 143:   r3 = *(u8 *)(r2 + 5)
 144:   *(u8 *)(r1 + 5) = r3
 145:   r3 = *(u8 *)(r2 + 6)
 146:   *(u8 *)(r1 + 6) = r3
 147:   r3 = *(u8 *)(r2 + 7)
 148:   *(u8 *)(r1 + 7) = r3
 149:   r3 = *(u8 *)(r2 + 8)
 150:   *(u8 *)(r1 + 8) = r3
 151:   r3 = *(u8 *)(r2 + 9)
 152:   *(u8 *)(r1 + 9) = r3
 153:   r3 = *(u8 *)(r2 + 10)
 154:   *(u8 *)(r1 + 10) = r3
 155:   r3 = *(u8 *)(r2 + 11)
 156:   *(u8 *)(r1 + 11) = r3
 157:   r3 = *(u8 *)(r2 + 12)
 158:   *(u8 *)(r1 + 12) = r3
 159:   r3 = *(u8 *)(r2 + 13)
 160:   *(u8 *)(r1 + 13) = r3
 161:   r3 = *(u8 *)(r2 + 14)
 162:   *(u8 *)(r1 + 14) = r3
 163:   r3 = *(u8 *)(r2 + 15)
 164:   *(u8 *)(r1 + 15) = r3
 165:   r3 = *(u8 *)(r2 + 16)
 166:   *(u8 *)(r1 + 16) = r3
 167:   r1 = r6
 168:   r2 = 0 ll
 170:   r3 = 4294967295 ll
 172:   r4 = r0
 173:   r5 = 84
 174:   call 25

0000000000000578 &amp;lt;LBB0_2&amp;gt;:
 175:   r0 = 2
 176:   exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So there's a lot here, we will defer a full explanation till later, note that there are now &lt;br&gt;
two system calls on line 7 and line 174: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   7:   call 1  
   ...
 174:   call 25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;call 1&lt;/code&gt; corresponds to &lt;code&gt;map_lookup_elem&lt;/code&gt; in &lt;a href="https://elixir.bootlin.com/linux/v5.3.7/source/include/uapi/linux/bpf.h#L2719"&gt;bpf.h&lt;/a&gt;&lt;br&gt;
&lt;code&gt;call 25&lt;/code&gt; corresponding to `&lt;code&gt;perf_event_output&lt;/code&gt; in &lt;a href="https://elixir.bootlin.com/linux/v5.3.7/source/include/uapi/linux/bpf.h#L2743"&gt;bpf.h&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much of the rest of the byte code is setting up the stack to pass arguments. &lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Seen how to set up and deploy a basic hello world program &lt;/li&gt;
&lt;li&gt;print out a message when a packet is received&lt;/li&gt;
&lt;li&gt;compared two different hello world programs&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ebpf</category>
      <category>rust</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>Aya Rust tutorial Part Three XDP Pass</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Thu, 09 May 2024 21:27:37 +0000</pubDate>
      <link>https://dev.to/stevelatif/aya-rust-tutorial-part-three-xdp-pass-35cc</link>
      <guid>https://dev.to/stevelatif/aya-rust-tutorial-part-three-xdp-pass-35cc</guid>
      <description>&lt;p&gt;© steve latif &lt;/p&gt;

&lt;h1&gt;
  
  
  Aya Rust Tutorial Part 3: XDP_pass
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Assumptions
&lt;/h2&gt;

&lt;p&gt;Assuming you already set up the prerequisites and installed the required tools&lt;br&gt;
and libraries.&lt;br&gt;
The eBPF program will load into the running kernel where it will be&lt;br&gt;
verified. &lt;/p&gt;

&lt;p&gt;The eBPF program will run in a virtual machine that is built into the Linux&lt;br&gt;
kernel. This virtual machine has nine general purpose registers R1-R9 and one &lt;br&gt;
read only register R10 that functions as a frame pointer. Running anything&lt;br&gt;
that can be loaded dynamically in the kernel with elevated privileges can &lt;br&gt;
be potential security issue. The eBPF virtual machine contains &lt;br&gt;
a verifier see &lt;a href="https://docs.kernel.org/bpf/verifier.html" rel="noopener noreferrer"&gt;https://docs.kernel.org/bpf/verifier.html&lt;/a&gt;&lt;br&gt;
The verifier will check and reject if the program that contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  loops&lt;/li&gt;
&lt;li&gt;  any type of pointer arithmetic&lt;/li&gt;
&lt;li&gt;  bounds or alignment violations&lt;/li&gt;
&lt;li&gt;  unreachable instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other restrictions, consult the documentation for more details&lt;/p&gt;

&lt;p&gt;If you have worked with rust code with cargo before, you will have cycled &lt;br&gt;
through iterations of &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo build
cargo run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Where the source tree of a simple application would like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and after the application had been compiled:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo build
   Compiling hello v0.1.0 (/tmp/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 1.07s
$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        │   ├── hello-20e1cfc616fb61ac
        │   └── hello-20e1cfc616fb61ac.d
        ├── examples
        ├── hello
        ├── hello.d
        └── incremental
            └── hello-3iozzekpyrysr
                ├── s-gvk87j1cfi-6yflog-9nq5zq3lt8rcg1slvtqhu2l92
                │   ├── 1cwggjlit3xor5e4.o
                │   ├── 3nmgwmthvx9ijli.o
                │   ├── 3qweoew2z2q7s3nh.o
                │   ├── 4j2x83e2uqqcjw4i.o
                │   ├── 4pluyvgu1vsjgq2o.o
                │   ├── 54dgri4zf1sqnocs.o
                │   ├── dep-graph.bin
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-gvk87j1cfi-6yflog.lock

9 directories, 18 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The compiled binary can be found in target/debug/hello and can be run &lt;br&gt;
directly from that location or by using cargo&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/hello`
Hello, world!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The aya framework creates two programs, an eBPF program that will &lt;br&gt;
be loaded into the kernel and user space program that will be load the&lt;br&gt;
eBPF program, and can also pass and receive data with the eBPF program&lt;br&gt;
using maps - more about these in later parts.&lt;/p&gt;

&lt;p&gt;The code framework for the eBPF and user space will be set up using a template.&lt;br&gt;
The eBPF program will be compiled and run using a cargo &lt;br&gt;
workflow extension:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo xtask build-ebpf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Compilation is a two stage process:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo xtask build-ebpf
cargo build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can examine the xtask part by looking at the files in xdp_pass/xtask after&lt;br&gt;
    you generate the code in the next step:&lt;br&gt;
    $ ls xdp-pass/xtask/src/&lt;br&gt;
    build_ebpf.rs  main.rs  run.rs&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the code
&lt;/h2&gt;

&lt;p&gt;Why use a template to generate the code? Aya-rs has been rapidly evolving,&lt;br&gt;
using older examples of code with the latest versions can lead to some&lt;br&gt;
errors that are hard to debug. Use the sample code here as a rough guide.&lt;br&gt;
Assuming that we have cargo and the generate extension have been installed, we&lt;br&gt;
can generate the code, at the prompt select xdp-pass as the project name&lt;/p&gt;

&lt;p&gt;Using the template, generate the code in directory &lt;code&gt;xdp-pass\&lt;/code&gt;, select the xdp option.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo generate https://github.com/aya-rs/aya-template  
⚠️   Favorite `https://github.com/aya-rs/aya-template` not found in config, using it as a git repository: https://github.com/aya-rs/aya-template
🤷   Project Name: xdp-pass
🔧   Destination: /home/steve/articles/learning_ebpf_with_rust/xdp-tutorial/basic01-xdp-pass/xdp-pass ...
🔧   project-name: xdp-pass ...
🔧   Generating template ...
? 🤷   Which type of eBPF program? ›
  cgroup_skb
  cgroup_sockopt
  cgroup_sysctl
  classifier
  fentry
  fexit
  kprobe
  kretprobe
  lsm
  perf_event
  raw_tracepoint
  sk_msg
  sock_ops
  socket_filter
  tp_btf
  tracepoint
  uprobe
  uretprobe
❯ xdp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The generated files:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ tree xdp-pass/
xdp-pass/
├── Cargo.toml
├── README.md
├── xdp-pass
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── xdp-pass-common
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── xdp-pass-ebpf
│   ├── Cargo.toml
│   ├── rust-toolchain.toml
│   └── src
│       └── main.rs
└── xtask
    ├── Cargo.toml
    └── src
        ├── build_ebpf.rs
        ├── main.rs
        └── run.rs

8 directories, 13 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Look at the file:  and modify so it looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#![no_std]
#![no_main]

use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext};

#[xdp]
pub fn xdp_pass(_ctx: XdpContext) -&amp;gt; u32 {
    xdp_action::XDP_PASS
}

#[panic_handler]
fn panic(_info: &amp;amp;core::panic::PanicInfo) -&amp;gt; ! {
    unsafe { core::hint::unreachable_unchecked() }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The templated code will run and return &lt;code&gt;XDP\_PASS\&lt;/code&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Compile the code
&lt;/h2&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo xtask build-ebpf
cargo build 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Compile in this order else the &lt;code&gt;cargo build\&lt;/code&gt; will fail.&lt;/p&gt;

&lt;p&gt;The xtask step will generate the eBPF object file:&lt;br&gt;
&lt;a href="https://raw.githubusercontent.com/stevelatif/articles/main/blogs/target/bpfel-unknown-none/debug/xdp-pass" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/stevelatif/articles/main/blogs/target/bpfel-unknown-none/debug/xdp-pass&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking into the BPF-ELF object
&lt;/h2&gt;

&lt;p&gt;eBPF bytecode is run in a virtual machine in the Linux kernel. There are 10 registers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  R0 stores function return values, and the exit value for an eBPF program&lt;/li&gt;
&lt;li&gt;  R1-R5 stores function arguments&lt;/li&gt;
&lt;li&gt;  R6-R9 are for general purpose usage&lt;/li&gt;
&lt;li&gt;  R10 stores adresses for the stack frame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inspecting the sections of the eBPF file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-readelf --sections target/bpfel-unknown-none/debug/xdp-pass
There are 5 section headers, starting at offset 0x228:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .strtab           STRTAB          0000000000000000 0001c0 000068 00      0   0  1
  [ 2] .text             PROGBITS        0000000000000000 000040 000098 00  AX  0   0  8
  [ 3] xdp               PROGBITS        0000000000000000 0000d8 000010 00  AX  0   0  8
  [ 4] .symtab           SYMTAB          0000000000000000 0000e8 0000d8 18      1   6  8
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  R (retain), p (processor specific)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can see the xdp section we defined with the xdp macro in the code, so lets inspect that&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-objdump --no-show-raw-insn --section=xdp  -S target/bpfel-unknown-none/debug/xdp-pass

target/bpfel-unknown-none/debug/xdp-pass:       file format elf64-bpf

Disassembly of section xdp:

0000000000000000 &amp;lt;xdp_pass&amp;gt;:
       0:       r0 = 2
       1:       exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Setting the r0 register to 2 corresponds to returning XDP_PASS&lt;/p&gt;

&lt;p&gt;Use the IOvisor documentation of the opcodes from here &lt;a href="https://github.com/iovisor/bpf-docs/blob/master/eBPF.md" rel="noopener noreferrer"&gt;https://github.com/iovisor/bpf-docs/blob/master/eBPF.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can run the program using cargo, as its an XDP program we will have to specify a network interface. &lt;br&gt;
For this introductory example we can use the the loopback &lt;br&gt;
interface for convenience:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ RUST_LOG=info cargo xtask run -- -i lo
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/xtask run -- -i lo`
    Finished `dev` profile [optimized] target(s) in 0.10s
    Finished dev [unoptimized + debuginfo] target(s) in 0.09s
[2024-04-28T06:14:44Z WARN  xdp_pass] failed to initialize eBPF logger: log event array AYA_LOGS doesn't exist
[2024-04-28T06:14:44Z INFO  xdp_pass] Waiting for Ctrl-C...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also load eBPF programs using iproute2&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ip link set dev lo xdpgeneric obj   https://raw.githubusercontent.com/stevelatif/articles/main/blogs/target/bpfel-unknown-none/debug/xdp-pass sec xdp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can see the loaded program with bpftool:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bpftool prog | grep -A 5 xdp
4509: xdp  name xdp_pass  tag 3b185187f1855c4c
        loaded_at 2024-04-28T09:15:17-0700  uid 0
        xlated 16B  jited 22B  memlock 4096B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can generate a dump of the byte code of the running eBPF byte code using bpftool. Generate a dot file using bpftool and the id number for 4509 &lt;br&gt;
from above.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo bpftool prog dump xlated id 4509 visual &amp;amp;&amp;gt; 4509.dot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And then use that to generate an image file with graphviz&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dot -Tpng /tmp/4509.dot -o ~/4509.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cuds44p2t73aa26gtt0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2cuds44p2t73aa26gtt0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The comparable C version of the eBPF looks like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* SPDX-License-Identifier: GPL-2.0 */
#include &amp;lt;linux/bpf.h&amp;gt;
#include &amp;lt;bpf/bpf_helpers.h&amp;gt;
SEC("xdp")
int  xdp_pass_func(struct xdp_md *ctx)
{
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which would be compiled like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clang -O2 -target bpf -c ebpf_program.c -o ebpf_program.oh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And loaded:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo  ip link set dev lo xdpgeneric obj   https://raw.githubusercontent.com/stevelatif/articles/main/blogs/xdp_pass.o sec xdp                                                                                                                                                                        
$ sudo ip link show dev lo                                                                                                                                                                                                              
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 xdpgeneric qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000                                                                                                                                                                
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00                                                                                                                                                                                                                          
    prog/xdp id 4529 tag 3b185187f1855c4c jited                         
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Dumping the byte code shows similar sections,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ llvm-readelf --sections xdp_pass.o
There are 7 section headers, starting at offset 0x108:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .strtab           STRTAB          0000000000000000 0000ba 00004e 00      0   0  1
  [ 2] .text             PROGBITS        0000000000000000 000040 000000 00  AX  0   0  4
  [ 3] xdp               PROGBITS        0000000000000000 000040 000010 00  AX  0   0  8
  [ 4] license           PROGBITS        0000000000000000 000050 000004 00  WA  0   0  1
  [ 5] .llvm_addrsig     LLVM_ADDRSIG    0000000000000000 0000b8 000002 00   E  6   0  1
  [ 6] .symtab           SYMTAB          0000000000000000 000058 000060 18      1   2  8
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  R (retain), p (processor specific)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Disassembly is the same as the Rust version:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;steve@Peshawer:~/git/aya_discovery/xdp_pass$ llvm-objdump --no-show-raw-insn --section=xdp  -S &lt;a href="https://raw.githubusercontent.com/stevelatif/articles/main/blogs/xdp_pass.o" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/stevelatif/articles/main/blogs/xdp_pass.o&lt;/a&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/stevelatif/articles/main/blogs/xdp_pass.o:" rel="noopener noreferrer"&gt;https://raw.githubusercontent.com/stevelatif/articles/main/blogs/xdp_pass.o:&lt;/a&gt;   file format elf64-bpf&lt;/p&gt;

&lt;p&gt;Disassembly of section xdp:&lt;/p&gt;

&lt;p&gt;0000000000000000 &amp;lt;xdp_pass_func_02&amp;gt;:&lt;br&gt;
       0:       r0 = 2&lt;br&gt;
       1:       exit&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;  We can use Rust with the aya crate to build eBPF programs&lt;/li&gt;
&lt;li&gt;  Load and unload the eBPF programs we created using 

&lt;ul&gt;
&lt;li&gt;  Cargo&lt;/li&gt;
&lt;li&gt;  ip net2&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Disassemble the byte code using 

&lt;ul&gt;
&lt;li&gt;  llvm-objdump&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  Generate graphics to aid in debugging using graphviz.&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>ebpf</category>
      <category>rust</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>Aya Rust tutorial Part Two - Setting up</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Thu, 09 May 2024 20:31:23 +0000</pubDate>
      <link>https://dev.to/stevelatif/aya-rust-tutorial-part-two-setting-up-1man</link>
      <guid>https://dev.to/stevelatif/aya-rust-tutorial-part-two-setting-up-1man</guid>
      <description>&lt;p&gt;© steve latif &lt;/p&gt;

&lt;h1&gt;
  
  
  Part Two: Setting up the Prerequisites
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Assumptions
&lt;/h2&gt;

&lt;p&gt;All the examples will be run on Ubuntu Linux. On other distributions your mileage may vary&lt;/p&gt;

&lt;h2&gt;
  
  
  First step: setup dependencies
&lt;/h2&gt;

&lt;p&gt;Install packages &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install clang llvm libelf-dev libpcap-dev build-essential libc6-dev-i386  \
graphviz  make gcc libssl-dev bc libelf-dev libcap-dev clang gcc-multilib  \
libncurses5-dev git pkg-config libmnl-dev bison flex linux-tools-$(uname -r)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Verify that you have bpftool installed on your system&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo bpftool prog 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If there are problems installing it from a package, you can install it from source:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone --recurse-submodules https://github.com/libbpf/bpftool.git
$ cd bpftool/src
$ make -j$(nproc)
$ sudo https://raw.githubusercontent.com/stevelatif/articles/main/blogs/bpftool prog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Install rust, following the instructions at &lt;a href="https://rustup.rs/"&gt;https://rustup.rs/&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once you have rust and cargo installed and in your path, install the following rust related tools:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rustup udpate
$ cargo install cargo-generate
$ cargo install bpf-linker
$ cargo install cargo-generate
$ cargo install rustfmt
$ cargo install bpf-linker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ebpf</category>
      <category>rust</category>
      <category>linux</category>
      <category>networking</category>
    </item>
    <item>
      <title>Aya Rust tutorial Part One</title>
      <dc:creator>stevelatif</dc:creator>
      <pubDate>Thu, 09 May 2024 18:46:22 +0000</pubDate>
      <link>https://dev.to/stevelatif/aya-rust-tutorial-part-one-5h6n</link>
      <guid>https://dev.to/stevelatif/aya-rust-tutorial-part-one-5h6n</guid>
      <description>&lt;p&gt;© steve latif &lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started with Aya and eBPF Part 1
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is the first in a series of posts looking at eBPF and the&lt;br&gt;
Rust Aya crate. eBPF can run sandboxed programs inside the kernel.&lt;br&gt;
Aya can create the byte code for both the kernel space&lt;br&gt;
programs, and the corresponding  userland programs to load the eBPF byte code.&lt;/p&gt;

&lt;p&gt;The Extended Berkeley Packet Filter came out as a development on &lt;br&gt;
the Berkeley Packet Filter&lt;br&gt;
dating back to the early 1990s. &lt;br&gt;
BPF based tools tcpdump, ethereal and &lt;br&gt;
the libpcap libraries were used to capture&lt;br&gt;
network packets on the wire, filter them, even inject faults. &lt;br&gt;
Doing anything  other than monitoring packets was a time intensive and tricky &lt;br&gt;
operation. More information on eBPF can be found here: &lt;a href="https://ebpf.io/" rel="noopener noreferrer"&gt;https://ebpf.io/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Rust has been around for several years and works well as a system and &lt;br&gt;
general programming language. There are many fine introductions to the language,&lt;br&gt;
a good place to start is here: &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;https://www.rust-lang.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this series of articles we will be looking at &lt;br&gt;
aya-rs, a rust interface to eBPF &lt;a href="https://aya-rs.dev/" rel="noopener noreferrer"&gt;https://aya-rs.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two past projects act as motivation for my work with &lt;br&gt;
eBPF and aya.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario 1 SMB Traffic generation
&lt;/h2&gt;

&lt;p&gt;The network interface on &lt;br&gt;
a storage filer was locking up after having &lt;br&gt;
mounted 255 SMB network shares. &lt;br&gt;
To emulate this we had a lab that consisted of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a linux client box&lt;/li&gt;
&lt;li&gt;  smbclient, an FTP like interface to Samba&lt;/li&gt;
&lt;li&gt;  Maxwell Pro from Interworking Labs (iwl.com) to rewrite ethernet headers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick side note on the Maxwell Pro, it &lt;br&gt;
consists of a linux box with two ethernet cards, packets coming in are passed to &lt;br&gt;
a user space application, where they can be modified or have their headers&lt;br&gt;
rewritten, they are then passed out from the other interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8f1bu01mbrzvfjka83n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8f1bu01mbrzvfjka83n.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This had to be thrown together in a few days using whatever was at hand.&lt;/p&gt;

&lt;p&gt;Here's a schematic of the setup, bear in mind that this is Linux circa 2004, &lt;br&gt;
Linux networking was more limited in its capabilities. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1az9sdsm5xkdmfp6tywi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1az9sdsm5xkdmfp6tywi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would simulate from several hundred, to several thousand windows computers&lt;br&gt;
mounting a network share. The share requests would come in from distinct IP and MAC &lt;br&gt;
addresses.&lt;/p&gt;

&lt;p&gt;There are 3 hosts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a linux client

&lt;ul&gt;
&lt;li&gt;  Depending on the test, this will have between 300 - 5000 virtual IP addresses, each with a unique IP&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  An IWL Maxwell Pro to rewrite the ethernet headers (iwl.com)&lt;/li&gt;

&lt;li&gt;  The device under test: An SMB server&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The procedure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A C wrapper script would run multiple invocations of smbclient &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  each smblcient invocation would have it's socket call intercepted and bound to one of the IP addresses 
using the dynamic linking loader &lt;a href="https://man7.org/linux/man-pages/man3/dlopen.3.html" rel="noopener noreferrer"&gt;https://man7.org/linux/man-pages/man3/dlopen.3.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  The Maxwell Pro would rewrite the outgoing MAC address to one based on the IP address&lt;/li&gt;
&lt;li&gt;  SMB server would respond to the smbclient request&lt;/li&gt;
&lt;li&gt;  The response packets would be intercepted by the Maxwell Pro which would rewrite the SMB server response so that the MAC address was the actual MAC on the linux client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;If we were to try to get this working now, could we do it in a more robust manner and not have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The Maxwell Pro&lt;/li&gt;
&lt;li&gt;  Manipulating the dynamic linking loader&lt;/li&gt;
&lt;li&gt;  All the virtual interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using eBPFs packet parsing and rewriting abilities we could might be able &lt;br&gt;
to do all or some of these. &lt;/p&gt;

&lt;p&gt;One of the major headaches with the original project was that it had several disparate &lt;br&gt;
elements implemented in different languages. This was a result of the ad hoc nature of the project.&lt;br&gt;
Being able to build it in a consistent and robust manner would be a major plus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario 2 Wan Simulation
&lt;/h2&gt;

&lt;p&gt;In this case the ask was to build a wan simulator between two servers to &lt;br&gt;
test acceleration algorithms. The product was a server that might sit in &lt;br&gt;
a remote office and communicate with a similar server in a corporate &lt;br&gt;
data center. Traffic would between the two boxes tunneled and cached &lt;br&gt;
to deal with low bandwidth lossy links.&lt;br&gt;
From the networking perspective this &lt;br&gt;
was more straight forward as it involved using a traffic shaping and &lt;br&gt;
firewalling tool to simulate different WAN scenarios. Most of the work &lt;br&gt;
ended up being in the reporting side of the project. &lt;/p&gt;

&lt;p&gt;The traffic shaper/firewall was a FreeBSD tool called dummynet: &lt;a href="http://info.iet.unipi.it/%7Eluigi/dummynet/" rel="noopener noreferrer"&gt;http://info.iet.unipi.it/~luigi/dummynet/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were many combinations to test the algorithms in. Stability and consistency &lt;br&gt;
was always a concern. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzk3afvk0mucn1xajvl4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzk3afvk0mucn1xajvl4w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use eBPF and Aya?
&lt;/h2&gt;

&lt;p&gt;Both these projects had rapid turnarounds from conception to implementation,&lt;br&gt;
but parts of them were quite fragile. My regret was that I didn't have &lt;br&gt;
full access to the networking stack to manipulate packets as they passed&lt;br&gt;
through the stack. eBPF goes a long way to giving us this ability with some&lt;br&gt;
restrictions.&lt;br&gt;
The SMB trafiic generator had small pieces of code in C for running smbclient, &lt;br&gt;
Perl for setting up the networking environment, C++ for running &lt;br&gt;
in the Maxwell Pro to rewrite the ethernet headers. Building and testing&lt;br&gt;
these small programs could only be done on the hosts where they would run&lt;br&gt;
for the most part. Deployment involved using rsync/sftp to move files around.&lt;br&gt;
Not having a consistent build CI pipeline incurs overhead. &lt;br&gt;
There was a similar situation for the WAN emulator. The traffic shaping tool&lt;br&gt;
was part of the FreeBSD kernel which required a kernel rebuild to deploy it &lt;br&gt;
and could only be tested once in place.&lt;/p&gt;

&lt;p&gt;Aya allows you to use eBPF, but also build both your userspace and kernel &lt;br&gt;
code with one command using Cargo. Testing and deployments are now&lt;br&gt;
much easier. There are other language bindings to use eBPF, several &lt;br&gt;
of which are relatively mature. Rust does have more stringent requirements&lt;br&gt;
during the compilation phase for code hygiene. This can only be a good thing&lt;br&gt;
when generating code that will be run with escalated privileges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;The first goal will be to learn enough about Aya and eBPF to see if we can&lt;br&gt;
implement, or at least think of implementing some parts of the traffic &lt;br&gt;
generator and traffic shaper. These are esoteric tools&lt;br&gt;
but the ideas that we will need for implementing them will mean that &lt;br&gt;
we can talk about&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  firewalls&lt;/li&gt;
&lt;li&gt;  load balancers&lt;/li&gt;
&lt;li&gt;  networking protocols&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ebpf</category>
      <category>rust</category>
      <category>linux</category>
      <category>networking</category>
    </item>
  </channel>
</rss>
