Skip to main content

netstack3_core/
context.rs

1// Copyright 2019 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//! Execution contexts.
6//!
7//! This module defines "context" traits, which allow code in this crate to be
8//! written agnostic to their execution context.
9//!
10//! All of the code in this crate operates in terms of "events". When an event
11//! occurs (for example, a packet is received, an application makes a request,
12//! or a timer fires), a function is called to handle that event. In response to
13//! that event, the code may wish to emit new events (for example, to send a
14//! packet, to respond to an application request, or to install a new timer).
15//! The traits in this module provide the ability to emit new events. For
16//! example, if, in order to handle some event, we need the ability to install
17//! new timers, then the function to handle that event would take a
18//! [`TimerContext`] parameter, which it could use to install new timers.
19//!
20//! Structuring code this way allows us to write code which is agnostic to
21//! execution context - a test fake or any number of possible "real-world"
22//! implementations of these traits all appear as indistinguishable, opaque
23//! trait implementations to our code.
24//!
25//! The benefits are deeper than this, though. Large units of code can be
26//! subdivided into smaller units that view each other as "contexts". For
27//! example, the ARP implementation in the [`crate::device::arp`] module defines
28//! the [`ArpContext`] trait, which is an execution context for ARP operations.
29//! It is implemented both by the test fakes in that module, and also by the
30//! Ethernet device implementation in the [`crate::device::ethernet`] module.
31//!
32//! This subdivision of code into small units in turn enables modularity. If,
33//! for example, the IP code sees transport layer protocols as execution
34//! contexts, then customizing which transport layer protocols are supported is
35//! just a matter of providing a different implementation of the transport layer
36//! context traits (this isn't what we do today, but we may in the future).
37
38use lock_order::Unlocked;
39
40use netstack3_base::ContextProvider;
41use netstack3_device as device;
42use netstack3_ip as ip;
43use netstack3_udp as udp;
44
45use crate::marker::{BindingsContext, BindingsTypes};
46use crate::state::StackState;
47
48// Enable all blanket implementations on CoreCtx.
49//
50// Some blanket implementations are enabled individually to sidestep coherence
51// issues with the fake context implementations in tests. We treat each of them
52// individually so it's easier to split things into separate crates and avoids
53// playing whack-a-mole with single markers that work for some traits/crates but
54// not others.
55impl<BC: BindingsContext, L> ip::marker::UseTransportIpContextBlanket for CoreCtx<'_, BC, L> {}
56impl<BC: BindingsContext, L> ip::marker::UseIpSocketContextBlanket for CoreCtx<'_, BC, L> {}
57impl<BC: BindingsContext, L> ip::marker::UseIpSocketHandlerBlanket for CoreCtx<'_, BC, L> {}
58impl<BC: BindingsContext, L> ip::marker::UseDeviceIpSocketHandlerBlanket for CoreCtx<'_, BC, L> {}
59impl<BC: BindingsContext, L> udp::UseUdpIpTransportContextBlanket for CoreCtx<'_, BC, L> {}
60impl<BC: BindingsContext, L> device::marker::UseArpFrameMetadataBlanket for CoreCtx<'_, BC, L> {}
61
62/// Provides access to core context implementations.
63///
64/// `L` is the current lock level of `CoreCtx`. The alias [`UnlockedCoreCtx`] is
65/// provided at the [`Unlocked`] level.
66pub type CoreCtx<'a, BT, L> = Locked<&'a StackState<BT>, L>;
67
68pub(crate) type CoreCtxAndResource<'a, BT, R, L> =
69    Locked<lock_order::OwnedTupleWrapper<&'a StackState<BT>, &'a R>, L>;
70
71/// An alias for an unlocked [`CoreCtx`].
72pub type UnlockedCoreCtx<'a, BT> = CoreCtx<'a, BT, Unlocked>;
73
74impl<'a, BT, L> ContextProvider for CoreCtx<'a, BT, L>
75where
76    BT: BindingsTypes,
77{
78    type Context = Self;
79
80    fn context(&mut self) -> &mut Self::Context {
81        self
82    }
83}
84
85pub(crate) use locked::{Locked, WrapLockLevel};
86
87/// Prelude import to enable the lock wrapper traits.
88pub(crate) mod prelude {
89    #[cfg(no_lock_order)]
90    pub(crate) use lock_order::wrap::disable::prelude::*;
91    #[cfg(not(no_lock_order))]
92    pub(crate) use lock_order::wrap::prelude::*;
93}
94
95/// Provides a crate-local wrapper for `[lock_order::Locked]`.
96///
97/// This module is intentionally private so usage is limited to the type alias
98/// in [`CoreCtx`].
99mod locked {
100    use super::{BindingsTypes, CoreCtx, StackState};
101
102    use core::ops::Deref;
103    use lock_order::wrap::LockedWrapper;
104    use lock_order::{Locked as ExternalLocked, TupleWrapper, Unlocked};
105
106    /// A crate-local wrapper on [`lock_order::Locked`].
107    pub struct Locked<T, L>(ExternalLocked<T, L>);
108
109    // SAFETY: This is only compiled when lock ordering is disabled.
110    unsafe impl<T, L> lock_order::wrap::disable::DisabledLockWrapper for Locked<T, L> {}
111
112    impl<T, L> LockedWrapper<T, L> for Locked<T, L>
113    where
114        T: Deref,
115        T::Target: Sized,
116    {
117        type AtLockLevel<'l, M>
118            = Locked<&'l T::Target, M>
119        where
120            M: 'l,
121            T: 'l;
122
123        type CastWrapper<X>
124            = Locked<X, L>
125        where
126            X: Deref,
127            X::Target: Sized;
128
129        fn wrap<'l, M>(locked: ExternalLocked<&'l T::Target, M>) -> Self::AtLockLevel<'l, M>
130        where
131            M: 'l,
132            T: 'l,
133        {
134            Locked(locked)
135        }
136
137        fn wrap_cast<R: Deref>(locked: ExternalLocked<R, L>) -> Self::CastWrapper<R>
138        where
139            R::Target: Sized,
140        {
141            Locked(locked)
142        }
143
144        fn get_mut(&mut self) -> &mut ExternalLocked<T, L> {
145            let Self(locked) = self;
146            locked
147        }
148
149        fn get(&self) -> &ExternalLocked<T, L> {
150            let Self(locked) = self;
151            locked
152        }
153    }
154
155    impl<'a, BT: BindingsTypes> CoreCtx<'a, BT, Unlocked> {
156        /// Creates a new `CoreCtx` from a borrowed [`StackState`].
157        pub fn new(stack_state: &'a StackState<BT>) -> Self {
158            Self(ExternalLocked::new(stack_state))
159        }
160    }
161
162    impl<'a, BT, R, L, T> Locked<T, L>
163    where
164        R: 'a,
165        T: Deref<Target = TupleWrapper<&'a StackState<BT>, &'a R>>,
166        BT: BindingsTypes,
167    {
168        pub(crate) fn cast_core_ctx(&mut self) -> CoreCtx<'_, BT, L> {
169            let Self(locked) = self;
170            crate::CoreCtx::<BT, L>::wrap(locked.cast_with(|c| c.left()))
171        }
172    }
173
174    /// Enables the [`WrapLockLevel`] type alias.
175    pub trait WrappedLockLevel {
176        type LockLevel;
177    }
178
179    impl<L> WrappedLockLevel for L {
180        /// All lock levels are actually [`Unlocked`].
181        #[cfg(no_lock_order)]
182        type LockLevel = Unlocked;
183        /// All lock levels are themselves.
184        #[cfg(not(no_lock_order))]
185        type LockLevel = L;
186    }
187
188    /// Wraps lock level `L` in [`WrappedLockLevel::LockLevel`], which allows
189    /// lock ordering to be disabled by build configuration.
190    ///
191    /// Whenever using a concrete instantiation of a lock level (i.e. not in a
192    /// `LockBefore` trait bound) it must be wrapped in `WrapLockLevel` for
193    /// compilation with `cfg(no_lock_order)` to succeed.
194    pub(crate) type WrapLockLevel<L> = <L as WrappedLockLevel>::LockLevel;
195}