Skip to main content

starnix_core/bpf/
mod.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Implementation of (e)BPF.
6//!
7//! BPF stands for Berkeley Packet Filter and is an API introduced in BSD that allows filtering
8//! network packets by running little programs in the kernel. eBPF stands for extended BFP and
9//! is a Linux extension of BPF that allows hooking BPF programs into many different
10//! non-networking-related contexts.
11
12pub mod attachments;
13pub mod context;
14pub mod fs;
15pub mod map;
16pub mod program;
17pub mod syscalls;
18
19use crate::bpf::attachments::EbpfAttachments;
20use crate::bpf::map::{BpfMapHandle, BpfMapId, WeakBpfMapHandle};
21use crate::bpf::program::{ProgramHandle, ProgramId, WeakProgramHandle};
22use starnix_sync::{EbpfStateLock, LockBefore, Locked, OrderedMutex};
23use starnix_uapi::{bpf_map_type, bpf_map_type_BPF_MAP_TYPE_SK_STORAGE};
24use std::collections::BTreeMap;
25use std::ops::Bound;
26use std::sync::Arc;
27use zerocopy::IntoBytes as _;
28
29struct WeakMapWithType {
30    map_type: bpf_map_type,
31    weak_map: WeakBpfMapHandle,
32}
33
34impl WeakMapWithType {
35    fn new(map: &BpfMapHandle) -> Self {
36        Self { map_type: map.schema.map_type, weak_map: Arc::downgrade(map) }
37    }
38}
39
40/// Stores global eBPF state.
41#[derive(Default)]
42pub struct EbpfState {
43    pub attachments: EbpfAttachments,
44
45    programs: OrderedMutex<BTreeMap<ProgramId, WeakProgramHandle>, EbpfStateLock>,
46    maps: OrderedMutex<BTreeMap<BpfMapId, WeakMapWithType>, EbpfStateLock>,
47}
48
49impl EbpfState {
50    fn register_program<L>(&self, locked: &mut Locked<L>, program: &ProgramHandle)
51    where
52        L: LockBefore<EbpfStateLock>,
53    {
54        self.programs.lock(locked).insert(program.id(), Arc::downgrade(program));
55    }
56
57    fn unregister_program<L>(&self, locked: &mut Locked<L>, id: ProgramId)
58    where
59        L: LockBefore<EbpfStateLock>,
60    {
61        self.programs.lock(locked).remove(&id).expect("Missing eBPF program");
62    }
63
64    fn get_next_program_id<L>(
65        &self,
66        locked: &mut Locked<L>,
67        start_id: ProgramId,
68    ) -> Option<ProgramId>
69    where
70        L: LockBefore<EbpfStateLock>,
71    {
72        self.programs
73            .lock(locked)
74            .range((Bound::Excluded(start_id), Bound::Unbounded))
75            .next()
76            .map(|(k, _)| *k)
77    }
78
79    fn get_program_by_id<L>(&self, locked: &mut Locked<L>, id: ProgramId) -> Option<ProgramHandle>
80    where
81        L: LockBefore<EbpfStateLock>,
82    {
83        self.programs.lock(locked).get(&id).map(|p| p.upgrade()).flatten()
84    }
85
86    fn register_map<L>(&self, locked: &mut Locked<L>, map: &BpfMapHandle)
87    where
88        L: LockBefore<EbpfStateLock>,
89    {
90        self.maps.lock(locked).insert(map.id(), WeakMapWithType::new(map));
91    }
92
93    fn unregister_map<L>(&self, locked: &mut Locked<L>, id: BpfMapId)
94    where
95        L: LockBefore<EbpfStateLock>,
96    {
97        self.maps.lock(locked).remove(&id).expect("Missing eBPF map");
98    }
99
100    fn get_next_map_id<L>(&self, locked: &mut Locked<L>, start_id: BpfMapId) -> Option<BpfMapId>
101    where
102        L: LockBefore<EbpfStateLock>,
103    {
104        self.maps
105            .lock(locked)
106            .range((Bound::Excluded(start_id), Bound::Unbounded))
107            .next()
108            .map(|(k, _)| *k)
109    }
110
111    fn get_map_by_id<L>(&self, locked: &mut Locked<L>, id: BpfMapId) -> Option<BpfMapHandle>
112    where
113        L: LockBefore<EbpfStateLock>,
114    {
115        self.maps.lock(locked).get(&id).map(|entry| entry.weak_map.upgrade()).flatten()
116    }
117
118    /// Removed socket with the specified `cookie` from all `sk_storage` maps.
119    // TODO(https://fxbug.dev/496639039): Move sk_storage cleanup to Netstack.
120    pub fn remove_sk_storage_entries<L>(&self, locked: &mut Locked<L>, cookie: u64)
121    where
122        L: LockBefore<EbpfStateLock>,
123    {
124        self.maps.lock(locked).iter().for_each(|(_, entry)| {
125            if entry.map_type == bpf_map_type_BPF_MAP_TYPE_SK_STORAGE
126                && let Some(map) = entry.weak_map.upgrade()
127            {
128                let _ = map.delete(cookie.as_bytes());
129            }
130        });
131    }
132}