snap_control/pg_wap.rs
1// Copyright 2026 Anapaya Systems
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! PathGuard WAP SNAP extension.
16//!
17//! The WAP control plane is assembled from four components:
18//!
19//! * [`grants::GrantManager`] - Manages which client IPs are authorized for which targets and
20//! segments, and when those authorizations expire.
21//! * [`segments::SegmentManager`] - Keeps public segments for the (src, dst) pairs in use fresh.
22//! * [`paths::PathManager`] - Combines public and granted segments into the single best path, and
23//! reports which segments it used.
24//! * [`uplinks::UplinkManager`] - Creates and manages one uplink per (path, WAG) pair, multiplexes
25//! SNI streams over it, refreshes its path, cleans it when unused or closed.
26//!
27//! Clients reach the control plane over the Connect RPC API in [`crpc`], which is where the
28//! authorizations that [`grants::GrantManager`] hands out come from.
29//!
30//! ## Time
31//!
32//! Every operation that depends on the current time takes it as a `now: SystemTime` argument, so
33//! all the decisions taken while serving one connection can be made against a single timestamp
34//! instead of drifting apart as the clock moves under them.
35//!
36//! The `run` maintenance loops are the exception: they own their cadence, so they read the wall
37//! clock themselves.
38
39use crate::pg_wap::{
40 grants::GrantManager,
41 paths::PathManager,
42 segments::SegmentManager,
43 uplinks::{UplinkEstablisher, UplinkManager},
44};
45
46pub mod crpc;
47pub mod grants;
48pub mod paths;
49pub mod segments;
50pub mod sni;
51pub mod uplinks;
52
53#[cfg(test)]
54mod test_util;
55
56/// The WAP control plane
57pub struct WapControlPlane<EstablisherType: UplinkEstablisher> {
58 /// Decides which client IP may reach which target over which private segments.
59 pub grant: GrantManager,
60 /// Public segments for all (src, dst) pairs currently in use.
61 pub segments: SegmentManager,
62 /// Combines public and granted segments into paths.
63 pub paths: PathManager,
64 /// Uplinks towards the WAGs, keyed by the (path, WAG) pair they were established for.
65 pub uplinks: UplinkManager<EstablisherType>,
66}
67impl<T: UplinkEstablisher> WapControlPlane<T> {
68 /// Creates a new WAP control plane.
69 pub fn new(
70 grant: GrantManager,
71 segments: SegmentManager,
72 paths: PathManager,
73 uplinks: UplinkManager<T>,
74 ) -> Self {
75 Self {
76 grant,
77 segments,
78 paths,
79 uplinks,
80 }
81 }
82
83 /// Runs the maintenance loops of every component that has one.
84 ///
85 /// Never returns, unless one of the loops panics.
86 pub async fn run(&self) {
87 tokio::join!(self.grant.run(), self.segments.run(), self.uplinks.run());
88 }
89}
90
91impl<T: UplinkEstablisher> Clone for WapControlPlane<T> {
92 fn clone(&self) -> Self {
93 Self {
94 grant: self.grant.clone(),
95 segments: self.segments.clone(),
96 paths: self.paths.clone(),
97 uplinks: self.uplinks.clone(),
98 }
99 }
100}