Repository: firecracker-microvm/firecracker-containerd
Pull request #305 (2019-10-25 03:55:50)

Adding netns to jailer 
This adds netns specification per create vm request. In the event that
no netns was found in the runc config, we will then make sure of what
was passed into the create vm request


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


xibz: > 
    Is it possible to have firecracker-containerd actually set the netns field in the go sdk's machine.JailerConfig when it was set in the CreateVM's JailerConfig?
    If the above isn't possible, could we change the Go SDK to move the existing machine.JailerConfig.NetNS field to just be directly in the machine object? Then we can conditionally set that field in firecracker-containerd w/out creating a whole machine.JailerConfig object.

I think what I can do is modify the SDK code to create a netns handler by passing in the netns path. This will use a default netns in the default handler, then during jailing it'll create and swap handlers with its netns. Then in the firecracker-containerd code I just need to inject the correct handlers.
xibz: Waiting on https://github.com/firecracker-microvm/firecracker-go-sdk/pull/155 to be merged
xibz: > You don't have to use Sprintf inside Wrapf :)

lol, fixed!

Patch:
diff --git a/go.mod b/go.mod
index 2e8d887..00bee0c 100644
--- a/go.mod
+++ b/go.mod
@@ -18,7 +18,7 @@ require (
 	github.com/docker/go-events v0.0.0-20170721190031-9461782956ad // indirect
 	github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 // indirect
 	github.com/docker/go-units v0.3.3
-	github.com/firecracker-microvm/firecracker-go-sdk v0.19.0
+	github.com/firecracker-microvm/firecracker-go-sdk v0.19.1-0.20191114205152-9e2ff62839b2
 	github.com/go-ole/go-ole v1.2.4 // indirect
 	github.com/godbus/dbus v0.0.0-20181025153459-66d97aec3384 // indirect
 	github.com/gofrs/uuid v3.2.0+incompatible
diff --git a/go.sum b/go.sum
index a874fe8..7ee35c4 100644
--- a/go.sum
+++ b/go.sum
@@ -59,8 +59,8 @@ github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zF
 github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
 github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
 github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/firecracker-microvm/firecracker-go-sdk v0.19.0 h1:Fgb3WhB4q3J5e+ksMBtjVwBTvbDtPAkx7eQulb2BOq8=
-github.com/firecracker-microvm/firecracker-go-sdk v0.19.0/go.mod h1:kW0gxvPpPvMukUxxTO9DrpSlScrtrTDGY3VgjAj/Qwc=
+github.com/firecracker-microvm/firecracker-go-sdk v0.19.1-0.20191114205152-9e2ff62839b2 h1:Ab52E0UlBOmMIAK/igRycsxSAJVDBDMYq+Wr/n7z2E0=
+github.com/firecracker-microvm/firecracker-go-sdk v0.19.1-0.20191114205152-9e2ff62839b2/go.mod h1:kW0gxvPpPvMukUxxTO9DrpSlScrtrTDGY3VgjAj/Qwc=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0=
 github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
diff --git a/proto/firecracker.pb.go b/proto/firecracker.pb.go
index b527e1d..6c04573 100644
--- a/proto/firecracker.pb.go
+++ b/proto/firecracker.pb.go
@@ -463,6 +463,7 @@ func (m *GetVMMetadataResponse) GetMetadata() string {
 }
 
 type JailerConfig struct {
+	NetNS                string   `protobuf:"bytes,1,opt,name=NetNS,json=netNS,proto3" json:"NetNS,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -492,6 +493,13 @@ func (m *JailerConfig) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_JailerConfig proto.InternalMessageInfo
 
+func (m *JailerConfig) GetNetNS() string {
+	if m != nil {
+		return m.NetNS
+	}
+	return ""
+}
+
 func init() {
 	proto.RegisterType((*CreateVMRequest)(nil), "CreateVMRequest")
 	proto.RegisterType((*StopVMRequest)(nil), "StopVMRequest")
@@ -507,38 +515,39 @@ func init() {
 func init() { proto.RegisterFile("firecracker.proto", fileDescriptor_a73317e9fb8da571) }
 
 var fileDescriptor_a73317e9fb8da571 = []byte{
-	// 528 bytes of a gzipped FileDescriptorProto
+	// 541 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4f, 0x6f, 0xd3, 0x4e,
-	0x10, 0x95, 0x7f, 0x4d, 0xda, 0x78, 0xdc, 0xa6, 0xbf, 0xac, 0x5a, 0x58, 0x55, 0x15, 0xb2, 0x7c,
-	0xa8, 0x2c, 0x0e, 0x95, 0x68, 0x2e, 0x88, 0x13, 0x21, 0x21, 0x95, 0x5b, 0x8c, 0xd0, 0xa6, 0xe4,
-	0xc0, 0x6d, 0x71, 0xc6, 0xa9, 0xb1, 0xb3, 0x1b, 0x76, 0x37, 0xa5, 0x9c, 0xf9, 0x44, 0x7c, 0x43,
-	0xe4, 0xcd, 0x3f, 0x27, 0x82, 0x08, 0x89, 0x93, 0x77, 0xdf, 0xbc, 0x99, 0xf7, 0x34, 0x7e, 0x36,
-	0xb4, 0xd2, 0x4c, 0x61, 0xa2, 0x78, 0x92, 0xa3, 0xba, 0x9c, 0x2a, 0x69, 0xe4, 0x99, 0x67, 0xbe,
-	0x4f, 0x51, 0xcf, 0x2f, 0xc1, 0x8f, 0x1a, 0x1c, 0x77, 0x15, 0x72, 0x83, 0xc3, 0x98, 0xe1, 0xd7,
-	0x19, 0x6a, 0x43, 0x08, 0xd4, 0x86, 0x71, 0xd4, 0xa3, 0x8e, 0xef, 0x84, 0x2e, 0xab, 0x3d, 0xc4,
-	0x51, 0x8f, 0xbc, 0x06, 0x88, 0x79, 0x72, 0x9f, 0x09, 0xec, 0xa6, 0x63, 0xfa, 0x9f, 0xef, 0x84,
-	0xde, 0x95, 0x7f, 0xd9, 0x5f, 0x0f, 0x5f, 0x56, 0xa5, 0x48, 0xb3, 0xf1, 0x4c, 0x71, 0x93, 0x49,
-	0xc1, 0x60, 0xb2, 0xea, 0x21, 0x21, 0x1c, 0xdf, 0xa2, 0x12, 0x58, 0x44, 0x13, 0x3e, 0xc6, 0x0f,
-	0xdc, 0xdc, 0xd3, 0x3d, 0x2b, 0x70, 0x9c, 0x6f, 0xc2, 0xe4, 0x19, 0xc0, 0x9c, 0xd9, 0x51, 0x63,
-	0x4d, 0x6b, 0x96, 0x04, 0xf9, 0x0a, 0x21, 0x6d, 0x70, 0x99, 0x94, 0xa6, 0xa7, 0xb2, 0x07, 0xa4,
-	0x75, 0x6b, 0xe5, 0xb4, 0x6a, 0x65, 0x55, 0x64, 0xae, 0x5a, 0x1e, 0xc9, 0x4b, 0xf0, 0xec, 0x21,
-	0x96, 0x33, 0x61, 0x34, 0xdd, 0xf7, 0xf7, 0x42, 0xef, 0xea, 0x49, 0xb5, 0x6d, 0x5d, 0x66, 0xde,
-	0x68, 0x4d, 0x25, 0x37, 0xd0, 0x7a, 0x8f, 0xe6, 0x9b, 0x54, 0x79, 0x24, 0x0c, 0xaa, 0x94, 0x27,
-	0xa8, 0xe9, 0x81, 0xed, 0x3f, 0xaf, 0xf6, 0x6f, 0x93, 0x58, 0x4b, 0x6c, 0xb7, 0x91, 0x0b, 0x68,
-	0x76, 0xa5, 0x30, 0x3c, 0x13, 0xa8, 0xba, 0xe5, 0x78, 0xda, 0xf0, 0x9d, 0xb0, 0xce, 0x9a, 0xc9,
-	0x06, 0x4a, 0x5e, 0x01, 0x7d, 0xfb, 0x98, 0x99, 0x4e, 0x6a, 0x50, 0x75, 0x8a, 0xe2, 0x8e, 0xeb,
-	0x5c, 0xf7, 0xb0, 0x40, 0x83, 0x23, 0xea, 0xfa, 0x4e, 0xd8, 0x60, 0x14, 0xff, 0x50, 0x27, 0x2f,
-	0xe0, 0xf0, 0x86, 0x67, 0x45, 0x39, 0xaa, 0x7c, 0x17, 0x14, 0xec, 0x86, 0x8e, 0x2e, 0xab, 0x20,
-	0x3b, 0xfc, 0x52, 0xb9, 0x05, 0xb7, 0x70, 0x34, 0x30, 0x72, 0xba, 0x3b, 0x02, 0x17, 0xd0, 0xbc,
-	0xcb, 0x26, 0x28, 0x67, 0x66, 0x80, 0x89, 0x14, 0x23, 0x6d, 0x63, 0x70, 0xc4, 0x9a, 0x66, 0x03,
-	0x0d, 0x2e, 0xe0, 0xff, 0x6b, 0x34, 0xc3, 0x38, 0x12, 0xa9, 0xdc, 0x31, 0x2f, 0xf8, 0xe9, 0x40,
-	0xab, 0x42, 0xd4, 0x53, 0x29, 0x34, 0xfe, 0x56, 0xf9, 0x1c, 0xdc, 0x72, 0x6b, 0xf8, 0x68, 0xa2,
-	0xde, 0x42, 0xd4, 0x4d, 0x96, 0x40, 0x19, 0x97, 0x81, 0x4c, 0x72, 0x34, 0x95, 0x4c, 0x81, 0x5e,
-	0x21, 0xc4, 0x07, 0xef, 0x9d, 0x1c, 0xf7, 0xb3, 0x54, 0x5a, 0xc2, 0x3c, 0x4f, 0x5e, 0xb1, 0x86,
-	0xca, 0x68, 0xc6, 0x68, 0x54, 0x96, 0xe8, 0x15, 0xab, 0x3e, 0x8f, 0xe6, 0x64, 0x13, 0x0e, 0xfa,
-	0x70, 0x32, 0x28, 0x2d, 0xc7, 0x68, 0xf8, 0x88, 0x1b, 0xbe, 0x6b, 0x5f, 0x67, 0xd0, 0x58, 0xd2,
-	0xac, 0x69, 0x97, 0x35, 0x26, 0x8b, 0x7b, 0x10, 0xc1, 0xd3, 0x8f, 0xd3, 0x91, 0xfd, 0xea, 0xfe,
-	0x75, 0xd4, 0x73, 0x38, 0xb9, 0xfe, 0x4b, 0x4b, 0x41, 0x1b, 0x4e, 0xb7, 0xb8, 0x8b, 0xad, 0x57,
-	0x05, 0x9c, 0x2d, 0x81, 0xe6, 0x66, 0x9e, 0xde, 0x1c, 0x7c, 0xaa, 0xdb, 0x7f, 0xc7, 0xe7, 0x7d,
-	0xfb, 0x68, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x04, 0x79, 0x66, 0xac, 0x64, 0x04, 0x00, 0x00,
+	0x10, 0x95, 0x7f, 0x4d, 0xda, 0x78, 0xdc, 0xa6, 0xbf, 0xac, 0x5a, 0x58, 0x55, 0x15, 0xb2, 0x2c,
+	0x54, 0x45, 0x1c, 0x2a, 0xd1, 0x5e, 0x10, 0x27, 0x4a, 0x42, 0x2b, 0xb7, 0xb8, 0x42, 0x9b, 0xd2,
+	0x03, 0xb7, 0xc5, 0x19, 0xa7, 0x26, 0xce, 0x6e, 0xd8, 0x9d, 0x94, 0x72, 0xe6, 0x13, 0xf1, 0x0d,
+	0x91, 0x37, 0xff, 0x9c, 0x08, 0x2a, 0x24, 0x4e, 0x9e, 0x79, 0xf3, 0x66, 0xe6, 0x69, 0xfc, 0x6c,
+	0x68, 0x65, 0xb9, 0xc1, 0xd4, 0xc8, 0x74, 0x88, 0xe6, 0x78, 0x6c, 0x34, 0xe9, 0x83, 0x80, 0xbe,
+	0x8f, 0xd1, 0x4e, 0x93, 0xe8, 0x47, 0x0d, 0x76, 0x3b, 0x06, 0x25, 0xe1, 0x6d, 0x22, 0xf0, 0xeb,
+	0x04, 0x2d, 0x31, 0x06, 0xb5, 0xdb, 0x24, 0xee, 0x72, 0x2f, 0xf4, 0xda, 0xbe, 0xa8, 0xdd, 0x27,
+	0x71, 0x97, 0xbd, 0x01, 0x48, 0x64, 0x7a, 0x97, 0x2b, 0xec, 0x64, 0x03, 0xfe, 0x5f, 0xe8, 0xb5,
+	0x83, 0x93, 0xf0, 0xf8, 0x7c, 0x39, 0x7c, 0x5e, 0xd5, 0x2a, 0xcb, 0x07, 0x13, 0x23, 0x29, 0xd7,
+	0x4a, 0xc0, 0x68, 0xd1, 0xc3, 0xda, 0xb0, 0x7b, 0x85, 0x46, 0x61, 0x11, 0x8f, 0xe4, 0x00, 0x3f,
+	0x48, 0xba, 0xe3, 0x1b, 0x6e, 0xc1, 0xee, 0x70, 0x15, 0x66, 0xcf, 0x00, 0xa6, 0xcc, 0x33, 0x33,
+	0xb0, 0xbc, 0xe6, 0x48, 0x30, 0x5c, 0x20, 0xec, 0x14, 0x7c, 0xa1, 0x35, 0x75, 0x4d, 0x7e, 0x8f,
+	0xbc, 0xee, 0xa4, 0xec, 0x57, 0xa5, 0x2c, 0x8a, 0xc2, 0x37, 0xf3, 0x90, 0xbd, 0x82, 0xc0, 0x05,
+	0x89, 0x9e, 0x28, 0xb2, 0x7c, 0x33, 0xdc, 0x68, 0x07, 0x27, 0x4f, 0xaa, 0x6d, 0xcb, 0xb2, 0x08,
+	0xfa, 0x4b, 0x2a, 0xbb, 0x84, 0xd6, 0x35, 0xd2, 0x37, 0x6d, 0x86, 0xb1, 0x22, 0x34, 0x99, 0x4c,
+	0xd1, 0xf2, 0x2d, 0xd7, 0x7f, 0x58, 0xed, 0x5f, 0x27, 0x89, 0x96, 0x5a, 0x6f, 0x63, 0x47, 0xd0,
+	0xec, 0x68, 0x45, 0x32, 0x57, 0x68, 0x3a, 0xe5, 0x78, 0xde, 0x08, 0xbd, 0x76, 0x5d, 0x34, 0xd3,
+	0x15, 0x94, 0xbd, 0x06, 0xfe, 0xee, 0x21, 0xa7, 0xb3, 0x8c, 0xd0, 0x9c, 0x15, 0xc5, 0x8d, 0xb4,
+	0x43, 0xdb, 0xc5, 0x02, 0x09, 0xfb, 0xdc, 0x0f, 0xbd, 0x76, 0x43, 0x70, 0xfc, 0x43, 0x9d, 0xbd,
+	0x84, 0xed, 0x4b, 0x99, 0x17, 0xe5, 0xa8, 0xf2, 0x5d, 0x70, 0x70, 0x17, 0xda, 0x39, 0xae, 0x82,
+	0x62, 0xfb, 0x4b, 0x25, 0x8b, 0xae, 0x60, 0xa7, 0x47, 0x7a, 0xfc, 0xb8, 0x05, 0x8e, 0xa0, 0x79,
+	0x93, 0x8f, 0x50, 0x4f, 0xa8, 0x87, 0xa9, 0x56, 0x7d, 0xeb, 0x6c, 0xb0, 0x23, 0x9a, 0xb4, 0x82,
+	0x46, 0x47, 0xf0, 0xff, 0x05, 0xd2, 0x6d, 0x12, 0xab, 0x4c, 0x3f, 0x32, 0x2f, 0xfa, 0xe9, 0x41,
+	0xab, 0x42, 0xb4, 0x63, 0xad, 0x2c, 0xfe, 0x76, 0xf3, 0x21, 0xf8, 0xe5, 0xd5, 0xf0, 0x81, 0xe2,
+	0xee, 0x6c, 0xa9, 0x9f, 0xce, 0x81, 0xd2, 0x2e, 0x3d, 0x9d, 0x0e, 0x91, 0x2a, 0x9e, 0x02, 0xbb,
+	0x40, 0x58, 0x08, 0xc1, 0x7b, 0x3d, 0x38, 0xcf, 0x33, 0xed, 0x08, 0x53, 0x3f, 0x05, 0xc5, 0x12,
+	0x2a, 0xad, 0x99, 0x20, 0x99, 0x3c, 0xb5, 0x0b, 0x56, 0x7d, 0x6a, 0xcd, 0xd1, 0x2a, 0x1c, 0x9d,
+	0xc3, 0x5e, 0xaf, 0x94, 0x9c, 0x20, 0xc9, 0xbe, 0x24, 0xf9, 0xd8, 0xbd, 0x0e, 0xa0, 0x31, 0xa7,
+	0x39, 0xd1, 0xbe, 0x68, 0x8c, 0x66, 0x79, 0x14, 0xc3, 0xd3, 0x8f, 0xe3, 0xbe, 0xfb, 0xea, 0xfe,
+	0x75, 0xd4, 0x0b, 0xd8, 0xbb, 0xf8, 0x4b, 0x49, 0xd1, 0x29, 0xec, 0xaf, 0x71, 0x67, 0x57, 0xaf,
+	0x2e, 0xf0, 0xd6, 0x16, 0x3c, 0x5f, 0xf5, 0x13, 0xdb, 0x83, 0xfa, 0x35, 0xd2, 0x75, 0x6f, 0x46,
+	0xac, 0xab, 0x32, 0x79, 0xbb, 0xf5, 0xa9, 0xee, 0xfe, 0x28, 0x9f, 0x37, 0xdd, 0xe3, 0xf4, 0x57,
+	0x00, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x16, 0x31, 0x73, 0x7a, 0x04, 0x00, 0x00,
 }
diff --git a/proto/firecracker.proto b/proto/firecracker.proto
index 239ed2d..9be1e22 100644
--- a/proto/firecracker.proto
+++ b/proto/firecracker.proto
@@ -72,5 +72,6 @@ message GetVMMetadataResponse {
 }
 
 message JailerConfig {
+    string NetNS = 1;
 }
 
diff --git a/runtime/runc_jailer.go b/runtime/runc_jailer.go
index bec617c..1f1207d 100644
--- a/runtime/runc_jailer.go
+++ b/runtime/runc_jailer.go
@@ -35,6 +35,10 @@ import (
 	"github.com/firecracker-microvm/firecracker-containerd/internal/vm"
 )
 
+const (
+	networkNamespaceRuncName = "network"
+)
+
 // runcJailer uses runc to set up a jailed environment for the Firecracker VM.
 type runcJailer struct {
 	ctx    context.Context
@@ -46,6 +50,7 @@ type runcJailer struct {
 	runcBinaryPath string
 	uid            uint32
 	gid            uint32
+	configSpec     specs.Spec
 }
 
 const firecrackerFileName = "firecracker"
@@ -63,6 +68,19 @@ func newRuncJailer(ctx context.Context, logger *logrus.Entry, ociBundlePath, run
 		gid:            gid,
 	}
 
+	spec := specs.Spec{}
+	var configBytes []byte
+	configBytes, err := ioutil.ReadFile(runcConfigPath)
+	if err != nil {
+		return nil, errors.Wrapf(err, "failed to read %s", runcConfigPath)
+	}
+
+	if err = json.Unmarshal(configBytes, &spec); err != nil {
+		return nil, errors.Wrapf(err, "failed to unmarshal %s", runcConfigPath)
+	}
+
+	j.configSpec = spec
+
 	rootPath := j.RootPath()
 
 	const mode = os.FileMode(0700)
@@ -77,17 +95,17 @@ func newRuncJailer(ctx context.Context, logger *logrus.Entry, ociBundlePath, run
 
 // JailPath returns the base directory from where the jail binary will be ran
 // from
-func (j runcJailer) OCIBundlePath() string {
+func (j *runcJailer) OCIBundlePath() string {
 	return j.ociBundlePath
 }
 
 // RootPath returns the root fs of the jailed system.
-func (j runcJailer) RootPath() string {
+func (j *runcJailer) RootPath() string {
 	return filepath.Join(j.OCIBundlePath(), rootfsFolder)
 }
 
 // JailPath will return the OCI bundle rootfs path
-func (j runcJailer) JailPath() vm.Dir {
+func (j *runcJailer) JailPath() vm.Dir {
 	return vm.Dir(j.RootPath())
 }
 
@@ -95,11 +113,17 @@ func (j runcJailer) JailPath() vm.Dir {
 // instance. In addition, some configuration values will be overwritten to the
 // jailed values, like SocketPath in the machineConfig.
 func (j *runcJailer) BuildJailedMachine(cfg *Config, machineConfig *firecracker.Config, vmID string) ([]firecracker.Opt, error) {
-	handler := j.BuildJailedRootHandler(cfg, &machineConfig.SocketPath, vmID)
+	handler := j.BuildJailedRootHandler(cfg, machineConfig, vmID)
 	fifoHandler := j.BuildLinkFifoHandler()
 	// Build a new client since BuildJailedRootHandler modifies the socket path value.
 	client := firecracker.NewClient(machineConfig.SocketPath, j.logger, machineConfig.Debug)
 
+	if machineConfig.NetNS == "" {
+		if netns := getNetNS(j.configSpec); netns != "" {
+			machineConfig.NetNS = netns
+		}
+	}
+
 	opts := []firecracker.Opt{
 		firecracker.WithProcessRunner(j.jailerCommand(vmID, cfg.Debug)),
 		firecracker.WithClient(client),
@@ -120,10 +144,10 @@ func (j *runcJailer) BuildJailedMachine(cfg *Config, machineConfig *firecracker.
 
 // BuildJailedRootHandler will populate the jail with the necessary files, which may be
 // device nodes, hard links, and/or bind-mount targets
-func (j *runcJailer) BuildJailedRootHandler(cfg *Config, socketPath *string, vmID string) firecracker.Handler {
+func (j *runcJailer) BuildJailedRootHandler(cfg *Config, machineConfig *firecracker.Config, vmID string) firecracker.Handler {
 	ociBundlePath := j.OCIBundlePath()
 	rootPath := j.RootPath()
-	*socketPath = filepath.Join(rootPath, "api.socket")
+	machineConfig.SocketPath = filepath.Join(rootPath, "api.socket")
 
 	return firecracker.Handler{
 		Name: jailerHandlerName,
@@ -136,7 +160,9 @@ func (j *runcJailer) BuildJailedRootHandler(cfg *Config, socketPath *string, vmI
 			}
 
 			j.logger.Debug("Overwritting process args of config")
-			if err := j.overwriteConfig(cfg, filepath.Base(m.Cfg.SocketPath), rootPathToConfig); err != nil {
+			// we pass m.Cfg as opposed to machineConfig as we want the populated
+			// config defaults when calling NewMachine
+			if err := j.overwriteConfig(cfg, &m.Cfg, filepath.Base(m.Cfg.SocketPath), rootPathToConfig); err != nil {
 				return errors.Wrap(err, "failed to overwrite config.json")
 			}
 
@@ -206,7 +232,7 @@ func (j *runcJailer) BuildJailedRootHandler(cfg *Config, socketPath *string, vmI
 
 // BuildLinkFifoHandler will return a new firecracker.Handler with the function
 // that will allow linking of the fifos making them visible to Firecracker.
-func (j runcJailer) BuildLinkFifoHandler() firecracker.Handler {
+func (j *runcJailer) BuildLinkFifoHandler() firecracker.Handler {
 	return firecracker.Handler{
 		Name: jailerFifoHandlerName,
 		Fn: func(ctx context.Context, m *firecracker.Machine) error {
@@ -232,7 +258,7 @@ func (j runcJailer) BuildLinkFifoHandler() firecracker.Handler {
 
 // StubDrivesOptions will return a set of options used to create a new stub
 // drive handler.
-func (j runcJailer) StubDrivesOptions() []stubDrivesOpt {
+func (j *runcJailer) StubDrivesOptions() []stubDrivesOpt {
 	return []stubDrivesOpt{
 		func(drives []models.Drive) error {
 			for _, drive := range drives {
@@ -251,7 +277,7 @@ func (j runcJailer) StubDrivesOptions() []stubDrivesOpt {
 // the jail. For block devices we will use mknod to create the device and then
 // set the correct permissions to ensure visibility in the jail. Regular files
 // will be copied into the jail.
-func (j runcJailer) ExposeFileToJail(srcPath string) error {
+func (j *runcJailer) ExposeFileToJail(srcPath string) error {
 	uid := j.uid
 	gid := j.gid
 
@@ -292,7 +318,7 @@ func (j runcJailer) ExposeFileToJail(srcPath string) error {
 }
 
 // copyFileToJail will copy a file from src to dst, and chown the new file to the jail user.
-func (j runcJailer) copyFileToJail(src, dst string, mode os.FileMode) error {
+func (j *runcJailer) copyFileToJail(src, dst string, mode os.FileMode) error {
 	if err := copyFile(src, dst, mode); err != nil {
 		return err
 	}
@@ -340,7 +366,7 @@ func copyFile(src, dst string, mode os.FileMode) error {
 	return nil
 }
 
-func (j runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd {
+func (j *runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd {
 	cmd := exec.CommandContext(j.ctx, j.runcBinaryPath, "run", containerName)
 	cmd.Dir = j.OCIBundlePath()
 
@@ -353,19 +379,8 @@ func (j runcJailer) jailerCommand(containerName string, isDebug bool) *exec.Cmd
 }
 
 // overwriteConfig will set the proper default values if a field had not been set.
-//
-// TODO: Add netns
-func (j runcJailer) overwriteConfig(cfg *Config, socketPath, configPath string) error {
-	spec := specs.Spec{}
-	configBytes, err := ioutil.ReadFile(configPath)
-	if err != nil {
-		return err
-	}
-
-	if err := json.Unmarshal(configBytes, &spec); err != nil {
-		return err
-	}
-
+func (j *runcJailer) overwriteConfig(cfg *Config, machineConfig *firecracker.Config, socketPath, configPath string) error {
+	spec := j.configSpec
 	if spec.Process.User.UID != 0 ||
 		spec.Process.User.GID != 0 {
 		return fmt.Errorf(
@@ -376,13 +391,22 @@ func (j runcJailer) overwriteConfig(cfg *Config, socketPath, configPath string)
 	}
 
 	spec = j.setDefaultConfigValues(cfg, socketPath, spec)
-
 	spec.Root.Path = rootfsFolder
 	spec.Root.Readonly = false
 	spec.Process.User.UID = j.uid
 	spec.Process.User.GID = j.gid
 
-	configBytes, err = json.Marshal(&spec)
+	if machineConfig.NetNS != "" {
+		for i, ns := range spec.Linux.Namespaces {
+			if ns.Type == networkNamespaceRuncName {
+				ns.Path = machineConfig.NetNS
+				spec.Linux.Namespaces[i] = ns
+				break
+			}
+		}
+	}
+
+	configBytes, err := json.Marshal(&spec)
 	if err != nil {
 		return err
 	}
@@ -396,7 +420,7 @@ func (j runcJailer) overwriteConfig(cfg *Config, socketPath, configPath string)
 
 // setDefaultConfigValues will process the spec file provided and allow any
 // empty/zero values to be replaced with default values.
-func (j runcJailer) setDefaultConfigValues(cfg *Config, socketPath string, spec specs.Spec) specs.Spec {
+func (j *runcJailer) setDefaultConfigValues(cfg *Config, socketPath string, spec specs.Spec) specs.Spec {
 	if spec.Process == nil {
 		spec.Process = &specs.Process{}
 	}
@@ -448,3 +472,13 @@ func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid uint32) err
 
 	return nil
 }
+
+func getNetNS(spec specs.Spec) string {
+	for _, ns := range spec.Linux.Namespaces {
+		if ns.Type == networkNamespaceRuncName {
+			return ns.Path
+		}
+	}
+
+	return ""
+}
diff --git a/runtime/service.go b/runtime/service.go
index f107224..4d4ebe5 100644
--- a/runtime/service.go
+++ b/runtime/service.go
@@ -698,6 +698,10 @@ func (s *service) buildVMConfiguration(req *proto.CreateVMRequest) (*firecracker
 		VMID:        s.vmID,
 	}
 
+	if req.JailerConfig != nil {
+		cfg.NetNS = req.JailerConfig.NetNS
+	}
+
 	s.logger.Debugf("using socket path: %s", cfg.SocketPath)
 
 	// Kernel configuration


Test patch:
diff --git a/runtime/cni_integ_test.go b/runtime/cni_integ_test.go
index e7e62cb..0029889 100644
--- a/runtime/cni_integ_test.go
+++ b/runtime/cni_integ_test.go
@@ -28,6 +28,7 @@ import (
 	"github.com/containerd/containerd/namespaces"
 	"github.com/containerd/containerd/oci"
 	"github.com/containerd/containerd/pkg/ttrpcutil"
+	"github.com/firecracker-microvm/firecracker-go-sdk/cni/cmd/tc-redirect-tap/args"
 	"github.com/shirou/gopsutil/cpu"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -39,8 +40,7 @@ import (
 )
 
 func TestCNISupport_Isolated(t *testing.T) {
-	prepareIntegTest(t)
-
+	prepareIntegTest(t, withJailer())
 	testTimeout := 120 * time.Second
 	ctx, cancel := context.WithTimeout(namespaces.WithNamespace(context.Background(), defaultNamespace), testTimeout)
 	defer cancel()
@@ -96,8 +96,23 @@ func TestCNISupport_Isolated(t *testing.T) {
 					CNIConfig: &proto.CNIConfiguration{
 						NetworkName:   cniNetworkName,
 						InterfaceName: "veth0",
+						Args: []*proto.CNIConfiguration_CNIArg{
+							{
+								Key:   "IgnoreUnknown",
+								Value: "true",
+							},
+							{
+								Key:   args.TCRedirectTapUID,
+								Value: fmt.Sprintf("%d", jailerUID),
+							},
+							{
+								Key:   args.TCRedirectTapGID,
+								Value: fmt.Sprintf("%d", jailerGID),
+							},
+						},
 					},
 				}},
+				JailerConfig: &proto.JailerConfig{},
 			})
 			require.NoError(t, err, "failed to create vm")
 
diff --git a/runtime/runc_jailer_test.go b/runtime/runc_jailer_test.go
index 52ad7fc..bb7d085 100644
--- a/runtime/runc_jailer_test.go
+++ b/runtime/runc_jailer_test.go
@@ -61,22 +61,22 @@ func TestBuildJailedRootHandler_Isolated(t *testing.T) {
 		KernelImagePath:       kernelImagePath,
 		RootDrive:             rootDrivePath,
 	}
-	socketPath := "/path/to/api.socket"
+	machineConfig := firecracker.Config{
+		SocketPath:      "/path/to/api.socket",
+		KernelImagePath: kernelImagePath,
+		Drives: []models.Drive{
+			{
+				PathOnHost:   firecracker.String(rootDrivePath),
+				IsRootDevice: firecracker.Bool(true),
+				IsReadOnly:   firecracker.Bool(true),
+			},
+		},
+	}
 	vmID := "foo"
-	handler := jailer.BuildJailedRootHandler(&cfg, &socketPath, vmID)
+	handler := jailer.BuildJailedRootHandler(&cfg, &machineConfig, vmID)
 
 	machine := firecracker.Machine{
-		Cfg: firecracker.Config{
-			SocketPath:      socketPath,
-			KernelImagePath: kernelImagePath,
-			Drives: []models.Drive{
-				{
-					PathOnHost:   firecracker.String(rootDrivePath),
-					IsRootDevice: firecracker.Bool(true),
-					IsReadOnly:   firecracker.Bool(true),
-				},
-			},
-		},
+		Cfg: machineConfig,
 	}
 	err = handler.Fn(context.Background(), &machine)
 	assert.NoError(t, err, "jailed handler failed to run")
diff --git a/runtime/service_integ_test.go b/runtime/service_integ_test.go
index ff730d3..423d7c0 100644
--- a/runtime/service_integ_test.go
+++ b/runtime/service_integ_test.go
@@ -37,6 +37,7 @@ import (
 	"github.com/containerd/containerd/pkg/ttrpcutil"
 	"github.com/containerd/containerd/runtime"
 	"github.com/containerd/typeurl"
+	"github.com/containernetworking/plugins/pkg/ns"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 	"github.com/shirou/gopsutil/process"
@@ -214,6 +215,8 @@ func createTapDevice(ctx context.Context, tapName string) error {
 func TestMultipleVMs_Isolated(t *testing.T) {
 	prepareIntegTest(t, withJailer())
 
+	netns, err := ns.GetCurrentNS()
+
 	cases := []struct {
 		MaxContainers int32
 		JailerConfig  *proto.JailerConfig
@@ -229,11 +232,15 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 		},
 		{
 			MaxContainers: 3,
-			JailerConfig:  &proto.JailerConfig{},
+			JailerConfig: &proto.JailerConfig{
+				NetNS: netns.Path(),
+			},
 		},
 		{
 			MaxContainers: 3,
-			JailerConfig:  &proto.JailerConfig{},
+			JailerConfig: &proto.JailerConfig{
+				NetNS: netns.Path(),
+			},
 		},
 	}
 
@@ -262,6 +269,7 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 
 			tapName := fmt.Sprintf("tap%d", vmID)
 			err = createTapDevice(ctx, tapName)
+
 			require.NoError(t, err, "failed to create tap device for vm %d", vmID)
 
 			rootfsPath := defaultVMRootfsPath
@@ -288,10 +296,6 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 				JailerConfig:   jailerConfig,
 			}
 
-			if jailerConfig != nil {
-				req.NetworkInterfaces = nil
-			}
-
 			_, err = fcClient.CreateVM(ctx, req)
 			require.NoError(t, err, "failed to create vm")
 
@@ -308,13 +312,6 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 						fmt.Sprintf("/bin/sleep %d", testTimeout/time.Second),
 					}, " && "))
 
-					if jailerConfig != nil {
-						// TODO: this if statement block can go away once we add netns
-						processArgs = oci.WithProcessArgs("/bin/sh", "-c", strings.Join([]string{
-							fmt.Sprintf("/bin/sleep %d", testTimeout/time.Second),
-						}, " && "))
-					}
-
 					// spawn a container that just prints the VM's eth0 mac address (which we have set uniquely per VM)
 					newContainer, err := client.NewContainer(ctx,
 						containerName,
@@ -443,20 +440,13 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 
 						stdoutLines := strings.Split(strings.TrimSpace(taskStdout.String()), "\n")
 						lines := 2
-						if jailerConfig != nil {
-							lines = 1
-						}
 						require.Len(t, stdoutLines, lines)
 
 						printedVMID := strings.TrimSpace(stdoutLines[0])
-						// TODO: Remove this if statement once we can add a netns which
-						// will allow firecracker to have visibility of the tap devices.
-						if jailerConfig == nil {
-							require.Equal(t, vmIDtoMacAddr(uint(vmID)), printedVMID, "unexpected VMID output from container %q", containerName)
+						require.Equal(t, vmIDtoMacAddr(uint(vmID)), printedVMID, "unexpected VMID output from container %q", containerName)
 
-							taskMntNS := strings.TrimSpace(stdoutLines[1])
-							require.Equal(t, execMntNS, taskMntNS, "unexpected mnt NS output from container %q", containerName)
-						}
+						taskMntNS := strings.TrimSpace(stdoutLines[1])
+						require.Equal(t, execMntNS, taskMntNS, "unexpected mnt NS output from container %q", containerName)
 
 					case <-ctx.Done():
 						require.Fail(t, "context cancelled",