1- use std:: sync:: Arc ;
21use tracing:: warn;
32use windows:: Win32 :: NetworkManagement :: IpHelper :: {
43 GetCurrentThreadCompartmentId , SetCurrentThreadCompartmentId ,
54} ;
65
76#[ derive( Debug , Clone , Eq , Hash , PartialEq ) ]
8- pub struct Namespace {
9- pub id : u32 ,
10- pub guid : String ,
11- }
12-
13- #[ derive( Clone , Debug ) ]
147pub struct InpodNamespace {
15- inner : Arc < NetnsInner > ,
16- }
17-
18- #[ derive( Debug , Eq , PartialEq ) ]
19- struct NetnsInner {
20- current_namespace : u32 ,
21- workload_namespace : Namespace ,
8+ // On Windows every network namespace is based
9+ // on a network compartment ID. This is the reference
10+ // we need when we want to create sockets inside
11+ // a network namespace or change IP stack configuration.
12+ pub compartment_id : u32 ,
13+ pub namespace_guid : String ,
2214}
2315
2416impl InpodNamespace {
@@ -32,56 +24,50 @@ impl InpodNamespace {
3224 }
3325
3426 pub fn capable ( ) -> std:: io:: Result < ( ) > {
35- // set the netns to our current netns. This is intended to be a no-op,
36- // and meant to be used as a test, so we can fail early if we can't set the netns
37- let curr_namespace = Self :: current ( ) ?;
38- setns ( curr_namespace)
27+ // Set the network compartment to the host compartment. This is intended to be a no-op,
28+ // and meant to be used as a test, so we can fail early if we can't set the netns.
29+ set_compartment ( 1 )
3930 }
4031
41- pub fn new ( cur_namespace : u32 , workload_namespace : String ) -> std:: io:: Result < Self > {
32+ pub fn new ( workload_namespace : String ) -> std:: io:: Result < Self > {
4233 let ns = hcn:: get_namespace ( & workload_namespace) ;
4334 match ns {
4435 Err ( e) => {
4536 warn ! ( "Failed to get namespace: {}" , e) ;
4637 Err ( std:: io:: Error :: last_os_error ( ) )
4738 }
4839 Ok ( ns) => Ok ( InpodNamespace {
49- inner : Arc :: new ( NetnsInner {
50- current_namespace : cur_namespace,
51- workload_namespace : Namespace {
52- id : ns
53- . namespace_id
54- . expect ( "There must always be a namespace id" ) ,
55- guid : ns. id ,
56- } ,
57- } ) ,
40+ compartment_id : ns
41+ . namespace_id
42+ // Compartment ID 0 means undefined compartment ID.
43+ // At the moment the JSON serialization ommits the field
44+ // if it is set to 0. This happens when the compartment
45+ // for the container is not yet available.
46+ . unwrap_or ( 0 ) ,
47+ namespace_guid : ns. id ,
5848 } ) ,
5949 }
6050 }
6151
62- pub fn workload_namespace ( & self ) -> u32 {
63- self . inner . workload_namespace . id
64- }
65-
66- // Useful for logging / debugging
67- pub fn workload_namespace_guid ( & self ) -> String {
68- self . inner . workload_namespace . guid . clone ( )
69- }
70-
7152 pub fn run < F , T > ( & self , f : F ) -> std:: io:: Result < T >
7253 where
7354 F : FnOnce ( ) -> T ,
7455 {
75- setns ( self . inner . workload_namespace . id ) ?;
56+ set_compartment ( self . compartment_id ) ?;
7657 let ret = f ( ) ;
77- setns ( self . inner . current_namespace ) . expect ( "this must never fail" ) ;
58+ // The Windows API defines the network compartment ID 1 as the
59+ // comapartment backing up the host network namespace.
60+ set_compartment ( 1 ) . expect ( "failed to switch to host namespace" ) ;
7861 Ok ( ret)
7962 }
8063}
8164
82- // hop into a namespace
83- fn setns ( namespace : u32 ) -> std:: io:: Result < ( ) > {
84- let error = unsafe { SetCurrentThreadCompartmentId ( namespace) } ;
65+ // Hop into a network compartment
66+ fn set_compartment ( compartment_id : u32 ) -> std:: io:: Result < ( ) > {
67+ if compartment_id == 0 {
68+ return Err ( std:: io:: Error :: other ( "undefined compartment ID" ) ) ;
69+ }
70+ let error = unsafe { SetCurrentThreadCompartmentId ( compartment_id) } ;
8571 if error. 0 != 0 {
8672 return Err ( std:: io:: Error :: from_raw_os_error ( error. 0 as i32 ) ) ;
8773 }
@@ -90,13 +76,13 @@ fn setns(namespace: u32) -> std::io::Result<()> {
9076
9177#[ cfg( test) ]
9278mod tests {
93- use hcn:: schema:: HostComputeQuery ;
9479 use hcn:: api;
80+ use hcn:: schema:: HostComputeQuery ;
9581 use windows:: core:: GUID ;
9682
9783 use super :: * ;
9884
99- fn new_namespace ( ) -> Namespace {
85+ fn new_namespace ( ) -> InpodNamespace {
10086 let api_namespace = hcn:: schema:: HostComputeNamespace :: default ( ) ;
10187
10288 let api_namespace = serde_json:: to_string ( & api_namespace) . unwrap ( ) ;
@@ -111,9 +97,9 @@ mod tests {
11197 let api_namespace: hcn:: schema:: HostComputeNamespace =
11298 serde_json:: from_str ( & api_namespace) . unwrap ( ) ;
11399
114- Namespace {
115- id : api_namespace. namespace_id . unwrap ( ) ,
116- guid : api_namespace. id ,
100+ InpodNamespace {
101+ compartment_id : api_namespace. namespace_id . unwrap ( ) ,
102+ namespace_guid : api_namespace. id ,
117103 }
118104 }
119105
0 commit comments