Skip to content

Commit a997502

Browse files
committed
Make overlay driver work without a kv store
Currently overlay driver requires a k/v store to allocate a vxlan id and add an entry in k/v store for network->vxlanIDs binding. But the overlay driver should be able to work without a k/v store provided libnetwork can pass along the vxlanIDs needed for the network, rather than the driver managing it themselves. Modified the driver to work with vxlanIDs passed down by libnetwork. Also made changes in the driver to make use of the gossip layer available in libnetwork if available. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
1 parent f8fe886 commit a997502

5 files changed

Lines changed: 116 additions & 47 deletions

File tree

drivers/overlay/joinleave.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package overlay
33
import (
44
"fmt"
55
"net"
6+
"strings"
67

78
log "github.com/Sirupsen/logrus"
89
"github.com/docker/libnetwork/driverapi"
@@ -104,11 +105,55 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
104105

105106
d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac,
106107
net.ParseIP(d.bindAddress), true)
108+
109+
if err := jinfo.AddTableEntry(ovPeerTable, eid, []byte(fmt.Sprintf("%s,%s,%s", ep.addr, ep.mac, d.bindAddress))); err != nil {
110+
log.Errorf("overlay: Failed adding table entry to joininfo: %v", err)
111+
}
112+
107113
d.pushLocalEndpointEvent("join", nid, eid)
108114

109115
return nil
110116
}
111117

118+
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
119+
if tableName != ovPeerTable {
120+
log.Errorf("Unexpected table notification for table %s received", tableName)
121+
return
122+
}
123+
124+
eid := key
125+
values := strings.Split(string(value), ",")
126+
if len(values) < 3 {
127+
log.Errorf("Invalid value %s received through event notify", string(value))
128+
return
129+
}
130+
131+
addr, err := types.ParseCIDR(values[0])
132+
if err != nil {
133+
log.Errorf("Invalid peer IP %s received in event notify", values[0])
134+
return
135+
}
136+
137+
mac, err := net.ParseMAC(values[1])
138+
if err != nil {
139+
log.Errorf("Invalid mac %s received in event notify", values[1])
140+
return
141+
}
142+
143+
vtep := net.ParseIP(values[2])
144+
if vtep == nil {
145+
log.Errorf("Invalid VTEP %s received in event notify", values[2])
146+
return
147+
}
148+
149+
if etype == driverapi.Delete {
150+
d.peerDelete(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
151+
return
152+
}
153+
154+
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
155+
}
156+
112157
// Leave method is invoked when a Sandbox detaches from an endpoint.
113158
func (d *driver) Leave(nid, eid string) error {
114159
if err := validateID(nid, eid); err != nil {

drivers/overlay/ov_network.go

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import (
66
"net"
77
"os"
88
"path/filepath"
9+
"strconv"
910
"strings"
1011
"sync"
1112
"syscall"
1213

1314
"github.com/Sirupsen/logrus"
1415
"github.com/docker/libnetwork/datastore"
1516
"github.com/docker/libnetwork/driverapi"
17+
"github.com/docker/libnetwork/netlabel"
1618
"github.com/docker/libnetwork/netutils"
1719
"github.com/docker/libnetwork/osl"
1820
"github.com/docker/libnetwork/resolvconf"
@@ -67,9 +69,6 @@ func (d *driver) NetworkFree(id string) error {
6769
return types.NotImplementedErrorf("not implemented")
6870
}
6971

70-
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
71-
}
72-
7372
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
7473
if id == "" {
7574
return fmt.Errorf("invalid network id")
@@ -92,21 +91,54 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
9291
subnets: []*subnet{},
9392
}
9493

95-
for _, ipd := range ipV4Data {
94+
vnis := make([]uint32, 0, len(ipV4Data))
95+
if gval, ok := option[netlabel.GenericData]; ok {
96+
optMap := gval.(map[string]string)
97+
if val, ok := optMap[netlabel.OverlayVxlanIDList]; ok {
98+
logrus.Debugf("overlay: Received vxlan IDs: %s", val)
99+
vniStrings := strings.Split(val, ",")
100+
for _, vniStr := range vniStrings {
101+
vni, err := strconv.Atoi(vniStr)
102+
if err != nil {
103+
return fmt.Errorf("invalid vxlan id value %q passed", vniStr)
104+
}
105+
106+
vnis = append(vnis, uint32(vni))
107+
}
108+
}
109+
}
110+
111+
// If we are getting vnis from libnetwork, either we get for
112+
// all subnets or none.
113+
if len(vnis) != 0 && len(vnis) < len(ipV4Data) {
114+
return fmt.Errorf("insufficient vnis(%d) passed to overlay", len(vnis))
115+
}
116+
117+
for i, ipd := range ipV4Data {
96118
s := &subnet{
97119
subnetIP: ipd.Pool,
98120
gwIP: ipd.Gateway,
99121
once: &sync.Once{},
100122
}
123+
124+
if len(vnis) != 0 {
125+
s.vni = vnis[i]
126+
}
127+
101128
n.subnets = append(n.subnets, s)
102129
}
103130

104131
if err := n.writeToStore(); err != nil {
105132
return fmt.Errorf("failed to update data store for network %v: %v", n.id, err)
106133
}
107134

108-
d.addNetwork(n)
135+
if nInfo != nil {
136+
if err := nInfo.TableEventRegister(ovPeerTable); err != nil {
137+
return err
138+
}
139+
}
109140

141+
d.addNetwork(n)
110142
return nil
111143
}
112144

@@ -255,11 +287,21 @@ func setHostMode() {
255287
}
256288

257289
func (n *network) generateVxlanName(s *subnet) string {
258-
return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
290+
id := n.id
291+
if len(n.id) > 5 {
292+
id = n.id[:5]
293+
}
294+
295+
return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + id
259296
}
260297

261298
func (n *network) generateBridgeName(s *subnet) string {
262-
return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + n.id[:5]
299+
id := n.id
300+
if len(n.id) > 5 {
301+
id = n.id[:5]
302+
}
303+
304+
return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + id
263305
}
264306

265307
func isOverlap(nw *net.IPNet) bool {
@@ -587,32 +629,38 @@ func (n *network) DataScope() string {
587629
}
588630

589631
func (n *network) writeToStore() error {
632+
if n.driver.store == nil {
633+
return nil
634+
}
635+
590636
return n.driver.store.PutObjectAtomic(n)
591637
}
592638

593639
func (n *network) releaseVxlanID() error {
594-
if n.driver.store == nil {
595-
return fmt.Errorf("no datastore configured. cannot release vxlan id")
596-
}
597-
598640
if len(n.subnets) == 0 {
599641
return nil
600642
}
601643

602-
if err := n.driver.store.DeleteObjectAtomic(n); err != nil {
603-
if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound {
604-
// In both the above cases we can safely assume that the key has been removed by some other
605-
// instance and so simply get out of here
606-
return nil
607-
}
644+
if n.driver.store != nil {
645+
if err := n.driver.store.DeleteObjectAtomic(n); err != nil {
646+
if err == datastore.ErrKeyModified || err == datastore.ErrKeyNotFound {
647+
// In both the above cases we can safely assume that the key has been removed by some other
648+
// instance and so simply get out of here
649+
return nil
650+
}
608651

609-
return fmt.Errorf("failed to delete network to vxlan id map: %v", err)
652+
return fmt.Errorf("failed to delete network to vxlan id map: %v", err)
653+
}
610654
}
611655

612656
for _, s := range n.subnets {
613-
n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
657+
if n.driver.vxlanIdm != nil {
658+
n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
659+
}
660+
614661
n.setVxlanID(s, 0)
615662
}
663+
616664
return nil
617665
}
618666

@@ -623,7 +671,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
623671
}
624672

625673
if n.driver.store == nil {
626-
return fmt.Errorf("no datastore configured. cannot obtain vxlan id")
674+
return fmt.Errorf("no valid vxlan id and no datastore configured, cannot obtain vxlan id")
627675
}
628676

629677
for {

drivers/overlay/overlay.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func Fini(drv driverapi.Driver) {
8888

8989
func (d *driver) configure() error {
9090
if d.store == nil {
91-
return types.NoServiceErrorf("datastore is not available")
91+
return nil
9292
}
9393

9494
if d.vxlanIdm == nil {

drivers/overlay/overlay_test.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/docker/libnetwork/discoverapi"
99
"github.com/docker/libnetwork/driverapi"
1010
_ "github.com/docker/libnetwork/testutils"
11-
"github.com/docker/libnetwork/types"
1211
)
1312

1413
type driverTester struct {
@@ -24,14 +23,6 @@ func setupDriver(t *testing.T) *driverTester {
2423
t.Fatal(err)
2524
}
2625

27-
err := dt.d.configure()
28-
if err == nil {
29-
t.Fatalf("Failed to detect nil store")
30-
}
31-
if _, ok := err.(types.NoServiceError); !ok {
32-
t.Fatalf("Unexpected error type: %v", err)
33-
}
34-
3526
iface, err := net.InterfaceByName("eth0")
3627
if err != nil {
3728
t.Fatal(err)
@@ -93,23 +84,6 @@ func TestOverlayFiniWithoutConfig(t *testing.T) {
9384
cleanupDriver(t, dt)
9485
}
9586

96-
func TestOverlayNilConfig(t *testing.T) {
97-
dt := &driverTester{t: t}
98-
if err := Init(dt, nil); err != nil {
99-
t.Fatal(err)
100-
}
101-
102-
err := dt.d.configure()
103-
if err == nil {
104-
t.Fatalf("Failed to detect nil store")
105-
}
106-
if _, ok := err.(types.NoServiceError); !ok {
107-
t.Fatalf("Unexpected error type: %v", err)
108-
}
109-
110-
cleanupDriver(t, dt)
111-
}
112-
11387
func TestOverlayConfig(t *testing.T) {
11488
dt := setupDriver(t)
11589

drivers/overlay/peerdb.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"syscall"
88
)
99

10+
const ovPeerTable = "overlay_peer_table"
11+
1012
type peerKey struct {
1113
peerIP net.IP
1214
peerMac net.HardwareAddr

0 commit comments

Comments
 (0)