mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
![Jana Radhakrishnan](/assets/img/avatar_default.png)
libnetwork agent mode is a mode where libnetwork can act as a local agent for network and discovery plumbing alone while the state management is done elsewhere. This completes the support for making libnetwork and its associated drivers to be completely independent of a k/v store(if needed) and work purely based on the state information passed along by some some external controller or manager. This does not mean that libnetwork support for decentralized state management via a k/v store is removed. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
238 lines
5.3 KiB
Go
238 lines
5.3 KiB
Go
package overlay
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/libnetwork/datastore"
|
|
"github.com/docker/libnetwork/discoverapi"
|
|
"github.com/docker/libnetwork/driverapi"
|
|
"github.com/docker/libnetwork/idm"
|
|
"github.com/docker/libnetwork/netlabel"
|
|
"github.com/docker/libnetwork/types"
|
|
"github.com/hashicorp/serf/serf"
|
|
)
|
|
|
|
const (
|
|
networkType = "overlay"
|
|
vethPrefix = "veth"
|
|
vethLen = 7
|
|
vxlanIDStart = 256
|
|
vxlanIDEnd = 1000
|
|
vxlanPort = 4789
|
|
vxlanVethMTU = 1450
|
|
)
|
|
|
|
var initVxlanIdm = make(chan (bool), 1)
|
|
|
|
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
|
|
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,
|
|
}
|
|
|
|
if data, ok := config[netlabel.GlobalKVClient]; ok {
|
|
var err error
|
|
dsc, ok := data.(discoverapi.DatastoreConfigData)
|
|
if !ok {
|
|
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
|
|
}
|
|
d.store, err = datastore.NewDataStoreFromConfig(dsc)
|
|
if err != nil {
|
|
return types.InternalErrorf("failed to initialize data store: %v", err)
|
|
}
|
|
}
|
|
|
|
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 {
|
|
if d.store == nil {
|
|
return nil
|
|
}
|
|
|
|
if d.vxlanIdm == nil {
|
|
return d.initializeVxlanIdm()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) initializeVxlanIdm() error {
|
|
var err error
|
|
|
|
initVxlanIdm <- true
|
|
defer func() { <-initVxlanIdm }()
|
|
|
|
if d.vxlanIdm != nil {
|
|
return nil
|
|
}
|
|
|
|
d.vxlanIdm, err = idm.New(d.store, "vxlan-id", vxlanIDStart, vxlanIDEnd)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to initialize vxlan id manager: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) Type() string {
|
|
return networkType
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
func (d *driver) nodeJoin(node string, self bool) {
|
|
if self && !d.isSerfAlive() {
|
|
if err := validateSelf(node); err != nil {
|
|
logrus.Errorf("%s", err.Error())
|
|
}
|
|
d.Lock()
|
|
d.bindAddress = node
|
|
d.Unlock()
|
|
|
|
// If there is no cluster store there is no need to start serf.
|
|
if d.store != nil {
|
|
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) {
|
|
n := d.network(nid)
|
|
if n == nil {
|
|
logrus.Debugf("Error pushing local endpoint event for network %s", nid)
|
|
return
|
|
}
|
|
ep := n.endpoint(eid)
|
|
if ep == nil {
|
|
logrus.Debugf("Error pushing local endpoint event for ep %s / %s", nid, eid)
|
|
return
|
|
}
|
|
|
|
if !d.isSerfAlive() {
|
|
return
|
|
}
|
|
d.notifyCh <- ovNotify{
|
|
action: "join",
|
|
nw: n,
|
|
ep: ep,
|
|
}
|
|
}
|
|
|
|
// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
|
|
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
switch dType {
|
|
case discoverapi.NodeDiscovery:
|
|
nodeData, ok := data.(discoverapi.NodeDiscoveryData)
|
|
if !ok || nodeData.Address == "" {
|
|
return fmt.Errorf("invalid discovery data")
|
|
}
|
|
d.nodeJoin(nodeData.Address, nodeData.Self)
|
|
case discoverapi.DatastoreConfig:
|
|
var err error
|
|
if d.store != nil {
|
|
return types.ForbiddenErrorf("cannot accept datastore configuration: Overlay driver has a datastore configured already")
|
|
}
|
|
dsc, ok := data.(discoverapi.DatastoreConfigData)
|
|
if !ok {
|
|
return types.InternalErrorf("incorrect data in datastore configuration: %v", data)
|
|
}
|
|
d.store, err = datastore.NewDataStoreFromConfig(dsc)
|
|
if err != nil {
|
|
return types.InternalErrorf("failed to initialize data store: %v", err)
|
|
}
|
|
default:
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
|
|
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
|
return nil
|
|
}
|