mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
![Jana Radhakrishnan](/assets/img/avatar_default.png)
This commit brings in the first implementation of overlay driver which makes use of vxlan tunneling protocol to create logical networks across multiple hosts. This is very much alpha code and should be used for demo and testing purposes only. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
280 lines
5.1 KiB
Go
280 lines
5.1 KiB
Go
package overlay
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/docker/libnetwork/types"
|
|
)
|
|
|
|
type peerKey struct {
|
|
peerIP net.IP
|
|
peerMac net.HardwareAddr
|
|
}
|
|
|
|
type peerEntry struct {
|
|
eid types.UUID
|
|
vtep net.IP
|
|
inSandbox bool
|
|
isLocal bool
|
|
}
|
|
|
|
type peerMap struct {
|
|
mp map[string]peerEntry
|
|
sync.Mutex
|
|
}
|
|
|
|
type peerNetworkMap struct {
|
|
mp map[types.UUID]peerMap
|
|
sync.Mutex
|
|
}
|
|
|
|
func (pKey peerKey) String() string {
|
|
return fmt.Sprintf("%s %s", pKey.peerIP, pKey.peerMac)
|
|
}
|
|
|
|
func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
|
|
ipB, err := state.Token(true, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pKey.peerIP = net.ParseIP(string(ipB))
|
|
|
|
macB, err := state.Token(true, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pKey.peerMac, err = net.ParseMAC(string(macB))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var peerDbWg sync.WaitGroup
|
|
|
|
func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) error {
|
|
d.peerDb.Lock()
|
|
pMap, ok := d.peerDb.mp[nid]
|
|
if !ok {
|
|
d.peerDb.Unlock()
|
|
return nil
|
|
}
|
|
d.peerDb.Unlock()
|
|
|
|
pMap.Lock()
|
|
for pKeyStr, pEntry := range pMap.mp {
|
|
var pKey peerKey
|
|
if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil {
|
|
fmt.Printf("peer key scan failed: %v", err)
|
|
}
|
|
|
|
if f(&pKey, &pEntry) {
|
|
pMap.Unlock()
|
|
return nil
|
|
}
|
|
}
|
|
pMap.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
|
|
var (
|
|
peerMac net.HardwareAddr
|
|
vtep net.IP
|
|
found bool
|
|
)
|
|
|
|
err := d.peerDbWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
|
|
if pKey.peerIP.Equal(peerIP) {
|
|
peerMac = pKey.peerMac
|
|
vtep = pEntry.vtep
|
|
found = true
|
|
return found
|
|
}
|
|
|
|
return found
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
|
|
}
|
|
|
|
if !found {
|
|
return nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
|
|
}
|
|
|
|
return peerMac, vtep, nil
|
|
}
|
|
|
|
func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
|
|
peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
|
|
|
|
peerDbWg.Wait()
|
|
|
|
d.peerDb.Lock()
|
|
pMap, ok := d.peerDb.mp[nid]
|
|
if !ok {
|
|
d.peerDb.mp[nid] = peerMap{
|
|
mp: make(map[string]peerEntry),
|
|
}
|
|
|
|
pMap = d.peerDb.mp[nid]
|
|
}
|
|
d.peerDb.Unlock()
|
|
|
|
pKey := peerKey{
|
|
peerIP: peerIP,
|
|
peerMac: peerMac,
|
|
}
|
|
|
|
pEntry := peerEntry{
|
|
eid: eid,
|
|
vtep: vtep,
|
|
isLocal: isLocal,
|
|
}
|
|
|
|
pMap.Lock()
|
|
pMap.mp[pKey.String()] = pEntry
|
|
pMap.Unlock()
|
|
}
|
|
|
|
func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
|
|
peerMac net.HardwareAddr, vtep net.IP) {
|
|
peerDbWg.Wait()
|
|
|
|
d.peerDb.Lock()
|
|
pMap, ok := d.peerDb.mp[nid]
|
|
if !ok {
|
|
d.peerDb.Unlock()
|
|
return
|
|
}
|
|
d.peerDb.Unlock()
|
|
|
|
pKey := peerKey{
|
|
peerIP: peerIP,
|
|
peerMac: peerMac,
|
|
}
|
|
|
|
pMap.Lock()
|
|
delete(pMap.mp, pKey.String())
|
|
pMap.Unlock()
|
|
}
|
|
|
|
func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
|
|
d.peerDb.Lock()
|
|
pMap, ok := d.peerDb.mp[nid]
|
|
if !ok {
|
|
d.peerDb.Unlock()
|
|
return
|
|
}
|
|
d.peerDb.Unlock()
|
|
|
|
peerDbWg.Add(1)
|
|
|
|
var peerOps []func()
|
|
pMap.Lock()
|
|
for pKeyStr, pEntry := range pMap.mp {
|
|
var pKey peerKey
|
|
if _, err := fmt.Sscan(pKeyStr, &pKey); err != nil {
|
|
fmt.Printf("peer key scan failed: %v", err)
|
|
}
|
|
|
|
if pEntry.isLocal {
|
|
continue
|
|
}
|
|
|
|
op := func() {
|
|
if err := d.peerAdd(nid, pEntry.eid, pKey.peerIP,
|
|
pKey.peerMac, pEntry.vtep,
|
|
false); err != nil {
|
|
fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v",
|
|
pKey.peerIP, pKey.peerMac, err)
|
|
}
|
|
}
|
|
|
|
peerOps = append(peerOps, op)
|
|
}
|
|
pMap.Unlock()
|
|
|
|
for _, op := range peerOps {
|
|
op()
|
|
}
|
|
|
|
peerDbWg.Done()
|
|
}
|
|
|
|
func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
|
|
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
|
|
|
if err := validateID(nid, eid); err != nil {
|
|
return err
|
|
}
|
|
|
|
if updateDb {
|
|
d.peerDbAdd(nid, eid, peerIP, peerMac, vtep, false)
|
|
}
|
|
|
|
n := d.network(nid)
|
|
if n == nil {
|
|
return nil
|
|
}
|
|
|
|
sbox := n.sandbox()
|
|
if sbox == nil {
|
|
return nil
|
|
}
|
|
|
|
// Add neighbor entry for the peer IP
|
|
if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName)); err != nil {
|
|
return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err)
|
|
}
|
|
|
|
// Add fdb entry to the bridge for the peer mac
|
|
if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName),
|
|
sbox.NeighborOptions().Family(syscall.AF_BRIDGE)); err != nil {
|
|
return fmt.Errorf("could not add fdb entry into the sandbox: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (d *driver) peerDelete(nid, eid types.UUID, peerIP net.IP,
|
|
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
|
|
|
if err := validateID(nid, eid); err != nil {
|
|
return err
|
|
}
|
|
|
|
if updateDb {
|
|
d.peerDbDelete(nid, eid, peerIP, peerMac, vtep)
|
|
}
|
|
|
|
n := d.network(nid)
|
|
if n == nil {
|
|
return nil
|
|
}
|
|
|
|
sbox := n.sandbox()
|
|
if sbox == nil {
|
|
return nil
|
|
}
|
|
|
|
// Delete fdb entry to the bridge for the peer mac
|
|
if err := sbox.DeleteNeighbor(vtep, peerMac); err != nil {
|
|
return fmt.Errorf("could not delete fdb entry into the sandbox: %v", err)
|
|
}
|
|
|
|
// Delete neighbor entry for the peer IP
|
|
if err := sbox.DeleteNeighbor(peerIP, peerMac); err != nil {
|
|
return fmt.Errorf("could not delete neigbor entry into the sandbox: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|