moby--moby/libnetwork/drivers/overlay/overlay.go

187 lines
3.9 KiB
Go

package overlay
import (
"fmt"
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/libkv/store"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/idm"
"github.com/docker/libnetwork/netlabel"
"github.com/hashicorp/serf/serf"
)
const (
networkType = "overlay"
vethPrefix = "veth"
vethLen = 7
vxlanIDStart = 256
vxlanIDEnd = 1000
vxlanPort = 4789
vxlanVethMTU = 1450
)
type driver struct {
eventCh chan serf.Event
notifyCh chan ovNotify
exitCh chan chan struct{}
bindAddress string
neighIP string
config map[string]interface{}
peerDb peerNetworkMap
serfInstance *serf.Serf
networks networkTable
store datastore.DataStore
ipAllocator *idm.Idm
vxlanIdm *idm.Idm
once sync.Once
joinOnce sync.Once
sync.Mutex
}
// Init registers a new instance of overlay driver
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
c := driverapi.Capability{
DataScope: datastore.GlobalScope,
}
d := &driver{
networks: networkTable{},
peerDb: peerNetworkMap{
mp: map[string]peerMap{},
},
config: config,
}
return dc.RegisterDriver(networkType, d, c)
}
// Fini cleans up the driver resources
func Fini(drv driverapi.Driver) {
d := drv.(*driver)
if d.exitCh != nil {
waitCh := make(chan struct{})
d.exitCh <- waitCh
<-waitCh
}
}
func (d *driver) configure() error {
var err error
if len(d.config) == 0 {
return nil
}
d.once.Do(func() {
provider, provOk := d.config[netlabel.GlobalKVProvider]
provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
if provOk && urlOk {
cfg := &datastore.ScopeCfg{
Client: datastore.ScopeClientCfg{
Provider: provider.(string),
Address: provURL.(string),
},
}
provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
if confOk {
cfg.Client.Config = provConfig.(*store.Config)
}
d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
if err != nil {
err = fmt.Errorf("failed to initialize data store: %v", err)
return
}
}
d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
if err != nil {
err = fmt.Errorf("failed to initialize vxlan id manager: %v", err)
return
}
d.ipAllocator, err = idm.New(d.store, "ipam-id", 1, 0xFFFF-2)
if err != nil {
err = fmt.Errorf("failed to initalize ipam id manager: %v", err)
return
}
})
return err
}
func (d *driver) Type() string {
return networkType
}
func (d *driver) nodeJoin(node string, self bool) {
if self && !d.isSerfAlive() {
d.Lock()
d.bindAddress = node
d.Unlock()
err := d.serfInit()
if err != nil {
logrus.Errorf("initializing serf instance failed: %v", err)
return
}
}
d.Lock()
if !self {
d.neighIP = node
}
neighIP := d.neighIP
d.Unlock()
if d.serfInstance != nil && neighIP != "" {
var err error
d.joinOnce.Do(func() {
err = d.serfJoin(neighIP)
if err == nil {
d.pushLocalDb()
}
})
if err != nil {
logrus.Errorf("joining serf neighbor %s failed: %v", node, err)
d.Lock()
d.joinOnce = sync.Once{}
d.Unlock()
return
}
}
}
func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
if !d.isSerfAlive() {
return
}
d.notifyCh <- ovNotify{
action: "join",
nid: nid,
eid: eid,
}
}
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
if dType == driverapi.NodeDiscovery {
nodeData, ok := data.(driverapi.NodeDiscoveryData)
if !ok || nodeData.Address == "" {
return fmt.Errorf("invalid discovery data")
}
d.nodeJoin(nodeData.Address, nodeData.Self)
}
return nil
}
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
return nil
}