dotcloud/docker

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

Summary

Maintainability
A
3 hrs
Test Coverage
package ovmanager

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

    "github.com/containerd/log"
    "github.com/docker/docker/libnetwork/bitmap"
    "github.com/docker/docker/libnetwork/driverapi"
    "github.com/docker/docker/libnetwork/drivers/overlay/overlayutils"
    "github.com/docker/docker/libnetwork/netlabel"
    "github.com/docker/docker/libnetwork/scope"
    "github.com/docker/docker/libnetwork/types"
)

const (
    networkType = "overlay"
    // The lowest VNI value to auto-assign. Windows does not support VXLAN IDs
    // which overlap the range of 802.1Q VLAN IDs [0, 4095].
    vxlanIDStart = 4096
    // The largest VNI value permitted by RFC 7348.
    vxlanIDEnd = (1 << 24) - 1
)

type networkTable map[string]*network

type driver struct {
    mu       sync.Mutex
    networks networkTable
    vxlanIdm *bitmap.Bitmap
}

type subnet struct {
    subnetIP *net.IPNet
    gwIP     *net.IPNet
    vni      uint32
}

type network struct {
    id      string
    driver  *driver
    subnets []*subnet
}

// Register registers a new instance of the overlay driver.
func Register(r driverapi.Registerer) error {
    return r.RegisterDriver(networkType, newDriver(), driverapi.Capability{
        DataScope:         scope.Global,
        ConnectivityScope: scope.Global,
    })
}

func newDriver() *driver {
    return &driver{
        networks: networkTable{},
        vxlanIdm: bitmap.New(vxlanIDEnd + 1), // The full range of valid vxlan IDs: [0, 2^24).
    }
}

func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
    if id == "" {
        return nil, fmt.Errorf("invalid network id for overlay network")
    }

    if ipV4Data == nil {
        return nil, fmt.Errorf("empty ipv4 data passed during overlay network creation")
    }

    n := &network{
        id:      id,
        driver:  d,
        subnets: []*subnet{},
    }

    opts := make(map[string]string)
    vxlanIDList := make([]uint32, 0, len(ipV4Data))
    for key, val := range option {
        if key == netlabel.OverlayVxlanIDList {
            log.G(context.TODO()).Debugf("overlay network option: %s", val)
            var err error
            vxlanIDList, err = overlayutils.AppendVNIList(vxlanIDList, val)
            if err != nil {
                return nil, err
            }
        } else {
            opts[key] = val
        }
    }

    d.mu.Lock()
    defer d.mu.Unlock()
    for i, ipd := range ipV4Data {
        s := &subnet{
            subnetIP: ipd.Pool,
            gwIP:     ipd.Gateway,
        }

        if len(vxlanIDList) > i { // The VNI for this subnet was specified in the network options.
            s.vni = vxlanIDList[i]
            err := d.vxlanIdm.Set(uint64(s.vni)) // Mark VNI as in-use.
            if err != nil {
                // The VNI is already in use by another subnet/network.
                n.releaseVxlanID()
                return nil, fmt.Errorf("could not assign vxlan id %v to pool %s: %v", s.vni, s.subnetIP, err)
            }
        } else {
            // Allocate an available VNI for the subnet, outside the range of 802.1Q VLAN IDs.
            vni, err := d.vxlanIdm.SetAnyInRange(vxlanIDStart, vxlanIDEnd, true)
            if err != nil {
                n.releaseVxlanID()
                return nil, fmt.Errorf("could not obtain vxlan id for pool %s: %v", s.subnetIP, err)
            }
            s.vni = uint32(vni)
        }

        n.subnets = append(n.subnets, s)
    }

    val := strconv.FormatUint(uint64(n.subnets[0].vni), 10)
    for _, s := range n.subnets[1:] {
        val = val + "," + strconv.FormatUint(uint64(s.vni), 10)
    }
    opts[netlabel.OverlayVxlanIDList] = val

    if _, ok := d.networks[id]; ok {
        n.releaseVxlanID()
        return nil, fmt.Errorf("network %s already exists", id)
    }
    d.networks[id] = n

    return opts, nil
}

func (d *driver) NetworkFree(id string) error {
    if id == "" {
        return fmt.Errorf("invalid network id passed while freeing overlay network")
    }

    d.mu.Lock()
    defer d.mu.Unlock()
    n, ok := d.networks[id]

    if !ok {
        return fmt.Errorf("overlay network with id %s not found", id)
    }

    // Release all vxlan IDs in one shot.
    n.releaseVxlanID()

    delete(d.networks, id)

    return nil
}

func (n *network) releaseVxlanID() {
    for _, s := range n.subnets {
        n.driver.vxlanIdm.Unset(uint64(s.vni))
        s.vni = 0
    }
}

func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
    return types.NotImplementedErrorf("not implemented")
}

func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}

func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
    return "", nil
}

func (d *driver) DeleteNetwork(nid string) error {
    return types.NotImplementedErrorf("not implemented")
}

func (d *driver) CreateEndpoint(_ context.Context, nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
    return types.NotImplementedErrorf("not implemented")
}

func (d *driver) DeleteEndpoint(nid, eid string) error {
    return types.NotImplementedErrorf("not implemented")
}

func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
    return nil, types.NotImplementedErrorf("not implemented")
}

// Join method is invoked when a Sandbox is attached to an endpoint.
func (d *driver) Join(_ context.Context, nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
    return types.NotImplementedErrorf("not implemented")
}

// Leave method is invoked when a Sandbox detaches from an endpoint.
func (d *driver) Leave(nid, eid string) error {
    return types.NotImplementedErrorf("not implemented")
}

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

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

func (d *driver) ProgramExternalConnectivity(_ context.Context, nid, eid string, options map[string]interface{}) error {
    return types.NotImplementedErrorf("not implemented")
}

func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
    return types.NotImplementedErrorf("not implemented")
}