1
1
use std:: {
2
2
env,
3
3
ffi:: CString ,
4
- net:: Ipv4Addr ,
5
4
os:: raw:: { c_char, c_void} ,
6
5
pin:: Pin ,
7
6
str:: FromStr ,
@@ -39,6 +38,7 @@ use crate::{
39
38
constants:: NVME_NQN_PREFIX ,
40
39
core:: {
41
40
nic,
41
+ nic:: SIpAddr ,
42
42
reactor:: { Reactor , ReactorState , Reactors } ,
43
43
Cores , MayastorFeatures , Mthread ,
44
44
} ,
@@ -101,6 +101,30 @@ fn parse_crdt(src: &str) -> Result<[u16; TARGET_CRDT_LEN], String> {
101
101
}
102
102
}
103
103
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
+
104
128
#[ derive( Debug , Clone , Parser ) ]
105
129
#[ clap(
106
130
name = package_description!( ) ,
@@ -112,9 +136,9 @@ pub struct MayastorCliArgs {
112
136
#[ deprecated = "Use grpc_ip and grpc_port instead" ]
113
137
/// IP address and port (optional) for the gRPC server to listen on.
114
138
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 ( ) ) ]
116
140
/// IP address for the gRPC server to listen on.
117
- pub grpc_ip : std :: net :: IpAddr ,
141
+ pub grpc_ip : SIpAddr ,
118
142
#[ clap( long, default_value_t = 10124 ) ]
119
143
/// Port for the gRPC server to listen on.
120
144
pub grpc_port : u16 ,
@@ -291,7 +315,7 @@ impl Default for MayastorCliArgs {
291
315
#[ allow( deprecated) ]
292
316
Self {
293
317
deprecated_grpc_endpoint : None ,
294
- grpc_ip : std:: net:: IpAddr :: V6 ( std :: net :: Ipv6Addr :: UNSPECIFIED ) ,
318
+ grpc_ip : std:: net:: Ipv6Addr :: UNSPECIFIED . into ( ) ,
295
319
grpc_port : 10124 ,
296
320
ps_endpoint : None ,
297
321
ps_timeout : Duration :: from_secs ( 10 ) ,
@@ -342,7 +366,8 @@ impl MayastorCliArgs {
342
366
if let Some ( deprecated_endpoint) = & self . deprecated_grpc_endpoint {
343
367
grpc:: endpoint_from_str ( deprecated_endpoint, self . grpc_port )
344
368
} 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 )
346
371
}
347
372
}
348
373
}
@@ -792,8 +817,8 @@ impl MayastorEnvironment {
792
817
}
793
818
794
819
/// 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 ( ) ;
797
822
TGT_IP
798
823
. get_or_try_init ( || match Self :: global_or_default ( ) . nvmf_tgt_interface {
799
824
Some ( ref iface) => Self :: detect_nvmf_tgt_iface_ip ( iface) ,
@@ -809,86 +834,90 @@ impl MayastorEnvironment {
809
834
810
835
/// Detects IP address for NVMF target by the interface specified in CLI
811
836
/// 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}' ..." ) ;
818
844
819
845
let ( cls, name) = match iface. split_once ( ':' ) {
820
846
Some ( p) => p,
821
847
None => ( "name" , iface) ,
822
848
} ;
823
849
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) ) ,
826
860
"mac" => {
827
861
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 ) )
829
863
}
830
864
"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) )
833
867
}
834
868
"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) )
837
871
}
838
872
_ => {
839
- return Err ( format ! ( "Invalid NVMF target interface: '{iface}'" , ) ) ;
873
+ return Err ( format ! ( "Invalid NVMF target interface: '{iface}'" ) ) ;
840
874
}
841
875
} ;
842
876
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) ) ;
844
879
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
+ } ?;
855
884
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}" ) ;
862
886
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" ,
866
891
res. name
867
- ) ) ;
892
+ ) ) ,
868
893
}
894
+ }
869
895
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
+ }
871
902
}
872
903
873
904
/// Detects pod IP address.
874
- fn detect_pod_ip ( ) -> Result < String , String > {
905
+ fn detect_pod_ip ( ) -> Result < SIpAddr , String > {
875
906
match env:: var ( "MY_POD_IP" ) {
876
907
Ok ( val) => {
877
908
info ! (
878
909
"Using 'MY_POD_IP' environment variable for IP address \
879
910
for NVMF target network interface"
880
911
) ;
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 ( ) )
884
917
} 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 ( ) )
889
919
}
890
920
}
891
- Err ( _) => Ok ( "127.0.0.1" . to_owned ( ) ) ,
892
921
}
893
922
}
894
923
0 commit comments