diff --git a/aya/src/sys/netlink.rs b/aya/src/sys/netlink.rs index 1dfae70d..9c5e815a 100644 --- a/aya/src/sys/netlink.rs +++ b/aya/src/sys/netlink.rs @@ -277,7 +277,10 @@ struct Request { struct TcRequest { header: nlmsghdr, tc_info: tcmsg, - attrs: [u8; 64], + // The buffer for attributes should be sized to hold at least 256 bytes, + // based on `CLS_BPF_NAME_LEN = 256` from the kernel: + // https://github.com/torvalds/linux/blob/02aee814/net/sched/cls_bpf.c#L28 + attrs: [u8; 512], } struct NetlinkSocket { diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index 38c097f3..6994cac1 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -42,3 +42,7 @@ path = "src/bpf_probe_read.rs" [[bin]] name = "two_progs" path = "src/two_progs.rs" + +[[bin]] +name = "tc_name_limit" +path = "src/tc_name_limit.rs" diff --git a/test/integration-ebpf/src/tc_name_limit.rs b/test/integration-ebpf/src/tc_name_limit.rs new file mode 100644 index 00000000..df321a82 --- /dev/null +++ b/test/integration-ebpf/src/tc_name_limit.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +use aya_bpf::{macros::classifier, programs::TcContext}; + +// This macro generates a function with arbitrary name +macro_rules! generate_ebpf_function { + ($fn_name:ident) => { + #[classifier] + pub fn $fn_name(_ctx: TcContext) -> i32 { + 0 + } + }; +} + +/* +Generating a function with a 256-byte-long name (all 'a's) to be used as +the ebpf program. This name must match the name passed to userspace side. +256 is the maximum length allowed by the kernel: +https://github.com/torvalds/linux/blob/02aee814/net/sched/cls_bpf.c#L28 +*/ +generate_ebpf_function!(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 80cd0b1d..42d7c394 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -12,6 +12,8 @@ pub const TEXT_64_64_RELOC: &[u8] = pub const LOG: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/log")); pub const MAP_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/map_test")); pub const NAME_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/name_test")); +pub const TC_NAME_LIMIT_TEST: &[u8] = + include_bytes_aligned!(concat!(env!("OUT_DIR"), "/tc_name_limit")); pub const PASS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/pass")); pub const TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/test")); pub const RELOCATIONS: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/relocations")); diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 0b0d1532..5c6373c3 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -4,7 +4,9 @@ use aya::{ maps::Array, programs::{ links::{FdLink, PinnedLink}, - loaded_links, loaded_programs, KProbe, TracePoint, UProbe, Xdp, XdpFlags, + loaded_links, loaded_programs, + tc::qdisc_add_clsact, + KProbe, SchedClassifier, TcAttachType, TracePoint, UProbe, Xdp, XdpFlags, }, util::KernelVersion, Bpf, @@ -13,6 +15,27 @@ use aya::{ const MAX_RETRIES: usize = 100; const RETRY_DURATION: time::Duration = time::Duration::from_millis(10); +#[test] +fn tc_name_limit() { + let _ = qdisc_add_clsact("lo"); + + let mut bpf = Bpf::load(crate::TC_NAME_LIMIT_TEST).unwrap(); + + // This magic number (256) is derived from the fact that the kernel + // permits names with a maximum length of 256 bytes: + // https://github.com/torvalds/linux/blob/02aee814/net/sched/cls_bpf.c#L28 + // In this case, the name is 256 'a's + let long_name = "a".repeat(256); + + let program: &mut SchedClassifier = bpf + .program_mut(long_name.as_str()) + .unwrap() + .try_into() + .unwrap(); + program.load().unwrap(); + program.attach("lo", TcAttachType::Ingress).unwrap(); +} + #[test] fn long_name() { let mut bpf = Bpf::load(crate::NAME_TEST).unwrap();