scion_sdk_address_manager/manager/
dto.rs

1// Copyright 2025 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//! Data transfer objects (DTOs) for the address registry.
15
16use std::time::Duration;
17
18use anyhow::Context;
19use scion_proto::address::IsdAsn;
20use serde::{Deserialize, Serialize};
21use utoipa::ToSchema;
22
23use crate::{
24    allocator::{AddressAllocator, dto::AddressAllocatorDto},
25    dto::IpNetDto,
26    manager::{AddressGrantEntry, AddressManager},
27};
28
29/// The data plane address registry.
30#[derive(Debug, Serialize, Deserialize, ToSchema, Clone)]
31pub struct AddressManagerDto {
32    /// The ISD-AS of the data plane.
33    pub isd_as: IsdAsn,
34    /// The duration for which an address is held.
35    pub hold_duration: Duration,
36    /// The list of address grants.
37    pub address_grants: Vec<AddressGrantDto>,
38    /// Bookkeeping of free IP addresses.
39    pub free_ips: AddressAllocatorDto,
40    /// The maximum number of attempts to allocate an address.
41    pub max_attempts: usize,
42    /// Prefixes this AddressManager is responsible for.
43    pub prefixes: Vec<IpNetDto>,
44}
45
46impl From<&AddressManager> for AddressManagerDto {
47    fn from(state: &AddressManager) -> Self {
48        AddressManagerDto {
49            isd_as: state.isd_as,
50            hold_duration: state.hold_duration,
51            address_grants: state.address_grants.values().map(|ag| ag.into()).collect(),
52            free_ips: (&state.free_ips).into(),
53            max_attempts: state.max_attempts,
54            prefixes: state.prefixes.iter().cloned().map(From::from).collect(),
55        }
56    }
57}
58
59impl TryFrom<AddressManagerDto> for AddressManager {
60    type Error = anyhow::Error;
61
62    fn try_from(value: AddressManagerDto) -> Result<Self, Self::Error> {
63        let address_grants = value
64            .address_grants
65            .into_iter()
66            .map(|ag| {
67                Ok((
68                    ag.endhost_addr.parse().context("invalid endhost address")?,
69                    AddressGrantEntry::try_from(ag).context("invalid address grant")?,
70                ))
71            })
72            .collect::<Result<_, Self::Error>>()?;
73
74        let free_ips = AddressAllocator::try_from(value.free_ips)?;
75
76        Ok(Self {
77            isd_as: value.isd_as,
78            hold_duration: value.hold_duration,
79            address_grants,
80            free_ips,
81            max_attempts: value.max_attempts,
82            prefixes: value
83                .prefixes
84                .into_iter()
85                .map(TryInto::try_into)
86                .collect::<Result<_, Self::Error>>()?,
87        })
88    }
89}
90/// An address grant.
91#[derive(Debug, Serialize, Deserialize, ToSchema, Clone)]
92pub struct AddressGrantDto {
93    /// The endhost address.
94    pub endhost_addr: String,
95    /// The ID of the token that was used to retrieve this address grant.
96    pub id: String,
97    /// The duration for which the grant is kept on hold.
98    pub on_hold_until: Option<Duration>,
99}
100
101impl TryFrom<AddressGrantDto> for AddressGrantEntry {
102    type Error = anyhow::Error;
103
104    fn try_from(value: AddressGrantDto) -> Result<Self, Self::Error> {
105        Ok(Self {
106            id: value.id,
107            on_hold_expiry: value.on_hold_until,
108            endhost_address: value
109                .endhost_addr
110                .parse()
111                .context("invalid endhost address")?,
112        })
113    }
114}
115
116impl From<&AddressGrantEntry> for AddressGrantDto {
117    fn from(rg: &AddressGrantEntry) -> Self {
118        AddressGrantDto {
119            endhost_addr: rg.endhost_address.to_string(),
120            id: rg.id.clone(),
121            on_hold_until: rg.on_hold_expiry,
122        }
123    }
124}