2015-06-10 17:24:19 -04:00
package overlay
import (
"fmt"
2015-10-26 06:13:34 -04:00
"net"
2015-06-10 17:24:19 -04:00
"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"
2016-01-28 14:54:03 -05:00
"github.com/docker/libnetwork/discoverapi"
2015-06-10 17:24:19 -04:00
"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
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-12-07 17:20:13 -05: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-10-06 20:28:47 -04:00
provider , provOk := d . config [ netlabel . GlobalKVProvider ]
provURL , urlOk := d . config [ netlabel . GlobalKVProviderURL ]
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-10-06 20:28:47 -04:00
provConfig , confOk := d . config [ netlabel . GlobalKVProviderConfig ]
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
}
} )
return err
}
func ( d * driver ) Type ( ) string {
return networkType
}
2015-09-18 15:54:08 -04:00
2015-10-26 06:13:34 -04:00
func validateSelf ( node string ) error {
advIP := net . ParseIP ( node )
if advIP == nil {
return fmt . Errorf ( "invalid self address (%s)" , node )
}
addrs , err := net . InterfaceAddrs ( )
if err != nil {
return fmt . Errorf ( "Unable to get interface addresses %v" , err )
}
for _ , addr := range addrs {
ip , _ , err := net . ParseCIDR ( addr . String ( ) )
if err == nil && ip . Equal ( advIP ) {
return nil
}
}
return fmt . Errorf ( "Multi-Host overlay networking requires cluster-advertise(%s) to be configured with a local ip-address that is reachable within the cluster" , advIP . String ( ) )
}
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-10-26 06:13:34 -04:00
if err := validateSelf ( node ) ; err != nil {
logrus . Errorf ( "%s" , err . Error ( ) )
}
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
2016-01-28 14:54:03 -05:00
func ( d * driver ) DiscoverNew ( dType discoverapi . DiscoveryType , data interface { } ) error {
if dType == discoverapi . NodeDiscovery {
nodeData , ok := data . ( discoverapi . 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
2016-01-28 14:54:03 -05:00
func ( d * driver ) DiscoverDelete ( dType discoverapi . DiscoveryType , data interface { } ) error {
2015-09-18 15:54:08 -04:00
return nil
}