netstack3_ip/multicast_forwarding/
state.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//! Declares types and functionality related to multicast-forwarding state.
6
7use alloc::collections::BTreeMap;
8use derivative::Derivative;
9use lock_order::lock::{OrderedLockAccess, OrderedLockRef};
10use netstack3_base::sync::{Mutex, RwLock};
11use netstack3_base::{
12    AnyDevice, CoreTimerContext, CounterContext, DeviceIdContext, StrongDeviceIdentifier,
13};
14
15use crate::internal::multicast_forwarding::counters::MulticastForwardingCounters;
16use crate::internal::multicast_forwarding::packet_queue::MulticastForwardingPendingPackets;
17use crate::internal::multicast_forwarding::route::{MulticastRouteEntry, MulticastRouteKey};
18use crate::internal::multicast_forwarding::{
19    MulticastForwardingBindingsContext, MulticastForwardingBindingsTypes,
20    MulticastForwardingTimerId,
21};
22use crate::IpLayerIpExt;
23
24/// Multicast forwarding state for an IP version `I`.
25///
26/// Multicast forwarding can be enabled/disabled for `I` globally. When disabled
27/// no state is held.
28#[derive(Derivative)]
29#[derivative(Debug(bound = ""), Default(bound = ""))]
30pub enum MulticastForwardingState<
31    I: IpLayerIpExt,
32    D: StrongDeviceIdentifier,
33    BT: MulticastForwardingBindingsTypes,
34> {
35    /// Multicast forwarding is disabled.
36    #[derivative(Default)]
37    Disabled,
38    /// Multicast forwarding is enabled.
39    Enabled(MulticastForwardingEnabledState<I, D, BT>),
40}
41
42impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: MulticastForwardingBindingsTypes>
43    MulticastForwardingState<I, D, BT>
44{
45    pub(crate) fn enabled(&self) -> Option<&MulticastForwardingEnabledState<I, D, BT>> {
46        match self {
47            MulticastForwardingState::Disabled => None,
48            MulticastForwardingState::Enabled(state) => Some(state),
49        }
50    }
51}
52
53/// State held by the netstack when multicast forwarding is enabled for `I`.
54#[derive(Derivative)]
55#[derivative(Debug(bound = ""))]
56pub struct MulticastForwardingEnabledState<
57    I: IpLayerIpExt,
58    D: StrongDeviceIdentifier,
59    BT: MulticastForwardingBindingsTypes,
60> {
61    /// The stack's multicast route table.
62    ///
63    /// Keys here must not be present in `pending_table`.
64    route_table: RwLock<MulticastRouteTable<I, D, BT>>,
65    /// The stack's table of pending multicast packets.
66    ///
67    /// Keys here must not be present in `route_table`.
68    pending_table: Mutex<MulticastForwardingPendingPackets<I, D::Weak, BT>>,
69}
70
71impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BC: MulticastForwardingBindingsContext<I, D>>
72    MulticastForwardingEnabledState<I, D, BC>
73{
74    pub(super) fn new<CC>(bindings_ctx: &mut BC) -> Self
75    where
76        CC: CoreTimerContext<MulticastForwardingTimerId<I>, BC>,
77    {
78        Self {
79            route_table: Default::default(),
80            pending_table: Mutex::new(MulticastForwardingPendingPackets::new::<CC>(bindings_ctx)),
81        }
82    }
83
84    // Helper function to circumvent lock ordering, for tests.
85    #[cfg(test)]
86    pub(super) fn route_table(&self) -> &RwLock<MulticastRouteTable<I, D, BC>> {
87        &self.route_table
88    }
89    // Helper function to circumvent lock ordering, for tests.
90    #[cfg(test)]
91    pub(super) fn pending_table(
92        &self,
93    ) -> &Mutex<MulticastForwardingPendingPackets<I, D::Weak, BC>> {
94        &self.pending_table
95    }
96}
97
98/// A table of multicast routes specifying how to forward multicast packets.
99pub type MulticastRouteTable<I, D, BT> = BTreeMap<MulticastRouteKey<I>, MulticastRouteEntry<D, BT>>;
100
101impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: MulticastForwardingBindingsTypes>
102    OrderedLockAccess<MulticastRouteTable<I, D, BT>> for MulticastForwardingEnabledState<I, D, BT>
103{
104    type Lock = RwLock<MulticastRouteTable<I, D, BT>>;
105    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
106        OrderedLockRef::new(&self.route_table)
107    }
108}
109
110impl<I: IpLayerIpExt, D: StrongDeviceIdentifier, BT: MulticastForwardingBindingsTypes>
111    OrderedLockAccess<MulticastForwardingPendingPackets<I, D::Weak, BT>>
112    for MulticastForwardingEnabledState<I, D, BT>
113{
114    type Lock = Mutex<MulticastForwardingPendingPackets<I, D::Weak, BT>>;
115    fn ordered_lock_access(&self) -> OrderedLockRef<'_, Self::Lock> {
116        OrderedLockRef::new(&self.pending_table)
117    }
118}
119
120/// A trait providing access to [`MulticastForwardingState`].
121pub trait MulticastForwardingStateContext<I: IpLayerIpExt, BT: MulticastForwardingBindingsTypes>:
122    DeviceIdContext<AnyDevice>
123{
124    /// The context available after locking the multicast forwarding state.
125    type Ctx<'a>: MulticastRouteTableContext<
126            I,
127            BT,
128            DeviceId = Self::DeviceId,
129            WeakDeviceId = Self::WeakDeviceId,
130        > + MulticastForwardingPendingPacketsContext<
131            I,
132            BT,
133            DeviceId = Self::DeviceId,
134            WeakDeviceId = Self::WeakDeviceId,
135        > + CounterContext<MulticastForwardingCounters<I>>;
136    /// Provides immutable access to the state.
137    fn with_state<
138        O,
139        F: FnOnce(&MulticastForwardingState<I, Self::DeviceId, BT>, &mut Self::Ctx<'_>) -> O,
140    >(
141        &mut self,
142        cb: F,
143    ) -> O;
144    /// Provides mutable access to the state.
145    fn with_state_mut<
146        O,
147        F: FnOnce(&mut MulticastForwardingState<I, Self::DeviceId, BT>, &mut Self::Ctx<'_>) -> O,
148    >(
149        &mut self,
150        cb: F,
151    ) -> O;
152}
153
154/// A trait providing access to [`MulticastRouteTable`].
155pub trait MulticastRouteTableContext<I: IpLayerIpExt, BT: MulticastForwardingBindingsTypes>:
156    DeviceIdContext<AnyDevice>
157{
158    /// The context available after locking the multicast route table.
159    type Ctx<'a>: MulticastForwardingPendingPacketsContext<
160            I,
161            BT,
162            DeviceId = Self::DeviceId,
163            WeakDeviceId = Self::WeakDeviceId,
164        > + CounterContext<MulticastForwardingCounters<I>>;
165    /// Provides immutable access to the route table.
166    fn with_route_table<
167        O,
168        F: FnOnce(&MulticastRouteTable<I, Self::DeviceId, BT>, &mut Self::Ctx<'_>) -> O,
169    >(
170        &mut self,
171        state: &MulticastForwardingEnabledState<I, Self::DeviceId, BT>,
172        cb: F,
173    ) -> O;
174    /// Provides mutable access to the route table.
175    fn with_route_table_mut<
176        O,
177        F: FnOnce(&mut MulticastRouteTable<I, Self::DeviceId, BT>, &mut Self::Ctx<'_>) -> O,
178    >(
179        &mut self,
180        state: &MulticastForwardingEnabledState<I, Self::DeviceId, BT>,
181        cb: F,
182    ) -> O;
183}
184
185/// A trait providing access to [`MulticastForwardingPendingPackets`].
186pub trait MulticastForwardingPendingPacketsContext<
187    I: IpLayerIpExt,
188    BT: MulticastForwardingBindingsTypes,
189>: DeviceIdContext<AnyDevice>
190{
191    /// Provides mutable access to the table of pending packets.
192    fn with_pending_table_mut<
193        O,
194        F: FnOnce(&mut MulticastForwardingPendingPackets<I, Self::WeakDeviceId, BT>) -> O,
195    >(
196        &mut self,
197        state: &MulticastForwardingEnabledState<I, Self::DeviceId, BT>,
198        cb: F,
199    ) -> O;
200}