_driver_rustc/
graph.rs

1// Copyright 2025 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
5use fidl_fuchsia_hardware_interconnect as icc;
6use log::error;
7use std::collections::{BTreeMap, BTreeSet, VecDeque};
8use zx::Status;
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
11pub struct NodeId(pub u32);
12
13#[derive(Debug, PartialEq, Eq)]
14struct IncomingEdge {
15    /// Weight to use for finding optimal path.
16    weight: u32,
17}
18
19#[derive(Debug, PartialEq, Eq)]
20struct BandwidthRequest {
21    average_bandwidth_bps: u64,
22    peak_bandwidth_bps: u64,
23}
24
25#[derive(Debug, PartialEq, Eq)]
26struct InterconnectNode {
27    name: String,
28    id: NodeId,
29    /// List of nodes can send to this node.
30    incoming_edges: BTreeMap<NodeId, IncomingEdge>,
31    /// List of paths with bandwidth requests.
32    path_bandwidth_requests: BTreeMap<PathId, BandwidthRequest>,
33    initial_avg_bandwidth_bps: u64,
34    initial_peak_bandwidth_bps: u64,
35}
36
37#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
38pub struct PathId(pub u32);
39
40#[derive(Debug, PartialEq, Eq)]
41pub struct Path {
42    name: String,
43    id: PathId,
44    nodes: Vec<NodeId>,
45}
46
47impl Path {
48    pub fn name(&self) -> &str {
49        &self.name
50    }
51
52    pub fn id(&self) -> PathId {
53        self.id
54    }
55}
56
57#[derive(Debug, PartialEq, Eq)]
58pub struct NodeGraph {
59    /// Flattened graph. Each node maintains a list of incoming edges
60    /// from other nodes.
61    nodes: BTreeMap<NodeId, InterconnectNode>,
62}
63
64impl NodeGraph {
65    pub fn new(nodes: Vec<icc::Node>, edges: Vec<icc::Edge>) -> Result<Self, Status> {
66        // Parse data out of tables into structs.
67        struct ParsedNode {
68            id: NodeId,
69            name: String,
70            #[allow(unused)]
71            interconnect_name: Option<String>,
72            initial_avg_bandwidth_bps: u64,
73            initial_peak_bandwidth_bps: u64,
74        }
75        let nodes: Vec<_> = Result::from_iter(nodes.into_iter().map(|node| {
76            Ok::<_, Status>(ParsedNode {
77                id: NodeId(node.id.ok_or(Status::INVALID_ARGS)?),
78                name: node.name.ok_or(Status::INVALID_ARGS)?,
79                interconnect_name: node.interconnect_name,
80                initial_avg_bandwidth_bps: node.initial_avg_bandwidth_bps.unwrap_or(0),
81                initial_peak_bandwidth_bps: node.initial_peak_bandwidth_bps.unwrap_or(0),
82            })
83        }))?;
84
85        struct ParsedEdge {
86            src_node_id: NodeId,
87            dst_node_id: NodeId,
88            weight: u32,
89        }
90        let edges: Vec<_> = Result::from_iter(edges.into_iter().map(|edge| {
91            Ok::<_, Status>(ParsedEdge {
92                src_node_id: NodeId(edge.src_node_id.ok_or(Status::INVALID_ARGS)?),
93                dst_node_id: NodeId(edge.dst_node_id.ok_or(Status::INVALID_ARGS)?),
94                weight: edge.weight.unwrap_or(1),
95            })
96        }))?;
97
98        // Validate nodes and edges
99        let valid_node_ids: BTreeSet<_> = nodes.iter().map(|node| node.id).collect();
100        if valid_node_ids.len() != nodes.len() {
101            error!("Node list contains duplicate entries.");
102            return Err(Status::INVALID_ARGS);
103        }
104
105        let edge_pairs: BTreeSet<_> =
106            edges.iter().map(|edge| (edge.src_node_id, edge.dst_node_id)).collect();
107        if edge_pairs.len() != edges.len() {
108            error!("Edge list contains duplicate pairs of source to destination node ids.");
109            return Err(Status::INVALID_ARGS);
110        }
111
112        for edge in edges.iter() {
113            if !valid_node_ids.contains(&edge.src_node_id) {
114                error!("Edge contains an invalid src node id {:?}.", edge.src_node_id);
115                return Err(Status::INVALID_ARGS);
116            }
117            if !valid_node_ids.contains(&edge.dst_node_id) {
118                error!("Edge contains an invalid dst node id {:?}.", edge.dst_node_id);
119                return Err(Status::INVALID_ARGS);
120            }
121            if edge.src_node_id == edge.dst_node_id {
122                error!("Edge cannot have src and dst node ids be the same.");
123                return Err(Status::INVALID_ARGS);
124            }
125        }
126
127        // Extract nodes
128        let mut graph = BTreeMap::new();
129        for node in nodes {
130            // Note that it's possible to improve the time complexity of this algorithm by only
131            // iterating over the set of edges once rather than n times, but that would complicate
132            // the logic and the total number of edges is not anticipated to be large so it's not
133            // necessarily worthwhile.
134            let incoming_edges: BTreeMap<_, _> = edges
135                .iter()
136                .filter(|edge| edge.dst_node_id == node.id)
137                .map(|edge| (edge.src_node_id, IncomingEdge { weight: edge.weight }))
138                .collect();
139            graph.insert(
140                node.id,
141                InterconnectNode {
142                    name: node.name,
143                    id: node.id,
144                    incoming_edges,
145                    path_bandwidth_requests: BTreeMap::new(),
146                    initial_avg_bandwidth_bps: node.initial_avg_bandwidth_bps,
147                    initial_peak_bandwidth_bps: node.initial_peak_bandwidth_bps,
148                },
149            );
150        }
151
152        Ok(NodeGraph { nodes: graph })
153    }
154
155    /// Sets the edge from |dst_node_id| to |src_node_id| to the provided bandwidth values.
156    pub fn update_path(
157        &mut self,
158        path: &Path,
159        average_bandwidth_bps: u64,
160        peak_bandwidth_bps: u64,
161    ) {
162        for node in &path.nodes {
163            let node = self.nodes.get_mut(&node).expect("path is already validated");
164            let request = node
165                .path_bandwidth_requests
166                .get_mut(&path.id)
167                .expect("path was created from graph");
168            request.average_bandwidth_bps = average_bandwidth_bps;
169            request.peak_bandwidth_bps = peak_bandwidth_bps;
170        }
171    }
172
173    /// Creates a bandwidth request for the specified path where the bandwidth request includes
174    /// an entry for each path that intersects with this node.
175    pub fn make_bandwidth_requests(&self, path: &Path) -> Vec<icc::NodeBandwidth> {
176        path.nodes
177            .iter()
178            .map(|node_id| {
179                let node = self.nodes.get(&node_id).expect("path is already validated");
180                let requests: Vec<_> = node
181                    .path_bandwidth_requests
182                    .iter()
183                    .map(|(_, request)| icc::BandwidthRequest {
184                        average_bandwidth_bps: Some(request.average_bandwidth_bps),
185                        peak_bandwidth_bps: Some(request.peak_bandwidth_bps),
186                        ..Default::default()
187                    })
188                    .collect();
189                icc::NodeBandwidth {
190                    node_id: Some(node_id.0),
191                    requests: Some(requests),
192                    ..Default::default()
193                }
194            })
195            .collect()
196    }
197
198    /// Returns a path that includes provides a path between src and dst.
199    pub fn make_path(
200        &mut self,
201        path_id: PathId,
202        path_name: impl Into<String>,
203        src_node_id: NodeId,
204        dst_node_id: NodeId,
205    ) -> Result<Path, Status> {
206        let mut queue = VecDeque::new();
207        // The graph is not guaranteed to be acyclic, so we need to avoid revisiting nodes.
208        let mut visited = BTreeSet::new();
209        queue.push_back((dst_node_id, Vec::new()));
210        // TODO(https://fxbug.dev/415837761): Update algorithm to take into account edge weights.
211        while let Some((node_id, mut path)) = queue.pop_front() {
212            if visited.contains(&node_id) {
213                continue;
214            }
215            visited.insert(node_id);
216            path.push(node_id);
217            if node_id == src_node_id {
218                path.reverse();
219                // Ensure there is no duplicates before inserting.
220                for node_id in path.iter() {
221                    let node = self.nodes.get(&node_id).unwrap();
222                    if node.path_bandwidth_requests.contains_key(&path_id) {
223                        error!("Duplicate path id {path_id:?}");
224                        return Err(Status::ALREADY_EXISTS);
225                    }
226                }
227                for node_id in path.iter() {
228                    let node = self.nodes.get_mut(&node_id).unwrap();
229                    node.path_bandwidth_requests.insert(
230                        path_id,
231                        BandwidthRequest {
232                            average_bandwidth_bps: node.initial_avg_bandwidth_bps,
233                            peak_bandwidth_bps: node.initial_peak_bandwidth_bps,
234                        },
235                    );
236                }
237                return Ok(Path { name: path_name.into(), id: path_id, nodes: path });
238            }
239            // We've already validated that all node ids are valid.
240            for (node_id, _) in &self.nodes.get(&node_id).unwrap().incoming_edges {
241                queue.push_back((*node_id, path.clone()));
242            }
243        }
244        error!("Path between {src_node_id:?} and {dst_node_id:?} not found");
245        Err(Status::NOT_FOUND)
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252
253    #[fuchsia::test]
254    fn test_node_graph_simple() {
255        let nodes = vec![
256            icc::Node {
257                id: Some(0),
258                name: Some("zero".to_string()),
259                interconnect_name: None,
260                ..Default::default()
261            },
262            icc::Node {
263                id: Some(1),
264                name: Some("one".to_string()),
265                interconnect_name: None,
266                ..Default::default()
267            },
268        ];
269        let edges = vec![icc::Edge {
270            src_node_id: Some(0),
271            dst_node_id: Some(1),
272            weight: None,
273            ..Default::default()
274        }];
275        let graph = NodeGraph::new(nodes, edges).unwrap();
276        assert_eq!(
277            graph,
278            NodeGraph {
279                nodes: BTreeMap::from([
280                    (
281                        NodeId(0),
282                        InterconnectNode {
283                            name: "zero".to_string(),
284                            id: NodeId(0),
285                            incoming_edges: BTreeMap::new(),
286                            path_bandwidth_requests: BTreeMap::new(),
287                            initial_avg_bandwidth_bps: 0,
288                            initial_peak_bandwidth_bps: 0,
289                        }
290                    ),
291                    (
292                        NodeId(1),
293                        InterconnectNode {
294                            name: "one".to_string(),
295                            id: NodeId(1),
296                            incoming_edges: BTreeMap::from([(
297                                NodeId(0),
298                                IncomingEdge { weight: 1 }
299                            )]),
300                            path_bandwidth_requests: BTreeMap::new(),
301                            initial_avg_bandwidth_bps: 0,
302                            initial_peak_bandwidth_bps: 0,
303                        }
304                    ),
305                ]),
306            }
307        );
308    }
309
310    #[fuchsia::test]
311    fn test_node_graph_missing_id() {
312        let nodes = vec![
313            icc::Node {
314                id: None,
315                name: Some("zero".to_string()),
316                interconnect_name: None,
317                ..Default::default()
318            },
319            icc::Node {
320                id: Some(1),
321                name: Some("one".to_string()),
322                interconnect_name: None,
323                ..Default::default()
324            },
325        ];
326        let edges = vec![icc::Edge {
327            src_node_id: Some(0),
328            dst_node_id: Some(1),
329            weight: Some(1),
330            ..Default::default()
331        }];
332        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
333    }
334
335    #[fuchsia::test]
336    fn test_node_graph_missing_name() {
337        let nodes = vec![
338            icc::Node { id: Some(0), name: None, interconnect_name: None, ..Default::default() },
339            icc::Node {
340                id: Some(1),
341                name: Some("one".to_string()),
342                interconnect_name: None,
343                ..Default::default()
344            },
345        ];
346        let edges = vec![icc::Edge {
347            src_node_id: Some(0),
348            dst_node_id: Some(1),
349            weight: Some(1),
350            ..Default::default()
351        }];
352        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
353    }
354
355    #[fuchsia::test]
356    fn test_node_graph_missing_src() {
357        let nodes = vec![
358            icc::Node {
359                id: Some(0),
360                name: Some("zero".to_string()),
361                interconnect_name: None,
362                ..Default::default()
363            },
364            icc::Node {
365                id: Some(1),
366                name: Some("one".to_string()),
367                interconnect_name: None,
368                ..Default::default()
369            },
370        ];
371        let edges = vec![icc::Edge {
372            src_node_id: None,
373            dst_node_id: Some(1),
374            weight: Some(1),
375            ..Default::default()
376        }];
377        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
378    }
379
380    #[fuchsia::test]
381    fn test_node_graph_missing_dst() {
382        let nodes = vec![
383            icc::Node {
384                id: Some(0),
385                name: Some("zero".to_string()),
386                interconnect_name: None,
387                ..Default::default()
388            },
389            icc::Node {
390                id: Some(1),
391                name: Some("one".to_string()),
392                interconnect_name: None,
393                ..Default::default()
394            },
395        ];
396        let edges = vec![icc::Edge {
397            src_node_id: Some(0),
398            dst_node_id: None,
399            weight: Some(1),
400            ..Default::default()
401        }];
402        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
403    }
404
405    #[fuchsia::test]
406    fn test_node_graph_invalid_edge() {
407        let nodes = vec![
408            icc::Node {
409                id: Some(0),
410                name: Some("zero".to_string()),
411                interconnect_name: None,
412                ..Default::default()
413            },
414            icc::Node {
415                id: Some(1),
416                name: Some("one".to_string()),
417                interconnect_name: None,
418                ..Default::default()
419            },
420        ];
421        let edges = vec![icc::Edge {
422            src_node_id: Some(0),
423            dst_node_id: Some(0),
424            weight: Some(1),
425            ..Default::default()
426        }];
427        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
428    }
429
430    #[fuchsia::test]
431    fn test_node_graph_missing_dst_node() {
432        let nodes = vec![icc::Node {
433            id: Some(0),
434            name: Some("zero".to_string()),
435            interconnect_name: None,
436            ..Default::default()
437        }];
438        let edges = vec![icc::Edge {
439            src_node_id: Some(0),
440            dst_node_id: Some(1),
441            weight: Some(1),
442            ..Default::default()
443        }];
444        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
445    }
446
447    #[fuchsia::test]
448    fn test_node_graph_missing_src_node() {
449        let nodes = vec![icc::Node {
450            id: Some(0),
451            name: Some("zero".to_string()),
452            interconnect_name: None,
453            ..Default::default()
454        }];
455        let edges = vec![icc::Edge {
456            src_node_id: Some(1),
457            dst_node_id: Some(0),
458            weight: Some(1),
459            ..Default::default()
460        }];
461        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
462    }
463
464    #[fuchsia::test]
465    fn test_node_graph_missing_duplicate_node() {
466        let nodes = vec![
467            icc::Node {
468                id: Some(0),
469                name: Some("zero".to_string()),
470                interconnect_name: None,
471                ..Default::default()
472            },
473            icc::Node {
474                id: Some(0),
475                name: Some("zero-2".to_string()),
476                interconnect_name: None,
477                ..Default::default()
478            },
479            icc::Node {
480                id: Some(1),
481                name: Some("one".to_string()),
482                interconnect_name: None,
483                ..Default::default()
484            },
485        ];
486        let edges = vec![icc::Edge {
487            src_node_id: Some(0),
488            dst_node_id: Some(1),
489            weight: Some(1),
490            ..Default::default()
491        }];
492        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
493    }
494
495    #[fuchsia::test]
496    fn test_node_graph_missing_duplicate_edge() {
497        let nodes = vec![
498            icc::Node {
499                id: Some(0),
500                name: Some("zero".to_string()),
501                interconnect_name: None,
502                ..Default::default()
503            },
504            icc::Node {
505                id: Some(1),
506                name: Some("one".to_string()),
507                interconnect_name: None,
508                ..Default::default()
509            },
510        ];
511        let edges = vec![
512            icc::Edge {
513                src_node_id: Some(0),
514                dst_node_id: Some(1),
515                weight: Some(1),
516                ..Default::default()
517            },
518            icc::Edge {
519                src_node_id: Some(0),
520                dst_node_id: Some(1),
521                weight: Some(4),
522                ..Default::default()
523            },
524        ];
525        assert_eq!(NodeGraph::new(nodes, edges), Err(Status::INVALID_ARGS));
526    }
527
528    #[fuchsia::test]
529    fn test_node_graph_complex() {
530        let nodes = vec![
531            icc::Node {
532                id: Some(0),
533                name: Some("zero".to_string()),
534                interconnect_name: None,
535                ..Default::default()
536            },
537            icc::Node {
538                id: Some(1),
539                name: Some("one".to_string()),
540                interconnect_name: None,
541                ..Default::default()
542            },
543            icc::Node {
544                id: Some(2),
545                name: Some("two".to_string()),
546                interconnect_name: None,
547                ..Default::default()
548            },
549            icc::Node {
550                id: Some(3),
551                name: Some("three".to_string()),
552                interconnect_name: None,
553                ..Default::default()
554            },
555        ];
556        let edges = vec![
557            icc::Edge {
558                src_node_id: Some(0),
559                dst_node_id: Some(1),
560                weight: Some(1),
561                ..Default::default()
562            },
563            icc::Edge {
564                src_node_id: Some(1),
565                dst_node_id: Some(2),
566                weight: Some(1),
567                ..Default::default()
568            },
569            icc::Edge {
570                src_node_id: Some(1),
571                dst_node_id: Some(3),
572                weight: Some(1),
573                ..Default::default()
574            },
575            icc::Edge {
576                src_node_id: Some(2),
577                dst_node_id: Some(1),
578                weight: Some(1),
579                ..Default::default()
580            },
581        ];
582        let graph = NodeGraph::new(nodes, edges).unwrap();
583        assert_eq!(
584            graph,
585            NodeGraph {
586                nodes: BTreeMap::from([
587                    (
588                        NodeId(0),
589                        InterconnectNode {
590                            name: "zero".to_string(),
591                            id: NodeId(0),
592                            incoming_edges: BTreeMap::new(),
593                            path_bandwidth_requests: BTreeMap::new(),
594                            initial_avg_bandwidth_bps: 0,
595                            initial_peak_bandwidth_bps: 0,
596                        }
597                    ),
598                    (
599                        NodeId(1),
600                        InterconnectNode {
601                            name: "one".to_string(),
602                            id: NodeId(1),
603                            incoming_edges: BTreeMap::from([
604                                (NodeId(0), IncomingEdge { weight: 1 }),
605                                (NodeId(2), IncomingEdge { weight: 1 }),
606                            ]),
607                            path_bandwidth_requests: BTreeMap::new(),
608                            initial_avg_bandwidth_bps: 0,
609                            initial_peak_bandwidth_bps: 0,
610                        }
611                    ),
612                    (
613                        NodeId(2),
614                        InterconnectNode {
615                            name: "two".to_string(),
616                            id: NodeId(2),
617                            incoming_edges: BTreeMap::from([(
618                                NodeId(1),
619                                IncomingEdge { weight: 1 }
620                            )]),
621                            path_bandwidth_requests: BTreeMap::new(),
622                            initial_avg_bandwidth_bps: 0,
623                            initial_peak_bandwidth_bps: 0,
624                        }
625                    ),
626                    (
627                        NodeId(3),
628                        InterconnectNode {
629                            name: "three".to_string(),
630                            id: NodeId(3),
631                            incoming_edges: BTreeMap::from([(
632                                NodeId(1),
633                                IncomingEdge { weight: 1 }
634                            )]),
635                            path_bandwidth_requests: BTreeMap::new(),
636                            initial_avg_bandwidth_bps: 0,
637                            initial_peak_bandwidth_bps: 0,
638                        }
639                    ),
640                ]),
641            }
642        );
643    }
644
645    #[fuchsia::test]
646    fn test_find_full_path() {
647        let nodes = vec![
648            icc::Node {
649                id: Some(0),
650                name: Some("zero".to_string()),
651                interconnect_name: None,
652                ..Default::default()
653            },
654            icc::Node {
655                id: Some(1),
656                name: Some("one".to_string()),
657                interconnect_name: None,
658                ..Default::default()
659            },
660            icc::Node {
661                id: Some(2),
662                name: Some("two".to_string()),
663                interconnect_name: None,
664                ..Default::default()
665            },
666            icc::Node {
667                id: Some(3),
668                name: Some("three".to_string()),
669                interconnect_name: None,
670                ..Default::default()
671            },
672        ];
673        let edges = vec![
674            icc::Edge {
675                src_node_id: Some(0),
676                dst_node_id: Some(1),
677                weight: Some(1),
678                ..Default::default()
679            },
680            icc::Edge {
681                src_node_id: Some(1),
682                dst_node_id: Some(2),
683                weight: Some(1),
684                ..Default::default()
685            },
686            icc::Edge {
687                src_node_id: Some(1),
688                dst_node_id: Some(3),
689                weight: Some(1),
690                ..Default::default()
691            },
692            icc::Edge {
693                src_node_id: Some(2),
694                dst_node_id: Some(1),
695                weight: Some(1),
696                ..Default::default()
697            },
698        ];
699        let mut graph = NodeGraph::new(nodes, edges).unwrap();
700
701        static PATH_NAME: &str = "";
702
703        let path = graph.make_path(PathId(0), PATH_NAME, NodeId(0), NodeId(2)).unwrap();
704        assert_eq!(
705            path,
706            Path {
707                id: PathId(0),
708                name: PATH_NAME.to_string(),
709                nodes: vec![NodeId(0), NodeId(1), NodeId(2)]
710            }
711        );
712        assert_eq!(
713            graph.make_path(PathId(1), PATH_NAME, NodeId(0), NodeId(3)),
714            Ok(Path {
715                id: PathId(1),
716                name: PATH_NAME.to_string(),
717                nodes: vec![NodeId(0), NodeId(1), NodeId(3)],
718            })
719        );
720        assert_eq!(
721            graph.make_path(PathId(2), PATH_NAME, NodeId(2), NodeId(3)),
722            Ok(Path {
723                id: PathId(2),
724                name: PATH_NAME.to_string(),
725                nodes: vec![NodeId(2), NodeId(1), NodeId(3)]
726            })
727        );
728        assert_eq!(
729            graph.make_path(PathId(2), PATH_NAME, NodeId(2), NodeId(3)),
730            Err(Status::ALREADY_EXISTS)
731        );
732        assert_eq!(
733            graph.make_path(PathId(3), PATH_NAME, NodeId(1), NodeId(0)),
734            Err(Status::NOT_FOUND)
735        );
736        assert_eq!(
737            graph.make_path(PathId(4), PATH_NAME, NodeId(2), NodeId(0)),
738            Err(Status::NOT_FOUND)
739        );
740        assert_eq!(
741            graph.make_path(PathId(5), PATH_NAME, NodeId(3), NodeId(2)),
742            Err(Status::NOT_FOUND)
743        );
744
745        graph.update_path(&path, 100, 500);
746
747        assert_eq!(
748            graph.make_bandwidth_requests(&path),
749            vec![
750                icc::NodeBandwidth {
751                    node_id: Some(0),
752                    requests: Some(vec![
753                        icc::BandwidthRequest {
754                            average_bandwidth_bps: Some(100),
755                            peak_bandwidth_bps: Some(500),
756                            ..Default::default()
757                        },
758                        icc::BandwidthRequest {
759                            average_bandwidth_bps: Some(0),
760                            peak_bandwidth_bps: Some(0),
761                            ..Default::default()
762                        },
763                    ]),
764                    ..Default::default()
765                },
766                icc::NodeBandwidth {
767                    node_id: Some(1),
768                    requests: Some(vec![
769                        icc::BandwidthRequest {
770                            average_bandwidth_bps: Some(100),
771                            peak_bandwidth_bps: Some(500),
772                            ..Default::default()
773                        },
774                        icc::BandwidthRequest {
775                            average_bandwidth_bps: Some(0),
776                            peak_bandwidth_bps: Some(0),
777                            ..Default::default()
778                        },
779                        icc::BandwidthRequest {
780                            average_bandwidth_bps: Some(0),
781                            peak_bandwidth_bps: Some(0),
782                            ..Default::default()
783                        },
784                    ]),
785                    ..Default::default()
786                },
787                icc::NodeBandwidth {
788                    node_id: Some(2),
789                    requests: Some(vec![
790                        icc::BandwidthRequest {
791                            average_bandwidth_bps: Some(100),
792                            peak_bandwidth_bps: Some(500),
793                            ..Default::default()
794                        },
795                        icc::BandwidthRequest {
796                            average_bandwidth_bps: Some(0),
797                            peak_bandwidth_bps: Some(0),
798                            ..Default::default()
799                        },
800                    ]),
801                    ..Default::default()
802                },
803            ]
804        );
805    }
806}