Преглед изворни кода

Merge pull request #1925 from pradipd/windows_routingmesh

Enabling ILB/ELB on windows using per-node, per-network LB endpoint.
Flavio Crisciani пре 7 година
родитељ
комит
fa61cbb30e

+ 16 - 2
libnetwork/endpoint.go

@@ -75,6 +75,7 @@ type endpoint struct {
 	dbIndex           uint64
 	dbIndex           uint64
 	dbExists          bool
 	dbExists          bool
 	serviceEnabled    bool
 	serviceEnabled    bool
+	loadBalancer      bool
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
@@ -101,6 +102,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
 	epMap["virtualIP"] = ep.virtualIP.String()
 	epMap["virtualIP"] = ep.virtualIP.String()
 	epMap["ingressPorts"] = ep.ingressPorts
 	epMap["ingressPorts"] = ep.ingressPorts
 	epMap["svcAliases"] = ep.svcAliases
 	epMap["svcAliases"] = ep.svcAliases
+	epMap["loadBalancer"] = ep.loadBalancer
 
 
 	return json.Marshal(epMap)
 	return json.Marshal(epMap)
 }
 }
@@ -201,6 +203,10 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 		ep.virtualIP = net.ParseIP(vip.(string))
 		ep.virtualIP = net.ParseIP(vip.(string))
 	}
 	}
 
 
+	if v, ok := epMap["loadBalancer"]; ok {
+		ep.loadBalancer = v.(bool)
+	}
+
 	sal, _ := json.Marshal(epMap["svcAliases"])
 	sal, _ := json.Marshal(epMap["svcAliases"])
 	var svcAliases []string
 	var svcAliases []string
 	json.Unmarshal(sal, &svcAliases)
 	json.Unmarshal(sal, &svcAliases)
@@ -238,6 +244,7 @@ func (ep *endpoint) CopyTo(o datastore.KVObject) error {
 	dstEp.svcName = ep.svcName
 	dstEp.svcName = ep.svcName
 	dstEp.svcID = ep.svcID
 	dstEp.svcID = ep.svcID
 	dstEp.virtualIP = ep.virtualIP
 	dstEp.virtualIP = ep.virtualIP
+	dstEp.loadBalancer = ep.loadBalancer
 
 
 	dstEp.svcAliases = make([]string, len(ep.svcAliases))
 	dstEp.svcAliases = make([]string, len(ep.svcAliases))
 	copy(dstEp.svcAliases, ep.svcAliases)
 	copy(dstEp.svcAliases, ep.svcAliases)
@@ -985,7 +992,7 @@ func CreateOptionDisableResolution() EndpointOption {
 	}
 	}
 }
 }
 
 
-//CreateOptionAlias function returns an option setter for setting endpoint alias
+// CreateOptionAlias function returns an option setter for setting endpoint alias
 func CreateOptionAlias(name string, alias string) EndpointOption {
 func CreateOptionAlias(name string, alias string) EndpointOption {
 	return func(ep *endpoint) {
 	return func(ep *endpoint) {
 		if ep.aliases == nil {
 		if ep.aliases == nil {
@@ -1006,13 +1013,20 @@ func CreateOptionService(name, id string, vip net.IP, ingressPorts []*PortConfig
 	}
 	}
 }
 }
 
 
-//CreateOptionMyAlias function returns an option setter for setting endpoint's self alias
+// CreateOptionMyAlias function returns an option setter for setting endpoint's self alias
 func CreateOptionMyAlias(alias string) EndpointOption {
 func CreateOptionMyAlias(alias string) EndpointOption {
 	return func(ep *endpoint) {
 	return func(ep *endpoint) {
 		ep.myAliases = append(ep.myAliases, alias)
 		ep.myAliases = append(ep.myAliases, alias)
 	}
 	}
 }
 }
 
 
+// CreateOptionLoadBalancer function returns an option setter for denoting the endpoint is a load balancer for a network
+func CreateOptionLoadBalancer() EndpointOption {
+	return func(ep *endpoint) {
+		ep.loadBalancer = true
+	}
+}
+
 // JoinOptionPriority function returns an option setter for priority option to
 // JoinOptionPriority function returns an option setter for priority option to
 // be passed to the endpoint.Join() method.
 // be passed to the endpoint.Join() method.
 func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
 func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {

+ 9 - 0
libnetwork/endpoint_info.go

@@ -31,6 +31,9 @@ type EndpointInfo interface {
 
 
 	// Sandbox returns the attached sandbox if there, nil otherwise.
 	// Sandbox returns the attached sandbox if there, nil otherwise.
 	Sandbox() Sandbox
 	Sandbox() Sandbox
+
+	// LoadBalancer returns whether the endpoint is the load balancer endpoint for the network.
+	LoadBalancer() bool
 }
 }
 
 
 // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
 // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
@@ -327,6 +330,12 @@ func (ep *endpoint) Sandbox() Sandbox {
 	return cnt
 	return cnt
 }
 }
 
 
+func (ep *endpoint) LoadBalancer() bool {
+	ep.Lock()
+	defer ep.Unlock()
+	return ep.loadBalancer
+}
+
 func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
 func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
 	ep.Lock()
 	ep.Lock()
 	defer ep.Unlock()
 	defer ep.Unlock()

+ 7 - 0
libnetwork/sandbox.go

@@ -916,6 +916,13 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
 			break
 			break
 		}
 		}
 	}
 	}
+
+	if index == -1 {
+		logrus.Warnf("Endpoint %s has already been deleted", ep.Name())
+		sb.Unlock()
+		return nil
+	}
+
 	heap.Remove(&sb.endpoints, index)
 	heap.Remove(&sb.endpoints, index)
 	for _, e := range sb.endpoints {
 	for _, e := range sb.endpoints {
 		if len(e.Gateway()) > 0 {
 		if len(e.Gateway()) > 0 {

+ 1 - 0
libnetwork/service.go

@@ -89,4 +89,5 @@ type loadBalancer struct {
 
 
 	// Back pointer to service to which the loadbalancer belongs.
 	// Back pointer to service to which the loadbalancer belongs.
 	service *service
 	service *service
+	sync.Mutex
 }
 }

+ 2 - 2
libnetwork/service_common.go

@@ -287,7 +287,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
 	// Add loadbalancer service and backend in all sandboxes in
 	// Add loadbalancer service and backend in all sandboxes in
 	// the network only if vip is valid.
 	// the network only if vip is valid.
 	if len(vip) != 0 {
 	if len(vip) != 0 {
-		n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts)
+		n.(*network).addLBBackend(ip, vip, lb, ingressPorts)
 	}
 	}
 
 
 	// Add the appropriate name resolutions
 	// Add the appropriate name resolutions
@@ -355,7 +355,7 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
 	// Remove loadbalancer service(if needed) and backend in all
 	// Remove loadbalancer service(if needed) and backend in all
 	// sandboxes in the network only if the vip is valid.
 	// sandboxes in the network only if the vip is valid.
 	if len(vip) != 0 && entries == 0 {
 	if len(vip) != 0 && entries == 0 {
-		n.(*network).rmLBBackend(ip, vip, lb.fwMark, ingressPorts, rmService)
+		n.(*network).rmLBBackend(ip, vip, lb, ingressPorts, rmService)
 	}
 	}
 
 
 	// Delete the name resolutions
 	// Delete the name resolutions

+ 4 - 4
libnetwork/service_linux.go

@@ -111,7 +111,7 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
 
 
 // Add loadbalancer backend to all sandboxes which has a connection to
 // Add loadbalancer backend to all sandboxes which has a connection to
 // this network. If needed add the service as well.
 // this network. If needed add the service as well.
-func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
+func (n *network) addLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig) {
 	n.WalkEndpoints(func(e Endpoint) bool {
 	n.WalkEndpoints(func(e Endpoint) bool {
 		ep := e.(*endpoint)
 		ep := e.(*endpoint)
 		if sb, ok := ep.getSandbox(); ok {
 		if sb, ok := ep.getSandbox(); ok {
@@ -124,7 +124,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
 				gwIP = ep.Iface().Address().IP
 				gwIP = ep.Iface().Address().IP
 			}
 			}
 
 
-			sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, n.ingress)
+			sb.addLBBackend(ip, vip, lb.fwMark, ingressPorts, ep.Iface().Address(), gwIP, n.ingress)
 		}
 		}
 
 
 		return false
 		return false
@@ -134,7 +134,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
 // Remove loadbalancer backend from all sandboxes which has a
 // Remove loadbalancer backend from all sandboxes which has a
 // connection to this network. If needed remove the service entry as
 // connection to this network. If needed remove the service entry as
 // well, as specified by the rmService bool.
 // well, as specified by the rmService bool.
-func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) {
+func (n *network) rmLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig, rmService bool) {
 	n.WalkEndpoints(func(e Endpoint) bool {
 	n.WalkEndpoints(func(e Endpoint) bool {
 		ep := e.(*endpoint)
 		ep := e.(*endpoint)
 		if sb, ok := ep.getSandbox(); ok {
 		if sb, ok := ep.getSandbox(); ok {
@@ -147,7 +147,7 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por
 				gwIP = ep.Iface().Address().IP
 				gwIP = ep.Iface().Address().IP
 			}
 			}
 
 
-			sb.rmLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress)
+			sb.rmLBBackend(ip, vip, lb.fwMark, ingressPorts, ep.Iface().Address(), gwIP, rmService, n.ingress)
 		}
 		}
 
 
 		return false
 		return false

+ 138 - 3
libnetwork/service_windows.go

@@ -1,11 +1,146 @@
 package libnetwork
 package libnetwork
 
 
-import "net"
+import (
+	"net"
 
 
-func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
+	"github.com/Microsoft/hcsshim"
+	"github.com/docker/docker/pkg/system"
+	"github.com/sirupsen/logrus"
+)
+
+type policyLists struct {
+	ilb *hcsshim.PolicyList
+	elb *hcsshim.PolicyList
+}
+
+var lbPolicylistMap map[*loadBalancer]*policyLists
+
+func init() {
+	lbPolicylistMap = make(map[*loadBalancer]*policyLists)
+}
+
+func (n *network) addLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig) {
+
+	if system.GetOSVersion().Build > 16236 {
+		lb.Lock()
+		defer lb.Unlock()
+		//find the load balancer IP for the network.
+		var sourceVIP string
+		for _, e := range n.Endpoints() {
+			epInfo := e.Info()
+			if epInfo == nil {
+				continue
+			}
+			if epInfo.LoadBalancer() {
+				sourceVIP = epInfo.Iface().Address().IP.String()
+				break
+			}
+		}
+
+		if sourceVIP == "" {
+			logrus.Errorf("Failed to find load balancer IP for network %s", n.Name())
+			return
+		}
+
+		var endpoints []hcsshim.HNSEndpoint
+
+		for eid := range lb.backEnds {
+			//Call HNS to get back ID (GUID) corresponding to the endpoint.
+			hnsEndpoint, err := hcsshim.GetHNSEndpointByName(eid)
+			if err != nil {
+				logrus.Errorf("Failed to find HNS ID for endpoint %v: %v", eid, err)
+				return
+			}
+
+			endpoints = append(endpoints, *hnsEndpoint)
+		}
+
+		if policies, ok := lbPolicylistMap[lb]; ok {
+
+			if policies.ilb != nil {
+				policies.ilb.Delete()
+				policies.ilb = nil
+			}
+
+			if policies.elb != nil {
+				policies.elb.Delete()
+				policies.elb = nil
+			}
+			delete(lbPolicylistMap, lb)
+		}
+
+		ilbPolicy, err := hcsshim.AddLoadBalancer(endpoints, true, sourceVIP, vip.String(), 0, 0, 0)
+		if err != nil {
+			logrus.Errorf("Failed to add ILB policy for service %s (%s) with endpoints %v using load balancer IP %s on network %s: %v",
+				lb.service.name, vip.String(), endpoints, sourceVIP, n.Name(), err)
+			return
+		}
+
+		lbPolicylistMap[lb] = &policyLists{
+			ilb: ilbPolicy,
+		}
+
+		publishedPorts := make(map[uint32]uint32)
+
+		for i, port := range ingressPorts {
+			protocol := uint16(6)
+
+			// Skip already published port
+			if publishedPorts[port.PublishedPort] == port.TargetPort {
+				continue
+			}
+
+			if port.Protocol == ProtocolUDP {
+				protocol = 17
+			}
+
+			// check if already has udp matching to add wild card publishing
+			for j := i + 1; j < len(ingressPorts); j++ {
+				if ingressPorts[j].TargetPort == port.TargetPort &&
+					ingressPorts[j].PublishedPort == port.PublishedPort {
+					protocol = 0
+				}
+			}
+
+			publishedPorts[port.PublishedPort] = port.TargetPort
+
+			lbPolicylistMap[lb].elb, err = hcsshim.AddLoadBalancer(endpoints, false, sourceVIP, "", protocol, uint16(port.TargetPort), uint16(port.PublishedPort))
+			if err != nil {
+				logrus.Errorf("Failed to add ELB policy for service %s (ip:%s target port:%v published port:%v) with endpoints %v using load balancer IP %s on network %s: %v",
+					lb.service.name, vip.String(), uint16(port.TargetPort), uint16(port.PublishedPort), endpoints, sourceVIP, n.Name(), err)
+				return
+			}
+		}
+	}
 }
 }
 
 
-func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) {
+func (n *network) rmLBBackend(ip, vip net.IP, lb *loadBalancer, ingressPorts []*PortConfig, rmService bool) {
+	if system.GetOSVersion().Build > 16236 {
+		if len(lb.backEnds) > 0 {
+			//Reprogram HNS (actually VFP) with the existing backends.
+			n.addLBBackend(ip, vip, lb, ingressPorts)
+		} else {
+			lb.Lock()
+			defer lb.Unlock()
+			logrus.Debugf("No more backends for service %s (ip:%s).  Removing all policies", lb.service.name, lb.vip.String())
+
+			if policyLists, ok := lbPolicylistMap[lb]; ok {
+				if policyLists.ilb != nil {
+					policyLists.ilb.Delete()
+					policyLists.ilb = nil
+				}
+
+				if policyLists.elb != nil {
+					policyLists.elb.Delete()
+					policyLists.elb = nil
+				}
+				delete(lbPolicylistMap, lb)
+
+			} else {
+				logrus.Errorf("Failed to find policies for service %s (%s)", lb.service.name, lb.vip.String())
+			}
+		}
+	}
 }
 }
 
 
 func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
 func (sb *sandbox) populateLoadbalancers(ep *endpoint) {

+ 1 - 1
libnetwork/vendor.conf

@@ -1,7 +1,7 @@
 github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
 github.com/Azure/go-ansiterm 19f72df4d05d31cbe1c56bfc8045c96babff6c7e
 github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
 github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
 github.com/Microsoft/go-winio ce2922f643c8fd76b46cadc7f404a06282678b34
 github.com/Microsoft/go-winio ce2922f643c8fd76b46cadc7f404a06282678b34
-github.com/Microsoft/hcsshim v0.6.1
+github.com/Microsoft/hcsshim v0.6.3
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/boltdb/bolt c6ba97b89e0454fec9aa92e1d33a4e2c5fc1f631
 github.com/boltdb/bolt c6ba97b89e0454fec9aa92e1d33a4e2c5fc1f631

+ 146 - 11
libnetwork/vendor/github.com/Microsoft/hcsshim/hnsendpoint.go

@@ -26,6 +26,31 @@ type HNSEndpoint struct {
 	IsRemoteEndpoint   bool              `json:",omitempty"`
 	IsRemoteEndpoint   bool              `json:",omitempty"`
 }
 }
 
 
+//SystemType represents the type of the system on which actions are done
+type SystemType string
+
+// SystemType const
+const (
+	ContainerType      SystemType = "Container"
+	VirtualMachineType SystemType = "VirtualMachine"
+	HostType           SystemType = "Host"
+)
+
+// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
+// Supported resource types are Network and Request Types are Add/Remove
+type EndpointAttachDetachRequest struct {
+	ContainerID    string     `json:"ContainerId,omitempty"`
+	SystemType     SystemType `json:"SystemType"`
+	CompartmentID  uint16     `json:"CompartmentId,omitempty"`
+	VirtualNICName string     `json:"VirtualNicName,omitempty"`
+}
+
+// EndpointResquestResponse is object to get the endpoint request response
+type EndpointResquestResponse struct {
+	Success bool
+	Error   string
+}
+
 // HNSEndpointRequest makes a HNS call to modify/query a network endpoint
 // HNSEndpointRequest makes a HNS call to modify/query a network endpoint
 func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
 func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
 	endpoint := &HNSEndpoint{}
 	endpoint := &HNSEndpoint{}
@@ -94,12 +119,12 @@ func modifyNetworkEndpoint(containerID string, endpointID string, request Reques
 	return nil
 	return nil
 }
 }
 
 
-// GetHNSEndpointByID
+// GetHNSEndpointByID get the Endpoint by ID
 func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
 func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
 	return HNSEndpointRequest("GET", endpointID, "")
 	return HNSEndpointRequest("GET", endpointID, "")
 }
 }
 
 
-// GetHNSNetworkName filtered by Name
+// GetHNSEndpointByName gets the endpoint filtered by Name
 func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
 func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
 	hnsResponse, err := HNSListEndpointRequest()
 	hnsResponse, err := HNSListEndpointRequest()
 	if err != nil {
 	if err != nil {
@@ -135,7 +160,7 @@ func (endpoint *HNSEndpoint) Delete() (*HNSEndpoint, error) {
 	return HNSEndpointRequest("DELETE", endpoint.Id, "")
 	return HNSEndpointRequest("DELETE", endpoint.Id, "")
 }
 }
 
 
-// Delete Endpoint by sending EndpointRequest to HNS
+// Update Endpoint
 func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) {
 func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) {
 	operation := "Update"
 	operation := "Update"
 	title := "HCSShim::HNSEndpoint::" + operation
 	title := "HCSShim::HNSEndpoint::" + operation
@@ -144,30 +169,30 @@ func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	err = hnsCall("POST", "/endpoints/"+endpoint.Id+"/update", string(jsonString), &endpoint)
+	err = hnsCall("POST", "/endpoints/"+endpoint.Id, string(jsonString), &endpoint)
 
 
 	return endpoint, err
 	return endpoint, err
 }
 }
 
 
-// Hot Attach an endpoint to a container
-func (endpoint *HNSEndpoint) HotAttach(containerID string) error {
-	operation := "HotAttach"
+// ContainerHotAttach attaches an endpoint to a running container
+func (endpoint *HNSEndpoint) ContainerHotAttach(containerID string) error {
+	operation := "ContainerHotAttach"
 	title := "HCSShim::HNSEndpoint::" + operation
 	title := "HCSShim::HNSEndpoint::" + operation
 	logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
 	logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
 
 
 	return modifyNetworkEndpoint(containerID, endpoint.Id, Add)
 	return modifyNetworkEndpoint(containerID, endpoint.Id, Add)
 }
 }
 
 
-// Hot Detach an endpoint from a container
-func (endpoint *HNSEndpoint) HotDetach(containerID string) error {
-	operation := "HotDetach"
+// ContainerHotDetach detaches an endpoint from a running container
+func (endpoint *HNSEndpoint) ContainerHotDetach(containerID string) error {
+	operation := "ContainerHotDetach"
 	title := "HCSShim::HNSEndpoint::" + operation
 	title := "HCSShim::HNSEndpoint::" + operation
 	logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
 	logrus.Debugf(title+" id=%s, containerId=%s", endpoint.Id, containerID)
 
 
 	return modifyNetworkEndpoint(containerID, endpoint.Id, Remove)
 	return modifyNetworkEndpoint(containerID, endpoint.Id, Remove)
 }
 }
 
 
-// Apply Acl Policy on the Endpoint
+// ApplyACLPolicy applies Acl Policy on the Endpoint
 func (endpoint *HNSEndpoint) ApplyACLPolicy(policy *ACLPolicy) error {
 func (endpoint *HNSEndpoint) ApplyACLPolicy(policy *ACLPolicy) error {
 	operation := "ApplyACLPolicy"
 	operation := "ApplyACLPolicy"
 	title := "HCSShim::HNSEndpoint::" + operation
 	title := "HCSShim::HNSEndpoint::" + operation
@@ -181,3 +206,113 @@ func (endpoint *HNSEndpoint) ApplyACLPolicy(policy *ACLPolicy) error {
 	_, err = endpoint.Update()
 	_, err = endpoint.Update()
 	return err
 	return err
 }
 }
+
+// ContainerAttach attaches an endpoint to container
+func (endpoint *HNSEndpoint) ContainerAttach(containerID string, compartmentID uint16) error {
+	operation := "ContainerAttach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+
+	requestMessage := &EndpointAttachDetachRequest{
+		ContainerID:   containerID,
+		CompartmentID: compartmentID,
+		SystemType:    ContainerType,
+	}
+	response := &EndpointResquestResponse{}
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
+}
+
+// ContainerDetach detaches an endpoint from container
+func (endpoint *HNSEndpoint) ContainerDetach(containerID string) error {
+	operation := "ContainerDetach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+
+	requestMessage := &EndpointAttachDetachRequest{
+		ContainerID: containerID,
+		SystemType:  ContainerType,
+	}
+	response := &EndpointResquestResponse{}
+
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
+}
+
+// HostAttach attaches a nic on the host
+func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error {
+	operation := "HostAttach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+	requestMessage := &EndpointAttachDetachRequest{
+		CompartmentID: compartmentID,
+		SystemType:    HostType,
+	}
+	response := &EndpointResquestResponse{}
+
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
+
+}
+
+// HostDetach detaches a nic on the host
+func (endpoint *HNSEndpoint) HostDetach() error {
+	operation := "HostDetach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+	requestMessage := &EndpointAttachDetachRequest{
+		SystemType: HostType,
+	}
+	response := &EndpointResquestResponse{}
+
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
+}
+
+// VirtualMachineNICAttach attaches a endpoint to a virtual machine
+func (endpoint *HNSEndpoint) VirtualMachineNICAttach(virtualMachineNICName string) error {
+	operation := "VirtualMachineNicAttach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+	requestMessage := &EndpointAttachDetachRequest{
+		VirtualNICName: virtualMachineNICName,
+		SystemType:     VirtualMachineType,
+	}
+	response := &EndpointResquestResponse{}
+
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response)
+}
+
+// VirtualMachineNICDetach detaches a endpoint  from a virtual machine
+func (endpoint *HNSEndpoint) VirtualMachineNICDetach() error {
+	operation := "VirtualMachineNicDetach"
+	title := "HCSShim::HNSEndpoint::" + operation
+	logrus.Debugf(title+" id=%s", endpoint.Id)
+
+	requestMessage := &EndpointAttachDetachRequest{
+		SystemType: VirtualMachineType,
+	}
+	response := &EndpointResquestResponse{}
+
+	jsonString, err := json.Marshal(requestMessage)
+	if err != nil {
+		return err
+	}
+	return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response)
+}

+ 33 - 20
libnetwork/vendor/github.com/Microsoft/hcsshim/hnspolicylist.go

@@ -6,6 +6,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
 )
 )
 
 
+// RoutePolicy is a structure defining schema for Route based Policy
 type RoutePolicy struct {
 type RoutePolicy struct {
 	Policy
 	Policy
 	DestinationPrefix string `json:"DestinationPrefix,omitempty"`
 	DestinationPrefix string `json:"DestinationPrefix,omitempty"`
@@ -13,6 +14,7 @@ type RoutePolicy struct {
 	EncapEnabled      bool   `json:"NeedEncap,omitempty"`
 	EncapEnabled      bool   `json:"NeedEncap,omitempty"`
 }
 }
 
 
+// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
 type ELBPolicy struct {
 type ELBPolicy struct {
 	LBPolicy
 	LBPolicy
 	SourceVIP string   `json:"SourceVIP,omitempty"`
 	SourceVIP string   `json:"SourceVIP,omitempty"`
@@ -20,6 +22,7 @@ type ELBPolicy struct {
 	ILB       bool     `json:"ILB,omitempty"`
 	ILB       bool     `json:"ILB,omitempty"`
 }
 }
 
 
+// LBPolicy is a structure defining schema for LoadBalancing based Policy
 type LBPolicy struct {
 type LBPolicy struct {
 	Policy
 	Policy
 	Protocol     uint16 `json:"Protocol,omitempty"`
 	Protocol     uint16 `json:"Protocol,omitempty"`
@@ -27,10 +30,11 @@ type LBPolicy struct {
 	ExternalPort uint16
 	ExternalPort uint16
 }
 }
 
 
+// PolicyList is a structure defining schema for Policy list request
 type PolicyList struct {
 type PolicyList struct {
-	Id                 string   `json:"ID,omitempty"`
-	EndpointReferences []string `json:"References,omitempty"`
-	Policies           []string `json:"Policies,omitempty"`
+	ID                 string            `json:"ID,omitempty"`
+	EndpointReferences []string          `json:"References,omitempty"`
+	Policies           []json.RawMessage `json:"Policies,omitempty"`
 }
 }
 
 
 // HNSPolicyListRequest makes a call into HNS to update/query a single network
 // HNSPolicyListRequest makes a call into HNS to update/query a single network
@@ -44,6 +48,7 @@ func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
 	return &policy, nil
 	return &policy, nil
 }
 }
 
 
+// HNSListPolicyListRequest gets all the policy list
 func HNSListPolicyListRequest() ([]PolicyList, error) {
 func HNSListPolicyListRequest() ([]PolicyList, error) {
 	var plist []PolicyList
 	var plist []PolicyList
 	err := hnsCall("GET", "/policylists/", "", &plist)
 	err := hnsCall("GET", "/policylists/", "", &plist)
@@ -54,7 +59,7 @@ func HNSListPolicyListRequest() ([]PolicyList, error) {
 	return plist, nil
 	return plist, nil
 }
 }
 
 
-// PolicyListRequest makes a HNS call to modify/query a network endpoint
+// PolicyListRequest makes a HNS call to modify/query a network policy list
 func PolicyListRequest(method, path, request string) (*PolicyList, error) {
 func PolicyListRequest(method, path, request string) (*PolicyList, error) {
 	policylist := &PolicyList{}
 	policylist := &PolicyList{}
 	err := hnsCall(method, "/policylists/"+path, request, &policylist)
 	err := hnsCall(method, "/policylists/"+path, request, &policylist)
@@ -65,11 +70,16 @@ func PolicyListRequest(method, path, request string) (*PolicyList, error) {
 	return policylist, nil
 	return policylist, nil
 }
 }
 
 
+// GetPolicyListByID get the policy list by ID
+func GetPolicyListByID(policyListID string) (*PolicyList, error) {
+	return PolicyListRequest("GET", policyListID, "")
+}
+
 // Create PolicyList by sending PolicyListRequest to HNS.
 // Create PolicyList by sending PolicyListRequest to HNS.
 func (policylist *PolicyList) Create() (*PolicyList, error) {
 func (policylist *PolicyList) Create() (*PolicyList, error) {
 	operation := "Create"
 	operation := "Create"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
-	logrus.Debugf(title+" id=%s", policylist.Id)
+	logrus.Debugf(title+" id=%s", policylist.ID)
 	jsonString, err := json.Marshal(policylist)
 	jsonString, err := json.Marshal(policylist)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -77,20 +87,20 @@ func (policylist *PolicyList) Create() (*PolicyList, error) {
 	return PolicyListRequest("POST", "", string(jsonString))
 	return PolicyListRequest("POST", "", string(jsonString))
 }
 }
 
 
-// Create PolicyList by sending PolicyListRequest to HNS
+// Delete deletes PolicyList
 func (policylist *PolicyList) Delete() (*PolicyList, error) {
 func (policylist *PolicyList) Delete() (*PolicyList, error) {
 	operation := "Delete"
 	operation := "Delete"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
-	logrus.Debugf(title+" id=%s", policylist.Id)
+	logrus.Debugf(title+" id=%s", policylist.ID)
 
 
-	return PolicyListRequest("DELETE", policylist.Id, "")
+	return PolicyListRequest("DELETE", policylist.ID, "")
 }
 }
 
 
-// Add an endpoint to a Policy List
+// AddEndpoint add an endpoint to a Policy List
 func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
 func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
 	operation := "AddEndpoint"
 	operation := "AddEndpoint"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
-	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.Id, endpoint.Id)
+	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id)
 
 
 	_, err := policylist.Delete()
 	_, err := policylist.Delete()
 	if err != nil {
 	if err != nil {
@@ -103,11 +113,11 @@ func (policylist *PolicyList) AddEndpoint(endpoint *HNSEndpoint) (*PolicyList, e
 	return policylist.Create()
 	return policylist.Create()
 }
 }
 
 
-// Remove an endpoint from the Policy List
+// RemoveEndpoint removes an endpoint from the Policy List
 func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
 func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList, error) {
 	operation := "RemoveEndpoint"
 	operation := "RemoveEndpoint"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
-	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.Id, endpoint.Id)
+	logrus.Debugf(title+" id=%s, endpointId:%s", policylist.ID, endpoint.Id)
 
 
 	_, err := policylist.Delete()
 	_, err := policylist.Delete()
 	if err != nil {
 	if err != nil {
@@ -129,16 +139,20 @@ func (policylist *PolicyList) RemoveEndpoint(endpoint *HNSEndpoint) (*PolicyList
 }
 }
 
 
 // AddLoadBalancer policy list for the specified endpoints
 // AddLoadBalancer policy list for the specified endpoints
-func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
+func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
 	operation := "AddLoadBalancer"
 	operation := "AddLoadBalancer"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
-	logrus.Debugf(title+" Vip:%s", vip)
+	logrus.Debugf(title+" endpointId=%v, isILB=%v, sourceVIP=%s, vip=%s, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
 
 
 	policylist := &PolicyList{}
 	policylist := &PolicyList{}
 
 
 	elbPolicy := &ELBPolicy{
 	elbPolicy := &ELBPolicy{
-		VIPs: []string{vip},
-		ILB:  isILB,
+		SourceVIP: sourceVIP,
+		ILB:       isILB,
+	}
+
+	if len(vip) > 0 {
+		elbPolicy.VIPs = []string{vip}
 	}
 	}
 	elbPolicy.Type = ExternalLoadBalancer
 	elbPolicy.Type = ExternalLoadBalancer
 	elbPolicy.Protocol = protocol
 	elbPolicy.Protocol = protocol
@@ -153,12 +167,11 @@ func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, vip string, protocol u
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
-	policylist.Policies[0] = string(jsonString)
+	policylist.Policies = append(policylist.Policies, jsonString)
 	return policylist.Create()
 	return policylist.Create()
 }
 }
 
 
-// AddLoadBalancer policy list for the specified endpoints
+// AddRoute adds route policy list for the specified endpoints
 func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
 func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
 	operation := "AddRoute"
 	operation := "AddRoute"
 	title := "HCSShim::PolicyList::" + operation
 	title := "HCSShim::PolicyList::" + operation
@@ -182,6 +195,6 @@ func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string,
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	policylist.Policies[0] = string(jsonString)
+	policylist.Policies = append(policylist.Policies, jsonString)
 	return policylist.Create()
 	return policylist.Create()
 }
 }

+ 2 - 0
libnetwork/vendor/github.com/Microsoft/hcsshim/interface.go

@@ -48,6 +48,8 @@ type HvRuntime struct {
 	LinuxInitrdFile     string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
 	LinuxInitrdFile     string `json:",omitempty"` // File under ImagePath on host containing an initrd image for starting a Linux utility VM
 	LinuxKernelFile     string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
 	LinuxKernelFile     string `json:",omitempty"` // File under ImagePath on host containing a kernel for starting a Linux utility VM
 	LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
 	LinuxBootParameters string `json:",omitempty"` // Additional boot parameters for starting a Linux Utility VM in initrd mode
+	BootSource          string `json:",omitempty"` // "Vhd" for Linux Utility VM booting from VHD
+	WritableBootSource  bool   `json:",omitempty"` // Linux Utility VM booting from VHD
 }
 }
 
 
 type MappedVirtualDisk struct {
 type MappedVirtualDisk struct {

+ 10 - 0
libnetwork/vendor/github.com/Microsoft/hcsshim/legacy.go

@@ -307,6 +307,16 @@ func (r *legacyLayerReader) Read(b []byte) (int, error) {
 	return r.backupReader.Read(b)
 	return r.backupReader.Read(b)
 }
 }
 
 
+func (r *legacyLayerReader) Seek(offset int64, whence int) (int64, error) {
+	if r.backupReader == nil {
+		if r.currentFile == nil {
+			return 0, errors.New("no current file")
+		}
+		return r.currentFile.Seek(offset, whence)
+	}
+	return 0, errors.New("seek not supported on this stream")
+}
+
 func (r *legacyLayerReader) Close() error {
 func (r *legacyLayerReader) Close() error {
 	r.proceed <- false
 	r.proceed <- false
 	<-r.result
 	<-r.result