1use crate::graph::{NodeGraph, NodeId, Path, PathId};
6use fdf_component::{
7 driver_register, Driver, DriverContext, Node, NodeBuilder, ZirconServiceOffer,
8};
9use fidl::endpoints::ClientEnd;
10use fidl_fuchsia_driver_framework::NodeControllerMarker;
11use fidl_fuchsia_hardware_interconnect as icc;
12use fuchsia_component::server::ServiceFs;
13use fuchsia_sync::Mutex;
14use futures::{StreamExt, TryStreamExt};
15use log::{error, warn};
16use std::collections::BTreeMap;
17use std::sync::Arc;
18use zx::Status;
19
20mod graph;
21
22driver_register!(InterconnectDriver);
23
24struct Child {
25 path: Path,
27 graph: Arc<Mutex<NodeGraph>>,
30 #[allow(unused)]
31 controller: ClientEnd<NodeControllerMarker>,
32 device: icc::DeviceProxy,
33}
34
35impl Child {
36 async fn set_bandwidth(
37 &self,
38 average_bandwidth_bps: Option<u64>,
39 peak_bandwidth_bps: Option<u64>,
40 ) -> Result<(), Status> {
41 let average_bandwidth_bps = average_bandwidth_bps.ok_or(Status::INVALID_ARGS)?;
42 let peak_bandwidth_bps = peak_bandwidth_bps.ok_or(Status::INVALID_ARGS)?;
43
44 let requests = {
45 let mut graph = self.graph.lock();
46 graph.update_path(&self.path, average_bandwidth_bps, peak_bandwidth_bps);
47 graph.make_bandwidth_requests(&self.path)
48 };
49
50 self.device
51 .set_nodes_bandwidth(&requests)
52 .await
53 .map_err(|err| {
54 error!("Failed to set bandwidth with {err}");
55 Status::INTERNAL
56 })?
57 .map_err(Status::from_raw)?;
58
59 Ok(())
62 }
63
64 async fn run_path_server(&self, mut service: icc::PathRequestStream) {
65 use icc::PathRequest::*;
66 while let Some(req) = service.try_next().await.unwrap() {
67 match req {
68 SetBandwidth { payload, responder, .. } => responder.send(
69 self.set_bandwidth(payload.average_bandwidth_bps, payload.peak_bandwidth_bps)
70 .await
71 .map_err(Status::into_raw),
72 ),
73 _ => {
75 warn!("Received unknown path request");
76 Ok(())
77 }
78 }
79 .unwrap();
80 }
81 }
82}
83
84#[allow(unused)]
85struct InterconnectDriver {
86 node: Node,
87 children: Arc<BTreeMap<String, Child>>,
88 scope: fuchsia_async::Scope,
89}
90
91impl Driver for InterconnectDriver {
92 const NAME: &str = "interconnect";
93
94 async fn start(mut context: DriverContext) -> Result<Self, Status> {
95 let node = context.take_node()?;
96
97 let device = context
98 .incoming
99 .service_marker(icc::ServiceMarker)
100 .connect()?
101 .connect_to_device()
102 .map_err(|err| {
103 error!("Error connecting to interconnect device at driver startup: {err}");
104 Status::INTERNAL
105 })?;
106
107 let (nodes, edges) = device.get_node_graph().await.map_err(|err| {
108 error!("Failed to get node graph with {err}");
109 Status::INTERNAL
110 })?;
111 let mut graph = NodeGraph::new(nodes, edges)?;
112
113 let path_endpoints = device.get_path_endpoints().await.map_err(|err| {
114 error!("Failed to get path endpoints with {err}");
115 Status::INTERNAL
116 })?;
117 let paths: Vec<_> = Result::from_iter(path_endpoints.into_iter().map(|path| {
118 let path_id = PathId(path.id.ok_or(Status::INVALID_ARGS)?);
119 let path_name = path.name.ok_or(Status::INVALID_ARGS)?;
120 let src_node_id = NodeId(path.src_node_id.ok_or(Status::INVALID_ARGS)?);
121 let dst_node_id = NodeId(path.dst_node_id.ok_or(Status::INVALID_ARGS)?);
122 Ok::<_, Status>(graph.make_path(path_id, path_name, src_node_id, dst_node_id)?)
123 }))?;
124
125 let mut outgoing = ServiceFs::new();
126
127 let graph = Arc::new(Mutex::new(graph));
128 let mut children = BTreeMap::new();
129 for path in paths {
130 let name = format!("{}-{}", path.name(), path.id());
131 let name_clone = name.clone();
132 let offer = ZirconServiceOffer::new()
133 .add_default_named(&mut outgoing, &name, move |req| {
134 let icc::PathServiceRequest::Path(service) = req;
135 (service, name_clone.clone())
136 })
137 .build();
138
139 let node_args = NodeBuilder::new(&name)
140 .add_property(bind_fuchsia::BIND_INTERCONNECT_PATH_ID, path.id().0)
141 .add_offer(offer)
142 .build();
143 let controller = node.add_child(node_args).await?;
144 let graph = graph.clone();
145 let device = device.clone();
146 children.insert(name.clone(), Child { path, graph, controller, device });
147 }
148 context.serve_outgoing(&mut outgoing)?;
151
152 let children = Arc::new(children);
153
154 let scope = fuchsia_async::Scope::new_with_name("outgoing_directory");
155 let children_clone = children.clone();
156 scope.spawn_local(async move {
157 outgoing
158 .for_each_concurrent(None, move |(request, child_name)| {
159 let children = children_clone.clone();
160 async move {
161 if let Some(node) = children.get(&child_name) {
162 node.run_path_server(request).await;
163 } else {
164 error!("Failed to find child {child_name}");
165 }
166 }
167 })
168 .await;
169 });
170
171 Ok(Self { node, children, scope })
172 }
173
174 async fn stop(&self) {}
175}