libnetwork/drivers/overlay/ovmanager/ovmanager.go
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")
}