nmstate/mptcp.rs
1// SPDX-License-Identifier: Apache-2.0
2
3// The document string for MptcpAddressFlag is copy from manpage of
4// `IP-MPTCP(8)` which is licensed under GPLv2.0+
5
6use serde::{Deserialize, Serialize};
7
8use crate::{BaseInterface, ErrorKind, MergedInterface, NmstateError};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
11#[serde(rename_all = "kebab-case", deny_unknown_fields)]
12#[non_exhaustive]
13pub struct MptcpConfig {
14 #[serde(skip_serializing_if = "Option::is_none")]
15 /// Automatically assign MPTCP flags to all valid IP addresses of this
16 /// interface including both static and dynamic ones.
17 pub address_flags: Option<Vec<MptcpAddressFlag>>,
18}
19
20#[derive(
21 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
22)]
23#[serde(rename_all = "kebab-case")]
24#[non_exhaustive]
25pub enum MptcpAddressFlag {
26 /// The endpoint will be announced/signaled to each peer via an MPTCP
27 /// ADD_ADDR sub-option. Upon reception of an ADD_ADDR sub-option, the
28 /// peer can try to create additional subflows. Cannot used along with
29 /// MptcpAddressFlag::Fullmesh as Linux kernel enforced.
30 Signal,
31 /// If additional subflow creation is allowed by the MPTCP limits, the
32 /// MPTCP path manager will try to create an additional subflow using
33 /// this endpoint as the source address after the MPTCP connection is
34 /// established.
35 Subflow,
36 /// If this is a subflow endpoint, the subflows created using this endpoint
37 /// will have the backup flag set during the connection process. This flag
38 /// instructs the peer to only send data on a given subflow when all
39 /// non-backup subflows are unavailable. This does not affect outgoing
40 /// data, where subflow priority is determined by the backup/non-backup
41 /// flag received from the peer.
42 Backup,
43 /// If this is a subflow endpoint and additional subflow creation is
44 /// allowed by the MPTCP limits, the MPTCP path manager will try to
45 /// create an additional subflow for each known peer address, using
46 /// this endpoint as the source address. This will occur after the
47 /// MPTCP connection is established. If the peer did not announce any
48 /// additional addresses using the MPTCP ADD_ADDR sub-option, this will
49 /// behave the same as a plain subflow endpoint. When the peer does
50 /// announce addresses, each received ADD_ADDR sub-option will trigger
51 /// creation of an additional subflow to generate a full mesh topology.
52 Fullmesh,
53}
54
55impl MergedInterface {
56 pub(crate) fn post_inter_ifaces_process_mptcp(
57 &self,
58 ) -> Result<(), NmstateError> {
59 if let Some(iface) = self.for_apply.as_ref().map(|i| i.base_iface()) {
60 if let Some(iface_flags) =
61 iface.mptcp.as_ref().and_then(|m| m.address_flags.as_ref())
62 && iface_flags.contains(&MptcpAddressFlag::Signal)
63 && iface_flags.contains(&MptcpAddressFlag::Fullmesh)
64 {
65 let e = NmstateError::new(
66 ErrorKind::InvalidArgument,
67 "MPTCP flags mustn't have both signal and fullmesh"
68 .to_string(),
69 );
70 log::error!("{e}");
71 return Err(e);
72 }
73 validate_iface_mptcp_and_addr_mptcp_flags(iface);
74 }
75
76 Ok(())
77 }
78}
79
80fn validate_iface_mptcp_and_addr_mptcp_flags(iface: &BaseInterface) {
81 let mut iface_flags =
82 match iface.mptcp.as_ref().and_then(|m| m.address_flags.as_ref()) {
83 Some(f) => f.clone(),
84 None => Vec::new(),
85 };
86 iface_flags.sort_unstable();
87
88 let empty_ip_addrs = Vec::new();
89
90 for ip_addr in iface
91 .ipv4
92 .as_ref()
93 .and_then(|i| i.addresses.as_ref())
94 .unwrap_or(&empty_ip_addrs)
95 .iter()
96 .chain(
97 iface
98 .ipv6
99 .as_ref()
100 .and_then(|i| i.addresses.as_ref())
101 .unwrap_or(&empty_ip_addrs)
102 .iter(),
103 )
104 {
105 if let Some(mut addr_flags) = ip_addr.mptcp_flags.as_ref().cloned() {
106 addr_flags.sort_unstable();
107 if iface_flags != addr_flags {
108 log::warn!(
109 "Nmstate does not support setting different MPTCP flags \
110 within the interface. Ignoring MPTCP flags {:?} of IP \
111 address {}/{} as it is different from interface level \
112 MPTCP flags {:?}",
113 addr_flags,
114 ip_addr.ip,
115 ip_addr.prefix_length,
116 iface_flags
117 );
118 }
119 }
120 }
121}