浏览代码

Merge pull request #917 from msabansal/master

Windows HNS integration
Jana Radhakrishnan 9 年之前
父节点
当前提交
a78129c6a1
共有 54 个文件被更改,包括 5381 次插入326 次删除
  1. 8 0
      libnetwork/Godeps/Godeps.json
  2. 22 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/LICENSE
  3. 15 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md
  4. 216 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/file.go
  5. 797 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/mksyscall_windows.go
  6. 280 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe.go
  7. 199 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe_test.go
  8. 83 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd.go
  9. 26 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd_test.go
  10. 3 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/syscall.go
  11. 218 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go
  12. 22 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/LICENSE
  13. 28 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/activatelayer.go
  14. 34 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/copylayer.go
  15. 22 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go
  16. 27 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createlayer.go
  17. 101 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go
  18. 35 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createsandboxlayer.go
  19. 26 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/deactivatelayer.go
  20. 27 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/destroylayer.go
  21. 36 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go
  22. 55 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/getlayermountpath.go
  23. 22 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/getsharedbaseimages.go
  24. 19 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/guid.go
  25. 98 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go
  26. 131 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go
  27. 35 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go
  28. 30 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/layerexists.go
  29. 111 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/layerutils.go
  30. 797 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go
  31. 20 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/nametoguid.go
  32. 36 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go
  33. 22 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go
  34. 43 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go
  35. 21 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go
  36. 20 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go
  37. 27 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/unpreparelayer.go
  38. 20 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go
  39. 559 0
      libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go
  40. 2 1
      libnetwork/drivers.go
  41. 12 0
      libnetwork/drivers/windows/labels.go
  42. 372 10
      libnetwork/drivers/windows/windows.go
  43. 141 0
      libnetwork/drivers/windows/windows_test.go
  44. 9 2
      libnetwork/drivers_windows.go
  45. 2 0
      libnetwork/ipams/builtin/builtin_unix.go
  46. 16 0
      libnetwork/ipams/builtin/builtin_windows.go
  47. 82 0
      libnetwork/ipams/windowsipam/windowsipam.go
  48. 71 0
      libnetwork/ipams/windowsipam/windowsipam_test.go
  49. 0 312
      libnetwork/sandbox.go
  50. 323 0
      libnetwork/sandbox_dns_unix.go
  51. 32 0
      libnetwork/sandbox_dns_windows.go
  52. 1 1
      libnetwork/sandbox_externalkey_unix.go
  53. 2 0
      libnetwork/testutils/context_unix.go
  54. 25 0
      libnetwork/testutils/context_windows.go

+ 8 - 0
libnetwork/Godeps/Godeps.json

@@ -9,6 +9,14 @@
 			"ImportPath": "github.com/Azure/go-ansiterm",
 			"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe"
 		},
+		{
+			"ImportPath": "github.com/Microsoft/hcsshim",
+			"Rev": "43858ef3c5c944dfaaabfbe8b6ea093da7f28dba"
+		},
+		{
+			"ImportPath": "github.com/Microsoft/go-winio",
+			"Rev": "eb176a9831c54b88eaf9eb4fbc24b94080d910ad"
+		},
 		{
 			"ImportPath": "github.com/BurntSushi/toml",
 			"Comment": "v0.1.0-16-gf706d00",

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

+ 15 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/README.md

@@ -0,0 +1,15 @@
+# go-winio
+
+This repository contains utilities for efficiently performing Win32 IO operations in 
+Go. Currently, this is focused on accessing named pipes and other file handles, and
+for using named pipes as a net transport.
+
+This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go 
+to reuse the thread to schedule another goroutine. This limits support to Windows Vista and 
+newer operating systems. This is similar to the implementation of network sockets in Go's net
+package.
+
+Please see the LICENSE file for licensing information.
+
+Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe 
+for another named pipe implementation.

+ 216 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/file.go

@@ -0,0 +1,216 @@
+package winio
+
+import (
+	"errors"
+	"io"
+	"runtime"
+	"sync"
+	"syscall"
+	"time"
+)
+
+//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
+//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
+//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
+//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
+
+const (
+	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
+	cFILE_SKIP_SET_EVENT_ON_HANDLE        = 2
+)
+
+var (
+	ErrFileClosed = errors.New("file has already been closed")
+	ErrTimeout    = &timeoutError{}
+)
+
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string   { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool   { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var ioInitOnce sync.Once
+var ioCompletionPort syscall.Handle
+
+// ioResult contains the result of an asynchronous IO operation
+type ioResult struct {
+	bytes uint32
+	err   error
+}
+
+// ioOperation represents an outstanding asynchronous Win32 IO
+type ioOperation struct {
+	o  syscall.Overlapped
+	ch chan ioResult
+}
+
+func initIo() {
+	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
+	if err != nil {
+		panic(err)
+	}
+	ioCompletionPort = h
+	go ioCompletionProcessor(h)
+}
+
+// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
+// It takes ownership of this handle and will close it if it is garbage collected.
+type win32File struct {
+	handle        syscall.Handle
+	wg            sync.WaitGroup
+	closing       bool
+	readDeadline  time.Time
+	writeDeadline time.Time
+}
+
+// makeWin32File makes a new win32File from an existing file handle
+func makeWin32File(h syscall.Handle) (*win32File, error) {
+	f := &win32File{handle: h}
+	ioInitOnce.Do(initIo)
+	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
+	if err != nil {
+		return nil, err
+	}
+	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
+	if err != nil {
+		return nil, err
+	}
+	runtime.SetFinalizer(f, (*win32File).closeHandle)
+	return f, nil
+}
+
+func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
+	return makeWin32File(h)
+}
+
+// closeHandle closes the resources associated with a Win32 handle
+func (f *win32File) closeHandle() {
+	if !f.closing {
+		// cancel all IO and wait for it to complete
+		f.closing = true
+		cancelIoEx(f.handle, nil)
+		f.wg.Wait()
+		// at this point, no new IO can start
+		syscall.Close(f.handle)
+		f.handle = 0
+	}
+}
+
+// Close closes a win32File.
+func (f *win32File) Close() error {
+	f.closeHandle()
+	runtime.SetFinalizer(f, nil)
+	return nil
+}
+
+// prepareIo prepares for a new IO operation
+func (f *win32File) prepareIo() (*ioOperation, error) {
+	f.wg.Add(1)
+	if f.closing {
+		return nil, ErrFileClosed
+	}
+	c := &ioOperation{}
+	c.ch = make(chan ioResult)
+	return c, nil
+}
+
+// ioCompletionProcessor processes completed async IOs forever
+func ioCompletionProcessor(h syscall.Handle) {
+	for {
+		var bytes uint32
+		var key uintptr
+		var op *ioOperation
+		err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
+		if op == nil {
+			panic(err)
+		}
+		op.ch <- ioResult{bytes, err}
+	}
+}
+
+// asyncIo processes the return value from ReadFile or WriteFile, blocking until
+// the operation has actually completed.
+func (f *win32File) asyncIo(c *ioOperation, deadline time.Time, bytes uint32, err error) (int, error) {
+	if err != syscall.ERROR_IO_PENDING {
+		f.wg.Done()
+		return int(bytes), err
+	} else {
+		var r ioResult
+		wait := true
+		timedout := false
+		if f.closing {
+			cancelIoEx(f.handle, &c.o)
+		} else if !deadline.IsZero() {
+			now := time.Now()
+			if !deadline.After(now) {
+				timedout = true
+			} else {
+				timeout := time.After(deadline.Sub(now))
+				select {
+				case r = <-c.ch:
+					wait = false
+				case <-timeout:
+					timedout = true
+				}
+			}
+		}
+		if timedout {
+			cancelIoEx(f.handle, &c.o)
+		}
+		if wait {
+			r = <-c.ch
+		}
+		err = r.err
+		if err == syscall.ERROR_OPERATION_ABORTED {
+			if f.closing {
+				err = ErrFileClosed
+			} else if timedout {
+				err = ErrTimeout
+			}
+		}
+		f.wg.Done()
+		return int(r.bytes), err
+	}
+}
+
+// Read reads from a file handle.
+func (f *win32File) Read(b []byte) (int, error) {
+	c, err := f.prepareIo()
+	if err != nil {
+		return 0, err
+	}
+	var bytes uint32
+	err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
+	n, err := f.asyncIo(c, f.readDeadline, bytes, err)
+
+	// Handle EOF conditions.
+	if err == nil && n == 0 && len(b) != 0 {
+		return 0, io.EOF
+	} else if err == syscall.ERROR_BROKEN_PIPE {
+		return 0, io.EOF
+	} else {
+		return n, err
+	}
+}
+
+// Write writes to a file handle.
+func (f *win32File) Write(b []byte) (int, error) {
+	c, err := f.prepareIo()
+	if err != nil {
+		return 0, err
+	}
+	var bytes uint32
+	err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
+	return f.asyncIo(c, f.writeDeadline, bytes, err)
+}
+
+func (f *win32File) SetReadDeadline(t time.Time) error {
+	f.readDeadline = t
+	return nil
+}
+
+func (f *win32File) SetWriteDeadline(t time.Time) error {
+	f.writeDeadline = t
+	return nil
+}

+ 797 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/mksyscall_windows.go

@@ -0,0 +1,797 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+mksyscall_windows generates windows system call bodies
+
+It parses all files specified on command line containing function
+prototypes (like syscall_windows.go) and prints system call bodies
+to standard output.
+
+The prototypes are marked by lines beginning with "//sys" and read
+like func declarations if //sys is replaced by func, but:
+
+* The parameter lists must give a name for each argument. This
+  includes return parameters.
+
+* The parameter lists must give a type for each argument:
+  the (x, y, z int) shorthand is not allowed.
+
+* If the return parameter is an error number, it must be named err.
+
+* If go func name needs to be different from it's winapi dll name,
+  the winapi name could be specified at the end, after "=" sign, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+
+* Each function that returns err needs to supply a condition, that
+  return value of winapi will be tested against to detect failure.
+  This would set err to windows "last-error", otherwise it will be nil.
+  The value can be provided at end of //sys declaration, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
+  and is [failretval==0] by default.
+
+Usage:
+	mksyscall_windows [flags] [path ...]
+
+The flags are:
+	-output
+		Specify output file name (outputs to console if blank).
+	-trace
+		Generate print statement after every syscall.
+*/
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+	"text/template"
+)
+
+var (
+	filename       = flag.String("output", "", "output file name (standard output if omitted)")
+	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+)
+
+func trim(s string) string {
+	return strings.Trim(s, " \t")
+}
+
+var packageName string
+
+func packagename() string {
+	return packageName
+}
+
+func syscalldot() string {
+	if packageName == "syscall" {
+		return ""
+	}
+	return "syscall."
+}
+
+// Param is function parameter
+type Param struct {
+	Name      string
+	Type      string
+	fn        *Fn
+	tmpVarIdx int
+}
+
+// tmpVar returns temp variable name that will be used to represent p during syscall.
+func (p *Param) tmpVar() string {
+	if p.tmpVarIdx < 0 {
+		p.tmpVarIdx = p.fn.curTmpVarIdx
+		p.fn.curTmpVarIdx++
+	}
+	return fmt.Sprintf("_p%d", p.tmpVarIdx)
+}
+
+// BoolTmpVarCode returns source code for bool temp variable.
+func (p *Param) BoolTmpVarCode() string {
+	const code = `var %s uint32
+	if %s {
+		%s = 1
+	} else {
+		%s = 0
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
+}
+
+// SliceTmpVarCode returns source code for slice temp variable.
+func (p *Param) SliceTmpVarCode() string {
+	const code = `var %s *%s
+	if len(%s) > 0 {
+		%s = &%s[0]
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
+}
+
+// StringTmpVarCode returns source code for string temp variable.
+func (p *Param) StringTmpVarCode() string {
+	errvar := p.fn.Rets.ErrorVarName()
+	if errvar == "" {
+		errvar = "_"
+	}
+	tmp := p.tmpVar()
+	const code = `var %s %s
+	%s, %s = %s(%s)`
+	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
+	if errvar == "-" {
+		return s
+	}
+	const morecode = `
+	if %s != nil {
+		return
+	}`
+	return s + fmt.Sprintf(morecode, errvar)
+}
+
+// TmpVarCode returns source code for temp variable.
+func (p *Param) TmpVarCode() string {
+	switch {
+	case p.Type == "bool":
+		return p.BoolTmpVarCode()
+	case strings.HasPrefix(p.Type, "[]"):
+		return p.SliceTmpVarCode()
+	default:
+		return ""
+	}
+}
+
+// TmpVarHelperCode returns source code for helper's temp variable.
+func (p *Param) TmpVarHelperCode() string {
+	if p.Type != "string" {
+		return ""
+	}
+	return p.StringTmpVarCode()
+}
+
+// SyscallArgList returns source code fragments representing p parameter
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
+// the first element and length.
+func (p *Param) SyscallArgList() []string {
+	t := p.HelperType()
+	var s string
+	switch {
+	case t[0] == '*':
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
+	case t == "bool":
+		s = p.tmpVar()
+	case strings.HasPrefix(t, "[]"):
+		return []string{
+			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
+			fmt.Sprintf("uintptr(len(%s))", p.Name),
+		}
+	default:
+		s = p.Name
+	}
+	return []string{fmt.Sprintf("uintptr(%s)", s)}
+}
+
+// IsError determines if p parameter is used to return error.
+func (p *Param) IsError() bool {
+	return p.Name == "err" && p.Type == "error"
+}
+
+// HelperType returns type of parameter p used in helper function.
+func (p *Param) HelperType() string {
+	if p.Type == "string" {
+		return p.fn.StrconvType()
+	}
+	return p.Type
+}
+
+// join concatenates parameters ps into a string with sep separator.
+// Each parameter is converted into string by applying fn to it
+// before conversion.
+func join(ps []*Param, fn func(*Param) string, sep string) string {
+	if len(ps) == 0 {
+		return ""
+	}
+	a := make([]string, 0)
+	for _, p := range ps {
+		a = append(a, fn(p))
+	}
+	return strings.Join(a, sep)
+}
+
+// Rets describes function return parameters.
+type Rets struct {
+	Name         string
+	Type         string
+	ReturnsError bool
+	FailCond     string
+}
+
+// ErrorVarName returns error variable name for r.
+func (r *Rets) ErrorVarName() string {
+	if r.ReturnsError {
+		return "err"
+	}
+	if r.Type == "error" {
+		return r.Name
+	}
+	return ""
+}
+
+// ToParams converts r into slice of *Param.
+func (r *Rets) ToParams() []*Param {
+	ps := make([]*Param, 0)
+	if len(r.Name) > 0 {
+		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
+	}
+	if r.ReturnsError {
+		ps = append(ps, &Param{Name: "err", Type: "error"})
+	}
+	return ps
+}
+
+// List returns source code of syscall return parameters.
+func (r *Rets) List() string {
+	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+	if len(s) > 0 {
+		s = "(" + s + ")"
+	}
+	return s
+}
+
+// PrintList returns source code of trace printing part correspondent
+// to syscall return values.
+func (r *Rets) PrintList() string {
+	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// SetReturnValuesCode returns source code that accepts syscall return values.
+func (r *Rets) SetReturnValuesCode() string {
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	retvar := "r0"
+	if r.Name == "" {
+		retvar = "r1"
+	}
+	errvar := "_"
+	if r.ReturnsError {
+		errvar = "e1"
+	}
+	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
+}
+
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
+	const code = `if %s {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = %sEINVAL
+		}
+	}`
+	cond := retvar + " == 0"
+	if r.FailCond != "" {
+		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
+	}
+	return fmt.Sprintf(code, cond, syscalldot())
+}
+
+// SetErrorCode returns source code that sets return parameters.
+func (r *Rets) SetErrorCode() string {
+	const code = `if r0 != 0 {
+		%s = %sErrno(r0)
+	}`
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	if r.Name == "" {
+		return r.useLongHandleErrorCode("r1")
+	}
+	if r.Type == "error" {
+		return fmt.Sprintf(code, r.Name, syscalldot())
+	}
+	s := ""
+	switch {
+	case r.Type[0] == '*':
+		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
+	case r.Type == "bool":
+		s = fmt.Sprintf("%s = r0 != 0", r.Name)
+	default:
+		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
+	}
+	if !r.ReturnsError {
+		return s
+	}
+	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
+}
+
+// Fn describes syscall function.
+type Fn struct {
+	Name        string
+	Params      []*Param
+	Rets        *Rets
+	PrintTrace  bool
+	confirmproc bool
+	dllname     string
+	dllfuncname string
+	src         string
+	// TODO: get rid of this field and just use parameter index instead
+	curTmpVarIdx int // insure tmp variables have uniq names
+}
+
+// extractParams parses s to extract function parameters.
+func extractParams(s string, f *Fn) ([]*Param, error) {
+	s = trim(s)
+	if s == "" {
+		return nil, nil
+	}
+	a := strings.Split(s, ",")
+	ps := make([]*Param, len(a))
+	for i := range ps {
+		s2 := trim(a[i])
+		b := strings.Split(s2, " ")
+		if len(b) != 2 {
+			b = strings.Split(s2, "\t")
+			if len(b) != 2 {
+				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
+			}
+		}
+		ps[i] = &Param{
+			Name:      trim(b[0]),
+			Type:      trim(b[1]),
+			fn:        f,
+			tmpVarIdx: -1,
+		}
+	}
+	return ps, nil
+}
+
+// extractSection extracts text out of string s starting after start
+// and ending just before end. found return value will indicate success,
+// and prefix, body and suffix will contain correspondent parts of string s.
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
+	s = trim(s)
+	if strings.HasPrefix(s, string(start)) {
+		// no prefix
+		body = s[1:]
+	} else {
+		a := strings.SplitN(s, string(start), 2)
+		if len(a) != 2 {
+			return "", "", s, false
+		}
+		prefix = a[0]
+		body = a[1]
+	}
+	a := strings.SplitN(body, string(end), 2)
+	if len(a) != 2 {
+		return "", "", "", false
+	}
+	return prefix, a[0], a[1], true
+}
+
+// newFn parses string s and return created function Fn.
+func newFn(s string) (*Fn, error) {
+	s = trim(s)
+	f := &Fn{
+		Rets:       &Rets{},
+		src:        s,
+		PrintTrace: *printTraceFlag,
+	}
+	// function name and args
+	prefix, body, s, found := extractSection(s, '(', ')')
+	if !found || prefix == "" {
+		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
+	}
+	f.Name = prefix
+	var err error
+	f.Params, err = extractParams(body, f)
+	if err != nil {
+		return nil, err
+	}
+	// return values
+	_, body, s, found = extractSection(s, '(', ')')
+	if found {
+		r, err := extractParams(body, f)
+		if err != nil {
+			return nil, err
+		}
+		switch len(r) {
+		case 0:
+		case 1:
+			if r[0].IsError() {
+				f.Rets.ReturnsError = true
+			} else {
+				f.Rets.Name = r[0].Name
+				f.Rets.Type = r[0].Type
+			}
+		case 2:
+			if !r[1].IsError() {
+				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
+			}
+			f.Rets.ReturnsError = true
+			f.Rets.Name = r[0].Name
+			f.Rets.Type = r[0].Type
+		default:
+			return nil, errors.New("Too many return values in \"" + f.src + "\"")
+		}
+	}
+	// fail condition
+	_, body, s, found = extractSection(s, '[', ']')
+	if found {
+		f.Rets.FailCond = body
+	}
+	// dll and dll function names
+	s = trim(s)
+	if s == "" {
+		return f, nil
+	}
+	if !strings.HasPrefix(s, "=") {
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	s = trim(s[1:])
+	a := strings.Split(s, ".")
+	switch len(a) {
+	case 1:
+		f.dllfuncname = a[0]
+	case 2:
+		f.dllname = a[0]
+		f.dllfuncname = a[1]
+	default:
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
+		f.confirmproc = true
+		f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
+	}
+	return f, nil
+}
+
+// DLLName returns DLL name for function f.
+func (f *Fn) DLLName() string {
+	if f.dllname == "" {
+		return "kernel32"
+	}
+	return f.dllname
+}
+
+// DLLName returns DLL function name for function f.
+func (f *Fn) DLLFuncName() string {
+	if f.dllfuncname == "" {
+		return f.Name
+	}
+	return f.dllfuncname
+}
+
+func (f *Fn) ConfirmProc() bool {
+	return f.confirmproc
+}
+
+// ParamList returns source code for function f parameters.
+func (f *Fn) ParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+}
+
+// HelperParamList returns source code for helper function f parameters.
+func (f *Fn) HelperParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
+}
+
+// ParamPrintList returns source code of trace printing part correspondent
+// to syscall input parameters.
+func (f *Fn) ParamPrintList() string {
+	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// ParamCount return number of syscall parameters for function f.
+func (f *Fn) ParamCount() int {
+	n := 0
+	for _, p := range f.Params {
+		n += len(p.SyscallArgList())
+	}
+	return n
+}
+
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
+// to use. It returns parameter count for correspondent SyscallX function.
+func (f *Fn) SyscallParamCount() int {
+	n := f.ParamCount()
+	switch {
+	case n <= 3:
+		return 3
+	case n <= 6:
+		return 6
+	case n <= 9:
+		return 9
+	case n <= 12:
+		return 12
+	case n <= 15:
+		return 15
+	default:
+		panic("too many arguments to system call")
+	}
+}
+
+// Syscall determines which SyscallX function to use for function f.
+func (f *Fn) Syscall() string {
+	c := f.SyscallParamCount()
+	if c == 3 {
+		return syscalldot() + "Syscall"
+	}
+	return syscalldot() + "Syscall" + strconv.Itoa(c)
+}
+
+// SyscallParamList returns source code for SyscallX parameters for function f.
+func (f *Fn) SyscallParamList() string {
+	a := make([]string, 0)
+	for _, p := range f.Params {
+		a = append(a, p.SyscallArgList()...)
+	}
+	for len(a) < f.SyscallParamCount() {
+		a = append(a, "0")
+	}
+	return strings.Join(a, ", ")
+}
+
+// HelperCallParamList returns source code of call into function f helper.
+func (f *Fn) HelperCallParamList() string {
+	a := make([]string, 0, len(f.Params))
+	for _, p := range f.Params {
+		s := p.Name
+		if p.Type == "string" {
+			s = p.tmpVar()
+		}
+		a = append(a, s)
+	}
+	return strings.Join(a, ", ")
+}
+
+// IsUTF16 is true, if f is W (utf16) function. It is false
+// for all A (ascii) functions.
+func (_ *Fn) IsUTF16() bool {
+	return true
+}
+
+// StrconvFunc returns name of Go string to OS string function for f.
+func (f *Fn) StrconvFunc() string {
+	if f.IsUTF16() {
+		return syscalldot() + "UTF16PtrFromString"
+	}
+	return syscalldot() + "BytePtrFromString"
+}
+
+// StrconvType returns Go type name used for OS string for f.
+func (f *Fn) StrconvType() string {
+	if f.IsUTF16() {
+		return "*uint16"
+	}
+	return "*byte"
+}
+
+// HasStringParam is true, if f has at least one string parameter.
+// Otherwise it is false.
+func (f *Fn) HasStringParam() bool {
+	for _, p := range f.Params {
+		if p.Type == "string" {
+			return true
+		}
+	}
+	return false
+}
+
+// HelperName returns name of function f helper.
+func (f *Fn) HelperName() string {
+	if !f.HasStringParam() {
+		return f.Name
+	}
+	return "_" + f.Name
+}
+
+// Source files and functions.
+type Source struct {
+	Funcs []*Fn
+	Files []string
+}
+
+// ParseFiles parses files listed in fs and extracts all syscall
+// functions listed in  sys comments. It returns source files
+// and functions collection *Source if successful.
+func ParseFiles(fs []string) (*Source, error) {
+	src := &Source{
+		Funcs: make([]*Fn, 0),
+		Files: make([]string, 0),
+	}
+	for _, file := range fs {
+		if err := src.ParseFile(file); err != nil {
+			return nil, err
+		}
+	}
+	return src, nil
+}
+
+// DLLs return dll names for a source set src.
+func (src *Source) DLLs() []string {
+	uniq := make(map[string]bool)
+	r := make([]string, 0)
+	for _, f := range src.Funcs {
+		name := f.DLLName()
+		if _, found := uniq[name]; !found {
+			uniq[name] = true
+			r = append(r, name)
+		}
+	}
+	return r
+}
+
+// ParseFile adds additional file path to a source set src.
+func (src *Source) ParseFile(path string) error {
+	file, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	s := bufio.NewScanner(file)
+	for s.Scan() {
+		t := trim(s.Text())
+		if len(t) < 7 {
+			continue
+		}
+		if !strings.HasPrefix(t, "//sys") {
+			continue
+		}
+		t = t[5:]
+		if !(t[0] == ' ' || t[0] == '\t') {
+			continue
+		}
+		f, err := newFn(t[1:])
+		if err != nil {
+			return err
+		}
+		src.Funcs = append(src.Funcs, f)
+	}
+	if err := s.Err(); err != nil {
+		return err
+	}
+	src.Files = append(src.Files, path)
+
+	// get package name
+	fset := token.NewFileSet()
+	_, err = file.Seek(0, 0)
+	if err != nil {
+		return err
+	}
+	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
+	if err != nil {
+		return err
+	}
+	packageName = pkg.Name.Name
+
+	return nil
+}
+
+// Generate output source file from a source set src.
+func (src *Source) Generate(w io.Writer) error {
+	funcMap := template.FuncMap{
+		"packagename": packagename,
+		"syscalldot":  syscalldot,
+	}
+	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
+	err := t.Execute(w, src)
+	if err != nil {
+		return errors.New("Failed to execute template: " + err.Error())
+	}
+	return nil
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
+	flag.PrintDefaults()
+	os.Exit(1)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+	if len(flag.Args()) <= 0 {
+		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
+		usage()
+	}
+
+	src, err := ParseFiles(flag.Args())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var buf bytes.Buffer
+	if err := src.Generate(&buf); err != nil {
+		log.Fatal(err)
+	}
+
+	data, err := format.Source(buf.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+	if *filename == "" {
+		_, err = os.Stdout.Write(data)
+	} else {
+		err = ioutil.WriteFile(*filename, data, 0644)
+	}
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+// TODO: use println instead to print in the following template
+const srcTemplate = `
+
+{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package {{packagename}}
+
+import "unsafe"{{if syscalldot}}
+import "syscall"{{end}}
+
+var _ unsafe.Pointer
+
+var (
+{{template "dlls" .}}
+{{template "funcnames" .}})
+{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
+{{end}}
+
+{{/* help functions */}}
+
+{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
+{{end}}{{end}}
+
+{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
+{{end}}{{end}}
+
+{{define "helperbody"}}
+func {{.Name}}({{.ParamList}}) {{template "results" .}}{
+{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
+}
+{{end}}
+
+{{define "funcbody"}}
+func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
+{{template "tmpvars" .}}	{{template "syscallcheck" .}}{{template "syscall" .}}
+{{template "seterror" .}}{{template "printtrace" .}}	return
+}
+{{end}}
+
+{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
+{{end}}{{end}}{{end}}
+
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
+{{end}}{{end}}{{end}}
+
+{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
+
+{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
+    return
+}
+{{end}}{{end}}
+
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+
+{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
+{{end}}{{end}}
+
+{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
+{{end}}{{end}}
+
+`

+ 280 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe.go

@@ -0,0 +1,280 @@
+package winio
+
+import (
+	"errors"
+	"net"
+	"os"
+	"syscall"
+	"time"
+	"unsafe"
+)
+
+//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
+//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error)  [failretval==syscall.InvalidHandle] = CreateNamedPipeW
+//sys createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
+//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
+
+type securityAttributes struct {
+	Length             uint32
+	SecurityDescriptor *byte
+	InheritHandle      uint32
+}
+
+const (
+	cERROR_PIPE_BUSY      = syscall.Errno(231)
+	cERROR_PIPE_CONNECTED = syscall.Errno(535)
+	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
+
+	cPIPE_ACCESS_DUPLEX            = 0x3
+	cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
+	cSECURITY_SQOS_PRESENT         = 0x100000
+	cSECURITY_ANONYMOUS            = 0
+
+	cPIPE_REJECT_REMOTE_CLIENTS = 0x8
+
+	cPIPE_UNLIMITED_INSTANCES = 255
+
+	cNMPWAIT_USE_DEFAULT_WAIT = 0
+	cNMPWAIT_NOWAIT           = 1
+)
+
+var (
+	// This error should match net.errClosing since docker takes a dependency on its text
+	ErrPipeListenerClosed = errors.New("use of closed network connection")
+)
+
+type win32Pipe struct {
+	*win32File
+	path string
+}
+
+type pipeAddress string
+
+func (f *win32Pipe) LocalAddr() net.Addr {
+	return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) RemoteAddr() net.Addr {
+	return pipeAddress(f.path)
+}
+
+func (f *win32Pipe) SetDeadline(t time.Time) error {
+	f.SetReadDeadline(t)
+	f.SetWriteDeadline(t)
+	return nil
+}
+
+func (s pipeAddress) Network() string {
+	return "pipe"
+}
+
+func (s pipeAddress) String() string {
+	return string(s)
+}
+
+func makeWin32Pipe(h syscall.Handle, path string) (*win32Pipe, error) {
+	f, err := makeWin32File(h)
+	if err != nil {
+		return nil, err
+	}
+	return &win32Pipe{f, path}, nil
+}
+
+// DialPipe connects to a named pipe by path, timing out if the connection
+// takes longer than the specified duration. If timeout is nil, then the timeout
+// is the default timeout established by the pipe server.
+func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
+	var absTimeout time.Time
+	if timeout != nil {
+		absTimeout = time.Now().Add(*timeout)
+	}
+	var err error
+	var h syscall.Handle
+	for {
+		h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
+		if err != cERROR_PIPE_BUSY {
+			break
+		}
+		now := time.Now()
+		var ms uint32
+		if absTimeout.IsZero() {
+			ms = cNMPWAIT_USE_DEFAULT_WAIT
+		} else if now.After(absTimeout) {
+			ms = cNMPWAIT_NOWAIT
+		} else {
+			ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
+		}
+		err = waitNamedPipe(path, ms)
+		if err != nil {
+			if err == cERROR_SEM_TIMEOUT {
+				return nil, ErrTimeout
+			}
+			break
+		}
+	}
+	if err != nil {
+		return nil, &os.PathError{"open", path, err}
+	}
+	p, err := makeWin32Pipe(h, path)
+	if err != nil {
+		syscall.Close(h)
+		return nil, err
+	}
+	return p, nil
+}
+
+type acceptResponse struct {
+	p   *win32Pipe
+	err error
+}
+
+type win32PipeListener struct {
+	firstHandle        syscall.Handle
+	path               string
+	securityDescriptor []byte
+	acceptCh           chan (chan acceptResponse)
+	closeCh            chan int
+	doneCh             chan int
+}
+
+func makeServerPipeHandle(path string, securityDescriptor []byte, first bool) (syscall.Handle, error) {
+	var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
+	if first {
+		flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
+	}
+	var sa securityAttributes
+	sa.Length = uint32(unsafe.Sizeof(sa))
+	if securityDescriptor != nil {
+		sa.SecurityDescriptor = &securityDescriptor[0]
+	}
+	h, err := createNamedPipe(path, flags, cPIPE_REJECT_REMOTE_CLIENTS, cPIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &sa)
+	if err != nil {
+		return 0, &os.PathError{"open", path, err}
+	}
+	return h, nil
+}
+
+func (l *win32PipeListener) makeServerPipe() (*win32Pipe, error) {
+	h, err := makeServerPipeHandle(l.path, l.securityDescriptor, false)
+	if err != nil {
+		return nil, err
+	}
+	p, err := makeWin32Pipe(h, l.path)
+	if err != nil {
+		syscall.Close(h)
+		return nil, err
+	}
+	return p, nil
+}
+
+func (l *win32PipeListener) listenerRoutine() {
+	closed := false
+	for !closed {
+		select {
+		case <-l.closeCh:
+			closed = true
+		case responseCh := <-l.acceptCh:
+			p, err := l.makeServerPipe()
+			if err == nil {
+				// Wait for the client to connect.
+				ch := make(chan error)
+				go func() {
+					ch <- connectPipe(p)
+				}()
+				select {
+				case err = <-ch:
+					if err != nil {
+						p.Close()
+						p = nil
+					}
+				case <-l.closeCh:
+					// Abort the connect request by closing the handle.
+					p.Close()
+					p = nil
+					err = <-ch
+					if err == nil || err == ErrFileClosed {
+						err = ErrPipeListenerClosed
+					}
+					closed = true
+				}
+			}
+			responseCh <- acceptResponse{p, err}
+		}
+	}
+	syscall.Close(l.firstHandle)
+	l.firstHandle = 0
+	// Notify Close() and Accept() callers that the handle has been closed.
+	close(l.doneCh)
+}
+
+func ListenPipe(path, sddl string) (net.Listener, error) {
+	var (
+		sd  []byte
+		err error
+	)
+	if sddl != "" {
+		sd, err = sddlToSecurityDescriptor(sddl)
+		if err != nil {
+			return nil, err
+		}
+	}
+	h, err := makeServerPipeHandle(path, sd, true)
+	if err != nil {
+		return nil, err
+	}
+	// Immediately open and then close a client handle so that the named pipe is
+	// created but not currently accepting connections.
+	h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
+	if err != nil {
+		syscall.Close(h)
+		return nil, err
+	}
+	syscall.Close(h2)
+	l := &win32PipeListener{
+		firstHandle:        h,
+		path:               path,
+		securityDescriptor: sd,
+		acceptCh:           make(chan (chan acceptResponse)),
+		closeCh:            make(chan int),
+		doneCh:             make(chan int),
+	}
+	go l.listenerRoutine()
+	return l, nil
+}
+
+func connectPipe(p *win32Pipe) error {
+	c, err := p.prepareIo()
+	if err != nil {
+		return err
+	}
+	err = connectNamedPipe(p.handle, &c.o)
+	_, err = p.asyncIo(c, time.Time{}, 0, err)
+	if err != nil && err != cERROR_PIPE_CONNECTED {
+		return err
+	}
+	return nil
+}
+
+func (l *win32PipeListener) Accept() (net.Conn, error) {
+	ch := make(chan acceptResponse)
+	select {
+	case l.acceptCh <- ch:
+		response := <-ch
+		return response.p, response.err
+	case <-l.doneCh:
+		return nil, ErrPipeListenerClosed
+	}
+}
+
+func (l *win32PipeListener) Close() error {
+	select {
+	case l.closeCh <- 1:
+		<-l.doneCh
+	case <-l.doneCh:
+	}
+	return nil
+}
+
+func (l *win32PipeListener) Addr() net.Addr {
+	return pipeAddress(l.path)
+}

+ 199 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/pipe_test.go

@@ -0,0 +1,199 @@
+package winio
+
+import (
+	"bufio"
+	"net"
+	"os"
+	"syscall"
+	"testing"
+	"time"
+)
+
+var testPipeName = `\\.\pipe\winiotestpipe`
+
+func TestDialUnknownFailsImmediately(t *testing.T) {
+	_, err := DialPipe(testPipeName, nil)
+	if err.(*os.PathError).Err != syscall.ENOENT {
+		t.Fatalf("expected ENOENT got %v", err)
+	}
+}
+
+func TestDialListenerTimesOut(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer l.Close()
+	var d = time.Duration(10 * time.Millisecond)
+	_, err = DialPipe(testPipeName, &d)
+	if err != ErrTimeout {
+		t.Fatalf("expected ErrTimeout, got %v", err)
+	}
+}
+
+func TestDialAccessDeniedWithRestrictedSD(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "D:P(A;;0x1200FF;;;WD)")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer l.Close()
+	_, err = DialPipe(testPipeName, nil)
+	if err.(*os.PathError).Err != syscall.ERROR_ACCESS_DENIED {
+		t.Fatalf("expected ERROR_ACCESS_DENIED, got %v", err)
+	}
+}
+
+func getConnection() (client net.Conn, server net.Conn, err error) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		return
+	}
+	defer l.Close()
+
+	type response struct {
+		c   net.Conn
+		err error
+	}
+	ch := make(chan response)
+	go func() {
+		c, err := l.Accept()
+		ch <- response{c, err}
+	}()
+
+	c, err := DialPipe(testPipeName, nil)
+	if err != nil {
+		return
+	}
+
+	r := <-ch
+	if err = r.err; err != nil {
+		c.Close()
+		return
+	}
+
+	client = c
+	server = r.c
+	return
+}
+
+func TestReadTimeout(t *testing.T) {
+	c, s, err := getConnection()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	defer s.Close()
+
+	c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
+
+	buf := make([]byte, 10)
+	_, err = c.Read(buf)
+	if err != ErrTimeout {
+		t.Fatalf("expected ErrTimeout, got %v", err)
+	}
+}
+
+func server(l net.Listener, ch chan int) {
+	c, err := l.Accept()
+	if err != nil {
+		panic(err)
+	}
+	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
+	s, err := rw.ReadString('\n')
+	if err != nil {
+		panic(err)
+	}
+	_, err = rw.WriteString("got " + s)
+	if err != nil {
+		panic(err)
+	}
+	err = rw.Flush()
+	if err != nil {
+		panic(err)
+	}
+	c.Close()
+	ch <- 1
+}
+
+func TestFullListenDialReadWrite(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer l.Close()
+
+	ch := make(chan int)
+	go server(l, ch)
+
+	c, err := DialPipe(testPipeName, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	rw := bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c))
+	_, err = rw.WriteString("hello world\n")
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = rw.Flush()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s, err := rw.ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	ms := "got hello world\n"
+	if s != ms {
+		t.Errorf("expected '%s', got '%s'", ms, s)
+	}
+
+	<-ch
+}
+
+func TestCloseAbortsListen(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ch := make(chan error)
+	go func() {
+		_, err := l.Accept()
+		ch <- err
+	}()
+
+	time.Sleep(30 * time.Millisecond)
+	l.Close()
+
+	err = <-ch
+	if err != ErrPipeListenerClosed {
+		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
+	}
+}
+
+func TestAcceptAfterCloseFails(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	l.Close()
+	_, err = l.Accept()
+	if err != ErrPipeListenerClosed {
+		t.Fatalf("expected ErrPipeListenerClosed, got %v", err)
+	}
+}
+
+func TestDialTimesOutByDefault(t *testing.T) {
+	l, err := ListenPipe(testPipeName, "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer l.Close()
+	_, err = DialPipe(testPipeName, nil)
+	if err != ErrTimeout {
+		t.Fatalf("expected ErrTimeout, got %v", err)
+	}
+}

+ 83 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd.go

@@ -0,0 +1,83 @@
+package winio
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
+//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
+//sys localFree(mem uintptr) = LocalFree
+//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
+
+const (
+	cERROR_NONE_MAPPED = syscall.Errno(1332)
+)
+
+type AccountLookupError struct {
+	Name string
+	Err  error
+}
+
+func (e *AccountLookupError) Error() string {
+	if e.Name == "" {
+		return "lookup account: empty account name specified"
+	}
+	var s string
+	switch e.Err {
+	case cERROR_NONE_MAPPED:
+		s = "not found"
+	default:
+		s = e.Err.Error()
+	}
+	return "lookup account " + e.Name + ": " + s
+}
+
+type SddlConversionError struct {
+	Sddl string
+	Err  error
+}
+
+func (e *SddlConversionError) Error() string {
+	return "convert " + e.Sddl + ": " + e.Err.Error()
+}
+
+// LookupSidByName looks up the SID of an account by name
+func LookupSidByName(name string) (sid string, err error) {
+	if name == "" {
+		return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
+	}
+
+	var sidSize, sidNameUse, refDomainSize uint32
+	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
+	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
+		return "", &AccountLookupError{name, err}
+	}
+	sidBuffer := make([]byte, sidSize)
+	refDomainBuffer := make([]uint16, refDomainSize)
+	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
+	if err != nil {
+		return "", &AccountLookupError{name, err}
+	}
+	var strBuffer *uint16
+	err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
+	if err != nil {
+		return "", &AccountLookupError{name, err}
+	}
+	sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
+	localFree(uintptr(unsafe.Pointer(strBuffer)))
+	return sid, nil
+}
+
+func sddlToSecurityDescriptor(sddl string) ([]byte, error) {
+	var sdBuffer uintptr
+	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
+	if err != nil {
+		return nil, &SddlConversionError{sddl, err}
+	}
+	defer localFree(sdBuffer)
+	sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
+	copy(sd, (*[1 << 30]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
+	return sd, nil
+}

+ 26 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/sd_test.go

@@ -0,0 +1,26 @@
+package winio
+
+import "testing"
+
+func TestLookupInvalidSid(t *testing.T) {
+	_, err := LookupSidByName(".\\weoifjdsklfj")
+	aerr, ok := err.(*AccountLookupError)
+	if !ok || aerr.Err != cERROR_NONE_MAPPED {
+		t.Fatalf("expected AccountLookupError with ERROR_NONE_MAPPED, got %s", err)
+	}
+}
+
+func TestLookupValidSid(t *testing.T) {
+	sid, err := LookupSidByName("Everyone")
+	if err != nil || sid != "S-1-1-0" {
+		t.Fatal("expected S-1-1-0, got %s, %s", sid, err)
+	}
+}
+
+func TestLookupEmptyNameFails(t *testing.T) {
+	_, err := LookupSidByName(".\\weoifjdsklfj")
+	aerr, ok := err.(*AccountLookupError)
+	if !ok || aerr.Err != cERROR_NONE_MAPPED {
+		t.Fatalf("expected AccountLookupError with ERROR_NONE_MAPPED, got %s", err)
+	}
+}

+ 3 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/syscall.go

@@ -0,0 +1,3 @@
+package winio
+
+//go:generate go run mksyscall_windows.go -output zsyscall.go file.go pipe.go sd.go

+ 218 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/go-winio/zsyscall.go

@@ -0,0 +1,218 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package winio
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
+
+	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx")
+	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort")
+	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus")
+	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes")
+	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe")
+	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW")
+	procCreateFileW                                          = modkernel32.NewProc("CreateFileW")
+	procWaitNamedPipeW                                       = modkernel32.NewProc("WaitNamedPipeW")
+	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
+	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
+	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
+	procLocalFree                                            = modkernel32.NewProc("LocalFree")
+	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
+)
+
+func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
+	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
+	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
+	newport = syscall.Handle(r0)
+	if newport == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
+	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
+	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
+}
+
+func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *securityAttributes) (handle syscall.Handle, err error) {
+	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func createFile(name string, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
+}
+
+func _createFile(name *uint16, access uint32, mode uint32, sa *securityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
+	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+	handle = syscall.Handle(r0)
+	if handle == syscall.InvalidHandle {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func waitNamedPipe(name string, timeout uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return
+	}
+	return _waitNamedPipe(_p0, timeout)
+}
+
+func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(accountName)
+	if err != nil {
+		return
+	}
+	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
+}
+
+func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func convertSidToStringSid(sid *byte, str **uint16) (err error) {
+	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
+	var _p0 *uint16
+	_p0, err = syscall.UTF16PtrFromString(str)
+	if err != nil {
+		return
+	}
+	return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
+}
+
+func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func localFree(mem uintptr) {
+	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
+	return
+}
+
+func getSecurityDescriptorLength(sd uintptr) (len uint32) {
+	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
+	len = uint32(r0)
+	return
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Microsoft
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+

+ 28 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/activatelayer.go

@@ -0,0 +1,28 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// ActivateLayer will find the layer with the given id and mount it's filesystem.
+// For a read/write layer, the mounted filesystem will appear as a volume on the
+// host, while a read-only layer is generally expected to be a no-op.
+// An activated layer must later be deactivated via DeactivateLayer.
+func ActivateLayer(info DriverInfo, id string) error {
+	title := "hcsshim::ActivateLayer "
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
+
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = activateLayer(&infop, id)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" - succeeded id=%s flavour=%d", id, info.Flavour)
+	return nil
+}

+ 34 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/copylayer.go

@@ -0,0 +1,34 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// CopyLayer performs a commit of the srcId (which is expected to be a read-write
+// layer) into a new read-only layer at dstId.  This requires the full list of
+// on-disk paths to parent layers, provided in parentLayerPaths, in order to
+// complete the commit.
+func CopyLayer(info DriverInfo, srcId, dstId string, parentLayerPaths []string) error {
+	title := "hcsshim::CopyLayer "
+	logrus.Debugf(title+"srcId %s dstId", srcId, dstId)
+
+	// Generate layer descriptors
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return err
+	}
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		return err
+	}
+
+	err = copyLayer(&infop, srcId, dstId, layers)
+	if err != nil {
+		err = makeErrorf(err, title, "srcId=%s dstId=%d", srcId, dstId)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" - succeeded srcId=%s dstId=%s", srcId, dstId)
+	return nil
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createcomputesystem.go

@@ -0,0 +1,22 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// CreateComputeSystem creates a container, initializing its configuration in
+// the Host Compute Service such that it can be started by a call to the
+// StartComputeSystem method.
+func CreateComputeSystem(id string, configuration string) error {
+
+	title := "HCSShim::CreateComputeSystem"
+	logrus.Debugln(title+" id=%s, configuration=%s", id, configuration)
+
+	err := createComputeSystem(id, configuration)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s configuration=%s", id, configuration)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"- succeeded %s", id)
+	return nil
+}

+ 27 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createlayer.go

@@ -0,0 +1,27 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// CreateLayer creates a new, empty, read-only layer on the filesystem based on
+// the parent layer provided.
+func CreateLayer(info DriverInfo, id, parent string) error {
+	title := "hcsshim::CreateLayer "
+	logrus.Debugf(title+"Flavour %d ID %s parent %s", info.Flavour, id, parent)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = createLayer(&infop, id, parent)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s parent=%s flavour=%d", id, parent, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" - succeeded id=%s parent=%s flavour=%d", id, parent, info.Flavour)
+	return nil
+}

+ 101 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createprocess.go

@@ -0,0 +1,101 @@
+package hcsshim
+
+import (
+	"encoding/json"
+	"io"
+	"syscall"
+
+	"github.com/Microsoft/go-winio"
+	"github.com/Sirupsen/logrus"
+)
+
+// CreateProcessParams is used as both the input of CreateProcessInComputeSystem
+// and to convert the parameters to JSON for passing onto the HCS
+type CreateProcessParams struct {
+	ApplicationName  string
+	CommandLine      string
+	WorkingDirectory string
+	Environment      map[string]string
+	EmulateConsole   bool
+	ConsoleSize      [2]int
+}
+
+// makeOpenFiles calls winio.MakeOpenFile for each handle in a slice but closes all the handles
+// if there is an error.
+func makeOpenFiles(hs []syscall.Handle) (_ []io.ReadWriteCloser, err error) {
+	fs := make([]io.ReadWriteCloser, len(hs))
+	for i, h := range hs {
+		if h != syscall.Handle(0) {
+			if err == nil {
+				fs[i], err = winio.MakeOpenFile(h)
+			}
+			if err != nil {
+				syscall.Close(h)
+			}
+		}
+	}
+	if err != nil {
+		for _, f := range fs {
+			if f != nil {
+				f.Close()
+			}
+		}
+		return nil, err
+	}
+	return fs, nil
+}
+
+// CreateProcessInComputeSystem starts a process in a container. This is invoked, for example,
+// as a result of docker run, docker exec, or RUN in Dockerfile. If successful,
+// it returns the PID of the process.
+func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (_ uint32, _ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
+	title := "HCSShim::CreateProcessInComputeSystem"
+	logrus.Debugf(title+" id=%s", id)
+
+	// If we are not emulating a console, ignore any console size passed to us
+	if !params.EmulateConsole {
+		params.ConsoleSize[0] = 0
+		params.ConsoleSize[1] = 0
+	}
+
+	paramsJson, err := json.Marshal(params)
+	if err != nil {
+		return
+	}
+
+	logrus.Debugf(title+" - Calling Win32 %s %s", id, paramsJson)
+
+	var pid uint32
+
+	handles := make([]syscall.Handle, 3)
+	var stdinParam, stdoutParam, stderrParam *syscall.Handle
+	if useStdin {
+		stdinParam = &handles[0]
+	}
+	if useStdout {
+		stdoutParam = &handles[1]
+	}
+	if useStderr {
+		stderrParam = &handles[2]
+	}
+
+	err = createProcessWithStdHandlesInComputeSystem(id, string(paramsJson), &pid, stdinParam, stdoutParam, stderrParam)
+	if err != nil {
+		herr := makeErrorf(err, title, "id=%s params=%v", id, params)
+		err = herr
+		// Windows TP4: Hyper-V Containers may return this error with more than one
+		// concurrent exec. Do not log it as an error
+		if herr.Err != WSAEINVAL {
+			logrus.Error(err)
+		}
+		return
+	}
+
+	pipes, err := makeOpenFiles(handles)
+	if err != nil {
+		return
+	}
+
+	logrus.Debugf(title+" - succeeded id=%s params=%s pid=%d", id, paramsJson, pid)
+	return pid, pipes[0], pipes[1], pipes[2], nil
+}

+ 35 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/createsandboxlayer.go

@@ -0,0 +1,35 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// CreateSandboxLayer creates and populates new read-write layer for use by a container.
+// This requires both the id of the direct parent layer, as well as the full list
+// of paths to all parent layers up to the base (and including the direct parent
+// whose id was provided).
+func CreateSandboxLayer(info DriverInfo, layerId, parentId string, parentLayerPaths []string) error {
+	title := "hcsshim::CreateSandboxLayer "
+	logrus.Debugf(title+"layerId %s parentId %s", layerId, parentId)
+
+	// Generate layer descriptors
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return err
+	}
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = createSandboxLayer(&infop, layerId, parentId, layers)
+	if err != nil {
+		err = makeErrorf(err, title, "layerId=%s parentId=%s", layerId, parentId)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"- succeeded layerId=%s parentId=%s", layerId, parentId)
+	return nil
+}

+ 26 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/deactivatelayer.go

@@ -0,0 +1,26 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
+func DeactivateLayer(info DriverInfo, id string) error {
+	title := "hcsshim::DeactivateLayer "
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = deactivateLayer(&infop, id)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
+	return nil
+}

+ 27 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/destroylayer.go

@@ -0,0 +1,27 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// DestroyLayer will remove the on-disk files representing the layer with the given
+// id, including that layer's containing folder, if any.
+func DestroyLayer(info DriverInfo, id string) error {
+	title := "hcsshim::DestroyLayer "
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = destroyLayer(&infop, id)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
+	return nil
+}

+ 36 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/exportlayer.go

@@ -0,0 +1,36 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// ExportLayer will create a folder at exportFolderPath and fill that folder with
+// the transport format version of the layer identified by layerId. This transport
+// format includes any metadata required for later importing the layer (using
+// ImportLayer), and requires the full list of parent layer paths in order to
+// perform the export.
+func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, parentLayerPaths []string) error {
+	title := "hcsshim::ExportLayer "
+	logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, exportFolderPath)
+
+	// Generate layer descriptors
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return err
+	}
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = exportLayer(&infop, layerId, exportFolderPath, layers)
+	if err != nil {
+		err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, exportFolderPath)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, exportFolderPath)
+	return nil
+}

+ 55 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/getlayermountpath.go

@@ -0,0 +1,55 @@
+package hcsshim
+
+import (
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+)
+
+// GetLayerMountPath will look for a mounted layer with the given id and return
+// the path at which that layer can be accessed.  This path may be a volume path
+// if the layer is a mounted read-write layer, otherwise it is expected to be the
+// folder path at which the layer is stored.
+func GetLayerMountPath(info DriverInfo, id string) (string, error) {
+	title := "hcsshim::GetLayerMountPath "
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return "", err
+	}
+
+	var mountPathLength uintptr
+	mountPathLength = 0
+
+	// Call the procedure itself.
+	logrus.Debugf("Calling proc (1)")
+	err = getLayerMountPath(&infop, id, &mountPathLength, nil)
+	if err != nil {
+		err = makeErrorf(err, title, "(first call) id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return "", err
+	}
+
+	// Allocate a mount path of the returned length.
+	if mountPathLength == 0 {
+		return "", nil
+	}
+	mountPathp := make([]uint16, mountPathLength)
+	mountPathp[0] = 0
+
+	// Call the procedure again
+	logrus.Debugf("Calling proc (2)")
+	err = getLayerMountPath(&infop, id, &mountPathLength, &mountPathp[0])
+	if err != nil {
+		err = makeErrorf(err, title, "(second call) id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return "", err
+	}
+
+	path := syscall.UTF16ToString(mountPathp[0:])
+	logrus.Debugf(title+"succeeded flavour=%d id=%s path=%s", info.Flavour, id, path)
+	return path, nil
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/getsharedbaseimages.go

@@ -0,0 +1,22 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// GetSharedBaseImages will enumerate the images stored in the common central
+// image store and return descriptive info about those images for the purpose
+// of registering them with the graphdriver, graph, and tagstore.
+func GetSharedBaseImages() (imageData string, err error) {
+	title := "hcsshim::GetSharedBaseImages "
+
+	logrus.Debugf("Calling proc")
+	var buffer *uint16
+	err = getBaseImages(&buffer)
+	if err != nil {
+		err = makeError(err, title, "")
+		logrus.Error(err)
+		return
+	}
+	imageData = convertAndFreeCoTaskMemString(buffer)
+	logrus.Debugf(title+" - succeeded output=%s", imageData)
+	return
+}

+ 19 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/guid.go

@@ -0,0 +1,19 @@
+package hcsshim
+
+import (
+	"crypto/sha1"
+	"fmt"
+)
+
+type GUID [16]byte
+
+func NewGUID(source string) *GUID {
+	h := sha1.Sum([]byte(source))
+	var g GUID
+	copy(g[0:], h[0:16])
+	return &g
+}
+
+func (g *GUID) ToString() string {
+	return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x", g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8:10], g[10:])
+}

+ 98 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hcsshim.go

@@ -0,0 +1,98 @@
+// Shim for the Host Compute Service (HSC) to manage Windows Server
+// containers and Hyper-V containers.
+
+package hcsshim
+
+import (
+	"fmt"
+	"syscall"
+	"unsafe"
+)
+
+//go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go
+
+//sys coTaskMemFree(buffer unsafe.Pointer) = ole32.CoTaskMemFree
+
+//sys activateLayer(info *driverInfo, id string) (hr error) = vmcompute.ActivateLayer?
+//sys copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CopyLayer?
+//sys createLayer(info *driverInfo, id string, parent string) (hr error) = vmcompute.CreateLayer?
+//sys createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.CreateSandboxLayer?
+//sys deactivateLayer(info *driverInfo, id string) (hr error) = vmcompute.DeactivateLayer?
+//sys destroyLayer(info *driverInfo, id string) (hr error) = vmcompute.DestroyLayer?
+//sys exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ExportLayer?
+//sys getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) = vmcompute.GetLayerMountPath?
+//sys getBaseImages(buffer **uint16) (hr error) = vmcompute.GetBaseImages?
+//sys importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.ImportLayer?
+//sys layerExists(info *driverInfo, id string, exists *uint32) (hr error) = vmcompute.LayerExists?
+//sys nameToGuid(name string, guid *GUID) (hr error) = vmcompute.NameToGuid?
+//sys prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) = vmcompute.PrepareLayer?
+//sys unprepareLayer(info *driverInfo, id string) (hr error) = vmcompute.UnprepareLayer?
+
+//sys createComputeSystem(id string, configuration string) (hr error) = vmcompute.CreateComputeSystem?
+//sys createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) = vmcompute.CreateProcessWithStdHandlesInComputeSystem?
+//sys resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) = vmcompute.ResizeConsoleInComputeSystem?
+//sys shutdownComputeSystem(id string, timeout uint32) (hr error) = vmcompute.ShutdownComputeSystem?
+//sys startComputeSystem(id string) (hr error) = vmcompute.StartComputeSystem?
+//sys terminateComputeSystem(id string) (hr error) = vmcompute.TerminateComputeSystem?
+//sys terminateProcessInComputeSystem(id string, pid uint32) (hr error) = vmcompute.TerminateProcessInComputeSystem?
+//sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem?
+
+//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
+
+const (
+	// Specific user-visible exit codes
+	WaitErrExecFailed = 32767
+
+	ERROR_GEN_FAILURE          = syscall.Errno(31)
+	ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
+	WSAEINVAL                  = syscall.Errno(10022)
+
+	// Timeout on wait calls
+	TimeoutInfinite = 0xFFFFFFFF
+)
+
+type HcsError struct {
+	title string
+	rest  string
+	Err   error
+}
+
+func makeError(err error, title, rest string) *HcsError {
+	if hr, ok := err.(syscall.Errno); ok {
+		// Convert the HRESULT to a Win32 error code so that it better matches
+		// error codes returned from go and other packages.
+		err = syscall.Errno(win32FromHresult(uint32(hr)))
+	}
+	return &HcsError{title, rest, err}
+}
+
+func makeErrorf(err error, title, format string, a ...interface{}) *HcsError {
+	return makeError(err, title, fmt.Sprintf(format, a...))
+}
+
+func win32FromError(err error) uint32 {
+	if herr, ok := err.(*HcsError); ok {
+		return win32FromError(herr.Err)
+	}
+	if code, ok := err.(syscall.Errno); ok {
+		return win32FromHresult(uint32(code))
+	}
+	return uint32(ERROR_GEN_FAILURE)
+}
+
+func win32FromHresult(hr uint32) uint32 {
+	if hr&0x1fff0000 == 0x00070000 {
+		return hr & 0xffff
+	}
+	return hr
+}
+
+func (e *HcsError) Error() string {
+	return fmt.Sprintf("%s- Win32 API call returned error r1=0x%x err=%s%s", e.title, win32FromError(e.Err), e.Err, e.rest)
+}
+
+func convertAndFreeCoTaskMemString(buffer *uint16) string {
+	str := syscall.UTF16ToString((*[1 << 30]uint16)(unsafe.Pointer(buffer))[:])
+	coTaskMemFree(unsafe.Pointer(buffer))
+	return str
+}

+ 131 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/hnsfuncs.go

@@ -0,0 +1,131 @@
+package hcsshim
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+
+	"github.com/Sirupsen/logrus"
+)
+
+type NatPolicy struct {
+	Type         string
+	Protocol     string
+	InternalPort uint16
+	ExternalPort uint16
+}
+
+type QosPolicy struct {
+	Type                            string
+	MaximumOutgoingBandwidthInBytes uint64
+}
+
+// Subnet is assoicated with a network and represents a list
+// of subnets available to the network
+type Subnet struct {
+	AddressPrefix  string `json:",omitempty"`
+	GatewayAddress string `json:",omitempty"`
+}
+
+// MacPool is assoicated with a network and represents a list
+// of macaddresses available to the network
+type MacPool struct {
+	StartMacAddress string `json:",omitempty"`
+	EndMacAddress   string `json:",omitempty"`
+}
+
+// HNSNetwork represents a network in HNS
+type HNSNetwork struct {
+	Id       string            `json:",omitempty"`
+	Name     string            `json:",omitempty"`
+	Type     string            `json:",omitempty"`
+	Policies []json.RawMessage `json:",omitempty"`
+	MacPools []MacPool         `json:",omitempty"`
+	Subnets  []Subnet          `json:",omitempty"`
+}
+
+// HNSEndpoint represents a network endpoint in HNS
+type HNSEndpoint struct {
+	Id                 string            `json:",omitempty"`
+	Name               string            `json:",omitempty"`
+	VirtualNetwork     string            `json:",omitempty"`
+	VirtualNetworkName string            `json:",omitempty"`
+	Policies           []json.RawMessage `json:",omitempty"`
+	MacAddress         string            `json:",omitempty"`
+	IPAddress          net.IP            `json:",omitempty"`
+}
+
+type hnsNetworkResponse struct {
+	Success bool
+	Error   string
+	Output  HNSNetwork
+}
+
+type hnsResponse struct {
+	Success bool
+	Error   string
+	Output  json.RawMessage
+}
+
+func hnsCall(method, path, request string, returnResponse interface{}) error {
+	var responseBuffer *uint16
+	err := _hnsCall(method, path, request, &responseBuffer)
+	if err != nil {
+		return makeError(err, "hnsCall ", "")
+	}
+	response := convertAndFreeCoTaskMemString(responseBuffer)
+
+	hnsresponse := &hnsResponse{}
+	if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
+		return err
+	}
+
+	if !hnsresponse.Success {
+		return fmt.Errorf("HNS failed with error : %s", hnsresponse.Error)
+	}
+
+	if len(hnsresponse.Output) == 0 {
+		return nil
+	}
+
+	logrus.Debugf("Network Response : %s", hnsresponse.Output)
+	err = json.Unmarshal(hnsresponse.Output, returnResponse)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// HNSNetworkRequest makes a call into HNS to update/query a single network
+func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
+	var network HNSNetwork
+	err := hnsCall(method, "/networks/"+path, request, &network)
+	if err != nil {
+		return nil, err
+	}
+
+	return &network, nil
+}
+
+// HNSListNetworkRequest makes a HNS call to query the list of available networks
+func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
+	var network []HNSNetwork
+	err := hnsCall(method, "/networks/"+path, request, &network)
+	if err != nil {
+		return nil, err
+	}
+
+	return network, nil
+}
+
+// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
+func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
+	endpoint := &HNSEndpoint{}
+	err := hnsCall(method, "/endpoints/"+path, request, &endpoint)
+	if err != nil {
+		return nil, err
+	}
+
+	return endpoint, nil
+}

+ 35 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/importlayer.go

@@ -0,0 +1,35 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// ImportLayer will take the contents of the folder at importFolderPath and import
+// that into a layer with the id layerId.  Note that in order to correctly populate
+// the layer and interperet the transport format, all parent layers must already
+// be present on the system at the paths provided in parentLayerPaths.
+func ImportLayer(info DriverInfo, layerId string, importFolderPath string, parentLayerPaths []string) error {
+	title := "hcsshim::ImportLayer "
+	logrus.Debugf(title+"flavour %d layerId %s folder %s", info.Flavour, layerId, importFolderPath)
+
+	// Generate layer descriptors
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return err
+	}
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = importLayer(&infop, layerId, importFolderPath, layers)
+	if err != nil {
+		err = makeErrorf(err, title, "layerId=%s flavour=%d folder=%s", layerId, info.Flavour, importFolderPath)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, importFolderPath)
+	return nil
+}

+ 30 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/layerexists.go

@@ -0,0 +1,30 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// LayerExists will return true if a layer with the given id exists and is known
+// to the system.
+func LayerExists(info DriverInfo, id string) (bool, error) {
+	title := "hcsshim::LayerExists "
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return false, err
+	}
+
+	// Call the procedure itself.
+	var exists uint32
+
+	err = layerExists(&infop, id, &exists)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s flavour=%d", id, info.Flavour)
+		logrus.Error(err)
+		return false, err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d id=%s exists=%d", info.Flavour, id, exists)
+	return exists != 0, nil
+}

+ 111 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/layerutils.go

@@ -0,0 +1,111 @@
+package hcsshim
+
+// This file contains utility functions to support storage (graph) related
+// functionality.
+
+import (
+	"path/filepath"
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+)
+
+/* To pass into syscall, we need a struct matching the following:
+enum GraphDriverType
+{
+    DiffDriver,
+    FilterDriver
+};
+
+struct DriverInfo {
+    GraphDriverType Flavour;
+    LPCWSTR HomeDir;
+};
+*/
+type DriverInfo struct {
+	Flavour int
+	HomeDir string
+}
+
+type driverInfo struct {
+	Flavour  int
+	HomeDirp *uint16
+}
+
+func convertDriverInfo(info DriverInfo) (driverInfo, error) {
+	homedirp, err := syscall.UTF16PtrFromString(info.HomeDir)
+	if err != nil {
+		logrus.Debugf("Failed conversion of home to pointer for driver info: %s", err.Error())
+		return driverInfo{}, err
+	}
+
+	return driverInfo{
+		Flavour:  info.Flavour,
+		HomeDirp: homedirp,
+	}, nil
+}
+
+/* To pass into syscall, we need a struct matching the following:
+typedef struct _WC_LAYER_DESCRIPTOR {
+
+    //
+    // The ID of the layer
+    //
+
+    GUID LayerId;
+
+    //
+    // Additional flags
+    //
+
+    union {
+        struct {
+            ULONG Reserved : 31;
+            ULONG Dirty : 1;    // Created from sandbox as a result of snapshot
+        };
+        ULONG Value;
+    } Flags;
+
+    //
+    // Path to the layer root directory, null-terminated
+    //
+
+    PCWSTR Path;
+
+} WC_LAYER_DESCRIPTOR, *PWC_LAYER_DESCRIPTOR;
+*/
+type WC_LAYER_DESCRIPTOR struct {
+	LayerId GUID
+	Flags   uint32
+	Pathp   *uint16
+}
+
+func layerPathsToDescriptors(parentLayerPaths []string) ([]WC_LAYER_DESCRIPTOR, error) {
+	// Array of descriptors that gets constructed.
+	var layers []WC_LAYER_DESCRIPTOR
+
+	for i := 0; i < len(parentLayerPaths); i++ {
+		// Create a layer descriptor, using the folder name
+		// as the source for a GUID LayerId
+		_, folderName := filepath.Split(parentLayerPaths[i])
+		g, err := NameToGuid(folderName)
+		if err != nil {
+			logrus.Debugf("Failed to convert name to guid %s", err)
+			return nil, err
+		}
+
+		p, err := syscall.UTF16PtrFromString(parentLayerPaths[i])
+		if err != nil {
+			logrus.Debugf("Failed conversion of parentLayerPath to pointer %s", err)
+			return nil, err
+		}
+
+		layers = append(layers, WC_LAYER_DESCRIPTOR{
+			LayerId: g,
+			Flags:   0,
+			Pathp:   p,
+		})
+	}
+
+	return layers, nil
+}

+ 797 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/mksyscall_windows.go

@@ -0,0 +1,797 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+/*
+mksyscall_windows generates windows system call bodies
+
+It parses all files specified on command line containing function
+prototypes (like syscall_windows.go) and prints system call bodies
+to standard output.
+
+The prototypes are marked by lines beginning with "//sys" and read
+like func declarations if //sys is replaced by func, but:
+
+* The parameter lists must give a name for each argument. This
+  includes return parameters.
+
+* The parameter lists must give a type for each argument:
+  the (x, y, z int) shorthand is not allowed.
+
+* If the return parameter is an error number, it must be named err.
+
+* If go func name needs to be different from it's winapi dll name,
+  the winapi name could be specified at the end, after "=" sign, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
+
+* Each function that returns err needs to supply a condition, that
+  return value of winapi will be tested against to detect failure.
+  This would set err to windows "last-error", otherwise it will be nil.
+  The value can be provided at end of //sys declaration, like
+  //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
+  and is [failretval==0] by default.
+
+Usage:
+	mksyscall_windows [flags] [path ...]
+
+The flags are:
+	-output
+		Specify output file name (outputs to console if blank).
+	-trace
+		Generate print statement after every syscall.
+*/
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+	"text/template"
+)
+
+var (
+	filename       = flag.String("output", "", "output file name (standard output if omitted)")
+	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+)
+
+func trim(s string) string {
+	return strings.Trim(s, " \t")
+}
+
+var packageName string
+
+func packagename() string {
+	return packageName
+}
+
+func syscalldot() string {
+	if packageName == "syscall" {
+		return ""
+	}
+	return "syscall."
+}
+
+// Param is function parameter
+type Param struct {
+	Name      string
+	Type      string
+	fn        *Fn
+	tmpVarIdx int
+}
+
+// tmpVar returns temp variable name that will be used to represent p during syscall.
+func (p *Param) tmpVar() string {
+	if p.tmpVarIdx < 0 {
+		p.tmpVarIdx = p.fn.curTmpVarIdx
+		p.fn.curTmpVarIdx++
+	}
+	return fmt.Sprintf("_p%d", p.tmpVarIdx)
+}
+
+// BoolTmpVarCode returns source code for bool temp variable.
+func (p *Param) BoolTmpVarCode() string {
+	const code = `var %s uint32
+	if %s {
+		%s = 1
+	} else {
+		%s = 0
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
+}
+
+// SliceTmpVarCode returns source code for slice temp variable.
+func (p *Param) SliceTmpVarCode() string {
+	const code = `var %s *%s
+	if len(%s) > 0 {
+		%s = &%s[0]
+	}`
+	tmp := p.tmpVar()
+	return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
+}
+
+// StringTmpVarCode returns source code for string temp variable.
+func (p *Param) StringTmpVarCode() string {
+	errvar := p.fn.Rets.ErrorVarName()
+	if errvar == "" {
+		errvar = "_"
+	}
+	tmp := p.tmpVar()
+	const code = `var %s %s
+	%s, %s = %s(%s)`
+	s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
+	if errvar == "-" {
+		return s
+	}
+	const morecode = `
+	if %s != nil {
+		return
+	}`
+	return s + fmt.Sprintf(morecode, errvar)
+}
+
+// TmpVarCode returns source code for temp variable.
+func (p *Param) TmpVarCode() string {
+	switch {
+	case p.Type == "bool":
+		return p.BoolTmpVarCode()
+	case strings.HasPrefix(p.Type, "[]"):
+		return p.SliceTmpVarCode()
+	default:
+		return ""
+	}
+}
+
+// TmpVarHelperCode returns source code for helper's temp variable.
+func (p *Param) TmpVarHelperCode() string {
+	if p.Type != "string" {
+		return ""
+	}
+	return p.StringTmpVarCode()
+}
+
+// SyscallArgList returns source code fragments representing p parameter
+// in syscall. Slices are translated into 2 syscall parameters: pointer to
+// the first element and length.
+func (p *Param) SyscallArgList() []string {
+	t := p.HelperType()
+	var s string
+	switch {
+	case t[0] == '*':
+		s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
+	case t == "bool":
+		s = p.tmpVar()
+	case strings.HasPrefix(t, "[]"):
+		return []string{
+			fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
+			fmt.Sprintf("uintptr(len(%s))", p.Name),
+		}
+	default:
+		s = p.Name
+	}
+	return []string{fmt.Sprintf("uintptr(%s)", s)}
+}
+
+// IsError determines if p parameter is used to return error.
+func (p *Param) IsError() bool {
+	return p.Name == "err" && p.Type == "error"
+}
+
+// HelperType returns type of parameter p used in helper function.
+func (p *Param) HelperType() string {
+	if p.Type == "string" {
+		return p.fn.StrconvType()
+	}
+	return p.Type
+}
+
+// join concatenates parameters ps into a string with sep separator.
+// Each parameter is converted into string by applying fn to it
+// before conversion.
+func join(ps []*Param, fn func(*Param) string, sep string) string {
+	if len(ps) == 0 {
+		return ""
+	}
+	a := make([]string, 0)
+	for _, p := range ps {
+		a = append(a, fn(p))
+	}
+	return strings.Join(a, sep)
+}
+
+// Rets describes function return parameters.
+type Rets struct {
+	Name         string
+	Type         string
+	ReturnsError bool
+	FailCond     string
+}
+
+// ErrorVarName returns error variable name for r.
+func (r *Rets) ErrorVarName() string {
+	if r.ReturnsError {
+		return "err"
+	}
+	if r.Type == "error" {
+		return r.Name
+	}
+	return ""
+}
+
+// ToParams converts r into slice of *Param.
+func (r *Rets) ToParams() []*Param {
+	ps := make([]*Param, 0)
+	if len(r.Name) > 0 {
+		ps = append(ps, &Param{Name: r.Name, Type: r.Type})
+	}
+	if r.ReturnsError {
+		ps = append(ps, &Param{Name: "err", Type: "error"})
+	}
+	return ps
+}
+
+// List returns source code of syscall return parameters.
+func (r *Rets) List() string {
+	s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+	if len(s) > 0 {
+		s = "(" + s + ")"
+	}
+	return s
+}
+
+// PrintList returns source code of trace printing part correspondent
+// to syscall return values.
+func (r *Rets) PrintList() string {
+	return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// SetReturnValuesCode returns source code that accepts syscall return values.
+func (r *Rets) SetReturnValuesCode() string {
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	retvar := "r0"
+	if r.Name == "" {
+		retvar = "r1"
+	}
+	errvar := "_"
+	if r.ReturnsError {
+		errvar = "e1"
+	}
+	return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
+}
+
+func (r *Rets) useLongHandleErrorCode(retvar string) string {
+	const code = `if %s {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = %sEINVAL
+		}
+	}`
+	cond := retvar + " == 0"
+	if r.FailCond != "" {
+		cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
+	}
+	return fmt.Sprintf(code, cond, syscalldot())
+}
+
+// SetErrorCode returns source code that sets return parameters.
+func (r *Rets) SetErrorCode() string {
+	const code = `if r0 != 0 {
+		%s = %sErrno(r0)
+	}`
+	if r.Name == "" && !r.ReturnsError {
+		return ""
+	}
+	if r.Name == "" {
+		return r.useLongHandleErrorCode("r1")
+	}
+	if r.Type == "error" {
+		return fmt.Sprintf(code, r.Name, syscalldot())
+	}
+	s := ""
+	switch {
+	case r.Type[0] == '*':
+		s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
+	case r.Type == "bool":
+		s = fmt.Sprintf("%s = r0 != 0", r.Name)
+	default:
+		s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
+	}
+	if !r.ReturnsError {
+		return s
+	}
+	return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
+}
+
+// Fn describes syscall function.
+type Fn struct {
+	Name        string
+	Params      []*Param
+	Rets        *Rets
+	PrintTrace  bool
+	confirmproc bool
+	dllname     string
+	dllfuncname string
+	src         string
+	// TODO: get rid of this field and just use parameter index instead
+	curTmpVarIdx int // insure tmp variables have uniq names
+}
+
+// extractParams parses s to extract function parameters.
+func extractParams(s string, f *Fn) ([]*Param, error) {
+	s = trim(s)
+	if s == "" {
+		return nil, nil
+	}
+	a := strings.Split(s, ",")
+	ps := make([]*Param, len(a))
+	for i := range ps {
+		s2 := trim(a[i])
+		b := strings.Split(s2, " ")
+		if len(b) != 2 {
+			b = strings.Split(s2, "\t")
+			if len(b) != 2 {
+				return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
+			}
+		}
+		ps[i] = &Param{
+			Name:      trim(b[0]),
+			Type:      trim(b[1]),
+			fn:        f,
+			tmpVarIdx: -1,
+		}
+	}
+	return ps, nil
+}
+
+// extractSection extracts text out of string s starting after start
+// and ending just before end. found return value will indicate success,
+// and prefix, body and suffix will contain correspondent parts of string s.
+func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
+	s = trim(s)
+	if strings.HasPrefix(s, string(start)) {
+		// no prefix
+		body = s[1:]
+	} else {
+		a := strings.SplitN(s, string(start), 2)
+		if len(a) != 2 {
+			return "", "", s, false
+		}
+		prefix = a[0]
+		body = a[1]
+	}
+	a := strings.SplitN(body, string(end), 2)
+	if len(a) != 2 {
+		return "", "", "", false
+	}
+	return prefix, a[0], a[1], true
+}
+
+// newFn parses string s and return created function Fn.
+func newFn(s string) (*Fn, error) {
+	s = trim(s)
+	f := &Fn{
+		Rets:       &Rets{},
+		src:        s,
+		PrintTrace: *printTraceFlag,
+	}
+	// function name and args
+	prefix, body, s, found := extractSection(s, '(', ')')
+	if !found || prefix == "" {
+		return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
+	}
+	f.Name = prefix
+	var err error
+	f.Params, err = extractParams(body, f)
+	if err != nil {
+		return nil, err
+	}
+	// return values
+	_, body, s, found = extractSection(s, '(', ')')
+	if found {
+		r, err := extractParams(body, f)
+		if err != nil {
+			return nil, err
+		}
+		switch len(r) {
+		case 0:
+		case 1:
+			if r[0].IsError() {
+				f.Rets.ReturnsError = true
+			} else {
+				f.Rets.Name = r[0].Name
+				f.Rets.Type = r[0].Type
+			}
+		case 2:
+			if !r[1].IsError() {
+				return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
+			}
+			f.Rets.ReturnsError = true
+			f.Rets.Name = r[0].Name
+			f.Rets.Type = r[0].Type
+		default:
+			return nil, errors.New("Too many return values in \"" + f.src + "\"")
+		}
+	}
+	// fail condition
+	_, body, s, found = extractSection(s, '[', ']')
+	if found {
+		f.Rets.FailCond = body
+	}
+	// dll and dll function names
+	s = trim(s)
+	if s == "" {
+		return f, nil
+	}
+	if !strings.HasPrefix(s, "=") {
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	s = trim(s[1:])
+	a := strings.Split(s, ".")
+	switch len(a) {
+	case 1:
+		f.dllfuncname = a[0]
+	case 2:
+		f.dllname = a[0]
+		f.dllfuncname = a[1]
+	default:
+		return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
+	}
+	if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
+		f.confirmproc = true
+		f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
+	}
+	return f, nil
+}
+
+// DLLName returns DLL name for function f.
+func (f *Fn) DLLName() string {
+	if f.dllname == "" {
+		return "kernel32"
+	}
+	return f.dllname
+}
+
+// DLLName returns DLL function name for function f.
+func (f *Fn) DLLFuncName() string {
+	if f.dllfuncname == "" {
+		return f.Name
+	}
+	return f.dllfuncname
+}
+
+func (f *Fn) ConfirmProc() bool {
+	return f.confirmproc
+}
+
+// ParamList returns source code for function f parameters.
+func (f *Fn) ParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
+}
+
+// HelperParamList returns source code for helper function f parameters.
+func (f *Fn) HelperParamList() string {
+	return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
+}
+
+// ParamPrintList returns source code of trace printing part correspondent
+// to syscall input parameters.
+func (f *Fn) ParamPrintList() string {
+	return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
+}
+
+// ParamCount return number of syscall parameters for function f.
+func (f *Fn) ParamCount() int {
+	n := 0
+	for _, p := range f.Params {
+		n += len(p.SyscallArgList())
+	}
+	return n
+}
+
+// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
+// to use. It returns parameter count for correspondent SyscallX function.
+func (f *Fn) SyscallParamCount() int {
+	n := f.ParamCount()
+	switch {
+	case n <= 3:
+		return 3
+	case n <= 6:
+		return 6
+	case n <= 9:
+		return 9
+	case n <= 12:
+		return 12
+	case n <= 15:
+		return 15
+	default:
+		panic("too many arguments to system call")
+	}
+}
+
+// Syscall determines which SyscallX function to use for function f.
+func (f *Fn) Syscall() string {
+	c := f.SyscallParamCount()
+	if c == 3 {
+		return syscalldot() + "Syscall"
+	}
+	return syscalldot() + "Syscall" + strconv.Itoa(c)
+}
+
+// SyscallParamList returns source code for SyscallX parameters for function f.
+func (f *Fn) SyscallParamList() string {
+	a := make([]string, 0)
+	for _, p := range f.Params {
+		a = append(a, p.SyscallArgList()...)
+	}
+	for len(a) < f.SyscallParamCount() {
+		a = append(a, "0")
+	}
+	return strings.Join(a, ", ")
+}
+
+// HelperCallParamList returns source code of call into function f helper.
+func (f *Fn) HelperCallParamList() string {
+	a := make([]string, 0, len(f.Params))
+	for _, p := range f.Params {
+		s := p.Name
+		if p.Type == "string" {
+			s = p.tmpVar()
+		}
+		a = append(a, s)
+	}
+	return strings.Join(a, ", ")
+}
+
+// IsUTF16 is true, if f is W (utf16) function. It is false
+// for all A (ascii) functions.
+func (_ *Fn) IsUTF16() bool {
+	return true
+}
+
+// StrconvFunc returns name of Go string to OS string function for f.
+func (f *Fn) StrconvFunc() string {
+	if f.IsUTF16() {
+		return syscalldot() + "UTF16PtrFromString"
+	}
+	return syscalldot() + "BytePtrFromString"
+}
+
+// StrconvType returns Go type name used for OS string for f.
+func (f *Fn) StrconvType() string {
+	if f.IsUTF16() {
+		return "*uint16"
+	}
+	return "*byte"
+}
+
+// HasStringParam is true, if f has at least one string parameter.
+// Otherwise it is false.
+func (f *Fn) HasStringParam() bool {
+	for _, p := range f.Params {
+		if p.Type == "string" {
+			return true
+		}
+	}
+	return false
+}
+
+// HelperName returns name of function f helper.
+func (f *Fn) HelperName() string {
+	if !f.HasStringParam() {
+		return f.Name
+	}
+	return "_" + f.Name
+}
+
+// Source files and functions.
+type Source struct {
+	Funcs []*Fn
+	Files []string
+}
+
+// ParseFiles parses files listed in fs and extracts all syscall
+// functions listed in  sys comments. It returns source files
+// and functions collection *Source if successful.
+func ParseFiles(fs []string) (*Source, error) {
+	src := &Source{
+		Funcs: make([]*Fn, 0),
+		Files: make([]string, 0),
+	}
+	for _, file := range fs {
+		if err := src.ParseFile(file); err != nil {
+			return nil, err
+		}
+	}
+	return src, nil
+}
+
+// DLLs return dll names for a source set src.
+func (src *Source) DLLs() []string {
+	uniq := make(map[string]bool)
+	r := make([]string, 0)
+	for _, f := range src.Funcs {
+		name := f.DLLName()
+		if _, found := uniq[name]; !found {
+			uniq[name] = true
+			r = append(r, name)
+		}
+	}
+	return r
+}
+
+// ParseFile adds additional file path to a source set src.
+func (src *Source) ParseFile(path string) error {
+	file, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	s := bufio.NewScanner(file)
+	for s.Scan() {
+		t := trim(s.Text())
+		if len(t) < 7 {
+			continue
+		}
+		if !strings.HasPrefix(t, "//sys") {
+			continue
+		}
+		t = t[5:]
+		if !(t[0] == ' ' || t[0] == '\t') {
+			continue
+		}
+		f, err := newFn(t[1:])
+		if err != nil {
+			return err
+		}
+		src.Funcs = append(src.Funcs, f)
+	}
+	if err := s.Err(); err != nil {
+		return err
+	}
+	src.Files = append(src.Files, path)
+
+	// get package name
+	fset := token.NewFileSet()
+	_, err = file.Seek(0, 0)
+	if err != nil {
+		return err
+	}
+	pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
+	if err != nil {
+		return err
+	}
+	packageName = pkg.Name.Name
+
+	return nil
+}
+
+// Generate output source file from a source set src.
+func (src *Source) Generate(w io.Writer) error {
+	funcMap := template.FuncMap{
+		"packagename": packagename,
+		"syscalldot":  syscalldot,
+	}
+	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
+	err := t.Execute(w, src)
+	if err != nil {
+		return errors.New("Failed to execute template: " + err.Error())
+	}
+	return nil
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
+	flag.PrintDefaults()
+	os.Exit(1)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+	if len(flag.Args()) <= 0 {
+		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
+		usage()
+	}
+
+	src, err := ParseFiles(flag.Args())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var buf bytes.Buffer
+	if err := src.Generate(&buf); err != nil {
+		log.Fatal(err)
+	}
+
+	data, err := format.Source(buf.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+	if *filename == "" {
+		_, err = os.Stdout.Write(data)
+	} else {
+		err = ioutil.WriteFile(*filename, data, 0644)
+	}
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+// TODO: use println instead to print in the following template
+const srcTemplate = `
+
+{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package {{packagename}}
+
+import "unsafe"{{if syscalldot}}
+import "syscall"{{end}}
+
+var _ unsafe.Pointer
+
+var (
+{{template "dlls" .}}
+{{template "funcnames" .}})
+{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
+{{end}}
+
+{{/* help functions */}}
+
+{{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
+{{end}}{{end}}
+
+{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
+{{end}}{{end}}
+
+{{define "helperbody"}}
+func {{.Name}}({{.ParamList}}) {{template "results" .}}{
+{{template "helpertmpvars" .}}	return {{.HelperName}}({{.HelperCallParamList}})
+}
+{{end}}
+
+{{define "funcbody"}}
+func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
+{{template "tmpvars" .}}	{{template "syscallcheck" .}}{{template "syscall" .}}
+{{template "seterror" .}}{{template "printtrace" .}}	return
+}
+{{end}}
+
+{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}}	{{.TmpVarHelperCode}}
+{{end}}{{end}}{{end}}
+
+{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}}	{{.TmpVarCode}}
+{{end}}{{end}}{{end}}
+
+{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
+
+{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
+    return
+}
+{{end}}{{end}}
+
+{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
+
+{{define "seterror"}}{{if .Rets.SetErrorCode}}	{{.Rets.SetErrorCode}}
+{{end}}{{end}}
+
+{{define "printtrace"}}{{if .PrintTrace}}	print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
+{{end}}{{end}}
+
+`

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/nametoguid.go

@@ -0,0 +1,20 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// NameToGuid converts the given string into a GUID using the algorithm in the
+// Host Compute Service, ensuring GUIDs generated with the same string are common
+// across all clients.
+func NameToGuid(name string) (id GUID, err error) {
+	title := "hcsshim::NameToGuid "
+	logrus.Debugf(title+"Name %s", name)
+
+	err = nameToGuid(name, &id)
+	if err != nil {
+		err = makeErrorf(err, title, "name=%s", name)
+		logrus.Error(err)
+		return
+	}
+
+	return
+}

+ 36 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/preparelayer.go

@@ -0,0 +1,36 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// PrepareLayer finds a mounted read-write layer matching layerId and enables the
+// the filesystem filter for use on that layer.  This requires the paths to all
+// parent layers, and is necessary in order to view or interact with the layer
+// as an actual filesystem (reading and writing files, creating directories, etc).
+// Disabling the filter must be done via UnprepareLayer.
+func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) error {
+	title := "hcsshim::PrepareLayer "
+	logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
+
+	// Generate layer descriptors
+	layers, err := layerPathsToDescriptors(parentLayerPaths)
+	if err != nil {
+		return err
+	}
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = prepareLayer(&infop, layerId, layers)
+	if err != nil {
+		err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s", info.Flavour, layerId)
+	return nil
+}

+ 22 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/resizeconsole.go

@@ -0,0 +1,22 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// ResizeConsoleInComputeSystem updates the height and width of the console
+// session for the process with the given id in the container with the given id.
+func ResizeConsoleInComputeSystem(id string, processid uint32, h, w int) error {
+
+	title := "HCSShim::ResizeConsoleInComputeSystem"
+	logrus.Debugf(title+" id=%s processid=%d (%d,%d)", id, processid, h, w)
+
+	err := resizeConsoleInComputeSystem(id, processid, uint16(h), uint16(w), 0)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s pid=%d", id, processid)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s processid=%d (%d,%d)", id, processid, h, w)
+	return nil
+
+}

+ 43 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/shutdownterminatecomputesystem.go

@@ -0,0 +1,43 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// TerminateComputeSystem force terminates a container.
+func TerminateComputeSystem(id string, timeout uint32, context string) error {
+	return shutdownTerminate(false, id, timeout, context)
+}
+
+// ShutdownComputeSystem shuts down a container by requesting a shutdown within
+// the container operating system.
+func ShutdownComputeSystem(id string, timeout uint32, context string) error {
+	return shutdownTerminate(true, id, timeout, context)
+}
+
+// shutdownTerminate is a wrapper for ShutdownComputeSystem and TerminateComputeSystem
+// which have very similar calling semantics
+func shutdownTerminate(shutdown bool, id string, timeout uint32, context string) error {
+
+	var (
+		title = "HCSShim::"
+	)
+	if shutdown {
+		title = title + "ShutdownComputeSystem"
+	} else {
+		title = title + "TerminateComputeSystem"
+	}
+	logrus.Debugf(title+" id=%s context=%s", id, context)
+
+	var err error
+	if shutdown {
+		err = shutdownComputeSystem(id, timeout)
+	} else {
+		err = terminateComputeSystem(id)
+	}
+
+	if err != nil {
+		return makeErrorf(err, title, "id=%s context=%s", id, context)
+	}
+
+	logrus.Debugf(title+" succeeded id=%s context=%s", id, context)
+	return nil
+}

+ 21 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/startcomputesystem.go

@@ -0,0 +1,21 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// StartComputeSystem starts a container that has previously been created via
+// CreateComputeSystem.
+func StartComputeSystem(id string) error {
+
+	title := "HCSShim::StartComputeSystem"
+	logrus.Debugf(title+" id=%s", id)
+
+	err := startComputeSystem(id)
+	if err != nil {
+		err = makeErrorf(err, title, "id=%s", id)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", id)
+	return nil
+}

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/terminateprocess.go

@@ -0,0 +1,20 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// TerminateProcessInComputeSystem kills a process in a running container.
+func TerminateProcessInComputeSystem(id string, processid uint32) (err error) {
+
+	title := "HCSShim::TerminateProcessInComputeSystem"
+	logrus.Debugf(title+" id=%s processid=%d", id, processid)
+
+	err = terminateProcessInComputeSystem(id, processid)
+	if err != nil {
+		err = makeErrorf(err, title, "err=%s id=%s", id)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+" succeeded id=%s", id)
+	return nil
+}

+ 27 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/unpreparelayer.go

@@ -0,0 +1,27 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// UnprepareLayer disables the filesystem filter for the read-write layer with
+// the given id.
+func UnprepareLayer(info DriverInfo, layerId string) error {
+	title := "hcsshim::UnprepareLayer "
+	logrus.Debugf(title+"flavour %d layerId %s", info.Flavour, layerId)
+
+	// Convert info to API calling convention
+	infop, err := convertDriverInfo(info)
+	if err != nil {
+		logrus.Error(err)
+		return err
+	}
+
+	err = unprepareLayer(&infop, layerId)
+	if err != nil {
+		err = makeErrorf(err, title, "layerId=%s flavour=%d", layerId, info.Flavour)
+		logrus.Error(err)
+		return err
+	}
+
+	logrus.Debugf(title+"succeeded flavour %d layerId=%s", info.Flavour, layerId)
+	return nil
+}

+ 20 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/waitprocess.go

@@ -0,0 +1,20 @@
+package hcsshim
+
+import "github.com/Sirupsen/logrus"
+
+// WaitForProcessInComputeSystem waits for a process ID to terminate and returns
+// the exit code. Returns exitcode, error
+func WaitForProcessInComputeSystem(id string, processid uint32, timeout uint32) (int32, error) {
+
+	title := "HCSShim::WaitForProcessInComputeSystem"
+	logrus.Debugf(title+" id=%s processid=%d", id, processid)
+
+	var exitCode uint32
+	err := waitForProcessInComputeSystem(id, processid, timeout, &exitCode)
+	if err != nil {
+		return 0, makeErrorf(err, title, "id=%s", id)
+	}
+
+	logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, exitCode)
+	return int32(exitCode), nil
+}

+ 559 - 0
libnetwork/Godeps/_workspace/src/github.com/Microsoft/hcsshim/zhcsshim.go

@@ -0,0 +1,559 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package hcsshim
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+	modole32     = syscall.NewLazyDLL("ole32.dll")
+	modvmcompute = syscall.NewLazyDLL("vmcompute.dll")
+
+	procCoTaskMemFree                              = modole32.NewProc("CoTaskMemFree")
+	procActivateLayer                              = modvmcompute.NewProc("ActivateLayer")
+	procCopyLayer                                  = modvmcompute.NewProc("CopyLayer")
+	procCreateLayer                                = modvmcompute.NewProc("CreateLayer")
+	procCreateSandboxLayer                         = modvmcompute.NewProc("CreateSandboxLayer")
+	procDeactivateLayer                            = modvmcompute.NewProc("DeactivateLayer")
+	procDestroyLayer                               = modvmcompute.NewProc("DestroyLayer")
+	procExportLayer                                = modvmcompute.NewProc("ExportLayer")
+	procGetLayerMountPath                          = modvmcompute.NewProc("GetLayerMountPath")
+	procGetBaseImages                              = modvmcompute.NewProc("GetBaseImages")
+	procImportLayer                                = modvmcompute.NewProc("ImportLayer")
+	procLayerExists                                = modvmcompute.NewProc("LayerExists")
+	procNameToGuid                                 = modvmcompute.NewProc("NameToGuid")
+	procPrepareLayer                               = modvmcompute.NewProc("PrepareLayer")
+	procUnprepareLayer                             = modvmcompute.NewProc("UnprepareLayer")
+	procCreateComputeSystem                        = modvmcompute.NewProc("CreateComputeSystem")
+	procCreateProcessWithStdHandlesInComputeSystem = modvmcompute.NewProc("CreateProcessWithStdHandlesInComputeSystem")
+	procResizeConsoleInComputeSystem               = modvmcompute.NewProc("ResizeConsoleInComputeSystem")
+	procShutdownComputeSystem                      = modvmcompute.NewProc("ShutdownComputeSystem")
+	procStartComputeSystem                         = modvmcompute.NewProc("StartComputeSystem")
+	procTerminateComputeSystem                     = modvmcompute.NewProc("TerminateComputeSystem")
+	procTerminateProcessInComputeSystem            = modvmcompute.NewProc("TerminateProcessInComputeSystem")
+	procWaitForProcessInComputeSystem              = modvmcompute.NewProc("WaitForProcessInComputeSystem")
+	procHNSCall                                    = modvmcompute.NewProc("HNSCall")
+)
+
+func coTaskMemFree(buffer unsafe.Pointer) {
+	syscall.Syscall(procCoTaskMemFree.Addr(), 1, uintptr(buffer), 0, 0)
+	return
+}
+
+func activateLayer(info *driverInfo, id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _activateLayer(info, _p0)
+}
+
+func _activateLayer(info *driverInfo, id *uint16) (hr error) {
+	if hr = procActivateLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procActivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func copyLayer(info *driverInfo, srcId string, dstId string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(srcId)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(dstId)
+	if hr != nil {
+		return
+	}
+	return _copyLayer(info, _p0, _p1, descriptors)
+}
+
+func _copyLayer(info *driverInfo, srcId *uint16, dstId *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p2 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p2 = &descriptors[0]
+	}
+	if hr = procCopyLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procCopyLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(srcId)), uintptr(unsafe.Pointer(dstId)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func createLayer(info *driverInfo, id string, parent string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(parent)
+	if hr != nil {
+		return
+	}
+	return _createLayer(info, _p0, _p1)
+}
+
+func _createLayer(info *driverInfo, id *uint16, parent *uint16) (hr error) {
+	if hr = procCreateLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procCreateLayer.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)))
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func createSandboxLayer(info *driverInfo, id string, parent string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(parent)
+	if hr != nil {
+		return
+	}
+	return _createSandboxLayer(info, _p0, _p1, descriptors)
+}
+
+func _createSandboxLayer(info *driverInfo, id *uint16, parent *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p2 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p2 = &descriptors[0]
+	}
+	if hr = procCreateSandboxLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procCreateSandboxLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(parent)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func deactivateLayer(info *driverInfo, id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _deactivateLayer(info, _p0)
+}
+
+func _deactivateLayer(info *driverInfo, id *uint16) (hr error) {
+	if hr = procDeactivateLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procDeactivateLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func destroyLayer(info *driverInfo, id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _destroyLayer(info, _p0)
+}
+
+func _destroyLayer(info *driverInfo, id *uint16) (hr error) {
+	if hr = procDestroyLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procDestroyLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func exportLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(path)
+	if hr != nil {
+		return
+	}
+	return _exportLayer(info, _p0, _p1, descriptors)
+}
+
+func _exportLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p2 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p2 = &descriptors[0]
+	}
+	if hr = procExportLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procExportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func getLayerMountPath(info *driverInfo, id string, length *uintptr, buffer *uint16) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _getLayerMountPath(info, _p0, length, buffer)
+}
+
+func _getLayerMountPath(info *driverInfo, id *uint16, length *uintptr, buffer *uint16) (hr error) {
+	if hr = procGetLayerMountPath.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procGetLayerMountPath.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(length)), uintptr(unsafe.Pointer(buffer)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func getBaseImages(buffer **uint16) (hr error) {
+	if hr = procGetBaseImages.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procGetBaseImages.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func importLayer(info *driverInfo, id string, path string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(path)
+	if hr != nil {
+		return
+	}
+	return _importLayer(info, _p0, _p1, descriptors)
+}
+
+func _importLayer(info *driverInfo, id *uint16, path *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p2 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p2 = &descriptors[0]
+	}
+	if hr = procImportLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procImportLayer.Addr(), 5, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(_p2)), uintptr(len(descriptors)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func layerExists(info *driverInfo, id string, exists *uint32) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _layerExists(info, _p0, exists)
+}
+
+func _layerExists(info *driverInfo, id *uint16, exists *uint32) (hr error) {
+	if hr = procLayerExists.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procLayerExists.Addr(), 3, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(exists)))
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func nameToGuid(name string, guid *GUID) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(name)
+	if hr != nil {
+		return
+	}
+	return _nameToGuid(_p0, guid)
+}
+
+func _nameToGuid(name *uint16, guid *GUID) (hr error) {
+	if hr = procNameToGuid.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procNameToGuid.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(guid)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func prepareLayer(info *driverInfo, id string, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _prepareLayer(info, _p0, descriptors)
+}
+
+func _prepareLayer(info *driverInfo, id *uint16, descriptors []WC_LAYER_DESCRIPTOR) (hr error) {
+	var _p1 *WC_LAYER_DESCRIPTOR
+	if len(descriptors) > 0 {
+		_p1 = &descriptors[0]
+	}
+	if hr = procPrepareLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procPrepareLayer.Addr(), 4, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(_p1)), uintptr(len(descriptors)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func unprepareLayer(info *driverInfo, id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _unprepareLayer(info, _p0)
+}
+
+func _unprepareLayer(info *driverInfo, id *uint16) (hr error) {
+	if hr = procUnprepareLayer.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procUnprepareLayer.Addr(), 2, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(id)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func createComputeSystem(id string, configuration string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(configuration)
+	if hr != nil {
+		return
+	}
+	return _createComputeSystem(_p0, _p1)
+}
+
+func _createComputeSystem(id *uint16, configuration *uint16) (hr error) {
+	if hr = procCreateComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procCreateComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func createProcessWithStdHandlesInComputeSystem(id string, paramsJson string, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(paramsJson)
+	if hr != nil {
+		return
+	}
+	return _createProcessWithStdHandlesInComputeSystem(_p0, _p1, pid, stdin, stdout, stderr)
+}
+
+func _createProcessWithStdHandlesInComputeSystem(id *uint16, paramsJson *uint16, pid *uint32, stdin *syscall.Handle, stdout *syscall.Handle, stderr *syscall.Handle) (hr error) {
+	if hr = procCreateProcessWithStdHandlesInComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procCreateProcessWithStdHandlesInComputeSystem.Addr(), 6, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(paramsJson)), uintptr(unsafe.Pointer(pid)), uintptr(unsafe.Pointer(stdin)), uintptr(unsafe.Pointer(stdout)), uintptr(unsafe.Pointer(stderr)))
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func resizeConsoleInComputeSystem(id string, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _resizeConsoleInComputeSystem(_p0, pid, height, width, flags)
+}
+
+func _resizeConsoleInComputeSystem(id *uint16, pid uint32, height uint16, width uint16, flags uint32) (hr error) {
+	if hr = procResizeConsoleInComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procResizeConsoleInComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(height), uintptr(width), uintptr(flags), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func shutdownComputeSystem(id string, timeout uint32) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _shutdownComputeSystem(_p0, timeout)
+}
+
+func _shutdownComputeSystem(id *uint16, timeout uint32) (hr error) {
+	if hr = procShutdownComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procShutdownComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(timeout), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func startComputeSystem(id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _startComputeSystem(_p0)
+}
+
+func _startComputeSystem(id *uint16) (hr error) {
+	if hr = procStartComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procStartComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func terminateComputeSystem(id string) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _terminateComputeSystem(_p0)
+}
+
+func _terminateComputeSystem(id *uint16) (hr error) {
+	if hr = procTerminateComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procTerminateComputeSystem.Addr(), 1, uintptr(unsafe.Pointer(id)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func terminateProcessInComputeSystem(id string, pid uint32) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _terminateProcessInComputeSystem(_p0, pid)
+}
+
+func _terminateProcessInComputeSystem(id *uint16, pid uint32) (hr error) {
+	if hr = procTerminateProcessInComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall(procTerminateProcessInComputeSystem.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(pid), 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(id)
+	if hr != nil {
+		return
+	}
+	return _waitForProcessInComputeSystem(_p0, pid, timeout, exitCode)
+}
+
+func _waitForProcessInComputeSystem(id *uint16, pid uint32, timeout uint32, exitCode *uint32) (hr error) {
+	if hr = procWaitForProcessInComputeSystem.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procWaitForProcessInComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(pid), uintptr(timeout), uintptr(unsafe.Pointer(exitCode)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}
+
+func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
+	var _p0 *uint16
+	_p0, hr = syscall.UTF16PtrFromString(method)
+	if hr != nil {
+		return
+	}
+	var _p1 *uint16
+	_p1, hr = syscall.UTF16PtrFromString(path)
+	if hr != nil {
+		return
+	}
+	var _p2 *uint16
+	_p2, hr = syscall.UTF16PtrFromString(object)
+	if hr != nil {
+		return
+	}
+	return __hnsCall(_p0, _p1, _p2, response)
+}
+
+func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) {
+	if hr = procHNSCall.Find(); hr != nil {
+		return
+	}
+	r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
+	if r0 != 0 {
+		hr = syscall.Errno(r0)
+	}
+	return
+}

+ 2 - 1
libnetwork/drivers.go

@@ -5,9 +5,10 @@ import (
 
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/netlabel"
+
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
-	"github.com/docker/libnetwork/netlabel"
 )
 
 type initializer struct {

+ 12 - 0
libnetwork/drivers/windows/labels.go

@@ -0,0 +1,12 @@
+package windows
+
+const (
+	// NetworkName label for bridge driver
+	NetworkName = "com.docker.network.windowsshim.networkname"
+
+	// HNSID of the discovered network
+	HNSID = "com.docker.network.windowsshim.hnsid"
+
+	// RoutingDomain of the network
+	RoutingDomain = "com.docker.network.windowsshim.routingdomain"
+)

+ 372 - 10
libnetwork/drivers/windows/windows.go

@@ -1,57 +1,419 @@
+// +build windows
+
+// Shim for the Host Network Service (HNS) to manage networking for
+// Windows Server containers and Hyper-V containers. This module
+// is a basic libnetwork driver that passes all the calls to HNS
+// It implements the 4 networking modes supported by HNS L2Bridge,
+// L2Tunnel, NAT and Transparent(DHCP)
+//
+// The network are stored in memory and docker daemon ensures discovering
+// and loading these networks on startup
+
 package windows
 
 import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"strings"
+	"sync"
+
+	"github.com/Microsoft/hcsshim"
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/types"
 )
 
-const networkType = "windows"
+// networkConfiguration for network specific configuration
+type networkConfiguration struct {
+	ID    string
+	Type  string
+	Name  string
+	HnsID string
+	RDID  string
+}
+
+type hnsEndpoint struct {
+	id         string
+	profileID  string
+	macAddress net.HardwareAddr
+	addr       *net.IPNet
+}
+
+type hnsNetwork struct {
+	id        string
+	config    *networkConfiguration
+	endpoints map[string]*hnsEndpoint // key: endpoint id
+	driver    *driver                 // The network's driver
+	sync.Mutex
+}
+
+type driver struct {
+	name     string
+	networks map[string]*hnsNetwork
+	sync.Mutex
+}
+
+func isValidNetworkType(networkType string) bool {
+	if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
+		return true
+	}
+
+	return false
+}
+
+// New constructs a new bridge driver
+func newDriver(networkType string) *driver {
+	return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
+}
+
+// GetInit returns an initializer for the given network type
+func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
+	return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
+		if !isValidNetworkType(networkType) {
+			return types.BadRequestErrorf("Network type not supported: %s", networkType)
+		}
+
+		return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{
+			DataScope: datastore.LocalScope,
+		})
+	}
+}
+
+func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
+	d.Lock()
+	defer d.Unlock()
+
+	if nw, ok := d.networks[id]; ok {
+		return nw, nil
+	}
+
+	return nil, types.NotFoundErrorf("network not found: %s", id)
+}
+
+func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
+	n.Lock()
+	defer n.Unlock()
+
+	if ep, ok := n.endpoints[eid]; ok {
+		return ep, nil
+	}
+
+	return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
+}
+
+func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
+	config := &networkConfiguration{}
 
-// TODO Windows. This is a placeholder for now
+	for label, value := range genericOptions {
+		switch label {
+		case NetworkName:
+			config.Name = value
+		case HNSID:
+			config.HnsID = value
+		case RoutingDomain:
+			config.RDID = value
+		}
+	}
 
-type driver struct{}
+	config.ID = id
+	config.Type = d.name
+	return config, nil
+}
+
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
+	if len(ipamV6Data) > 0 {
+		return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
+	}
 
-// Init registers a new instance of null driver
-func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
-	c := driverapi.Capability{
-		DataScope: datastore.LocalScope,
+	if len(ipamV4Data) == 0 {
+		return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
 	}
-	return dc.RegisterDriver(networkType, &driver{}, c)
+
+	return nil
 }
 
+// Create a new network
 func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+	if _, err := d.getNetwork(id); err == nil {
+		return types.ForbiddenErrorf("network %s exists", id)
+	}
+
+	genData, ok := option[netlabel.GenericData].(map[string]string)
+	if !ok {
+		return fmt.Errorf("Unknown generic data option")
+	}
+
+	// Parse and validate the config. It should not conflict with existing networks' config
+	config, err := d.parseNetworkOptions(id, genData)
+	if err != nil {
+		return err
+	}
+
+	err = config.processIPAM(id, ipV4Data, ipV6Data)
+	if err != nil {
+		return err
+	}
+
+	network := &hnsNetwork{
+		id:        config.ID,
+		endpoints: make(map[string]*hnsEndpoint),
+		config:    config,
+		driver:    d,
+	}
+
+	d.Lock()
+	d.networks[config.ID] = network
+	d.Unlock()
+
+	// A non blank hnsid indicates that the network was discovered
+	// from HNS. No need to call HNS if this network was discovered
+	// from HNS
+	if config.HnsID == "" {
+		subnets := []hcsshim.Subnet{}
+
+		for _, ipData := range ipV4Data {
+			subnet := hcsshim.Subnet{
+				AddressPrefix:  ipData.Pool.String(),
+				GatewayAddress: ipData.Gateway.IP.String(),
+			}
+
+			subnets = append(subnets, subnet)
+		}
+
+		network := &hcsshim.HNSNetwork{
+			Name:    config.Name,
+			Type:    d.name,
+			Subnets: subnets,
+		}
+
+		if network.Name == "" {
+			network.Name = id
+		}
+
+		configurationb, err := json.Marshal(network)
+		if err != nil {
+			return err
+		}
+
+		configuration := string(configurationb)
+		log.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
+
+		hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
+		if err != nil {
+			return err
+		}
+
+		config.HnsID = hnsresponse.Id
+		genData[HNSID] = config.HnsID
+	}
+
 	return nil
 }
 
 func (d *driver) DeleteNetwork(nid string) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	n.Lock()
+	config := n.config
+	n.Unlock()
+
+	// Cannot remove network if endpoints are still present
+	if len(n.endpoints) != 0 {
+		return fmt.Errorf("network %s has active endpoint", n.id)
+	}
+
+	_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
+	if err != nil {
+		return err
+	}
+
+	d.Lock()
+	delete(d.networks, nid)
+	d.Unlock()
+
 	return nil
 }
 
+func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
+	var pbs []json.RawMessage
+
+	// Enumerate through the port bindings specified by the user and convert
+	// them into the internal structure matching the JSON blob that can be
+	// understood by the HCS.
+	for _, elem := range portBindings {
+		proto := strings.ToUpper(elem.Proto.String())
+		if proto != "TCP" && proto != "UDP" {
+			return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
+		}
+
+		if elem.HostPort != elem.HostPortEnd {
+			return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
+		}
+
+		if len(elem.HostIP) != 0 {
+			return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
+		}
+
+		encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
+			Type:         "NAT",
+			ExternalPort: elem.HostPort,
+			InternalPort: elem.Port,
+			Protocol:     elem.Proto.String(),
+		})
+
+		if err != nil {
+			return nil, err
+		}
+		pbs = append(pbs, encodedPolicy)
+	}
+	return pbs, nil
+}
+
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return err
+	}
+
+	// Check if endpoint id is good and retrieve corresponding endpoint
+	ep, err := n.getEndpoint(eid)
+	if err == nil && ep != nil {
+		return driverapi.ErrEndpointExists(eid)
+	}
+
+	endpointStruct := &hcsshim.HNSEndpoint{
+		VirtualNetwork: n.config.HnsID,
+	}
+
+	// Convert the port mapping for the network
+	if opt, ok := epOptions[netlabel.PortMap]; ok {
+		if bs, ok := opt.([]types.PortBinding); ok {
+			endpointStruct.Policies, err = convertPortBindings(bs)
+			if err != nil {
+				return err
+			}
+		} else {
+			return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
+		}
+	}
+
+	configurationb, err := json.Marshal(endpointStruct)
+	if err != nil {
+		return err
+	}
+
+	hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
+	if err != nil {
+		return err
+	}
+
+	mac, err := net.ParseMAC(hnsresponse.MacAddress)
+	if err != nil {
+		return err
+	}
+
+	// TODO For now the ip mask is not in the info generated by HNS
+	endpoint := &hnsEndpoint{
+		id:         eid,
+		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
+		macAddress: mac,
+	}
+	endpoint.profileID = hnsresponse.Id
+	n.Lock()
+	n.endpoints[eid] = endpoint
+	n.Unlock()
+
+	ifInfo.SetIPAddress(endpoint.addr)
+	ifInfo.SetMacAddress(endpoint.macAddress)
+
 	return nil
 }
 
 func (d *driver) DeleteEndpoint(nid, eid string) error {
+	n, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	ep, err := n.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	n.Lock()
+	delete(n.endpoints, eid)
+	n.Unlock()
+
+	_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
+	if err != nil {
+		return err
+	}
+
 	return nil
 }
 
 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
-	return make(map[string]interface{}, 0), nil
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return nil, err
+	}
+
+	endpoint, err := network.getEndpoint(eid)
+	if err != nil {
+		return nil, err
+	}
+
+	data := make(map[string]interface{}, 1)
+	data["hnsid"] = endpoint.profileID
+	return data, nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return err
+	}
+
+	// Ensure that the endpoint exists
+	_, err = network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	// This is just a stub for now
+
+	jinfo.DisableGatewayService()
 	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 func (d *driver) Leave(nid, eid string) error {
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return types.InternalMaskableErrorf("%s", err)
+	}
+
+	// Ensure that the endpoint exists
+	_, err = network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	// This is just a stub for now
+
 	return nil
 }
 
 func (d *driver) Type() string {
-	return networkType
+	return d.name
 }
 
 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster

+ 141 - 0
libnetwork/drivers/windows/windows_test.go

@@ -0,0 +1,141 @@
+// +build windows
+
+package windows
+
+import (
+	"net"
+	"testing"
+
+	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/types"
+)
+
+func testNetwork(networkType string, t *testing.T) {
+	d := newDriver(networkType)
+	bnw, _ := types.ParseCIDR("172.16.0.0/24")
+	br, _ := types.ParseCIDR("172.16.0.1/16")
+
+	netOption := make(map[string]interface{})
+	networkOptions := map[string]string{
+		NetworkName: "TestNetwork",
+	}
+
+	netOption[netlabel.GenericData] = networkOptions
+	ipdList := []driverapi.IPAMData{
+		driverapi.IPAMData{
+			Pool:    bnw,
+			Gateway: br,
+		},
+	}
+
+	err := d.CreateNetwork("dummy", netOption, ipdList, nil)
+	if err != nil {
+		t.Fatalf("Failed to create bridge: %v", err)
+	}
+	defer func() {
+		err = d.DeleteNetwork("dummy")
+		if err != nil {
+			t.Fatalf("Failed to create bridge: %v", err)
+		}
+	}()
+
+	epOptions := make(map[string]interface{})
+	te := &testEndpoint{}
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
+	if err != nil {
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
+	}
+
+	err = d.DeleteEndpoint("dummy", "ep1")
+	if err != nil {
+		t.Fatalf("Failed to delete an endpoint : %s", err.Error())
+	}
+}
+
+func TestNAT(t *testing.T) {
+	testNetwork("NAT", t)
+}
+
+func TestTransparent(t *testing.T) {
+	testNetwork("Transparent", t)
+}
+
+type testEndpoint struct {
+	t                     *testing.T
+	src                   string
+	dst                   string
+	address               string
+	macAddress            string
+	gateway               string
+	disableGatewayService bool
+}
+
+func (test *testEndpoint) Interface() driverapi.InterfaceInfo {
+	return test
+}
+
+func (test *testEndpoint) Address() *net.IPNet {
+	if test.address == "" {
+		return nil
+	}
+	nw, _ := types.ParseCIDR(test.address)
+	return nw
+}
+
+func (test *testEndpoint) AddressIPv6() *net.IPNet {
+	return nil
+}
+
+func (test *testEndpoint) MacAddress() net.HardwareAddr {
+	if test.macAddress == "" {
+		return nil
+	}
+	mac, _ := net.ParseMAC(test.macAddress)
+	return mac
+}
+
+func (test *testEndpoint) SetMacAddress(mac net.HardwareAddr) error {
+	if test.macAddress != "" {
+		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", test.macAddress, mac)
+	}
+
+	if mac == nil {
+		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
+	}
+	test.macAddress = mac.String()
+	return nil
+}
+
+func (test *testEndpoint) SetIPAddress(address *net.IPNet) error {
+	if address.IP == nil {
+		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
+	}
+
+	test.address = address.String()
+	return nil
+}
+
+func (test *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
+	return test
+}
+
+func (test *testEndpoint) SetGateway(ipv4 net.IP) error {
+	return nil
+}
+
+func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error {
+	return nil
+}
+
+func (test *testEndpoint) SetNames(src string, dst string) error {
+	return nil
+}
+
+func (test *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
+	return nil
+}
+
+func (test *testEndpoint) DisableGatewayService() {
+	test.disableGatewayService = true
+}

+ 9 - 2
libnetwork/drivers_windows.go

@@ -1,9 +1,16 @@
 package libnetwork
 
-import "github.com/docker/libnetwork/drivers/windows"
+import (
+	"github.com/docker/libnetwork/drivers/null"
+	"github.com/docker/libnetwork/drivers/windows"
+)
 
 func getInitializers() []initializer {
 	return []initializer{
-		{windows.Init, "windows"},
+		{null.Init, "null"},
+		{windows.GetInit("Transparent"), "Transparent"},
+		{windows.GetInit("L2Bridge"), "L2Bridge"},
+		{windows.GetInit("L2Tunnel"), "L2Tunnel"},
+		{windows.GetInit("NAT"), "NAT"},
 	}
 }

+ 2 - 0
libnetwork/ipams/builtin/builtin.go → libnetwork/ipams/builtin/builtin_unix.go

@@ -1,3 +1,5 @@
+// +build linux freebsd
+
 package builtin
 
 import (

+ 16 - 0
libnetwork/ipams/builtin/builtin_windows.go

@@ -0,0 +1,16 @@
+// +build windows
+
+package builtin
+
+import (
+	"github.com/docker/libnetwork/ipamapi"
+
+	windowsipam "github.com/docker/libnetwork/ipams/windowsipam"
+)
+
+// Init registers the built-in ipam service with libnetwork
+func Init(ic ipamapi.Callback, l, g interface{}) error {
+	initFunc := windowsipam.GetInit(ipamapi.DefaultIPAM)
+
+	return initFunc(ic, l, g)
+}

+ 82 - 0
libnetwork/ipams/windowsipam/windowsipam.go

@@ -0,0 +1,82 @@
+package windowsipam
+
+import (
+	"net"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/types"
+)
+
+const (
+	localAddressSpace  = "LocalDefault"
+	globalAddressSpace = "GlobalDefault"
+)
+
+var (
+	defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
+)
+
+type allocator struct {
+}
+
+// GetInit registers the built-in ipam service with libnetwork
+func GetInit(ipamName string) func(ic ipamapi.Callback, l, g interface{}) error {
+	return func(ic ipamapi.Callback, l, g interface{}) error {
+		return ic.RegisterIpamDriver(ipamName, &allocator{})
+	}
+}
+
+func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
+	return localAddressSpace, globalAddressSpace, nil
+}
+
+// RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
+// subnet user asked and does not validate anything. Doesnt support subpool allocation
+func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
+	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
+	if subPool != "" || v6 {
+		return "", nil, nil, types.InternalErrorf("This request is not supported by null ipam driver")
+	}
+
+	var ipNet *net.IPNet
+	var err error
+
+	if pool != "" {
+		_, ipNet, err = net.ParseCIDR(pool)
+		if err != nil {
+			return "", nil, nil, err
+		}
+	} else {
+		ipNet = defaultPool
+	}
+
+	return ipNet.String(), ipNet, nil, nil
+}
+
+// ReleasePool releases the address pool - always succeeds
+func (a *allocator) ReleasePool(poolID string) error {
+	log.Debugf("ReleasePool(%s)", poolID)
+	return nil
+}
+
+// RequestAddress returns an address from the specified pool ID.
+// Always allocate the 0.0.0.0/32 ip if no preferred address was specified
+func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
+	log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
+	_, ipNet, err := net.ParseCIDR(poolID)
+
+	if err != nil {
+		return nil, nil, err
+	}
+	if prefAddress == nil {
+		return ipNet, nil, nil
+	}
+	return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
+}
+
+// ReleaseAddress releases the address - always succeeds
+func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
+	log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
+	return nil
+}

+ 71 - 0
libnetwork/ipams/windowsipam/windowsipam_test.go

@@ -0,0 +1,71 @@
+package windowsipam
+
+import (
+	"net"
+	"testing"
+
+	_ "github.com/docker/libnetwork/testutils"
+	"github.com/docker/libnetwork/types"
+)
+
+func TestWindowsIPAM(t *testing.T) {
+	a := &allocator{}
+	requestPool, _ := types.ParseCIDR("192.168.0.0/16")
+	requestAddress := net.ParseIP("192.168.1.1")
+
+	pid, pool, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !types.CompareIPNet(defaultPool, pool) ||
+		pid != pool.String() {
+		t.Fatalf("Unexpected data returned. Expected %v : %s. Got: %v : %s", defaultPool, pid, pool, pool.String())
+	}
+
+	pid, pool, _, err = a.RequestPool(localAddressSpace, requestPool.String(), "", nil, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !types.CompareIPNet(requestPool, pool) ||
+		pid != requestPool.String() {
+		t.Fatalf("Unexpected data returned. Expected %v : %s. Got: %v : %s", requestPool, requestPool.String(), pool, pool.String())
+	}
+
+	_, _, _, err = a.RequestPool(localAddressSpace, requestPool.String(), requestPool.String(), nil, false)
+	if err == nil {
+		t.Fatal("Unexpected success for subpool request")
+	}
+
+	_, _, _, err = a.RequestPool(localAddressSpace, requestPool.String(), "", nil, true)
+	if err == nil {
+		t.Fatal("Unexpected success for v6 request")
+	}
+
+	err = a.ReleasePool(requestPool.String())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ip, _, err := a.RequestAddress(requestPool.String(), nil, map[string]string{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !types.CompareIPNet(ip, requestPool) {
+		t.Fatalf("Unexpected data returned. Expected %v . Got: %v ", requestPool, ip)
+	}
+
+	ip, _, err = a.RequestAddress(requestPool.String(), requestAddress, map[string]string{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !ip.IP.Equal(requestAddress) {
+		t.Fatalf("Unexpected data returned. Expected %v . Got: %v ", requestAddress, ip.IP)
+	}
+
+	err = a.ReleaseAddress(requestPool.String(), requestAddress)
+	if err != nil {
+		t.Fatal(err)
+	}
+}

+ 0 - 312
libnetwork/sandbox.go

@@ -4,19 +4,13 @@ import (
 	"container/heap"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net"
-	"os"
-	"path"
-	"path/filepath"
 	"strings"
 	"sync"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/osl"
-	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -309,46 +303,6 @@ func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
-func (sb *sandbox) startResolver() {
-	sb.resolverOnce.Do(func() {
-		var err error
-		sb.resolver = NewResolver(sb)
-		defer func() {
-			if err != nil {
-				sb.resolver = nil
-			}
-		}()
-
-		err = sb.rebuildDNS()
-		if err != nil {
-			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
-			return
-		}
-		sb.resolver.SetExtServers(sb.extDNS)
-
-		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
-		if err = sb.resolver.Start(); err != nil {
-			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
-		}
-	})
-}
-
-func (sb *sandbox) setupResolutionFiles() error {
-	if err := sb.buildHostsFile(); err != nil {
-		return err
-	}
-
-	if err := sb.updateParentHosts(); err != nil {
-		return err
-	}
-
-	if err := sb.setupDNS(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
 func (sb *sandbox) Endpoints() []Endpoint {
 	sb.Lock()
 	defer sb.Unlock()
@@ -753,243 +707,6 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
 	return nil
 }
 
-const (
-	defaultPrefix = "/var/lib/docker/network/files"
-	dirPerm       = 0755
-	filePerm      = 0644
-)
-
-func (sb *sandbox) buildHostsFile() error {
-	if sb.config.hostsPath == "" {
-		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
-	}
-
-	dir, _ := filepath.Split(sb.config.hostsPath)
-	if err := createBasePath(dir); err != nil {
-		return err
-	}
-
-	// This is for the host mode networking
-	if sb.config.originHostsPath != "" {
-		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
-			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
-		}
-		return nil
-	}
-
-	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
-	for _, extraHost := range sb.config.extraHosts {
-		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
-	}
-
-	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
-}
-
-func (sb *sandbox) updateHostsFile(ifaceIP string) error {
-	var mhost string
-
-	if sb.config.originHostsPath != "" {
-		return nil
-	}
-
-	if sb.config.domainName != "" {
-		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
-			sb.config.hostName)
-	} else {
-		mhost = sb.config.hostName
-	}
-
-	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
-
-	sb.addHostsEntries(extraContent)
-	return nil
-}
-
-func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
-	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed adding service host entries to the running container: %v", err)
-	}
-}
-
-func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
-	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed deleting service host entries to the running container: %v", err)
-	}
-}
-
-func (sb *sandbox) updateParentHosts() error {
-	var pSb Sandbox
-
-	for _, update := range sb.config.parentUpdates {
-		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
-		if pSb == nil {
-			continue
-		}
-		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func (sb *sandbox) setupDNS() error {
-	var newRC *resolvconf.File
-
-	if sb.config.resolvConfPath == "" {
-		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
-	}
-
-	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
-
-	dir, _ := filepath.Split(sb.config.resolvConfPath)
-	if err := createBasePath(dir); err != nil {
-		return err
-	}
-
-	// This is for the host mode networking
-	if sb.config.originResolvConfPath != "" {
-		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
-			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
-		}
-		return nil
-	}
-
-	currRC, err := resolvconf.Get()
-	if err != nil {
-		return err
-	}
-
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
-		var (
-			err            error
-			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
-			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
-			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
-		)
-		if len(sb.config.dnsList) > 0 {
-			dnsList = sb.config.dnsList
-		}
-		if len(sb.config.dnsSearchList) > 0 {
-			dnsSearchList = sb.config.dnsSearchList
-		}
-		if len(sb.config.dnsOptionsList) > 0 {
-			dnsOptionsList = sb.config.dnsOptionsList
-		}
-		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
-		if err != nil {
-			return err
-		}
-	} else {
-		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
-		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
-			return err
-		}
-		// No contention on container resolv.conf file at sandbox creation
-		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
-			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
-		}
-	}
-
-	// Write hash
-	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
-		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
-	}
-
-	return nil
-}
-
-func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
-	var (
-		currHash string
-		hashFile = sb.config.resolvConfHashFile
-	)
-
-	// This is for the host mode networking
-	if sb.config.originResolvConfPath != "" {
-		return nil
-	}
-
-	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
-		return nil
-	}
-
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-	} else {
-		h, err := ioutil.ReadFile(hashFile)
-		if err != nil {
-			if !os.IsNotExist(err) {
-				return err
-			}
-		} else {
-			currHash = string(h)
-		}
-	}
-
-	if currHash != "" && currHash != currRC.Hash {
-		// Seems the user has changed the container resolv.conf since the last time
-		// we checked so return without doing anything.
-		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
-		return nil
-	}
-
-	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
-	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
-	if err != nil {
-		return err
-	}
-	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
-	if err != nil {
-		return err
-	}
-
-	// write the new hash in a temp file and rename it to make the update atomic
-	dir := path.Dir(sb.config.resolvConfPath)
-	tmpHashFile, err := ioutil.TempFile(dir, "hash")
-	if err != nil {
-		return err
-	}
-	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
-		return err
-	}
-	return os.Rename(tmpHashFile.Name(), hashFile)
-}
-
-// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
-// resolv.conf by doing the follwing
-// - Save the external name servers in resolv.conf in the sandbox
-// - Add only the embedded server's IP to container's resolv.conf
-// - If the embedded server needs any resolv.conf options add it to the current list
-func (sb *sandbox) rebuildDNS() error {
-	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
-	if err != nil {
-		return err
-	}
-
-	// localhost entries have already been filtered out from the list
-	// retain only the v4 servers in sb for forwarding the DNS queries
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
-
-	var (
-		dnsList        = []string{sb.resolver.NameServer()}
-		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
-		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
-	)
-
-	// external v6 DNS servers has to be listed in resolv.conf
-	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
-
-	// Resolver returns the options in the format resolv.conf expects
-	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
-
-	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
-	return err
-}
-
 // joinLeaveStart waits to ensure there are no joins or leaves in progress and
 // marks this join/leave in progress without race
 func (sb *sandbox) joinLeaveStart() {
@@ -1191,32 +908,3 @@ func (eh *epHeap) Pop() interface{} {
 	*eh = old[0 : n-1]
 	return x
 }
-
-func createBasePath(dir string) error {
-	return os.MkdirAll(dir, dirPerm)
-}
-
-func createFile(path string) error {
-	var f *os.File
-
-	dir, _ := filepath.Split(path)
-	err := createBasePath(dir)
-	if err != nil {
-		return err
-	}
-
-	f, err = os.Create(path)
-	if err == nil {
-		f.Close()
-	}
-
-	return err
-}
-
-func copyFile(src, dst string) error {
-	sBytes, err := ioutil.ReadFile(src)
-	if err != nil {
-		return err
-	}
-	return ioutil.WriteFile(dst, sBytes, filePerm)
-}

+ 323 - 0
libnetwork/sandbox_dns_unix.go

@@ -0,0 +1,323 @@
+// +build !windows
+
+package libnetwork
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/etchosts"
+	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/resolvconf"
+	"github.com/docker/libnetwork/types"
+)
+
+const (
+	defaultPrefix = "/var/lib/docker/network/files"
+	dirPerm       = 0755
+	filePerm      = 0644
+)
+
+func (sb *sandbox) startResolver() {
+	sb.resolverOnce.Do(func() {
+		var err error
+		sb.resolver = NewResolver(sb)
+		defer func() {
+			if err != nil {
+				sb.resolver = nil
+			}
+		}()
+
+		err = sb.rebuildDNS()
+		if err != nil {
+			log.Errorf("Updating resolv.conf failed for container %s, %q", sb.ContainerID(), err)
+			return
+		}
+		sb.resolver.SetExtServers(sb.extDNS)
+
+		sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())
+		if err = sb.resolver.Start(); err != nil {
+			log.Errorf("Resolver Setup/Start failed for container %s, %q", sb.ContainerID(), err)
+		}
+	})
+}
+
+func (sb *sandbox) setupResolutionFiles() error {
+	if err := sb.buildHostsFile(); err != nil {
+		return err
+	}
+
+	if err := sb.updateParentHosts(); err != nil {
+		return err
+	}
+
+	if err := sb.setupDNS(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (sb *sandbox) buildHostsFile() error {
+	if sb.config.hostsPath == "" {
+		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
+	}
+
+	dir, _ := filepath.Split(sb.config.hostsPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originHostsPath != "" {
+		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
+			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
+		}
+		return nil
+	}
+
+	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
+	for _, extraHost := range sb.config.extraHosts {
+		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+	}
+
+	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
+}
+
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
+	var mhost string
+
+	if sb.config.originHostsPath != "" {
+		return nil
+	}
+
+	if sb.config.domainName != "" {
+		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
+			sb.config.hostName)
+	} else {
+		mhost = sb.config.hostName
+	}
+
+	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
+
+	sb.addHostsEntries(extraContent)
+	return nil
+}
+
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed adding service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed deleting service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) updateParentHosts() error {
+	var pSb Sandbox
+
+	for _, update := range sb.config.parentUpdates {
+		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
+		if pSb == nil {
+			continue
+		}
+		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (sb *sandbox) setupDNS() error {
+	var newRC *resolvconf.File
+
+	if sb.config.resolvConfPath == "" {
+		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
+	}
+
+	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
+
+	dir, _ := filepath.Split(sb.config.resolvConfPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originResolvConfPath != "" {
+		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
+			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
+		}
+		return nil
+	}
+
+	currRC, err := resolvconf.Get()
+	if err != nil {
+		return err
+	}
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		var (
+			err            error
+			dnsList        = resolvconf.GetNameservers(currRC.Content, netutils.IP)
+			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
+			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
+		)
+		if len(sb.config.dnsList) > 0 {
+			dnsList = sb.config.dnsList
+		}
+		if len(sb.config.dnsSearchList) > 0 {
+			dnsSearchList = sb.config.dnsSearchList
+		}
+		if len(sb.config.dnsOptionsList) > 0 {
+			dnsOptionsList = sb.config.dnsOptionsList
+		}
+		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
+		if err != nil {
+			return err
+		}
+	} else {
+		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
+		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
+			return err
+		}
+		// No contention on container resolv.conf file at sandbox creation
+		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
+			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
+		}
+	}
+
+	// Write hash
+	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
+		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
+	}
+
+	return nil
+}
+
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
+	var (
+		currHash string
+		hashFile = sb.config.resolvConfHashFile
+	)
+
+	// This is for the host mode networking
+	if sb.config.originResolvConfPath != "" {
+		return nil
+	}
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		return nil
+	}
+
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return err
+		}
+	} else {
+		h, err := ioutil.ReadFile(hashFile)
+		if err != nil {
+			if !os.IsNotExist(err) {
+				return err
+			}
+		} else {
+			currHash = string(h)
+		}
+	}
+
+	if currHash != "" && currHash != currRC.Hash {
+		// Seems the user has changed the container resolv.conf since the last time
+		// we checked so return without doing anything.
+		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
+		return nil
+	}
+
+	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
+	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
+	if err != nil {
+		return err
+	}
+	err = ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, 0644)
+	if err != nil {
+		return err
+	}
+
+	// write the new hash in a temp file and rename it to make the update atomic
+	dir := path.Dir(sb.config.resolvConfPath)
+	tmpHashFile, err := ioutil.TempFile(dir, "hash")
+	if err != nil {
+		return err
+	}
+	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
+		return err
+	}
+	return os.Rename(tmpHashFile.Name(), hashFile)
+}
+
+// Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
+// resolv.conf by doing the follwing
+// - Save the external name servers in resolv.conf in the sandbox
+// - Add only the embedded server's IP to container's resolv.conf
+// - If the embedded server needs any resolv.conf options add it to the current list
+func (sb *sandbox) rebuildDNS() error {
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
+	if err != nil {
+		return err
+	}
+
+	// localhost entries have already been filtered out from the list
+	// retain only the v4 servers in sb for forwarding the DNS queries
+	sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4)
+
+	var (
+		dnsList        = []string{sb.resolver.NameServer()}
+		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
+		dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
+	)
+
+	// external v6 DNS servers has to be listed in resolv.conf
+	dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...)
+
+	// Resolver returns the options in the format resolv.conf expects
+	dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...)
+
+	_, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
+	return err
+}
+
+func createBasePath(dir string) error {
+	return os.MkdirAll(dir, dirPerm)
+}
+
+func createFile(path string) error {
+	var f *os.File
+
+	dir, _ := filepath.Split(path)
+	err := createBasePath(dir)
+	if err != nil {
+		return err
+	}
+
+	f, err = os.Create(path)
+	if err == nil {
+		f.Close()
+	}
+
+	return err
+}
+
+func copyFile(src, dst string) error {
+	sBytes, err := ioutil.ReadFile(src)
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(dst, sBytes, filePerm)
+}

+ 32 - 0
libnetwork/sandbox_dns_windows.go

@@ -0,0 +1,32 @@
+// +build windows
+
+package libnetwork
+
+import (
+	"github.com/docker/libnetwork/etchosts"
+)
+
+// Stub implementations for DNS related functions
+
+func (sb *sandbox) startResolver() {
+}
+
+func (sb *sandbox) setupResolutionFiles() error {
+	return nil
+}
+
+func (sb *sandbox) updateHostsFile(ifaceIP string) error {
+	return nil
+}
+
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
+
+}
+
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
+
+}
+
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
+	return nil
+}

+ 1 - 1
libnetwork/sandbox_externalkey_unix.go

@@ -1,4 +1,4 @@
-// +build !windows
+// +build linux freebsd
 
 package libnetwork
 

+ 2 - 0
libnetwork/testutils/context.go → libnetwork/testutils/context_unix.go

@@ -1,3 +1,5 @@
+// +build linux freebsd
+
 package testutils
 
 import (

+ 25 - 0
libnetwork/testutils/context_windows.go

@@ -0,0 +1,25 @@
+// +build windows
+
+package testutils
+
+import (
+	"os"
+	"testing"
+)
+
+// SetupTestOSContext joins a new network namespace, and returns its associated
+// teardown function.
+//
+// Example usage:
+//
+//     defer SetupTestOSContext(t)()
+//
+func SetupTestOSContext(t *testing.T) func() {
+	return func() {
+	}
+}
+
+// RunningOnCircleCI returns true if being executed on libnetwork Circle CI setup
+func RunningOnCircleCI() bool {
+	return os.Getenv("CIRCLECI") != ""
+}