Skip to content

Commit d1710f5

Browse files
authored
Merge pull request #13 from ThinkParQ/rb/ipv6
Server nodes IPv6 support
2 parents 835d0ca + f62aa67 commit d1710f5

File tree

17 files changed

+523
-96
lines changed

17 files changed

+523
-96
lines changed

mgmtd/assets/beegfs-mgmtd.toml

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,35 @@
3737
# The private key file belonging to the above certificate.
3838
# tls-key-file = "/etc/beegfs/key.pem"
3939

40-
# Restricts network interfaces reported to other nodes for incoming BeeMsg communication.
41-
# The interfaces are reported in the given order. If not given, all suitable interfaces can be used.
42-
# interfaces = ["eth0", "eth1"]
40+
# Restricts and prioritizes network interfaces reported to other nodes for incoming BeeMsg
41+
# communication.
42+
#
43+
# Accepts a list of interface/nic filters. Interfaces can be filtered by name, address and protocol
44+
# (ipv4 or ipv6). Each filter entry has the form `[!] [<name>|*] [<addr>|*] [<protocol>|*]`, where
45+
# protocol can be "4" or "6". Each field can be set to "*" to match any value. Stars on the right
46+
# can be omitted. The order of the filter entries determines the priority of the interfaces as they
47+
# should be used by other nodes for BeeMsg communication. The first entry an interface matches is
48+
# that interfaces priority - the earlier the match, the higher the priority. Any interface that
49+
# doesn't match any entry is not reported and will thus not be contacted by other nodes. A single
50+
# `!` before the entry blacklists the matching interfaces - it is not reported even if a later entry
51+
# does match it.
52+
#
53+
# If not given, all suitable interfaces can be used and are reported in default order.
54+
#
55+
# EXAMPLES:
56+
#
57+
# * Prefer IPv6: ["* * 6", "* * 4"]
58+
# * IPv6 only: ["* * 6"]
59+
# * Only the eth0 interface using IPv6: ["eth0 * 6"]
60+
# * Prefer one IPv6 address, allow only IPv4 otherwise: ["* fd00::1", "* * 4"]
61+
# * Deny eth0 interface, allow everything else: ["! eth0", "*"]
62+
#
63+
# interfaces = ["*"]
64+
65+
# Prefers an interfaces ipv6 addresses over ipv4.
66+
# By default, ipv4 addresses are preferred. If the interface filter is given, the interface
67+
# order has higher priority than the address family, which is sorted per interface.
68+
# interfaces_prefer_ipv6 = false
4369

4470
# Maximum number of outgoing connections per node.
4571
# connection-limit = 12

mgmtd/src/bee_msg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ pub async fn notify_nodes<M: Msg + Serializable>(
194194
node_types: &'static [NodeType],
195195
msg: &M,
196196
) {
197-
log::trace!("NOTIFICATION to {:?}: {:?}", node_types, msg);
197+
log::trace!("NOTIFICATION to {node_types:?}: {msg:?}");
198198

199199
if let Err(err) = async {
200200
for t in node_types {

mgmtd/src/bee_msg/target.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ impl HandleWithResponse for SetStorageTargetInfo {
262262
})
263263
.await?;
264264

265-
log::debug!("Updated {:?} target info", node_type,);
265+
log::debug!("Updated {node_type:?} target info");
266266

267267
// in the old mgmtd, a notice to refresh cap pools is sent out here if a cap pool
268268
// changed I consider this being to expensive to check here and just don't

mgmtd/src/config.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use anyhow::{Context, Result, bail};
55
use clap::{Parser, ValueEnum};
66
use log::LevelFilter;
77
use serde::{Deserialize, Deserializer};
8+
use shared::nic::{self, NicFilter};
89
use shared::parser::{duration, integer_range};
910
use shared::types::{Port, QuotaId};
1011
use std::fmt::Debug;
@@ -203,14 +204,33 @@ generate_structs! {
203204
#[arg(value_name = "PATH")]
204205
tls_key_file: PathBuf = "/etc/beegfs/key.pem".into(),
205206

206-
/// Restricts network interfaces reported to other nodes for incoming BeeMsg communication.
207+
/// Restricts and prioritizes network interfaces reported to other nodes for incoming BeeMsg
208+
/// communication.
207209
///
208-
/// Accepts a comma separated list of interface names. They are reported in the given order. If
209-
/// not given, all suitable interfaces can be used.
210+
/// Accepts a comma separated list of interface/nic filters. Interfaces can be filtered by
211+
/// name, address and protocol (ipv4 or ipv6). Each filter entry has the form `[!] [<name>|*]
212+
/// [<addr>|*] [<protocol>|*]`, where protocol can be "4" or "6". Each field can be set to
213+
/// "*" to match any value. Stars on the right can be omitted. The order of the filter entries
214+
/// determines the priority of the interfaces as they should be used by other nodes for BeeMsg
215+
/// communication. The first entry an interface matches is that interfaces priority - the
216+
/// earlier the match, the higher the priority. Any interface that doesn't match any entry is
217+
/// not reported and will thus not be contacted by other nodes. A single `!` before the entry
218+
/// blacklists the matching interfaces - it is not reported even if a later entry does match it.
219+
///
220+
/// If not given, all suitable interfaces can be used and are reported in default order.
221+
///
222+
/// EXAMPLES:
223+
///
224+
/// * Prefer IPv6: `* * 6,* * 4`
225+
/// * IPv6 only: `* * 6`
226+
/// * Only the eth0 interface using IPv6: `eth0 * 6`
227+
/// * Prefer one IPv6 address, allow only IPv4 otherwise: `* fd00::1,* * 4`
228+
/// * Deny eth0 interface, allow everything else: `! eth0,*`
210229
#[arg(long)]
211-
#[arg(value_name = "NAMES")]
230+
#[arg(value_name = "FILTERS")]
212231
#[arg(value_delimiter = ',')]
213-
interfaces: Vec<String> = vec![],
232+
#[arg(value_parser = nic::NicFilter::parse)]
233+
interfaces: Vec<NicFilter> = vec![],
214234

215235
/// Maximum number of outgoing BeeMsg connections per node. [default: 12]
216236
#[arg(long)]
@@ -482,13 +502,13 @@ pub fn load_and_parse() -> Result<(Config, Vec<String>)> {
482502
let file_config: OptionalConfig =
483503
toml::from_str(toml_config).with_context(|| "Could not parse config file")?;
484504

485-
info_log.push(format!("Loaded config file from {:?}", config_file));
505+
info_log.push(format!("Loaded config file from {config_file:?}"));
486506
config.update_from_optional(file_config);
487507
}
488508
Err(err) => {
489509
if config_file != &config.config_file {
490510
return Err(err)
491-
.with_context(|| format!("Could not open config file at {:?}", config_file));
511+
.with_context(|| format!("Could not open config file at {config_file:?}"));
492512
}
493513

494514
info_log.push("No config file found at default location, ignoring".to_string());

mgmtd/src/db/import_v7.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,7 @@ fn quota(tx: &Transaction, quota_path: &Path) -> Result<()> {
374374

375375
quota_default_limits(tx, &e.path().join("quotaDefaultLimits.store"), pool_id)
376376
.with_context(|| {
377-
format!(
378-
"quota default limits ({}/quotaDefaultLimits.store)",
379-
pool_id
380-
)
377+
format!("quota default limits ({pool_id}/quotaDefaultLimits.store)")
381378
})?;
382379

383380
quota_limits(
@@ -386,15 +383,15 @@ fn quota(tx: &Transaction, quota_path: &Path) -> Result<()> {
386383
pool_id,
387384
QuotaIdType::User,
388385
)
389-
.with_context(|| format!("quota user limits ({}/quotaUserLimits.store)", pool_id))?;
386+
.with_context(|| format!("quota user limits ({pool_id}/quotaUserLimits.store)"))?;
390387

391388
quota_limits(
392389
tx,
393390
&e.path().join("quotaGroupLimits.store"),
394391
pool_id,
395392
QuotaIdType::Group,
396393
)
397-
.with_context(|| format!("quota group limits ({}/quotaGroupLimits.store)", pool_id))?;
394+
.with_context(|| format!("quota group limits ({pool_id}/quotaGroupLimits.store)"))?;
398395

399396
// We intentionally ignore the quota usage data - it is fetched and updated from the
400397
// nodes on a regular basis anyway.

mgmtd/src/db/target.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ mod test {
331331

332332
assert_eq!(19, targets.len());
333333

334-
assert!(targets.iter().any(|e| *e == new_target_id));
335-
assert!(targets.iter().any(|e| *e == 1000));
334+
assert!(targets.contains(&new_target_id));
335+
assert!(targets.contains(&1000));
336336
})
337337
}
338338
}

mgmtd/src/grpc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ pub(crate) fn serve(ctx: Context, mut shutdown: RunStateHandle) -> Result<()> {
181181
builder
182182
};
183183

184-
let serve_addr = SocketAddr::new("0.0.0.0".parse()?, ctx.info.user_config.grpc_port);
184+
let serve_addr = SocketAddr::new("::".parse()?, ctx.info.user_config.grpc_port);
185185

186186
let service = pm::management_server::ManagementServer::with_interceptor(
187187
ManagementService { ctx: ctx.clone() },

mgmtd/src/grpc/buddy_group.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ Primary result: {:?}, Secondary result: {:?}",
219219
.await?;
220220

221221
if execute {
222-
log::info!("Buddy group deleted: {}", group);
222+
log::info!("Buddy group deleted: {group}");
223223
}
224224

225225
Ok(pm::DeleteBuddyGroupResponse {

mgmtd/src/grpc/node.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use super::*;
22
use shared::bee_msg::node::RemoveNode;
3+
use std::net::{IpAddr, Ipv6Addr};
4+
use std::str::FromStr;
35

46
/// Delivers a list of nodes
57
pub(crate) async fn get(ctx: Context, req: pm::GetNodesRequest) -> Result<pm::GetNodesResponse> {
@@ -139,7 +141,11 @@ pub(crate) async fn get(ctx: Context, req: pm::GetNodesRequest) -> Result<pm::Ge
139141
.filter(|(uid, _)| node.id.as_ref().is_some_and(|e| e.uid == Some(*uid)))
140142
.cloned()
141143
.map(|(_, mut nic)| {
142-
nic.addr = format!("{}:{}", nic.addr, node.port);
144+
nic.addr = SocketAddr::new(
145+
IpAddr::from_str(&nic.addr).unwrap_or(Ipv6Addr::UNSPECIFIED.into()),
146+
node.port as u16,
147+
)
148+
.to_string();
143149
nic
144150
})
145151
.collect();

mgmtd/src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use anyhow::Result;
1818
use bee_msg::notify_nodes;
1919
use db::node_nic::ReplaceNic;
2020
use license::LicenseVerifier;
21-
use shared::NetworkAddr;
2221
use shared::bee_msg::target::RefreshTargetStates;
2322
use shared::conn::{Pool, incoming};
23+
use shared::nic::Nic;
2424
use shared::run_state::{self, RunStateControl};
2525
use shared::types::{AuthSecret, MGMTD_UID, NicType, NodeId, NodeType};
2626
use sqlite::TransactionExt;
@@ -39,7 +39,7 @@ use types::SqliteEnumExt;
3939
pub struct StaticInfo {
4040
pub user_config: Config,
4141
pub auth_secret: Option<AuthSecret>,
42-
pub network_addrs: Vec<NetworkAddr>,
42+
pub network_addrs: Vec<Nic>,
4343
}
4444

4545
/// Starts the management service.
@@ -63,7 +63,7 @@ pub async fn start(info: StaticInfo, license: LicenseVerifier) -> Result<RunCont
6363
// UDP socket for in- and outgoing messages
6464
let udp_socket = Arc::new(
6565
UdpSocket::bind(SocketAddr::new(
66-
"0.0.0.0".parse()?,
66+
"::0".parse()?,
6767
info.user_config.beemsg_port,
6868
))
6969
.await?,
@@ -94,7 +94,7 @@ pub async fn start(info: StaticInfo, license: LicenseVerifier) -> Result<RunCont
9494
MGMTD_UID,
9595
info.network_addrs.iter().map(|e| ReplaceNic {
9696
nic_type: NicType::Ethernet,
97-
addr: &e.addr,
97+
addr: &e.address,
9898
name: e.name.as_str().into(),
9999
}),
100100
)
@@ -122,7 +122,7 @@ pub async fn start(info: StaticInfo, license: LicenseVerifier) -> Result<RunCont
122122

123123
// Listen for incoming TCP connections
124124
incoming::listen_tcp(
125-
SocketAddr::new("0.0.0.0".parse()?, ctx.info.user_config.beemsg_port),
125+
SocketAddr::new("::0".parse()?, ctx.info.user_config.beemsg_port),
126126
ctx.clone(),
127127
info.auth_secret.is_some(),
128128
run_state.clone(),

0 commit comments

Comments
 (0)