From c9eeea179b397ccf004b87fd51a2d8eb2b72d50b Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Fri, 20 May 2022 00:05:52 +0100 Subject: [PATCH] bpf: Support BPF_PROG_TYPE_SK_LOOKUP Signed-off-by: Dave Tucker --- aya/src/programs/sk_lookup.rs | 4 ++-- bpf/aya-bpf-macros/src/expand.rs | 32 ++++++++++++++++++++++++++ bpf/aya-bpf-macros/src/lib.rs | 33 +++++++++++++++++++++++++-- bpf/aya-bpf/src/maps/sock_hash.rs | 27 ++++++++++++++++++++-- bpf/aya-bpf/src/maps/sock_map.rs | 27 ++++++++++++++++++++-- bpf/aya-bpf/src/programs/mod.rs | 2 ++ bpf/aya-bpf/src/programs/sk_lookup.rs | 19 +++++++++++++++ 7 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 bpf/aya-bpf/src/programs/sk_lookup.rs diff --git a/aya/src/programs/sk_lookup.rs b/aya/src/programs/sk_lookup.rs index 7fe239fad..4f8e2f033 100644 --- a/aya/src/programs/sk_lookup.rs +++ b/aya/src/programs/sk_lookup.rs @@ -11,7 +11,7 @@ use super::links::FdLink; /// A program used to redirect incoming packets to a local socket. /// /// [`SkLookup`] programs are attached to network namespaces to provide programmable -/// socket lookup for TCP/UDP when a packet is to be delievered locally +/// socket lookup for TCP/UDP when a packet is to be delievered locally. /// /// You may attach multiple programs to the same namespace and they are executed /// in the order they were attached. @@ -58,7 +58,7 @@ impl SkLookup { load_program(BPF_PROG_TYPE_SK_LOOKUP, &mut self.data) } - /// Attaches the program to the given network namespace + /// Attaches the program to the given network namespace. /// /// The returned value can be used to detach, see [SkLookup::detach]. pub fn attach(&mut self, netns: T) -> Result { diff --git a/bpf/aya-bpf-macros/src/expand.rs b/bpf/aya-bpf-macros/src/expand.rs index df628711b..81e7bb74f 100644 --- a/bpf/aya-bpf-macros/src/expand.rs +++ b/bpf/aya-bpf-macros/src/expand.rs @@ -744,6 +744,38 @@ impl FExit { } } +pub struct SkLookup { + item: ItemFn, + name: Option, +} + +impl SkLookup { + pub fn from_syn(mut args: Args, item: ItemFn) -> Result { + let name = name_arg(&mut args)?; + + Ok(SkLookup { item, name }) + } + + pub fn expand(&self) -> Result { + let section_name = if let Some(name) = &self.name { + format!("sk_lookup/{}", name) + } else { + "sk_lookup".to_owned() + }; + let fn_name = &self.item.sig.ident; + let item = &self.item; + Ok(quote! { + #[no_mangle] + #[link_section = #section_name] + fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sk_lookup) -> u32 { + return #fn_name(::aya_bpf::programs::SkLookupContext::new(ctx)); + + #item + } + }) + } +} + #[cfg(test)] mod tests { use syn::parse_quote; diff --git a/bpf/aya-bpf-macros/src/lib.rs b/bpf/aya-bpf-macros/src/lib.rs index 853b50a85..a22e9d25f 100644 --- a/bpf/aya-bpf-macros/src/lib.rs +++ b/bpf/aya-bpf-macros/src/lib.rs @@ -2,8 +2,8 @@ mod expand; use expand::{ Args, BtfTracePoint, CgroupSkb, CgroupSockAddr, CgroupSockopt, CgroupSysctl, FEntry, FExit, - Lsm, Map, PerfEvent, Probe, ProbeKind, RawTracePoint, SchedClassifier, SkMsg, SkSkb, SkSkbKind, - SockAddrArgs, SockOps, SocketFilter, SockoptArgs, TracePoint, Xdp, + Lsm, Map, PerfEvent, Probe, ProbeKind, RawTracePoint, SchedClassifier, SkLookup, SkMsg, SkSkb, + SkSkbKind, SockAddrArgs, SockOps, SocketFilter, SockoptArgs, TracePoint, Xdp, }; use proc_macro::TokenStream; use syn::{parse_macro_input, ItemFn, ItemStatic}; @@ -467,3 +467,32 @@ pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream { .unwrap_or_else(|err| err.to_compile_error()) .into() } + +/// Marks a function as an eBPF Socket Lookup program that can be attached to +/// a network namespace. +/// +/// # Minimum kernel version +/// +/// The minimum kernel version required to use this feature is 5.9 +/// +/// # Examples +/// +/// ```no_run +/// use aya_bpf::{macros::sk_lookup, programs::SkLookupContext}; +/// +/// #[sk_lookup(name = "redirect")] +/// pub fn accept_all(_ctx: SkLookupContext) -> u32 { +/// // use sk_assign to redirect +/// return 0 +/// } +/// ``` +#[proc_macro_attribute] +pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream { + let args = parse_macro_input!(attrs as Args); + let item = parse_macro_input!(item as ItemFn); + + SkLookup::from_syn(args, item) + .and_then(|u| u.expand()) + .unwrap_or_else(|err| err.to_compile_error()) + .into() +} diff --git a/bpf/aya-bpf/src/maps/sock_hash.rs b/bpf/aya-bpf/src/maps/sock_hash.rs index 3148ee243..cd3d0c047 100644 --- a/bpf/aya-bpf/src/maps/sock_hash.rs +++ b/bpf/aya-bpf/src/maps/sock_hash.rs @@ -4,9 +4,12 @@ use aya_bpf_cty::c_void; use crate::{ bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_SOCKHASH, bpf_sock_ops}, - helpers::{bpf_msg_redirect_hash, bpf_sk_redirect_hash, bpf_sock_hash_update}, + helpers::{ + bpf_map_lookup_elem, bpf_msg_redirect_hash, bpf_sk_assign, bpf_sk_redirect_hash, + bpf_sk_release, bpf_sock_hash_update, + }, maps::PinningType, - programs::{SkBuffContext, SkMsgContext}, + programs::{SkBuffContext, SkLookupContext, SkMsgContext}, BpfContext, }; @@ -85,4 +88,24 @@ impl SockHash { ) } } + + pub fn redirect_sk_lookup( + &mut self, + ctx: &SkLookupContext, + key: K, + flags: u64, + ) -> Result<(), u32> { + unsafe { + let sk = bpf_map_lookup_elem( + &mut self.def as *mut _ as *mut _, + &key as *const _ as *const c_void, + ); + if sk.is_null() { + return Err(1); + } + let ret = bpf_sk_assign(ctx.as_ptr() as *mut _, sk, flags); + bpf_sk_release(sk); + (ret >= 0).then(|| ()).ok_or(1) + } + } } diff --git a/bpf/aya-bpf/src/maps/sock_map.rs b/bpf/aya-bpf/src/maps/sock_map.rs index 7d546419c..907d288cd 100644 --- a/bpf/aya-bpf/src/maps/sock_map.rs +++ b/bpf/aya-bpf/src/maps/sock_map.rs @@ -4,9 +4,12 @@ use aya_bpf_cty::c_void; use crate::{ bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_SOCKMAP, bpf_sock_ops}, - helpers::{bpf_msg_redirect_map, bpf_sk_redirect_map, bpf_sock_map_update}, + helpers::{ + bpf_map_lookup_elem, bpf_msg_redirect_map, bpf_sk_assign, bpf_sk_redirect_map, + bpf_sk_release, bpf_sock_map_update, + }, maps::PinningType, - programs::{SkBuffContext, SkMsgContext}, + programs::{SkBuffContext, SkLookupContext, SkMsgContext}, BpfContext, }; @@ -80,4 +83,24 @@ impl SockMap { flags, ) } + + pub fn redirect_sk_lookup( + &mut self, + ctx: &SkLookupContext, + index: u32, + flags: u64, + ) -> Result<(), u32> { + unsafe { + let sk = bpf_map_lookup_elem( + &mut self.def as *mut _ as *mut _, + &index as *const _ as *const c_void, + ); + if sk.is_null() { + return Err(1); + } + let ret = bpf_sk_assign(ctx.as_ptr() as *mut _, sk, flags); + bpf_sk_release(sk); + (ret >= 0).then(|| ()).ok_or(1) + } + } } diff --git a/bpf/aya-bpf/src/programs/mod.rs b/bpf/aya-bpf/src/programs/mod.rs index ceaed5f88..c2c8034c0 100644 --- a/bpf/aya-bpf/src/programs/mod.rs +++ b/bpf/aya-bpf/src/programs/mod.rs @@ -5,6 +5,7 @@ pub mod perf_event; pub mod probe; pub mod raw_tracepoint; pub mod sk_buff; +pub mod sk_lookup; pub mod sk_msg; pub mod sock_addr; pub mod sock_ops; @@ -21,6 +22,7 @@ pub use perf_event::PerfEventContext; pub use probe::ProbeContext; pub use raw_tracepoint::RawTracePointContext; pub use sk_buff::SkBuffContext; +pub use sk_lookup::SkLookupContext; pub use sk_msg::SkMsgContext; pub use sock_addr::SockAddrContext; pub use sock_ops::SockOpsContext; diff --git a/bpf/aya-bpf/src/programs/sk_lookup.rs b/bpf/aya-bpf/src/programs/sk_lookup.rs new file mode 100644 index 000000000..5c37066e8 --- /dev/null +++ b/bpf/aya-bpf/src/programs/sk_lookup.rs @@ -0,0 +1,19 @@ +use core::ffi::c_void; + +use crate::{bindings::bpf_sk_lookup, BpfContext}; + +pub struct SkLookupContext { + pub lookup: *mut bpf_sk_lookup, +} + +impl SkLookupContext { + pub fn new(lookup: *mut bpf_sk_lookup) -> SkLookupContext { + SkLookupContext { lookup } + } +} + +impl BpfContext for SkLookupContext { + fn as_ptr(&self) -> *mut c_void { + self.lookup as *mut _ + } +}