dotcloud/docker

View on GitHub
libnetwork/drivers/overlay/overlay.go

Summary

Maintainability
A
1 hr
Test Coverage
//go:build linux

package overlay

//go:generate protoc -I=. -I=../../../vendor/ --gogofaster_out=import_path=github.com/docker/docker/libnetwork/drivers/overlay:. overlay.proto

import (
    "context"
    "fmt"
    "net"
    "sync"

    "github.com/containerd/log"
    "github.com/docker/docker/libnetwork/discoverapi"
    "github.com/docker/docker/libnetwork/driverapi"
    "github.com/docker/docker/libnetwork/scope"
)

const (
    NetworkType  = "overlay"
    vethPrefix   = "veth"
    vethLen      = len(vethPrefix) + 7
    vxlanEncap   = 50
    secureOption = "encrypted"
)

// overlay driver must implement the discover-API.
var _ discoverapi.Discover = (*driver)(nil)

type driver struct {
    bindAddress, advertiseAddress net.IP

    config        map[string]interface{}
    peerDb        peerNetworkMap
    secMap        *encrMap
    networks      networkTable
    initOS        sync.Once
    localJoinOnce sync.Once
    keys          []*key
    peerOpMu      sync.Mutex
    sync.Mutex
}

// Register registers a new instance of the overlay driver.
func Register(r driverapi.Registerer, config map[string]interface{}) error {
    d := &driver{
        networks: networkTable{},
        peerDb: peerNetworkMap{
            mp: map[string]*peerMap{},
        },
        secMap: &encrMap{nodes: map[string][]*spi{}},
        config: config,
    }
    return r.RegisterDriver(NetworkType, d, driverapi.Capability{
        DataScope:         scope.Global,
        ConnectivityScope: scope.Global,
    })
}

func (d *driver) configure() error {
    // Apply OS specific kernel configs if needed
    d.initOS.Do(applyOStweaks)

    return nil
}

func (d *driver) Type() string {
    return NetworkType
}

func (d *driver) IsBuiltIn() bool {
    return true
}

// isIPv6Transport reports whether the outer Layer-3 transport for VXLAN datagrams is IPv6.
func (d *driver) isIPv6Transport() (bool, error) {
    // Infer whether remote peers' virtual tunnel endpoints will be IPv4 or IPv6
    // from the address family of our own advertise address. This is a
    // reasonable inference to make as Linux VXLAN links do not support
    // mixed-address-family remote peers.
    if d.advertiseAddress == nil {
        return false, fmt.Errorf("overlay: cannot determine address family of transport: the local data-plane address is not currently known")
    }
    return d.advertiseAddress.To4() == nil, nil
}

func (d *driver) nodeJoin(data discoverapi.NodeDiscoveryData) error {
    if data.Self {
        advAddr, bindAddr := net.ParseIP(data.Address), net.ParseIP(data.BindAddress)
        if advAddr == nil {
            return fmt.Errorf("invalid discovery data")
        }
        d.Lock()
        d.advertiseAddress = advAddr
        d.bindAddress = bindAddr
        d.Unlock()

        // If containers are already running on this network update the
        // advertise address in the peerDB
        d.localJoinOnce.Do(func() {
            d.peerDBUpdateSelf()
        })
    }
    return nil
}

// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
    switch dType {
    case discoverapi.NodeDiscovery:
        nodeData, ok := data.(discoverapi.NodeDiscoveryData)
        if !ok {
            return fmt.Errorf("invalid discovery data type: %T", data)
        }
        return d.nodeJoin(nodeData)
    case discoverapi.EncryptionKeysConfig:
        encrData, ok := data.(discoverapi.DriverEncryptionConfig)
        if !ok {
            return fmt.Errorf("invalid encryption key notification data")
        }
        keys := make([]*key, 0, len(encrData.Keys))
        for i := 0; i < len(encrData.Keys); i++ {
            k := &key{
                value: encrData.Keys[i],
                tag:   uint32(encrData.Tags[i]),
            }
            keys = append(keys, k)
        }
        if err := d.setKeys(keys); err != nil {
            log.G(context.TODO()).Warn(err)
        }
    case discoverapi.EncryptionKeysUpdate:
        var newKey, delKey, priKey *key
        encrData, ok := data.(discoverapi.DriverEncryptionUpdate)
        if !ok {
            return fmt.Errorf("invalid encryption key notification data")
        }
        if encrData.Key != nil {
            newKey = &key{
                value: encrData.Key,
                tag:   uint32(encrData.Tag),
            }
        }
        if encrData.Primary != nil {
            priKey = &key{
                value: encrData.Primary,
                tag:   uint32(encrData.PrimaryTag),
            }
        }
        if encrData.Prune != nil {
            delKey = &key{
                value: encrData.Prune,
                tag:   uint32(encrData.PruneTag),
            }
        }
        if err := d.updateKeys(newKey, priKey, delKey); err != nil {
            return err
        }
    default:
    }
    return nil
}

// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
    return nil
}