diff --git a/aya/src/programs/links.rs b/aya/src/programs/links.rs
index 2cb4c7d5..6ed7e8e9 100644
--- a/aya/src/programs/links.rs
+++ b/aya/src/programs/links.rs
@@ -410,7 +410,7 @@ impl LinkId {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub(crate) enum LinkRef {
     Id(u32),
     Fd(RawFd),
@@ -438,19 +438,26 @@ bitflags::bitflags! {
 ///
 ///```no_run
 /// # let mut bpf = aya::Ebpf::load(&[])?;
-/// use aya::programs::{tc, SchedClassifier, TcAttachType, tc::TcAttachOptions, LinkOrder};
+/// use aya::{
+///     programs::{
+///         tc::{TcAttachOptions, TcxOptions},
+///         LinkOrder, SchedClassifier, TcAttachType,
+///     },
+/// };
 ///
 /// let prog: &mut SchedClassifier = bpf.program_mut("redirect_ingress").unwrap().try_into()?;
 /// prog.load()?;
-/// let options = TcAttachOptions::TcxOrder(LinkOrder::first());
+/// let options = TcAttachOptions::Tcx(TcxOptions {
+///     link_order: LinkOrder::first(),
+///     expected_revision: None, // incorrect expected_revision
+/// });
 /// prog.attach_with_options("eth0", TcAttachType::Ingress, options)?;
 ///
 /// # Ok::<(), aya::EbpfError>(())
 /// ```
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub struct LinkOrder {
     pub(crate) link_ref: LinkRef,
-    pub(crate) expected_revision: Option<u64>,
     pub(crate) flags: MprogFlags,
 }
 
@@ -460,7 +467,6 @@ impl Default for LinkOrder {
         Self {
             link_ref: LinkRef::Fd(0),
             flags: MprogFlags::AFTER,
-            expected_revision: None,
         }
     }
 }
@@ -471,7 +477,6 @@ impl LinkOrder {
         Self {
             link_ref: LinkRef::Id(0),
             flags: MprogFlags::BEFORE,
-            expected_revision: None,
         }
     }
 
@@ -480,7 +485,6 @@ impl LinkOrder {
         Self {
             link_ref: LinkRef::Id(0),
             flags: MprogFlags::AFTER,
-            expected_revision: None,
         }
     }
 
@@ -489,7 +493,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Fd(link.fd()?.as_raw_fd()),
             flags: MprogFlags::BEFORE | MprogFlags::LINK,
-            expected_revision: None,
         })
     }
 
@@ -498,7 +501,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Fd(link.fd()?.as_raw_fd()),
             flags: MprogFlags::AFTER | MprogFlags::LINK,
-            expected_revision: None,
         })
     }
 
@@ -507,7 +509,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Id(id.0),
             flags: MprogFlags::BEFORE | MprogFlags::LINK | MprogFlags::ID,
-            expected_revision: None,
         })
     }
 
@@ -516,7 +517,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Id(id.0),
             flags: MprogFlags::AFTER | MprogFlags::LINK | MprogFlags::ID,
-            expected_revision: None,
         })
     }
 
@@ -525,7 +525,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Fd(program.fd()?.as_raw_fd()),
             flags: MprogFlags::BEFORE,
-            expected_revision: None,
         })
     }
 
@@ -534,7 +533,6 @@ impl LinkOrder {
         Ok(Self {
             link_ref: LinkRef::Fd(program.fd()?.as_raw_fd()),
             flags: MprogFlags::AFTER,
-            expected_revision: None,
         })
     }
 
@@ -543,7 +541,6 @@ impl LinkOrder {
         Self {
             link_ref: LinkRef::Id(id.0),
             flags: MprogFlags::BEFORE | MprogFlags::ID,
-            expected_revision: None,
         }
     }
 
@@ -552,17 +549,8 @@ impl LinkOrder {
         Self {
             link_ref: LinkRef::Id(id.0),
             flags: MprogFlags::AFTER | MprogFlags::ID,
-            expected_revision: None,
         }
     }
-
-    /// set the expected revision for the link, the revision changes
-    /// with each modification of the list of attached programs. User space
-    /// can pass an expected revision when creating a new link. The kernel
-    /// then rejects the update if the revision has changed.
-    pub fn set_expected_revision(&mut self, revision: u64) {
-        self.expected_revision = Some(revision);
-    }
 }
 
 #[cfg(test)]
diff --git a/aya/src/programs/tc.rs b/aya/src/programs/tc.rs
index 1f397789..45b43716 100644
--- a/aya/src/programs/tc.rs
+++ b/aya/src/programs/tc.rs
@@ -128,16 +128,16 @@ impl TcAttachType {
 /// older than 6.6.0 must utilize netlink for attachments, while newer kernels
 /// can utilize the modern TCX eBPF link type which supports the kernel's
 /// multi-prog API.
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub enum TcAttachOptions {
     /// Netlink attach options.
     Netlink(NlOptions),
     /// Tcx attach options.
-    TcxOrder(LinkOrder),
+    Tcx(TcxOptions),
 }
 
 /// Options for SchedClassifier attach via netlink.
-#[derive(Debug, Default, Hash, Eq, PartialEq)]
+#[derive(Debug, Default, Hash, Eq, PartialEq, Copy, Clone)]
 pub struct NlOptions {
     /// Priority assigned to tc program with lower number = higher priority.
     /// If set to default (0), the system chooses the next highest priority or 49152 if no filters exist yet
@@ -147,6 +147,21 @@ pub struct NlOptions {
     pub handle: u32,
 }
 
+/// Options for SchedClassifier attach via TCX.
+#[derive(Debug, Default, Copy, Clone)]
+pub struct TcxOptions {
+    /// Attributes that define the position of the program in the TCX chain.
+    pub link_order: LinkOrder,
+    /// Expected revision for the attach operation.  The kernel maintains a
+    /// revision for each attach point (interface/direction).  Each time a
+    /// program is attached or detached to a given attach point, the revision
+    /// for that attach point is incremented.  If the expected revision does not
+    /// match the revision, the attach will fail.
+    ///
+    /// TODO: Implement an API to query the current revision for an interface.
+    pub expected_revision: Option<u64>,
+}
+
 impl SchedClassifier {
     /// Loads the program inside the kernel.
     pub fn load(&mut self) -> Result<(), ProgramError> {
@@ -179,7 +194,7 @@ impl SchedClassifier {
             self.attach_with_options(
                 interface,
                 attach_type,
-                TcAttachOptions::TcxOrder(LinkOrder::default()),
+                TcAttachOptions::Tcx(TcxOptions::default()),
             )
         } else {
             self.attach_with_options(
@@ -294,14 +309,14 @@ impl SchedClassifier {
                         handle,
                     })))
             }
-            TcAttachOptions::TcxOrder(options) => {
+            TcAttachOptions::Tcx(options) => {
                 let link_fd = bpf_link_create(
                     prog_fd,
                     LinkTarget::IfIndex(if_index),
                     attach_type.tcx_attach_type()?,
                     None,
-                    options.flags.bits(),
-                    Some(&options.link_ref),
+                    options.link_order.flags.bits(),
+                    Some(&options.link_order.link_ref),
                     options.expected_revision,
                 )
                 .map_err(|(_, io_error)| SyscallError {
diff --git a/test/integration-test/src/tests/tcx.rs b/test/integration-test/src/tests/tcx.rs
index bf3c0537..c48cca17 100644
--- a/test/integration-test/src/tests/tcx.rs
+++ b/test/integration-test/src/tests/tcx.rs
@@ -5,7 +5,10 @@ use std::{
 };
 
 use aya::{
-    programs::{tc::TcAttachOptions, LinkOrder, SchedClassifier, TcAttachType},
+    programs::{
+        tc::{TcAttachOptions, TcxOptions},
+        LinkOrder, SchedClassifier, TcAttachType,
+    },
     util::KernelVersion,
     Ebpf, EbpfLoader,
 };
@@ -105,17 +108,19 @@ async fn tcx_ordering() {
     prog3.load().unwrap();
 
     // Test LinkOrder::last() with correct expected_revision
-    let mut order: LinkOrder = LinkOrder::last();
-    order.set_expected_revision(1);
-    let options = TcAttachOptions::TcxOrder(order);
+    let options = TcAttachOptions::Tcx(TcxOptions {
+        link_order: LinkOrder::first(),
+        expected_revision: Some(1),
+    });
     prog0
         .attach_with_options("lo", TcAttachType::Ingress, options)
         .unwrap();
 
     // Test LinkOrder::after_program() with correct expected_revision
-    let mut order = LinkOrder::after_program(prog0).unwrap();
-    order.set_expected_revision(2);
-    let options = TcAttachOptions::TcxOrder(order);
+    let options = TcAttachOptions::Tcx(TcxOptions {
+        link_order: LinkOrder::after_program(prog0).unwrap(),
+        expected_revision: Some(2),
+    });
     let prog1_link_id = prog1
         .attach_with_options("lo", TcAttachType::Ingress, options)
         .unwrap();
@@ -123,23 +128,33 @@ async fn tcx_ordering() {
     let prog1_link = prog1.take_link(prog1_link_id).unwrap();
 
     // Test incorrect expected_revision and expect an error
-    let mut order = LinkOrder::after_link(&prog1_link).unwrap();
-    order.set_expected_revision(7);
-    let options = TcAttachOptions::TcxOrder(order);
-    let result = prog2.attach_with_options("lo", TcAttachType::Ingress, options);
+    let mut tcx_options = TcxOptions {
+        link_order: LinkOrder::after_link(&prog1_link).unwrap(),
+        expected_revision: Some(7), // incorrect expected_revision
+    };
+    let result = prog2.attach_with_options(
+        "lo",
+        TcAttachType::Ingress,
+        TcAttachOptions::Tcx(tcx_options),
+    );
     assert!(result.is_err());
 
-    // Test LinkOrder::after_link() again with expected_revision == 0 which
-    // means the expected_revision should be ignored.
-    let mut order = LinkOrder::after_link(&prog1_link).unwrap();
-    order.set_expected_revision(0);
-    let options = TcAttachOptions::TcxOrder(order);
+    // Test LinkOrder::after_link() again after updating expected_revision to 3
+    // which should be the correct revision.
+    tcx_options.expected_revision = Some(3);
     prog2
-        .attach_with_options("lo", TcAttachType::Ingress, options)
+        .attach_with_options(
+            "lo",
+            TcAttachType::Ingress,
+            TcAttachOptions::Tcx(tcx_options),
+        )
         .unwrap();
 
     // Test LinkOrder::last() with no expected_revision
-    let options = TcAttachOptions::TcxOrder(LinkOrder::last());
+    let options = TcAttachOptions::Tcx(TcxOptions {
+        link_order: LinkOrder::last(),
+        expected_revision: None, // incorrect expected_revision
+    });
     prog3
         .attach_with_options("lo", TcAttachType::Ingress, options)
         .unwrap();