2015-06-10 17:24:19 -04:00
|
|
|
package overlay
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
|
2015-09-18 15:54:08 -04:00
|
|
|
"github.com/Sirupsen/logrus"
|
2015-09-16 07:39:46 -04:00
|
|
|
"github.com/docker/libkv/store"
|
2015-06-10 17:24:19 -04:00
|
|
|
"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
|
2015-07-02 22:43:02 -04:00
|
|
|
vxlanPort = 4789
|
2015-09-02 11:31:45 -04:00
|
|
|
vxlanVethMTU = 1450
|
2015-06-10 17:24:19 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type driver struct {
|
|
|
|
eventCh chan serf.Event
|
|
|
|
notifyCh chan ovNotify
|
|
|
|
exitCh chan chan struct{}
|
2015-09-18 15:54:08 -04:00
|
|
|
bindAddress string
|
2015-06-10 17:24:19 -04:00
|
|
|
neighIP string
|
2015-09-24 22:01:15 -04:00
|
|
|
config map[string]interface{}
|
2015-06-10 17:24:19 -04:00
|
|
|
peerDb peerNetworkMap
|
|
|
|
serfInstance *serf.Serf
|
|
|
|
networks networkTable
|
|
|
|
store datastore.DataStore
|
|
|
|
ipAllocator *idm.Idm
|
|
|
|
vxlanIdm *idm.Idm
|
2015-09-18 15:54:08 -04:00
|
|
|
once sync.Once
|
|
|
|
joinOnce sync.Once
|
2015-06-10 17:24:19 -04:00
|
|
|
sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init registers a new instance of overlay driver
|
2015-09-18 17:00:36 -04:00
|
|
|
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
2015-06-10 17:24:19 -04:00
|
|
|
c := driverapi.Capability{
|
2015-09-16 07:39:46 -04:00
|
|
|
DataScope: datastore.GlobalScope,
|
2015-06-10 17:24:19 -04:00
|
|
|
}
|
|
|
|
|
2015-09-18 17:00:36 -04:00
|
|
|
d := &driver{
|
2015-06-10 17:24:19 -04:00
|
|
|
networks: networkTable{},
|
|
|
|
peerDb: peerNetworkMap{
|
2015-07-02 01:00:48 -04:00
|
|
|
mp: map[string]peerMap{},
|
2015-06-10 17:24:19 -04:00
|
|
|
},
|
2015-09-24 22:01:15 -04:00
|
|
|
config: config,
|
2015-09-18 17:00:36 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return dc.RegisterDriver(networkType, d, c)
|
2015-06-10 17:24:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-24 22:01:15 -04:00
|
|
|
func (d *driver) configure() error {
|
2015-06-10 17:24:19 -04:00
|
|
|
var err error
|
|
|
|
|
2015-09-24 22:01:15 -04:00
|
|
|
if len(d.config) == 0 {
|
2015-09-18 17:00:36 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-09-18 15:54:08 -04:00
|
|
|
d.once.Do(func() {
|
2015-09-24 22:01:15 -04:00
|
|
|
provider, provOk := d.config[netlabel.KVProvider]
|
|
|
|
provURL, urlOk := d.config[netlabel.KVProviderURL]
|
2015-06-10 17:24:19 -04:00
|
|
|
|
|
|
|
if provOk && urlOk {
|
2015-10-05 07:21:15 -04:00
|
|
|
cfg := &datastore.ScopeCfg{
|
|
|
|
Client: datastore.ScopeClientCfg{
|
2015-06-10 17:24:19 -04:00
|
|
|
Provider: provider.(string),
|
|
|
|
Address: provURL.(string),
|
|
|
|
},
|
|
|
|
}
|
2015-09-24 22:01:15 -04:00
|
|
|
provConfig, confOk := d.config[netlabel.KVProviderConfig]
|
2015-09-16 07:39:46 -04:00
|
|
|
if confOk {
|
|
|
|
cfg.Client.Config = provConfig.(*store.Config)
|
|
|
|
}
|
2015-10-05 07:21:15 -04:00
|
|
|
d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
|
2015-06-10 17:24:19 -04:00
|
|
|
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
|
|
|
|
}
|
2015-09-18 15:54:08 -04:00
|
|
|
|
|
|
|
func (d *driver) nodeJoin(node string, self bool) {
|
2015-10-02 00:50:54 -04:00
|
|
|
if self && !d.isSerfAlive() {
|
2015-09-18 15:54:08 -04:00
|
|
|
d.Lock()
|
|
|
|
d.bindAddress = node
|
|
|
|
d.Unlock()
|
|
|
|
err := d.serfInit()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("initializing serf instance failed: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 00:50:54 -04:00
|
|
|
d.Lock()
|
|
|
|
if !self {
|
|
|
|
d.neighIP = node
|
|
|
|
}
|
|
|
|
neighIP := d.neighIP
|
|
|
|
d.Unlock()
|
|
|
|
|
|
|
|
if d.serfInstance != nil && neighIP != "" {
|
2015-09-18 15:54:08 -04:00
|
|
|
var err error
|
|
|
|
d.joinOnce.Do(func() {
|
2015-10-02 00:50:54 -04:00
|
|
|
err = d.serfJoin(neighIP)
|
2015-10-02 15:20:29 -04:00
|
|
|
if err == nil {
|
|
|
|
d.pushLocalDb()
|
|
|
|
}
|
2015-09-18 15:54:08 -04:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("joining serf neighbor %s failed: %v", node, err)
|
|
|
|
d.Lock()
|
|
|
|
d.joinOnce = sync.Once{}
|
|
|
|
d.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-02 15:20:29 -04:00
|
|
|
func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
|
|
|
|
if !d.isSerfAlive() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
d.notifyCh <- ovNotify{
|
|
|
|
action: "join",
|
|
|
|
nid: nid,
|
|
|
|
eid: eid,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-18 15:54:08 -04:00
|
|
|
// 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)
|
2015-10-02 00:50:54 -04:00
|
|
|
if !ok || nodeData.Address == "" {
|
2015-09-18 15:54:08 -04:00
|
|
|
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
|
|
|
|
}
|