1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Support for multiple subnets in a overlay network

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
This commit is contained in:
Santhosh Manohar 2015-09-28 23:06:57 -07:00
parent 8dde3b2380
commit 6e327a5afb
5 changed files with 317 additions and 125 deletions

View file

@ -24,10 +24,23 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not find endpoint with id %s", eid) return fmt.Errorf("could not find endpoint with id %s", eid)
} }
s := n.getSubnetforIP(ep.addr)
if s == nil {
return fmt.Errorf("could not find subnet for endpoint %s", eid)
}
if err := n.obtainVxlanID(s); err != nil {
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
}
if err := n.joinSandbox(); err != nil { if err := n.joinSandbox(); err != nil {
return fmt.Errorf("network sandbox join failed: %v", err) return fmt.Errorf("network sandbox join failed: %v", err)
} }
if err := n.joinSubnetSandbox(s); err != nil {
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
}
sbox := n.sandbox() sbox := n.sandbox()
name1, name2, err := createVethPair() name1, name2, err := createVethPair()
@ -48,7 +61,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
} }
if err := sbox.AddInterface(name1, "veth", if err := sbox.AddInterface(name1, "veth",
sbox.InterfaceOptions().Master("bridge1")); err != nil { sbox.InterfaceOptions().Master(s.brName)); err != nil {
return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err) return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err)
} }
@ -72,7 +85,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
} }
} }
d.peerDbAdd(nid, eid, ep.addr.IP, ep.mac, d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac,
net.ParseIP(d.bindAddress), true) net.ParseIP(d.bindAddress), true)
d.pushLocalEndpointEvent("join", nid, eid) d.pushLocalEndpointEvent("join", nid, eid)

View file

@ -37,25 +37,33 @@ func (n *network) deleteEndpoint(eid string) {
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
epOptions map[string]interface{}) error { epOptions map[string]interface{}) error {
if err := validateID(nid, eid); err != nil { var err error
if err = validateID(nid, eid); err != nil {
return err return err
} }
n := d.network(nid) n := d.network(nid)
if n == nil { if n == nil {
n, err = d.createNetworkfromStore(nid)
if err != nil {
return fmt.Errorf("network id %q not found", nid) return fmt.Errorf("network id %q not found", nid)
} }
}
ep := &endpoint{ ep := &endpoint{
id: eid, id: eid,
addr: ifInfo.Address(), addr: ifInfo.Address(),
mac: ifInfo.MacAddress(), mac: ifInfo.MacAddress(),
} }
if ep.addr == nil { if ep.addr == nil {
return fmt.Errorf("create endpoint was not passed interface IP address") return fmt.Errorf("create endpoint was not passed interface IP address")
} }
if s := n.getSubnetforIP(ep.addr); s == nil {
return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid)
}
if ep.mac == nil { if ep.mac == nil {
ep.mac = netutils.GenerateMACFromIP(ep.addr.IP) ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
if err := ifInfo.SetMacAddress(ep.mac); err != nil { if err := ifInfo.SetMacAddress(ep.mac); err != nil {

View file

@ -10,37 +10,47 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl" "github.com/vishvananda/netlink/nl"
) )
type networkTable map[string]*network type networkTable map[string]*network
type subnet struct {
once *sync.Once
vxlanName string
brName string
vni uint32
initErr error
subnetIP *net.IPNet
gwIP *net.IPNet
}
type network struct { type network struct {
id string id string
vni uint32
dbIndex uint64 dbIndex uint64
dbExists bool dbExists bool
sbox osl.Sandbox sbox osl.Sandbox
endpoints endpointTable endpoints endpointTable
vxlanName string
driver *driver driver *driver
joinCnt int joinCnt int
once *sync.Once once *sync.Once
initEpoch int initEpoch int
initErr error initErr error
subnets []*net.IPNet subnets []*subnet
gateways []*net.IPNet
sync.Mutex sync.Mutex
} }
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error { func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
var err error
if id == "" { if id == "" {
return fmt.Errorf("invalid network id") return fmt.Errorf("invalid network id")
} }
if err := d.configure(); err != nil { if err = d.configure(); err != nil {
return err return err
} }
@ -49,23 +59,54 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
driver: d, driver: d,
endpoints: endpointTable{}, endpoints: endpointTable{},
once: &sync.Once{}, once: &sync.Once{},
subnets: []*subnet{},
} }
n.subnets = make([]*net.IPNet, len(ipV4Data)) for _, ipd := range ipV4Data {
n.gateways = make([]*net.IPNet, len(ipV4Data)) s := &subnet{
subnetIP: ipd.Pool,
for i, ipd := range ipV4Data { gwIP: ipd.Gateway,
n.subnets[i] = ipd.Pool once: &sync.Once{},
n.gateways[i] = ipd.Gateway }
n.subnets = append(n.subnets, s)
} }
for {
// If the datastore has the network object already
// there is no need to do a write.
err = d.store.GetObject(datastore.Key(n.Key()...), n)
if err == nil || err != datastore.ErrKeyNotFound {
break
}
err = n.writeToStore()
if err == nil || err != datastore.ErrKeyModified {
break
}
}
if err != nil {
return fmt.Errorf("failed to update data store for network %v: %v", n.id, err)
}
d.addNetwork(n) d.addNetwork(n)
if err := n.obtainVxlanID(); err != nil { return nil
return err
} }
return nil func (d *driver) createNetworkfromStore(nid string) (*network, error) {
n := &network{
id: nid,
driver: d,
endpoints: endpointTable{},
once: &sync.Once{},
subnets: []*subnet{},
}
err := d.store.GetObject(datastore.Key(n.Key()...), n)
if err != nil {
return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err)
}
return n, nil
} }
func (d *driver) DeleteNetwork(nid string) error { func (d *driver) DeleteNetwork(nid string) error {
@ -100,13 +141,21 @@ func (n *network) joinSandbox() error {
n.initErr = n.initSandbox() n.initErr = n.initSandbox()
}) })
return n.initErr
}
func (n *network) joinSubnetSandbox(s *subnet) error {
s.once.Do(func() {
s.initErr = n.initSubnetSandbox(s)
})
// Increment joinCnt in all the goroutines only when the one time initSandbox // Increment joinCnt in all the goroutines only when the one time initSandbox
// was a success. // was a success.
n.Lock() n.Lock()
if n.initErr == nil { if s.initErr == nil {
n.joinCnt++ n.joinCnt++
} }
err := n.initErr err := s.initErr
n.Unlock() n.Unlock()
return err return err
@ -124,6 +173,9 @@ func (n *network) leaveSandbox() {
// Reinitialize the once variable so that we will be able to trigger one time // Reinitialize the once variable so that we will be able to trigger one time
// sandbox initialization(again) when another container joins subsequently. // sandbox initialization(again) when another container joins subsequently.
n.once = &sync.Once{} n.once = &sync.Once{}
for _, s := range n.subnets {
s.once = &sync.Once{}
}
n.Unlock() n.Unlock()
n.destroySandbox() n.destroySandbox()
@ -136,14 +188,50 @@ func (n *network) destroySandbox() {
iface.Remove() iface.Remove()
} }
if err := deleteVxlan(n.vxlanName); err != nil { for _, s := range n.subnets {
if s.vxlanName != "" {
err := deleteVxlan(s.vxlanName)
if err != nil {
logrus.Warnf("could not cleanup sandbox properly: %v", err) logrus.Warnf("could not cleanup sandbox properly: %v", err)
} }
}
}
sbox.Destroy() sbox.Destroy()
} }
} }
func (n *network) initSubnetSandbox(s *subnet) error {
// create a bridge and vxlan device for this subnet and move it to the sandbox
brName, err := netutils.GenerateIfaceName("bridge", 7)
if err != nil {
return err
}
sbox := n.sandbox()
if err := sbox.AddInterface(brName, "br",
sbox.InterfaceOptions().Address(s.gwIP),
sbox.InterfaceOptions().Bridge(true)); err != nil {
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.IP.String(), err)
}
vxlanName, err := createVxlan(n.vxlanID(s))
if err != nil {
return err
}
if err := sbox.AddInterface(vxlanName, "vxlan",
sbox.InterfaceOptions().Master(brName)); err != nil {
return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.IP.String(), err)
}
n.Lock()
s.vxlanName = vxlanName
s.brName = brName
n.Unlock()
return nil
}
func (n *network) initSandbox() error { func (n *network) initSandbox() error {
n.Lock() n.Lock()
n.initEpoch++ n.initEpoch++
@ -155,15 +243,10 @@ func (n *network) initSandbox() error {
return fmt.Errorf("could not create network sandbox: %v", err) return fmt.Errorf("could not create network sandbox: %v", err)
} }
// Add a bridge inside the namespace
if err := sbox.AddInterface("bridge1", "br",
sbox.InterfaceOptions().Address(n.gateways[0]),
sbox.InterfaceOptions().Bridge(true)); err != nil {
return fmt.Errorf("could not create bridge inside the network sandbox: %v", err)
}
n.setSandbox(sbox) n.setSandbox(sbox)
n.driver.peerDbUpdateSandbox(n.id)
var nlSock *nl.NetlinkSocket var nlSock *nl.NetlinkSocket
sbox.InvokeFunc(func() { sbox.InvokeFunc(func() {
nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH) nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
@ -173,27 +256,6 @@ func (n *network) initSandbox() error {
}) })
go n.watchMiss(nlSock) go n.watchMiss(nlSock)
return n.initVxlan()
}
func (n *network) initVxlan() error {
var vxlanName string
n.Lock()
sbox := n.sbox
n.Unlock()
vxlanName, err := createVxlan(n.vxlanID())
if err != nil {
return err
}
if err = sbox.AddInterface(vxlanName, "vxlan",
sbox.InterfaceOptions().Master("bridge1")); err != nil {
return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v", err)
}
n.vxlanName = vxlanName
n.driver.peerDbUpdateSandbox(n.id)
return nil return nil
} }
@ -224,14 +286,14 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
continue continue
} }
mac, vtep, err := n.driver.resolvePeer(n.id, neigh.IP) mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, neigh.IP)
if err != nil { if err != nil {
logrus.Errorf("could not resolve peer %q: %v", neigh.IP, err) logrus.Errorf("could not resolve peer %q: %v", neigh.IP, err)
continue continue
} }
if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, mac, vtep, true); err != nil { if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, IPmask, mac, vtep, true); err != nil {
logrus.Errorf("could not add neighbor entry for missed peer: %v", err) logrus.Errorf("could not add neighbor entry for missed peer %q: %v", neigh.IP, err)
} }
} }
} }
@ -269,16 +331,16 @@ func (n *network) setSandbox(sbox osl.Sandbox) {
n.Unlock() n.Unlock()
} }
func (n *network) vxlanID() uint32 { func (n *network) vxlanID(s *subnet) uint32 {
n.Lock() n.Lock()
defer n.Unlock() defer n.Unlock()
return n.vni return s.vni
} }
func (n *network) setVxlanID(vni uint32) { func (n *network) setVxlanID(s *subnet, vni uint32) {
n.Lock() n.Lock()
n.vni = vni s.vni = vni
n.Unlock() n.Unlock()
} }
@ -291,7 +353,19 @@ func (n *network) KeyPrefix() []string {
} }
func (n *network) Value() []byte { func (n *network) Value() []byte {
b, err := json.Marshal(n.vxlanID()) overlayNetmap := make(map[string]interface{})
s := n.subnets[0]
if s == nil {
logrus.Errorf("Network %s has no subnets", n.id)
return []byte{}
}
overlayNetmap["subnetIP"] = s.subnetIP.String()
overlayNetmap["gwIP"] = s.gwIP.String()
overlayNetmap["vni"] = s.vni
b, err := json.Marshal(overlayNetmap)
if err != nil { if err != nil {
return []byte{} return []byte{}
} }
@ -317,14 +391,46 @@ func (n *network) Skip() bool {
} }
func (n *network) SetValue(value []byte) error { func (n *network) SetValue(value []byte) error {
var vni uint32 var (
err := json.Unmarshal(value, &vni) overlayNetmap map[string]interface{}
if err == nil { err error
n.setVxlanID(vni) )
}
err = json.Unmarshal(value, &overlayNetmap)
if err != nil {
return err return err
} }
subnetIPstr := overlayNetmap["subnetIP"].(string)
gwIPstr := overlayNetmap["gwIP"].(string)
vni := uint32(overlayNetmap["vni"].(float64))
subnetIP, _ := types.ParseCIDR(subnetIPstr)
gwIP, _ := types.ParseCIDR(gwIPstr)
// If the network is being created by reading from the
// datastore subnets have to created. If the network
// already exists update only the subnets' vni field
if len(n.subnets) == 0 {
s := &subnet{
subnetIP: subnetIP,
gwIP: gwIP,
vni: vni,
once: &sync.Once{},
}
n.subnets = append(n.subnets, s)
return nil
}
sNet := n.getMatchingSubnet(subnetIP)
if sNet != nil {
if vni != 0 {
sNet.vni = vni
}
}
return nil
}
func (n *network) DataScope() datastore.DataScope { func (n *network) DataScope() datastore.DataScope {
return datastore.GlobalScope return datastore.GlobalScope
} }
@ -338,7 +444,7 @@ func (n *network) releaseVxlanID() error {
return fmt.Errorf("no datastore configured. cannot release vxlan id") return fmt.Errorf("no datastore configured. cannot release vxlan id")
} }
if n.vxlanID() == 0 { if len(n.subnets) == 0 {
return nil return nil
} }
@ -352,38 +458,80 @@ func (n *network) releaseVxlanID() error {
return fmt.Errorf("failed to delete network to vxlan id map: %v", err) return fmt.Errorf("failed to delete network to vxlan id map: %v", err)
} }
n.driver.vxlanIdm.Release(n.vxlanID()) for _, s := range n.subnets {
n.setVxlanID(0) n.driver.vxlanIdm.Release(n.vxlanID(s))
n.setVxlanID(s, 0)
}
return nil
}
func (n *network) obtainVxlanID(s *subnet) error {
//return if the subnet already has a vxlan id assigned
if s.vni != 0 {
return nil return nil
} }
func (n *network) obtainVxlanID() error {
if n.driver.store == nil { if n.driver.store == nil {
return fmt.Errorf("no datastore configured. cannot obtain vxlan id") return fmt.Errorf("no datastore configured. cannot obtain vxlan id")
} }
for { for {
var vxlanID uint32
if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil { if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
if err == datastore.ErrKeyNotFound { return fmt.Errorf("getting network %q from datastore failed %v", n.id, err)
vxlanID, err = n.driver.vxlanIdm.GetID() }
if s.vni == 0 {
vxlanID, err := n.driver.vxlanIdm.GetID()
if err != nil { if err != nil {
return fmt.Errorf("failed to allocate vxlan id: %v", err) return fmt.Errorf("failed to allocate vxlan id: %v", err)
} }
n.setVxlanID(vxlanID) n.setVxlanID(s, vxlanID)
if err := n.writeToStore(); err != nil { if err := n.writeToStore(); err != nil {
n.driver.vxlanIdm.Release(n.vxlanID()) n.driver.vxlanIdm.Release(n.vxlanID(s))
n.setVxlanID(0) n.setVxlanID(s, 0)
if err == datastore.ErrKeyModified { if err == datastore.ErrKeyModified {
continue continue
} }
return fmt.Errorf("failed to update data store with vxlan id: %v", err) return fmt.Errorf("network %q failed to update data store: %v", n.id, err)
} }
return nil return nil
} }
return fmt.Errorf("failed to obtain vxlan id from data store: %v", err)
}
return nil return nil
} }
} }
// getSubnetforIP returns the subnet to which the given IP belongs
func (n *network) getSubnetforIP(ip *net.IPNet) *subnet {
for _, s := range n.subnets {
// first check if the mask lengths are the same
i, _ := s.subnetIP.Mask.Size()
j, _ := ip.Mask.Size()
if i != j {
continue
}
if s.subnetIP.Contains(ip.IP) {
return s
}
}
return nil
}
// getMatchingSubnet return the network's subnet that matches the input
func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet {
if ip == nil {
return nil
}
for _, s := range n.subnets {
// first check if the mask lengths are the same
i, _ := s.subnetIP.Mask.Size()
j, _ := ip.Mask.Size()
if i != j {
continue
}
if s.subnetIP.IP.Equal(ip.IP) {
return s
}
}
return nil
}

View file

@ -83,7 +83,8 @@ func (d *driver) notifyEvent(event ovNotify) {
n := d.network(event.nid) n := d.network(event.nid)
ep := n.endpoint(event.eid) ep := n.endpoint(event.eid)
ePayload := fmt.Sprintf("%s %s %s", event.action, ep.addr.IP.String(), ep.mac.String()) ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
net.IP(ep.addr.Mask).String(), ep.mac.String())
eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(), eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
event.nid, event.eid) event.nid, event.eid)
@ -96,17 +97,17 @@ func (d *driver) processEvent(u serf.UserEvent) {
fmt.Printf("Received user event name:%s, payload:%s\n", u.Name, fmt.Printf("Received user event name:%s, payload:%s\n", u.Name,
string(u.Payload)) string(u.Payload))
var dummy, action, vtepStr, nid, eid, ipStr, macStr string var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil { if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
fmt.Printf("Failed to scan name string: %v\n", err) fmt.Printf("Failed to scan name string: %v\n", err)
} }
if _, err := fmt.Sscan(string(u.Payload), &action, if _, err := fmt.Sscan(string(u.Payload), &action,
&ipStr, &macStr); err != nil { &ipStr, &maskStr, &macStr); err != nil {
fmt.Printf("Failed to scan value string: %v\n", err) fmt.Printf("Failed to scan value string: %v\n", err)
} }
fmt.Printf("Parsed data = %s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, macStr) fmt.Printf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)
mac, err := net.ParseMAC(macStr) mac, err := net.ParseMAC(macStr)
if err != nil { if err != nil {
@ -119,12 +120,12 @@ func (d *driver) processEvent(u serf.UserEvent) {
switch action { switch action {
case "join": case "join":
if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), mac, if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
net.ParseIP(vtepStr), true); err != nil { net.ParseIP(vtepStr), true); err != nil {
fmt.Printf("Peer add failed in the driver: %v\n", err) fmt.Printf("Peer add failed in the driver: %v\n", err)
} }
case "leave": case "leave":
if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), mac, if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
net.ParseIP(vtepStr), true); err != nil { net.ParseIP(vtepStr), true); err != nil {
fmt.Printf("Peer delete failed in the driver: %v\n", err) fmt.Printf("Peer delete failed in the driver: %v\n", err)
} }
@ -140,38 +141,38 @@ func (d *driver) processQuery(q *serf.Query) {
fmt.Printf("Failed to scan query payload string: %v\n", err) fmt.Printf("Failed to scan query payload string: %v\n", err)
} }
peerMac, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr)) peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
if err != nil { if err != nil {
return return
} }
q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String()))) q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String())))
} }
func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) { func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String()) qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil) resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err) return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
} }
respCh := resp.ResponseCh() respCh := resp.ResponseCh()
select { select {
case r := <-respCh: case r := <-respCh:
var macStr, vtepStr string var macStr, maskStr, vtepStr string
if _, err := fmt.Sscan(string(r.Payload), &macStr, &vtepStr); err != nil { if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
return nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err) return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
} }
mac, err := net.ParseMAC(macStr) mac, err := net.ParseMAC(macStr)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to parse mac: %v", err) return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
} }
return mac, net.ParseIP(vtepStr), nil return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil
case <-time.After(time.Second): case <-time.After(time.Second):
return nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster") return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
} }
} }

View file

@ -15,6 +15,7 @@ type peerKey struct {
type peerEntry struct { type peerEntry struct {
eid string eid string
vtep net.IP vtep net.IP
peerIPMask net.IPMask
inSandbox bool inSandbox bool
isLocal bool isLocal bool
} }
@ -98,16 +99,18 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool
return nil return nil
} }
func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) { func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
var ( var (
peerMac net.HardwareAddr peerMac net.HardwareAddr
vtep net.IP vtep net.IP
peerIPMask net.IPMask
found bool found bool
) )
err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
if pKey.peerIP.Equal(peerIP) { if pKey.peerIP.Equal(peerIP) {
peerMac = pKey.peerMac peerMac = pKey.peerMac
peerIPMask = pEntry.peerIPMask
vtep = pEntry.vtep vtep = pEntry.vtep
found = true found = true
return found return found
@ -117,17 +120,17 @@ func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.
}) })
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err) return nil, nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
} }
if !found { if !found {
return nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP) return nil, nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
} }
return peerMac, vtep, nil return peerMac, peerIPMask, vtep, nil
} }
func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
peerMac net.HardwareAddr, vtep net.IP, isLocal bool) { peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
peerDbWg.Wait() peerDbWg.Wait()
@ -151,6 +154,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
pEntry := peerEntry{ pEntry := peerEntry{
eid: eid, eid: eid,
vtep: vtep, vtep: vtep,
peerIPMask: peerIPMask,
isLocal: isLocal, isLocal: isLocal,
} }
@ -159,7 +163,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
pMap.Unlock() pMap.Unlock()
} }
func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
peerMac net.HardwareAddr, vtep net.IP) { peerMac net.HardwareAddr, vtep net.IP) {
peerDbWg.Wait() peerDbWg.Wait()
@ -209,7 +213,7 @@ func (d *driver) peerDbUpdateSandbox(nid string) {
// a copy of pEntry before capturing it in the following closure. // a copy of pEntry before capturing it in the following closure.
entry := pEntry entry := pEntry
op := func() { op := func() {
if err := d.peerAdd(nid, entry.eid, pKey.peerIP, if err := d.peerAdd(nid, entry.eid, pKey.peerIP, entry.peerIPMask,
pKey.peerMac, entry.vtep, pKey.peerMac, entry.vtep,
false); err != nil { false); err != nil {
fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v", fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v",
@ -228,7 +232,7 @@ func (d *driver) peerDbUpdateSandbox(nid string) {
peerDbWg.Done() peerDbWg.Done()
} }
func (d *driver) peerAdd(nid, eid string, peerIP net.IP, func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
if err := validateID(nid, eid); err != nil { if err := validateID(nid, eid); err != nil {
@ -236,7 +240,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
} }
if updateDb { if updateDb {
d.peerDbAdd(nid, eid, peerIP, peerMac, vtep, false) d.peerDbAdd(nid, eid, peerIP, peerIPMask, peerMac, vtep, false)
} }
n := d.network(nid) n := d.network(nid)
@ -249,13 +253,31 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
return nil return nil
} }
IP := &net.IPNet{
IP: peerIP,
Mask: peerIPMask,
}
s := n.getSubnetforIP(IP)
if s == nil {
return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id)
}
if err := n.obtainVxlanID(s); err != nil {
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
}
if err := n.joinSubnetSandbox(s); err != nil {
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
}
// Add neighbor entry for the peer IP // Add neighbor entry for the peer IP
if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName)); err != nil { if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil {
return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err) return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err)
} }
// Add fdb entry to the bridge for the peer mac // Add fdb entry to the bridge for the peer mac
if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName), if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName),
sbox.NeighborOptions().Family(syscall.AF_BRIDGE)); err != nil { sbox.NeighborOptions().Family(syscall.AF_BRIDGE)); err != nil {
return fmt.Errorf("could not add fdb entry into the sandbox: %v", err) return fmt.Errorf("could not add fdb entry into the sandbox: %v", err)
} }
@ -263,7 +285,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
return nil return nil
} }
func (d *driver) peerDelete(nid, eid string, peerIP net.IP, func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
if err := validateID(nid, eid); err != nil { if err := validateID(nid, eid); err != nil {
@ -271,7 +293,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
} }
if updateDb { if updateDb {
d.peerDbDelete(nid, eid, peerIP, peerMac, vtep) d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep)
} }
n := d.network(nid) n := d.network(nid)