mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
281 lines
5.1 KiB
Go
281 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
|
||
|
}
|