Repository: libbpf/libbpf-rs (language: rust)

Issue:
Support XDP replace
Currently, libbpf-rs has supported xdp attach and detach, but not for xdp replace, this is necessary for xdp program upgrade case.
For xdp replace functionality, an old program fd need to be filled in bpf_xdp_attach_opts struct for attach API。




Discussion / hints:

Fix patch:
diff --git a/libbpf-rs/src/xdp.rs b/libbpf-rs/src/xdp.rs
index 40488ebe..2bf86be8 100644
--- a/libbpf-rs/src/xdp.rs
+++ b/libbpf-rs/src/xdp.rs
@@ -91,4 +91,19 @@ impl<'fd> Xdp<'fd> {
             unsafe { libbpf_sys::bpf_xdp_query_id(ifindex, flags.bits() as i32, &mut prog_id) };
         util::parse_ret(err).map(|()| prog_id)
     }
+
+    /// Replace an existing xdp program (identified by old_prog_fd) with this xdp program
+    pub fn replace(&self, ifindex: i32, old_prog_fd: BorrowedFd<'_>) -> Result<()> {
+        let mut opts = self.attach_opts;
+        opts.old_prog_fd = old_prog_fd.as_raw_fd();
+        let ret = unsafe {
+            libbpf_sys::bpf_xdp_attach(
+                ifindex,
+                self.fd.as_raw_fd(),
+                XdpFlags::REPLACE.bits(),
+                &opts,
+            )
+        };
+        util::parse_ret(ret)
+    }
 }


Test patch:
diff --git a/libbpf-rs/tests/test_xdp.rs b/libbpf-rs/tests/test_xdp.rs
index 2b919a8a..a31d191b 100644
--- a/libbpf-rs/tests/test_xdp.rs
+++ b/libbpf-rs/tests/test_xdp.rs
@@ -18,7 +18,11 @@ fn test_sudo_xdp() {
     let obj = get_test_object("xdp.bpf.o");
     let fd = obj.prog("xdp_filter").unwrap().as_fd();
 
+    let obj1 = get_test_object("xdp.bpf.o");
+    let fd1 = obj1.prog("xdp_filter").unwrap().as_fd();
+
     let xdp_prog = Xdp::new(fd);
+    let xdp_prog1 = Xdp::new(fd1);
 
     defer! {
         xdp_prog.detach(LO_IFINDEX, XdpFlags::UPDATE_IF_NOEXIST).unwrap();
@@ -41,6 +45,14 @@ fn test_sudo_xdp() {
         .query(LO_IFINDEX, XdpFlags::UPDATE_IF_NOEXIST)
         .is_ok());
 
+    let old_prog_id = xdp_prog
+        .query_id(LO_IFINDEX, XdpFlags::UPDATE_IF_NOEXIST)
+        .unwrap();
+    assert!(xdp_prog1.replace(LO_IFINDEX, fd).is_ok());
+    let new_prog_id = xdp_prog1.query_id(LO_IFINDEX, XdpFlags::NONE).unwrap();
+    // If xdp prog is replaced, prog id should change.
+    assert!(old_prog_id != new_prog_id);
+
     assert!(xdp_prog
         .detach(LO_IFINDEX, XdpFlags::UPDATE_IF_NOEXIST)
         .is_ok());