11use 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 ,
@@ -289,7 +313,7 @@ impl Default for MayastorCliArgs {
289313 #[ allow( deprecated) ]
290314 Self {
291315 deprecated_grpc_endpoint : None ,
292- grpc_ip : std:: net:: IpAddr :: V6 ( std :: net :: Ipv6Addr :: UNSPECIFIED ) ,
316+ grpc_ip : std:: net:: Ipv6Addr :: UNSPECIFIED . into ( ) ,
293317 grpc_port : 10124 ,
294318 ps_endpoint : None ,
295319 ps_timeout : Duration :: from_secs ( 10 ) ,
@@ -340,7 +364,8 @@ impl MayastorCliArgs {
340364 if let Some ( deprecated_endpoint) = & self . deprecated_grpc_endpoint {
341365 grpc:: endpoint_from_str ( deprecated_endpoint, self . grpc_port )
342366 } else {
343- std:: net:: SocketAddr :: new ( self . grpc_ip , self . grpc_port )
367+ // todo: scope ids are not properly supported on SPDK
368+ std:: net:: SocketAddr :: new ( self . grpc_ip . ip ( ) , self . grpc_port )
344369 }
345370 }
346371}
@@ -790,8 +815,8 @@ impl MayastorEnvironment {
790815 }
791816
792817 /// Returns NVMF target's IP address.
793- pub ( crate ) fn get_nvmf_tgt_ip ( ) -> Result < String , String > {
794- static TGT_IP : OnceCell < String > = OnceCell :: new ( ) ;
818+ pub ( crate ) fn get_nvmf_tgt_ip ( ) -> Result < SIpAddr , String > {
819+ static TGT_IP : OnceCell < SIpAddr > = OnceCell :: new ( ) ;
795820 TGT_IP
796821 . get_or_try_init ( || match Self :: global_or_default ( ) . nvmf_tgt_interface {
797822 Some ( ref iface) => Self :: detect_nvmf_tgt_iface_ip ( iface) ,
@@ -807,86 +832,90 @@ impl MayastorEnvironment {
807832
808833 /// Detects IP address for NVMF target by the interface specified in CLI
809834 /// arguments.
810- fn detect_nvmf_tgt_iface_ip ( iface : & str ) -> Result < String , String > {
811- info ! (
812- "Detecting IP address for NVMF target network interface \
813- specified as '{}' ...",
814- iface
815- ) ;
835+ fn detect_nvmf_tgt_iface_ip ( iface : & str ) -> Result < SIpAddr , String > {
836+ // In case of matching by name, mac or subnet, the adapter may have multiple ips, and
837+ // in this case how to prioritize them?
838+ // For now, we can at least match ipv4 or ipv6 to match the grpc.
839+ let env = MayastorEnvironment :: global_or_default ( ) ;
840+ let prefer_ipv4 = Self :: prefer_ipv4 ( env. grpc_endpoint . expect ( "Should always be set" ) ) ;
841+ info ! ( "Detecting IP address (prefer ipv4: {prefer_ipv4}) for NVMF target network interface specified as '{iface}' ..." ) ;
816842
817843 let ( cls, name) = match iface. split_once ( ':' ) {
818844 Some ( p) => p,
819845 None => ( "name" , iface) ,
820846 } ;
821847
822- let pred: Box < dyn Fn ( & nic:: Interface ) -> bool > = match cls {
823- "name" => Box :: new ( |n| n. name == name) ,
848+ let map_ok = |filter : bool , n : nic:: Interface | -> Option < nic:: Interface > {
849+ if filter {
850+ Some ( n)
851+ } else {
852+ None
853+ }
854+ } ;
855+
856+ let pred: Box < dyn FnMut ( nic:: Interface ) -> Option < nic:: Interface > > = match cls {
857+ "name" => Box :: new ( |n| map_ok ( n. name == name, n) ) ,
824858 "mac" => {
825859 let mac = Some ( name. parse :: < nic:: MacAddr > ( ) ?) ;
826- Box :: new ( move |n| n. mac == mac)
860+ Box :: new ( move |n| map_ok ( n. mac == mac, n ) )
827861 }
828862 "ip" => {
829- let addr = Some ( nic:: parse_ipv4 ( name) ?) ;
830- Box :: new ( move |n| n. inet . addr == addr )
863+ let addr = nic:: parse_ip ( name) ?;
864+ Box :: new ( move |n| n. matched_ip_kind ( addr) )
831865 }
832866 "subnet" => {
833- let ( subnet, mask) = nic:: parse_ipv4_subnet ( name) ?;
834- Box :: new ( move |n| n. ipv4_subnet_eq ( subnet, mask) )
867+ let ( subnet, mask) = nic:: parse_ip_subnet ( name) ?;
868+ Box :: new ( move |n| n. matched_subnet_kind ( subnet, mask) )
835869 }
836870 _ => {
837- return Err ( format ! ( "Invalid NVMF target interface: '{iface}'" , ) ) ;
871+ return Err ( format ! ( "Invalid NVMF target interface: '{iface}'" ) ) ;
838872 }
839873 } ;
840874
841- let mut nics: Vec < _ > = nic:: find_all_nics ( ) . into_iter ( ) . filter ( pred) . collect ( ) ;
875+ let mut nics: Vec < _ > = nic:: find_all_nics ( ) . into_iter ( ) . filter_map ( pred) . collect ( ) ;
876+ nics. sort_by ( |a, b| a. sort ( b, prefer_ipv4) ) ;
842877
843- if nics. is_empty ( ) {
844- return Err ( format ! ( "Network interface matching '{iface}' not found" , ) ) ;
845- }
846-
847- if nics. len ( ) > 1 {
848- return Err ( format ! (
849- "Multiple network interfaces that \
850- match '{iface}' are found",
851- ) ) ;
852- }
878+ let res: nic:: Interface = match nics. pop ( ) {
879+ None => Err ( format ! ( "Network interface matching '{iface}' not found" ) ) ,
880+ Some ( nic) => Ok ( nic) ,
881+ } ?;
853882
854- let res = nics. pop ( ) . unwrap ( ) ;
855-
856- info ! (
857- "NVMF target network interface '{}' matches to {}" ,
858- iface, res
859- ) ;
883+ info ! ( "NVMF target network interface '{iface}' matches to {res}" ) ;
860884
861- if res. inet . addr . is_none ( ) {
862- return Err ( format ! (
863- "Network interface '{}' has no IPv4 address configured" ,
885+ match res. ip ( prefer_ipv4) {
886+ Some ( ip) => Ok ( ip) ,
887+ None => Err ( format ! (
888+ "Network interface '{}' has no IP address configured" ,
864889 res. name
865- ) ) ;
890+ ) ) ,
866891 }
892+ }
867893
868- Ok ( res. inet . addr . unwrap ( ) . to_string ( ) )
894+ fn prefer_ipv4 ( grpc : std:: net:: SocketAddr ) -> bool {
895+ match grpc {
896+ std:: net:: SocketAddr :: V4 ( _) => true ,
897+ std:: net:: SocketAddr :: V6 ( socket) if socket. ip ( ) . is_unspecified ( ) => true ,
898+ std:: net:: SocketAddr :: V6 ( _) => false ,
899+ }
869900 }
870901
871902 /// Detects pod IP address.
872- fn detect_pod_ip ( ) -> Result < String , String > {
903+ fn detect_pod_ip ( ) -> Result < SIpAddr , String > {
873904 match env:: var ( "MY_POD_IP" ) {
874905 Ok ( val) => {
875906 info ! (
876907 "Using 'MY_POD_IP' environment variable for IP address \
877908 for NVMF target network interface"
878909 ) ;
879-
880- if val. parse :: < Ipv4Addr > ( ) . is_ok ( ) {
881- Ok ( val)
910+ Ok ( parse_grpc_ip ( & val) ?)
911+ }
912+ Err ( _) => {
913+ if Self :: prefer_ipv4 ( Self :: global_or_default ( ) . grpc_endpoint . unwrap ( ) ) {
914+ Ok ( std:: net:: Ipv4Addr :: LOCALHOST . into ( ) )
882915 } else {
883- Err ( format ! (
884- "MY_POD_IP environment variable is set to an \
885- invalid IPv4 address: '{val}'"
886- ) )
916+ Ok ( std:: net:: Ipv6Addr :: LOCALHOST . into ( ) )
887917 }
888918 }
889- Err ( _) => Ok ( "127.0.0.1" . to_owned ( ) ) ,
890919 }
891920 }
892921
0 commit comments