Vendor in Libnetwork changes

Brings in https://github.com/moby/libnetwork/pull/2604

Signed-off-by: Arko Dasgupta <arko.dasgupta@docker.com>
This commit is contained in:
Arko Dasgupta 2020-12-15 10:22:03 -08:00
parent f0014860c1
commit 78eafdd947
6 changed files with 112 additions and 66 deletions

View File

@ -3,7 +3,7 @@
# LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
# updating the binary version, consider updating github.com/docker/libnetwork
# in vendor.conf accordingly
: "${LIBNETWORK_COMMIT:=5c6a95bfb20c61571a00f913c6b91959ede84e8d}"
: "${LIBNETWORK_COMMIT:=fa125a3512ee0f6187721c88582bf8c4378bd4d7}"
install_proxy() {
case "$1" in

View File

@ -47,7 +47,7 @@ github.com/grpc-ecosystem/go-grpc-middleware 3c51f7f332123e8be5a157c0802a
# libnetwork
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
github.com/docker/libnetwork 5c6a95bfb20c61571a00f913c6b91959ede84e8d
github.com/docker/libnetwork fa125a3512ee0f6187721c88582bf8c4378bd4d7
github.com/docker/go-events e31b211e4f1cd09aa76fe4ac244571fab96ae47f
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec

View File

@ -11,72 +11,114 @@ import (
"github.com/sirupsen/logrus"
)
var (
defaultBindingIP = net.IPv4(0, 0, 0, 0)
defaultBindingIPV6 = net.ParseIP("::")
)
func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
return nil, nil
}
defHostIP := defaultBindingIP
defHostIP := net.IPv4zero // 0.0.0.0
if reqDefBindIP != nil {
defHostIP = reqDefBindIP
}
// IPv4 port binding including user land proxy
pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
if err != nil {
return nil, err
var containerIPv6 net.IP
if ep.addrv6 != nil {
containerIPv6 = ep.addrv6.IP
}
// IPv6 port binding excluding user land proxy
if n.driver.config.EnableIP6Tables && ep.addrv6 != nil {
// TODO IPv6 custom default binding IP
pbv6, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addrv6.IP, defaultBindingIPV6, false)
if err != nil {
// ensure we clear the previous allocated IPv4 ports
n.releasePortsInternal(pb)
return nil, err
}
pb = append(pb, pbv6...)
pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
if err != nil {
return nil, err
}
return pb, nil
}
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
bs := make([]types.PortBinding, 0, len(bindings))
for _, c := range bindings {
b := c.GetCopy()
if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
bIPv4 := c.GetCopy()
bIPv6 := c.GetCopy()
// Allocate IPv4 Port mappings
if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
}
return nil, err
}
return nil, err
bs = append(bs, bIPv4)
}
// Allocate IPv6 Port mappings
if ok := n.validatePortBindingIPv6(&bIPv6, containerIPv6, defHostIP); ok {
if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
}
return nil, err
}
bs = append(bs, bIPv6)
}
bs = append(bs, b)
}
return bs, nil
}
func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IPv4 binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
//Return early if there is a valid Host IP, but its not a IPv6 address
if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
return false
}
// Adjust the host address in the operational binding
if len(bnd.HostIP) == 0 {
// Return early if the default binding address is an IPv6 address
if defHostIP.To4() == nil {
return false
}
bnd.HostIP = defHostIP
}
bnd.IP = containerIPv4
return true
}
// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
// if this is a valid IP6v binding, else returns false
func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIPv6, defHostIP net.IP) bool {
// Return early if there is no IPv6 container endpoint
if containerIPv6 == nil {
return false
}
// Return early if there is a valid Host IP, which is a IPv4 address
if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
return false
}
// Setup a binding to "::" if Host IP is empty and the default binding IP is 0.0.0.0
if len(bnd.HostIP) == 0 {
if defHostIP.Equal(net.IPv4zero) {
bnd.HostIP = net.IPv6zero
// If the default binding IP is an IPv6 address, use it
} else if defHostIP.To4() == nil {
bnd.HostIP = defHostIP
// Return false if default binding ip is an IPv4 address
} else {
return false
}
}
bnd.IP = containerIPv6
return true
}
func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
var (
host net.Addr
err error
)
// Store the container interface address in the operational binding
bnd.IP = containerIP
// Adjust the host address in the operational binding
if len(bnd.HostIP) == 0 {
bnd.HostIP = defHostIP
}
// Adjust HostPortEnd if this is not a range.
if bnd.HostPortEnd == 0 {
bnd.HostPortEnd = bnd.HostPort
@ -90,7 +132,7 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
portmapper := n.portMapper
if containerIP.To4() == nil {
if bnd.IP.To4() == nil {
portmapper = n.portMapperV6
}

View File

@ -151,20 +151,16 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
}
containerIP, containerPort := getIPAndPort(m.container)
if pm.checkIP(hostIP) {
if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
return nil, err
}
if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
return nil, err
}
cleanup := func() error {
// need to undo the iptables rules before we return
m.userlandProxy.Stop()
if pm.checkIP(hostIP) {
pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
return err
}
pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
return err
}
return nil

View File

@ -44,11 +44,3 @@ func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net
}
return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
}
// checkIP checks if IP is valid and matching to chain version
func (pm *PortMapper) checkIP(ip net.IP) bool {
if pm.chain == nil || pm.chain.IPTable.Version == iptables.IPv4 {
return ip.To4() != nil
}
return ip.To16() != nil
}

View File

@ -19,6 +19,16 @@ type userlandProxy interface {
Stop() error
}
// ipVersion refers to IP version - v4 or v6
type ipVersion string
const (
// IPv4 is version 4
ipv4 ipVersion = "4"
// IPv4 is version 6
ipv6 ipVersion = "6"
)
// proxyCommand wraps an exec.Cmd to run the userland TCP and UDP
// proxies as separate processes.
type proxyCommand struct {
@ -77,21 +87,27 @@ func (p *proxyCommand) Stop() error {
// port allocations on bound port, because without userland proxy we using
// iptables rules and not net.Listen
type dummyProxy struct {
listener io.Closer
addr net.Addr
listener io.Closer
addr net.Addr
ipVersion ipVersion
}
func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) {
// detect version of hostIP to bind only to correct version
version := ipv4
if hostIP.To4() == nil {
version = ipv6
}
switch proto {
case "tcp":
addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
return &dummyProxy{addr: addr}, nil
return &dummyProxy{addr: addr, ipVersion: version}, nil
case "udp":
addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
return &dummyProxy{addr: addr}, nil
return &dummyProxy{addr: addr, ipVersion: version}, nil
case "sctp":
addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort}
return &dummyProxy{addr: addr}, nil
return &dummyProxy{addr: addr, ipVersion: version}, nil
default:
return nil, fmt.Errorf("Unknown addr type: %s", proto)
}
@ -100,19 +116,19 @@ func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, er
func (p *dummyProxy) Start() error {
switch addr := p.addr.(type) {
case *net.TCPAddr:
l, err := net.ListenTCP("tcp", addr)
l, err := net.ListenTCP("tcp"+string(p.ipVersion), addr)
if err != nil {
return err
}
p.listener = l
case *net.UDPAddr:
l, err := net.ListenUDP("udp", addr)
l, err := net.ListenUDP("udp"+string(p.ipVersion), addr)
if err != nil {
return err
}
p.listener = l
case *sctp.SCTPAddr:
l, err := sctp.ListenSCTP("sctp", addr)
l, err := sctp.ListenSCTP("sctp"+string(p.ipVersion), addr)
if err != nil {
return err
}