Skip to content

Commit

Permalink
Merge pull request #20478 from msabansal/HNSIntegration
Browse files Browse the repository at this point in the history
Windows libnetwork integration
  • Loading branch information
Arnaud Porterie committed Mar 10, 2016
2 parents 9ff7439 + e8026d8 commit 2b8e7ad
Show file tree
Hide file tree
Showing 15 changed files with 1,336 additions and 1,107 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ bundles:

cross: build
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross


win: build
$(DOCKER_RUN_DOCKER) hack/make.sh win


deb: build
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb
Expand Down
301 changes: 301 additions & 0 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import (
"encoding/json"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
Expand All @@ -23,14 +26,25 @@ import (
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/runconfig"
runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/docker/docker/volume"
containertypes "github.com/docker/engine-api/types/container"
networktypes "github.com/docker/engine-api/types/network"
"github.com/docker/go-connections/nat"
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/types"
"github.com/opencontainers/runc/libcontainer/label"
)

const configFileName = "config.v2.json"

var (
errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info")
)

// CommonContainer holds the fields for a container which are
// applicable across all platforms supported by the daemon.
type CommonContainer struct {
Expand Down Expand Up @@ -581,6 +595,293 @@ func (container *Container) InitDNSHostConfig() {
}
}

// GetEndpointInNetwork returns the container's endpoint to the provided network.
func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
endpointName := strings.TrimPrefix(container.Name, "/")
return n.EndpointByName(endpointName)
}

func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
if ep == nil {
return errInvalidEndpoint
}

networkSettings := container.NetworkSettings
if networkSettings == nil {
return errInvalidNetwork
}

if len(networkSettings.Ports) == 0 {
pm, err := getEndpointPortMapInfo(ep)
if err != nil {
return err
}
networkSettings.Ports = pm
}
return nil
}

func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
pm := nat.PortMap{}
driverInfo, err := ep.DriverInfo()
if err != nil {
return pm, err
}

if driverInfo == nil {
// It is not an error for epInfo to be nil
return pm, nil
}

if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
if exposedPorts, ok := expData.([]types.TransportPort); ok {
for _, tp := range exposedPorts {
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
if err != nil {
return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
}
pm[natPort] = nil
}
}
}

mapData, ok := driverInfo[netlabel.PortMap]
if !ok {
return pm, nil
}

if portMapping, ok := mapData.([]types.PortBinding); ok {
for _, pp := range portMapping {
natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
if err != nil {
return pm, err
}
natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
pm[natPort] = append(pm[natPort], natBndg)
}
}

return pm, nil
}

func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
pm := nat.PortMap{}
if sb == nil {
return pm
}

for _, ep := range sb.Endpoints() {
pm, _ = getEndpointPortMapInfo(ep)
if len(pm) > 0 {
break
}
}
return pm
}

// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
if ep == nil {
return errInvalidEndpoint
}

networkSettings := container.NetworkSettings
if networkSettings == nil {
return errInvalidNetwork
}

epInfo := ep.Info()
if epInfo == nil {
// It is not an error to get an empty endpoint info
return nil
}

if _, ok := networkSettings.Networks[n.Name()]; !ok {
networkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
}
networkSettings.Networks[n.Name()].NetworkID = n.ID()
networkSettings.Networks[n.Name()].EndpointID = ep.ID()

iface := epInfo.Iface()
if iface == nil {
return nil
}

if iface.MacAddress() != nil {
networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
}

if iface.Address() != nil {
ones, _ := iface.Address().Mask.Size()
networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
networkSettings.Networks[n.Name()].IPPrefixLen = ones
}

if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
onesv6, _ := iface.AddressIPv6().Mask.Size()
networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
}

return nil
}

// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
if err := container.buildPortMapInfo(ep); err != nil {
return err
}

epInfo := ep.Info()
if epInfo == nil {
// It is not an error to get an empty endpoint info
return nil
}
if epInfo.Gateway() != nil {
container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
}
if epInfo.GatewayIPv6().To16() != nil {
container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
}

return nil
}

// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
container.NetworkSettings.SandboxID = sb.ID()
container.NetworkSettings.SandboxKey = sb.Key()
return nil
}

// BuildJoinOptions builds endpoint Join options from a given network.
func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
var joinOptions []libnetwork.EndpointOption
if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
for _, str := range epConfig.Links {
name, alias, err := runconfigopts.ParseLink(str)
if err != nil {
return nil, err
}
joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
}
}
return joinOptions, nil
}

// BuildCreateEndpointOptions builds endpoint options from a given network.
func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
var (
bindings = make(nat.PortMap)
pbList []types.PortBinding
exposeList []types.TransportPort
createOptions []libnetwork.EndpointOption
)

defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()

if n.Name() == defaultNetName || container.NetworkSettings.IsAnonymousEndpoint {
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
}

if epConfig != nil {
ipam := epConfig.IPAMConfig
if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") {
createOptions = append(createOptions,
libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil))
}

for _, alias := range epConfig.Aliases {
createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
}
}

if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
}

// configs that are applicable only for the endpoint in the network
// to which container was connected to on docker run.
// Ideally all these network-specific endpoint configurations must be moved under
// container.NetworkSettings.Networks[n.Name()]
if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
(n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) {
if container.Config.MacAddress != "" {
mac, err := net.ParseMAC(container.Config.MacAddress)
if err != nil {
return nil, err
}

genericOption := options.Generic{
netlabel.MacAddress: mac,
}

createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
}
}

// Port-mapping rules belong to the container & applicable only to non-internal networks
portmaps := getSandboxPortMapInfo(sb)
if n.Info().Internal() || len(portmaps) > 0 {
return createOptions, nil
}

if container.HostConfig.PortBindings != nil {
for p, b := range container.HostConfig.PortBindings {
bindings[p] = []nat.PortBinding{}
for _, bb := range b {
bindings[p] = append(bindings[p], nat.PortBinding{
HostIP: bb.HostIP,
HostPort: bb.HostPort,
})
}
}
}

portSpecs := container.Config.ExposedPorts
ports := make([]nat.Port, len(portSpecs))
var i int
for p := range portSpecs {
ports[i] = p
i++
}
nat.SortPortMap(ports, bindings)
for _, port := range ports {
expose := types.TransportPort{}
expose.Proto = types.ParseProtocol(port.Proto())
expose.Port = uint16(port.Int())
exposeList = append(exposeList, expose)

pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
binding := bindings[port]
for i := 0; i < len(binding); i++ {
pbCopy := pb.GetCopy()
newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
var portStart, portEnd int
if err == nil {
portStart, portEnd, err = newP.Range()
}
if err != nil {
return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
}
pbCopy.HostPort = uint16(portStart)
pbCopy.HostPortEnd = uint16(portEnd)
pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
pbList = append(pbList, pbCopy)
}

if container.HostConfig.PublishAllPorts && len(binding) == 0 {
pbList = append(pbList, pb)
}
}

createOptions = append(createOptions,
libnetwork.CreateOptionPortMapping(pbList),
libnetwork.CreateOptionExposedPorts(exposeList))

return createOptions, nil
}

// UpdateMonitor updates monitor configure for running container
func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
monitor := container.monitor
Expand Down

0 comments on commit 2b8e7ad

Please sign in to comment.