Skip to content

Commit d2562b2

Browse files
author
mayastor-bors
committed
Try #1840:
2 parents 32cb19a + f7a81f5 commit d2562b2

File tree

6 files changed

+325
-109
lines changed

6 files changed

+325
-109
lines changed

io-engine/src/bin/io-engine.rs

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ fn start_tokio_runtime(args: &MayastorCliArgs) {
159159
Registration::init(
160160
&node_name,
161161
&node_nqn,
162+
// todo: handle scope ids?
162163
&grpc_socket_addr.to_string(),
163164
registration_addr,
164165
api_versions,

io-engine/src/core/env.rs

+81-52
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{
22
env,
33
ffi::CString,
4-
net::Ipv4Addr,
54
os::raw::{c_char, c_void},
65
pin::Pin,
76
str::FromStr,
@@ -39,6 +38,7 @@ use crate::{
3938
constants::NVME_NQN_PREFIX,
4039
core::{
4140
nic,
41+
nic::SIpAddr,
4242
reactor::{Reactor, ReactorState, Reactors},
4343
Cores, MayastorFeatures, Mthread,
4444
},
@@ -101,6 +101,30 @@ fn parse_crdt(src: &str) -> Result<[u16; TARGET_CRDT_LEN], String> {
101101
}
102102
}
103103

104+
/// Parses a grpc ip as a socket address.
105+
/// The port is ignored but we use the socket to keep the scope ip, which can be specified
106+
/// like so: `fe80::779c:c5ea:e9c5:2cc4%2`.
107+
/// # Warning
108+
/// Scope Ids are disabled for now as spdk posix sock seems to not format the traddr correctly
109+
/// when the endpoint has a scope id.
110+
fn parse_grpc_ip(src: &str) -> Result<SIpAddr, String> {
111+
let (ip, scope_ip) = match src.split_once('%') {
112+
Some(p) => p,
113+
None => (src, ""),
114+
};
115+
116+
match ip.parse::<std::net::IpAddr>() {
117+
Ok(ip) => match ip {
118+
std::net::IpAddr::V4(ip) => Ok(SIpAddr::from(ip)),
119+
std::net::IpAddr::V6(ip) if scope_ip.is_empty() => Ok(SIpAddr::from(ip)),
120+
std::net::IpAddr::V6(_) => Err(format!(
121+
"Ip '{src}' has a scope_id '{scope_ip}' which is not currently supported"
122+
)),
123+
},
124+
Err(error) => Err(format!("Invalid ip '{src}': {error}")),
125+
}
126+
}
127+
104128
#[derive(Debug, Clone, Parser)]
105129
#[clap(
106130
name = package_description!(),
@@ -112,9 +136,9 @@ pub struct MayastorCliArgs {
112136
#[deprecated = "Use grpc_ip and grpc_port instead"]
113137
/// IP address and port (optional) for the gRPC server to listen on.
114138
pub deprecated_grpc_endpoint: Option<String>,
115-
#[clap(long, default_value_t = std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED))]
139+
#[clap(long, value_parser = parse_grpc_ip, default_value_t = std::net::Ipv6Addr::UNSPECIFIED.into())]
116140
/// IP address for the gRPC server to listen on.
117-
pub grpc_ip: std::net::IpAddr,
141+
pub grpc_ip: SIpAddr,
118142
#[clap(long, default_value_t = 10124)]
119143
/// Port for the gRPC server to listen on.
120144
pub grpc_port: u16,
@@ -291,7 +315,7 @@ impl Default for MayastorCliArgs {
291315
#[allow(deprecated)]
292316
Self {
293317
deprecated_grpc_endpoint: None,
294-
grpc_ip: std::net::IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED),
318+
grpc_ip: std::net::Ipv6Addr::UNSPECIFIED.into(),
295319
grpc_port: 10124,
296320
ps_endpoint: None,
297321
ps_timeout: Duration::from_secs(10),
@@ -342,7 +366,8 @@ impl MayastorCliArgs {
342366
if let Some(deprecated_endpoint) = &self.deprecated_grpc_endpoint {
343367
grpc::endpoint_from_str(deprecated_endpoint, self.grpc_port)
344368
} else {
345-
std::net::SocketAddr::new(self.grpc_ip, self.grpc_port)
369+
// todo: scope ids are not properly supported on SPDK
370+
std::net::SocketAddr::new(self.grpc_ip.ip(), self.grpc_port)
346371
}
347372
}
348373
}
@@ -792,8 +817,8 @@ impl MayastorEnvironment {
792817
}
793818

794819
/// Returns NVMF target's IP address.
795-
pub(crate) fn get_nvmf_tgt_ip() -> Result<String, String> {
796-
static TGT_IP: OnceCell<String> = OnceCell::new();
820+
pub(crate) fn get_nvmf_tgt_ip() -> Result<SIpAddr, String> {
821+
static TGT_IP: OnceCell<SIpAddr> = OnceCell::new();
797822
TGT_IP
798823
.get_or_try_init(|| match Self::global_or_default().nvmf_tgt_interface {
799824
Some(ref iface) => Self::detect_nvmf_tgt_iface_ip(iface),
@@ -809,86 +834,90 @@ impl MayastorEnvironment {
809834

810835
/// Detects IP address for NVMF target by the interface specified in CLI
811836
/// arguments.
812-
fn detect_nvmf_tgt_iface_ip(iface: &str) -> Result<String, String> {
813-
info!(
814-
"Detecting IP address for NVMF target network interface \
815-
specified as '{}' ...",
816-
iface
817-
);
837+
fn detect_nvmf_tgt_iface_ip(iface: &str) -> Result<SIpAddr, String> {
838+
// In case of matching by name, mac or subnet, the adapter may have multiple ips, and
839+
// in this case how to prioritize them?
840+
// For now, we can at least match ipv4 or ipv6 to match the grpc.
841+
let env = MayastorEnvironment::global_or_default();
842+
let prefer_ipv4 = Self::prefer_ipv4(env.grpc_endpoint.expect("Should always be set"));
843+
info!("Detecting IP address (prefer ipv4: {prefer_ipv4}) for NVMF target network interface specified as '{iface}' ...");
818844

819845
let (cls, name) = match iface.split_once(':') {
820846
Some(p) => p,
821847
None => ("name", iface),
822848
};
823849

824-
let pred: Box<dyn Fn(&nic::Interface) -> bool> = match cls {
825-
"name" => Box::new(|n| n.name == name),
850+
let map_ok = |filter: bool, n: nic::Interface| -> Option<nic::Interface> {
851+
if filter {
852+
Some(n)
853+
} else {
854+
None
855+
}
856+
};
857+
858+
let pred: Box<dyn FnMut(nic::Interface) -> Option<nic::Interface>> = match cls {
859+
"name" => Box::new(|n| map_ok(n.name == name, n)),
826860
"mac" => {
827861
let mac = Some(name.parse::<nic::MacAddr>()?);
828-
Box::new(move |n| n.mac == mac)
862+
Box::new(move |n| map_ok(n.mac == mac, n))
829863
}
830864
"ip" => {
831-
let addr = Some(nic::parse_ipv4(name)?);
832-
Box::new(move |n| n.inet.addr == addr)
865+
let addr = nic::parse_ip(name)?;
866+
Box::new(move |n| n.matched_ip_kind(addr))
833867
}
834868
"subnet" => {
835-
let (subnet, mask) = nic::parse_ipv4_subnet(name)?;
836-
Box::new(move |n| n.ipv4_subnet_eq(subnet, mask))
869+
let (subnet, mask) = nic::parse_ip_subnet(name)?;
870+
Box::new(move |n| n.matched_subnet_kind(subnet, mask))
837871
}
838872
_ => {
839-
return Err(format!("Invalid NVMF target interface: '{iface}'",));
873+
return Err(format!("Invalid NVMF target interface: '{iface}'"));
840874
}
841875
};
842876

843-
let mut nics: Vec<_> = nic::find_all_nics().into_iter().filter(pred).collect();
877+
let mut nics: Vec<_> = nic::find_all_nics().into_iter().filter_map(pred).collect();
878+
nics.sort_by(|a, b| a.sort(b, prefer_ipv4));
844879

845-
if nics.is_empty() {
846-
return Err(format!("Network interface matching '{iface}' not found",));
847-
}
848-
849-
if nics.len() > 1 {
850-
return Err(format!(
851-
"Multiple network interfaces that \
852-
match '{iface}' are found",
853-
));
854-
}
880+
let res: nic::Interface = match nics.pop() {
881+
None => Err(format!("Network interface matching '{iface}' not found")),
882+
Some(nic) => Ok(nic),
883+
}?;
855884

856-
let res = nics.pop().unwrap();
857-
858-
info!(
859-
"NVMF target network interface '{}' matches to {}",
860-
iface, res
861-
);
885+
info!("NVMF target network interface '{iface}' matches to {res}");
862886

863-
if res.inet.addr.is_none() {
864-
return Err(format!(
865-
"Network interface '{}' has no IPv4 address configured",
887+
match res.ip(prefer_ipv4) {
888+
Some(ip) => Ok(ip),
889+
None => Err(format!(
890+
"Network interface '{}' has no IP address configured",
866891
res.name
867-
));
892+
)),
868893
}
894+
}
869895

870-
Ok(res.inet.addr.unwrap().to_string())
896+
fn prefer_ipv4(grpc: std::net::SocketAddr) -> bool {
897+
match grpc {
898+
std::net::SocketAddr::V4(_) => true,
899+
std::net::SocketAddr::V6(socket) if socket.ip().is_unspecified() => true,
900+
std::net::SocketAddr::V6(_) => false,
901+
}
871902
}
872903

873904
/// Detects pod IP address.
874-
fn detect_pod_ip() -> Result<String, String> {
905+
fn detect_pod_ip() -> Result<SIpAddr, String> {
875906
match env::var("MY_POD_IP") {
876907
Ok(val) => {
877908
info!(
878909
"Using 'MY_POD_IP' environment variable for IP address \
879910
for NVMF target network interface"
880911
);
881-
882-
if val.parse::<Ipv4Addr>().is_ok() {
883-
Ok(val)
912+
Ok(parse_grpc_ip(&val)?)
913+
}
914+
Err(_) => {
915+
if Self::prefer_ipv4(Self::global_or_default().grpc_endpoint.unwrap()) {
916+
Ok(std::net::Ipv4Addr::LOCALHOST.into())
884917
} else {
885-
Err(format!(
886-
"MY_POD_IP environment variable is set to an \
887-
invalid IPv4 address: '{val}'"
888-
))
918+
Ok(std::net::Ipv6Addr::LOCALHOST.into())
889919
}
890920
}
891-
Err(_) => Ok("127.0.0.1".to_owned()),
892921
}
893922
}
894923

io-engine/src/core/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub use env::{mayastor_env_stop, MayastorCliArgs, MayastorEnvironment, GLOBAL_RC
2424
pub use handle::{BdevHandle, UntypedBdevHandle};
2525
pub use io_device::IoDevice;
2626
pub use logical_volume::LogicalVolume;
27+
pub use nic::SIpAddr;
2728
pub use reactor::{reactor_monitor_loop, Reactor, ReactorState, Reactors, REACTOR_LIST};
2829

2930
pub use lock::{

0 commit comments

Comments
 (0)