Browse Source

Use protobuf in networkdb core messages

Convert all networkdb core message types from go message types to
protobuf message types. This faciliates future modification of the
message structure without breaking backward compatibility.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Jana Radhakrishnan 9 năm trước cách đây
mục cha
commit
77abea9c1e

+ 1 - 1
libnetwork/Makefile

@@ -47,7 +47,7 @@ check: ${build_image}.created
 
 check-code:
 	@echo "Checking code... "
-	test -z "$$(golint ./... | tee /dev/stderr)"
+	test -z "$$(golint ./... | grep -v .pb.go: | tee /dev/stderr)"
 	go vet ./...
 	@echo "Done checking code"
 

+ 8 - 40
libnetwork/networkdb/broadcast.go

@@ -5,20 +5,6 @@ import (
 	"github.com/hashicorp/serf/serf"
 )
 
-type networkEventType uint8
-
-const (
-	networkJoin networkEventType = 1 + iota
-	networkLeave
-)
-
-type networkEventData struct {
-	Event     networkEventType
-	LTime     serf.LamportTime
-	NodeName  string
-	NetworkID string
-}
-
 type networkEventMessage struct {
 	id   string
 	node string
@@ -37,15 +23,15 @@ func (m *networkEventMessage) Message() []byte {
 func (m *networkEventMessage) Finished() {
 }
 
-func (nDB *NetworkDB) sendNetworkEvent(nid string, event networkEventType, ltime serf.LamportTime) error {
-	nEvent := networkEventData{
-		Event:     event,
+func (nDB *NetworkDB) sendNetworkEvent(nid string, event NetworkEvent_Type, ltime serf.LamportTime) error {
+	nEvent := NetworkEvent{
+		Type:      event,
 		LTime:     ltime,
 		NodeName:  nDB.config.NodeName,
 		NetworkID: nid,
 	}
 
-	raw, err := encodeMessage(networkEventMsg, &nEvent)
+	raw, err := encodeMessage(MessageTypeNetworkEvent, &nEvent)
 	if err != nil {
 		return err
 	}
@@ -58,24 +44,6 @@ func (nDB *NetworkDB) sendNetworkEvent(nid string, event networkEventType, ltime
 	return nil
 }
 
-type tableEventType uint8
-
-const (
-	tableEntryCreate tableEventType = 1 + iota
-	tableEntryUpdate
-	tableEntryDelete
-)
-
-type tableEventData struct {
-	Event     tableEventType
-	LTime     serf.LamportTime
-	NetworkID string
-	TableName string
-	NodeName  string
-	Value     []byte
-	Key       string
-}
-
 type tableEventMessage struct {
 	id    string
 	tname string
@@ -96,9 +64,9 @@ func (m *tableEventMessage) Message() []byte {
 func (m *tableEventMessage) Finished() {
 }
 
-func (nDB *NetworkDB) sendTableEvent(event tableEventType, nid string, tname string, key string, entry *entry) error {
-	tEvent := tableEventData{
-		Event:     event,
+func (nDB *NetworkDB) sendTableEvent(event TableEvent_Type, nid string, tname string, key string, entry *entry) error {
+	tEvent := TableEvent{
+		Type:      event,
 		LTime:     entry.ltime,
 		NodeName:  nDB.config.NodeName,
 		NetworkID: nid,
@@ -107,7 +75,7 @@ func (nDB *NetworkDB) sendTableEvent(event tableEventType, nid string, tname str
 		Value:     entry.value,
 	}
 
-	raw, err := encodeMessage(tableEventMsg, &tEvent)
+	raw, err := encodeMessage(MessageTypeTableEvent, &tEvent)
 	if err != nil {
 		return err
 	}

+ 7 - 16
libnetwork/networkdb/cluster.go

@@ -10,7 +10,6 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/hashicorp/memberlist"
-	"github.com/hashicorp/serf/serf"
 )
 
 const reapInterval = 2 * time.Second
@@ -222,21 +221,13 @@ func (nDB *NetworkDB) gossip() {
 			}
 
 			// Send the compound message
-			if err := nDB.memberlist.SendToUDP(mnode, compound.Bytes()); err != nil {
+			if err := nDB.memberlist.SendToUDP(mnode, compound); err != nil {
 				logrus.Errorf("Failed to send gossip to %s: %s", mnode.Addr, err)
 			}
 		}
 	}
 }
 
-type bulkSyncMessage struct {
-	LTime       serf.LamportTime
-	Unsolicited bool
-	NodeName    string
-	Networks    []string
-	Payload     []byte
-}
-
 func (nDB *NetworkDB) bulkSyncTables() {
 	var networks []string
 	nDB.RLock()
@@ -331,8 +322,8 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b
 			}
 
 			params := strings.Split(path[1:], "/")
-			tEvent := tableEventData{
-				Event:     tableEntryCreate,
+			tEvent := TableEvent{
+				Type:      TableEventTypeCreate,
 				LTime:     entry.ltime,
 				NodeName:  entry.node,
 				NetworkID: nid,
@@ -341,7 +332,7 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b
 				Value:     entry.value,
 			}
 
-			msg, err := encodeMessage(tableEventMsg, &tEvent)
+			msg, err := encodeMessage(MessageTypeTableEvent, &tEvent)
 			if err != nil {
 				logrus.Errorf("Encode failure during bulk sync: %#v", tEvent)
 				return false
@@ -356,15 +347,15 @@ func (nDB *NetworkDB) bulkSyncNode(networks []string, node string, unsolicited b
 	// Create a compound message
 	compound := makeCompoundMessage(msgs)
 
-	bsm := bulkSyncMessage{
+	bsm := BulkSyncMessage{
 		LTime:       nDB.tableClock.Time(),
 		Unsolicited: unsolicited,
 		NodeName:    nDB.config.NodeName,
 		Networks:    networks,
-		Payload:     compound.Bytes(),
+		Payload:     compound,
 	}
 
-	buf, err := encodeMessage(bulkSyncMsg, &bsm)
+	buf, err := encodeMessage(MessageTypeBulkSync, &bsm)
 	if err != nil {
 		return fmt.Errorf("failed to encode bulk sync message: %v", err)
 	}

+ 69 - 69
libnetwork/networkdb/delegate.go

@@ -5,21 +5,9 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
-	"github.com/hashicorp/serf/serf"
+	"github.com/gogo/protobuf/proto"
 )
 
-type networkData struct {
-	LTime    serf.LamportTime
-	ID       string
-	NodeName string
-	Leaving  bool
-}
-
-type networkPushPull struct {
-	LTime    serf.LamportTime
-	Networks []networkData
-}
-
 type delegate struct {
 	nDB *NetworkDB
 }
@@ -28,7 +16,7 @@ func (d *delegate) NodeMeta(limit int) []byte {
 	return []byte{}
 }
 
-func (nDB *NetworkDB) handleNetworkEvent(nEvent *networkEventData) bool {
+func (nDB *NetworkDB) handleNetworkEvent(nEvent *NetworkEvent) bool {
 	// Update our local clock if the received messages has newer
 	// time.
 	nDB.networkClock.Witness(nEvent.LTime)
@@ -39,7 +27,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *networkEventData) bool {
 	nodeNetworks, ok := nDB.networks[nEvent.NodeName]
 	if !ok {
 		// We haven't heard about this node at all.  Ignore the leave
-		if nEvent.Event == networkLeave {
+		if nEvent.Type == NetworkEventTypeLeave {
 			return false
 		}
 
@@ -55,7 +43,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *networkEventData) bool {
 		}
 
 		n.ltime = nEvent.LTime
-		n.leaving = nEvent.Event == networkLeave
+		n.leaving = nEvent.Type == NetworkEventTypeLeave
 		if n.leaving {
 			n.leaveTime = time.Now()
 		}
@@ -63,7 +51,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *networkEventData) bool {
 		return true
 	}
 
-	if nEvent.Event == networkLeave {
+	if nEvent.Type == NetworkEventTypeLeave {
 		return false
 	}
 
@@ -77,7 +65,7 @@ func (nDB *NetworkDB) handleNetworkEvent(nEvent *networkEventData) bool {
 	return true
 }
 
-func (nDB *NetworkDB) handleTableEvent(tEvent *tableEventData) bool {
+func (nDB *NetworkDB) handleTableEvent(tEvent *TableEvent) bool {
 	// Update our local clock if the received messages has newer
 	// time.
 	nDB.tableClock.Witness(tEvent.LTime)
@@ -94,7 +82,7 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *tableEventData) bool {
 		ltime:    tEvent.LTime,
 		node:     tEvent.NodeName,
 		value:    tEvent.Value,
-		deleting: tEvent.Event == tableEntryDelete,
+		deleting: tEvent.Type == TableEventTypeDelete,
 	}
 
 	if entry.deleting {
@@ -107,12 +95,12 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *tableEventData) bool {
 	nDB.Unlock()
 
 	var op opType
-	switch tEvent.Event {
-	case tableEntryCreate:
+	switch tEvent.Type {
+	case TableEventTypeCreate:
 		op = opCreate
-	case tableEntryUpdate:
+	case TableEventTypeUpdate:
 		op = opUpdate
-	case tableEntryDelete:
+	case TableEventTypeDelete:
 		op = opDelete
 	}
 
@@ -122,17 +110,12 @@ func (nDB *NetworkDB) handleTableEvent(tEvent *tableEventData) bool {
 
 func (nDB *NetworkDB) handleCompound(buf []byte) {
 	// Decode the parts
-	trunc, parts, err := decodeCompoundMessage(buf[1:])
+	parts, err := decodeCompoundMessage(buf)
 	if err != nil {
 		logrus.Errorf("Failed to decode compound request: %v", err)
 		return
 	}
 
-	// Log any truncation
-	if trunc > 0 {
-		logrus.Warnf("Compound request had %d truncated messages", trunc)
-	}
-
 	// Handle each message
 	for _, part := range parts {
 		nDB.handleMessage(part)
@@ -140,16 +123,19 @@ func (nDB *NetworkDB) handleCompound(buf []byte) {
 }
 
 func (nDB *NetworkDB) handleTableMessage(buf []byte) {
-	var tEvent tableEventData
-	if err := decodeMessage(buf[1:], &tEvent); err != nil {
+	var tEvent TableEvent
+	if err := proto.Unmarshal(buf, &tEvent); err != nil {
 		logrus.Errorf("Error decoding table event message: %v", err)
 		return
 	}
 
 	if rebroadcast := nDB.handleTableEvent(&tEvent); rebroadcast {
-		// Copy the buffer since we cannot rely on the slice not changing
-		newBuf := make([]byte, len(buf))
-		copy(newBuf, buf)
+		var err error
+		buf, err = encodeRawMessage(MessageTypeTableEvent, buf)
+		if err != nil {
+			logrus.Errorf("Error marshalling gossip message for network event rebroadcast: %v", err)
+			return
+		}
 
 		nDB.RLock()
 		n, ok := nDB.networks[nDB.config.NodeName][tEvent.NetworkID]
@@ -161,7 +147,7 @@ func (nDB *NetworkDB) handleTableMessage(buf []byte) {
 
 		broadcastQ := n.tableBroadcasts
 		broadcastQ.QueueBroadcast(&tableEventMessage{
-			msg:   newBuf,
+			msg:   buf,
 			id:    tEvent.NetworkID,
 			tname: tEvent.TableName,
 			key:   tEvent.Key,
@@ -171,19 +157,22 @@ func (nDB *NetworkDB) handleTableMessage(buf []byte) {
 }
 
 func (nDB *NetworkDB) handleNetworkMessage(buf []byte) {
-	var nEvent networkEventData
-	if err := decodeMessage(buf[1:], &nEvent); err != nil {
+	var nEvent NetworkEvent
+	if err := proto.Unmarshal(buf, &nEvent); err != nil {
 		logrus.Errorf("Error decoding network event message: %v", err)
 		return
 	}
 
 	if rebroadcast := nDB.handleNetworkEvent(&nEvent); rebroadcast {
-		// Copy the buffer since it we cannot rely on the slice not changing
-		newBuf := make([]byte, len(buf))
-		copy(newBuf, buf)
+		var err error
+		buf, err = encodeRawMessage(MessageTypeNetworkEvent, buf)
+		if err != nil {
+			logrus.Errorf("Error marshalling gossip message for network event rebroadcast: %v", err)
+			return
+		}
 
 		nDB.networkBroadcasts.QueueBroadcast(&networkEventMessage{
-			msg:  newBuf,
+			msg:  buf,
 			id:   nEvent.NetworkID,
 			node: nEvent.NodeName,
 		})
@@ -191,8 +180,8 @@ func (nDB *NetworkDB) handleNetworkMessage(buf []byte) {
 }
 
 func (nDB *NetworkDB) handleBulkSync(buf []byte) {
-	var bsm bulkSyncMessage
-	if err := decodeMessage(buf[1:], &bsm); err != nil {
+	var bsm BulkSyncMessage
+	if err := proto.Unmarshal(buf, &bsm); err != nil {
 		logrus.Errorf("Error decoding bulk sync message: %v", err)
 		return
 	}
@@ -221,19 +210,23 @@ func (nDB *NetworkDB) handleBulkSync(buf []byte) {
 }
 
 func (nDB *NetworkDB) handleMessage(buf []byte) {
-	msgType := messageType(buf[0])
-
-	switch msgType {
-	case networkEventMsg:
-		nDB.handleNetworkMessage(buf)
-	case tableEventMsg:
-		nDB.handleTableMessage(buf)
-	case compoundMsg:
-		nDB.handleCompound(buf)
-	case bulkSyncMsg:
-		nDB.handleBulkSync(buf)
+	mType, data, err := decodeMessage(buf)
+	if err != nil {
+		logrus.Errorf("Error decoding gossip message to get message type: %v", err)
+		return
+	}
+
+	switch mType {
+	case MessageTypeNetworkEvent:
+		nDB.handleNetworkMessage(data)
+	case MessageTypeTableEvent:
+		nDB.handleTableMessage(data)
+	case MessageTypeBulkSync:
+		nDB.handleBulkSync(data)
+	case MessageTypeCompound:
+		nDB.handleCompound(data)
 	default:
-		logrus.Errorf("%s: unknown message type %d payload = %v", nDB.config.NodeName, msgType, buf[:8])
+		logrus.Errorf("%s: unknown message type %d", nDB.config.NodeName, mType)
 	}
 }
 
@@ -253,22 +246,22 @@ func (d *delegate) LocalState(join bool) []byte {
 	d.nDB.RLock()
 	defer d.nDB.RUnlock()
 
-	pp := networkPushPull{
+	pp := NetworkPushPull{
 		LTime: d.nDB.networkClock.Time(),
 	}
 
 	for name, nn := range d.nDB.networks {
 		for _, n := range nn {
-			pp.Networks = append(pp.Networks, networkData{
-				LTime:    n.ltime,
-				ID:       n.id,
-				NodeName: name,
-				Leaving:  n.leaving,
+			pp.Networks = append(pp.Networks, &NetworkEntry{
+				LTime:     n.ltime,
+				NetworkID: n.id,
+				NodeName:  name,
+				Leaving:   n.leaving,
 			})
 		}
 	}
 
-	buf, err := encodeMessage(networkPushPullMsg, &pp)
+	buf, err := encodeMessage(MessageTypePushPull, &pp)
 	if err != nil {
 		logrus.Errorf("Failed to encode local network state: %v", err)
 		return nil
@@ -283,12 +276,19 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) {
 		return
 	}
 
-	if messageType(buf[0]) != networkPushPullMsg {
+	var gMsg GossipMessage
+	err := proto.Unmarshal(buf, &gMsg)
+	if err != nil {
+		logrus.Errorf("Error unmarshalling push pull messsage: %v", err)
+		return
+	}
+
+	if gMsg.Type != MessageTypePushPull {
 		logrus.Errorf("Invalid message type %v received from remote", buf[0])
 	}
 
-	pp := networkPushPull{}
-	if err := decodeMessage(buf[1:], &pp); err != nil {
+	pp := NetworkPushPull{}
+	if err := proto.Unmarshal(gMsg.Data, &pp); err != nil {
 		logrus.Errorf("Failed to decode remote network state: %v", err)
 		return
 	}
@@ -298,15 +298,15 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) {
 	}
 
 	for _, n := range pp.Networks {
-		nEvent := &networkEventData{
+		nEvent := &NetworkEvent{
 			LTime:     n.LTime,
 			NodeName:  n.NodeName,
-			NetworkID: n.ID,
-			Event:     networkJoin,
+			NetworkID: n.NetworkID,
+			Type:      NetworkEventTypeJoin,
 		}
 
 		if n.Leaving {
-			nEvent.Event = networkLeave
+			nEvent.Type = NetworkEventTypeLeave
 		}
 
 		d.nDB.handleNetworkEvent(nEvent)

+ 64 - 84
libnetwork/networkdb/message.go

@@ -1,32 +1,6 @@
 package networkdb
 
-import (
-	"bytes"
-	"encoding/binary"
-	"fmt"
-
-	"github.com/hashicorp/go-msgpack/codec"
-)
-
-type messageType uint8
-
-const (
-	// For network join/leave event message
-	networkEventMsg messageType = 1 + iota
-
-	// For pushing/pulling network/node association state
-	networkPushPullMsg
-
-	// For table entry CRUD event message
-	tableEventMsg
-
-	// For building a compound message which packs many different
-	// message types together
-	compoundMsg
-
-	// For syncing table entries in bulk b/w nodes.
-	bulkSyncMsg
-)
+import "github.com/gogo/protobuf/proto"
 
 const (
 	// Max udp message size chosen to avoid network packet
@@ -37,86 +11,92 @@ const (
 	// bytes (num messages)
 	compoundHeaderOverhead = 5
 
-	// Overhead for each embedded message in a compound message 2
+	// Overhead for each embedded message in a compound message 4
 	// bytes (len of embedded message)
-	compoundOverhead = 2
+	compoundOverhead = 4
 )
 
-func decodeMessage(buf []byte, out interface{}) error {
-	var handle codec.MsgpackHandle
-	return codec.NewDecoder(bytes.NewReader(buf), &handle).Decode(out)
+func encodeRawMessage(t MessageType, raw []byte) ([]byte, error) {
+	gMsg := GossipMessage{
+		Type: t,
+		Data: raw,
+	}
+
+	buf, err := proto.Marshal(&gMsg)
+	if err != nil {
+		return nil, err
+	}
+
+	return buf, nil
 }
 
-func encodeMessage(t messageType, msg interface{}) ([]byte, error) {
-	buf := bytes.NewBuffer(nil)
-	buf.WriteByte(uint8(t))
+func encodeMessage(t MessageType, msg interface{}) ([]byte, error) {
+	buf, err := proto.Marshal(msg.(proto.Message))
+	if err != nil {
+		return nil, err
+	}
 
-	handle := codec.MsgpackHandle{}
-	encoder := codec.NewEncoder(buf, &handle)
-	err := encoder.Encode(msg)
-	return buf.Bytes(), err
+	buf, err = encodeRawMessage(t, buf)
+	if err != nil {
+		return nil, err
+	}
+
+	return buf, nil
+}
+
+func decodeMessage(buf []byte) (MessageType, []byte, error) {
+	var gMsg GossipMessage
+
+	err := proto.Unmarshal(buf, &gMsg)
+	if err != nil {
+		return MessageTypeInvalid, nil, err
+	}
+
+	return gMsg.Type, gMsg.Data, nil
 }
 
 // makeCompoundMessage takes a list of messages and generates
 // a single compound message containing all of them
-func makeCompoundMessage(msgs [][]byte) *bytes.Buffer {
-	// Create a local buffer
-	buf := bytes.NewBuffer(nil)
+func makeCompoundMessage(msgs [][]byte) []byte {
+	cMsg := CompoundMessage{}
 
-	// Write out the type
-	buf.WriteByte(uint8(compoundMsg))
+	cMsg.Messages = make([]*CompoundMessage_SimpleMessage, 0, len(msgs))
+	for _, m := range msgs {
+		cMsg.Messages = append(cMsg.Messages, &CompoundMessage_SimpleMessage{
+			Payload: m,
+		})
+	}
 
-	// Write out the number of message
-	binary.Write(buf, binary.BigEndian, uint32(len(msgs)))
+	buf, err := proto.Marshal(&cMsg)
+	if err != nil {
+		return nil
+	}
 
-	// Add the message lengths
-	for _, m := range msgs {
-		binary.Write(buf, binary.BigEndian, uint16(len(m)))
+	gMsg := GossipMessage{
+		Type: MessageTypeCompound,
+		Data: buf,
 	}
 
-	// Append the messages
-	for _, m := range msgs {
-		buf.Write(m)
+	buf, err = proto.Marshal(&gMsg)
+	if err != nil {
+		return nil
 	}
 
 	return buf
 }
 
 // decodeCompoundMessage splits a compound message and returns
-// the slices of individual messages. Also returns the number
-// of truncated messages and any potential error
-func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
-	if len(buf) < 1 {
-		err = fmt.Errorf("missing compound length byte")
-		return
+// the slices of individual messages. Returns any potential error.
+func decodeCompoundMessage(buf []byte) ([][]byte, error) {
+	var cMsg CompoundMessage
+	if err := proto.Unmarshal(buf, &cMsg); err != nil {
+		return nil, err
 	}
-	numParts := binary.BigEndian.Uint32(buf[0:4])
-	buf = buf[4:]
 
-	// Check we have enough bytes
-	if len(buf) < int(numParts*2) {
-		err = fmt.Errorf("truncated len slice")
-		return
+	parts := make([][]byte, 0, len(cMsg.Messages))
+	for _, m := range cMsg.Messages {
+		parts = append(parts, m.Payload)
 	}
 
-	// Decode the lengths
-	lengths := make([]uint16, numParts)
-	for i := 0; i < int(numParts); i++ {
-		lengths[i] = binary.BigEndian.Uint16(buf[i*2 : i*2+2])
-	}
-	buf = buf[numParts*2:]
-
-	// Split each message
-	for idx, msgLen := range lengths {
-		if len(buf) < int(msgLen) {
-			trunc = int(numParts) - idx
-			return
-		}
-
-		// Extract the slice, seek past on the buffer
-		slice := buf[:msgLen]
-		buf = buf[msgLen:]
-		parts = append(parts, slice)
-	}
-	return
+	return parts, nil
 }

+ 7 - 5
libnetwork/networkdb/networkdb.go

@@ -1,5 +1,7 @@
 package networkdb
 
+//go:generate protoc -I.:../Godeps/_workspace/src/github.com/gogo/protobuf  --gogo_out=import_path=github.com/docker/libnetwork/networkdb,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto:. networkdb.proto
+
 import (
 	"fmt"
 	"strings"
@@ -206,7 +208,7 @@ func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error {
 		value: value,
 	}
 
-	if err := nDB.sendTableEvent(tableEntryCreate, nid, tname, key, entry); err != nil {
+	if err := nDB.sendTableEvent(TableEventTypeCreate, nid, tname, key, entry); err != nil {
 		return fmt.Errorf("cannot send table create event: %v", err)
 	}
 
@@ -234,7 +236,7 @@ func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error {
 		value: value,
 	}
 
-	if err := nDB.sendTableEvent(tableEntryUpdate, nid, tname, key, entry); err != nil {
+	if err := nDB.sendTableEvent(TableEventTypeUpdate, nid, tname, key, entry); err != nil {
 		return fmt.Errorf("cannot send table update event: %v", err)
 	}
 
@@ -264,7 +266,7 @@ func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error {
 		deleteTime: time.Now(),
 	}
 
-	if err := nDB.sendTableEvent(tableEntryDelete, nid, tname, key, entry); err != nil {
+	if err := nDB.sendTableEvent(TableEventTypeDelete, nid, tname, key, entry); err != nil {
 		return fmt.Errorf("cannot send table delete event: %v", err)
 	}
 
@@ -352,7 +354,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error {
 	nDB.networkNodes[nid] = append(nDB.networkNodes[nid], nDB.config.NodeName)
 	nDB.Unlock()
 
-	if err := nDB.sendNetworkEvent(nid, networkJoin, ltime); err != nil {
+	if err := nDB.sendNetworkEvent(nid, NetworkEventTypeJoin, ltime); err != nil {
 		return fmt.Errorf("failed to send leave network event for %s: %v", nid, err)
 	}
 
@@ -371,7 +373,7 @@ func (nDB *NetworkDB) JoinNetwork(nid string) error {
 // network.
 func (nDB *NetworkDB) LeaveNetwork(nid string) error {
 	ltime := nDB.networkClock.Increment()
-	if err := nDB.sendNetworkEvent(nid, networkLeave, ltime); err != nil {
+	if err := nDB.sendNetworkEvent(nid, NetworkEventTypeLeave, ltime); err != nil {
 		return fmt.Errorf("failed to send leave network event for %s: %v", nid, err)
 	}
 

+ 2266 - 0
libnetwork/networkdb/networkdb.pb.go

@@ -0,0 +1,2266 @@
+// Code generated by protoc-gen-gogo.
+// source: networkdb.proto
+// DO NOT EDIT!
+
+/*
+	Package networkdb is a generated protocol buffer package.
+
+	It is generated from these files:
+		networkdb.proto
+
+	It has these top-level messages:
+		GossipMessage
+		NetworkEvent
+		NetworkEntry
+		NetworkPushPull
+		TableEvent
+		BulkSyncMessage
+		CompoundMessage
+*/
+package networkdb
+
+import proto "github.com/gogo/protobuf/proto"
+import fmt "fmt"
+import math "math"
+import _ "github.com/gogo/protobuf/gogoproto"
+
+import github_com_hashicorp_serf_serf "github.com/hashicorp/serf/serf"
+
+import strings "strings"
+import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
+import sort "sort"
+import strconv "strconv"
+import reflect "reflect"
+
+import io "io"
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+const _ = proto.GoGoProtoPackageIsVersion1
+
+// MessageType enum defines all the core message types that networkdb
+// uses to communicate to peers.
+type MessageType int32
+
+const (
+	MessageTypeInvalid MessageType = 0
+	// NetworEvent message type is used to communicate network
+	// attachments on the node.
+	MessageTypeNetworkEvent MessageType = 1
+	// TableEvent message type is used to communicate any table
+	// CRUD event that happened on the node.
+	MessageTypeTableEvent MessageType = 2
+	// PushPull message type is used to syncup all network
+	// attachments on a peer node either during startup of this
+	// node or with a random peer node periodically thereafter.
+	MessageTypePushPull MessageType = 3
+	// BulkSync message is used to bulksync the whole networkdb
+	// state with a peer node during startup of this node or with
+	// a random peer node periodically thereafter.
+	MessageTypeBulkSync MessageType = 4
+	// Compound message type is used to form a compound message
+	// which is a pack of many message of above types, packed into
+	// a single compound message.
+	MessageTypeCompound MessageType = 5
+)
+
+var MessageType_name = map[int32]string{
+	0: "INVALID",
+	1: "NETWORK_EVENT",
+	2: "TABLE_EVENT",
+	3: "PUSH_PULL",
+	4: "BULK_SYNC",
+	5: "COMPOUND",
+}
+var MessageType_value = map[string]int32{
+	"INVALID":       0,
+	"NETWORK_EVENT": 1,
+	"TABLE_EVENT":   2,
+	"PUSH_PULL":     3,
+	"BULK_SYNC":     4,
+	"COMPOUND":      5,
+}
+
+func (x MessageType) String() string {
+	return proto.EnumName(MessageType_name, int32(x))
+}
+func (MessageType) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{0} }
+
+type NetworkEvent_Type int32
+
+const (
+	NetworkEventTypeInvalid NetworkEvent_Type = 0
+	// Join event is generated when this node joins a network.
+	NetworkEventTypeJoin NetworkEvent_Type = 1
+	// Leave event is generated when this node leaves a network.
+	NetworkEventTypeLeave NetworkEvent_Type = 2
+)
+
+var NetworkEvent_Type_name = map[int32]string{
+	0: "INVALID",
+	1: "JOIN",
+	2: "LEAVE",
+}
+var NetworkEvent_Type_value = map[string]int32{
+	"INVALID": 0,
+	"JOIN":    1,
+	"LEAVE":   2,
+}
+
+func (x NetworkEvent_Type) String() string {
+	return proto.EnumName(NetworkEvent_Type_name, int32(x))
+}
+func (NetworkEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1, 0} }
+
+type TableEvent_Type int32
+
+const (
+	TableEventTypeInvalid TableEvent_Type = 0
+	// Create signifies that this table entry was just
+	// created.
+	TableEventTypeCreate TableEvent_Type = 1
+	// Update signifies that this table entry was just
+	// updated.
+	TableEventTypeUpdate TableEvent_Type = 2
+	// Delete signifies that this table entry was just
+	// updated.
+	TableEventTypeDelete TableEvent_Type = 3
+)
+
+var TableEvent_Type_name = map[int32]string{
+	0: "INVALID",
+	1: "CREATE",
+	2: "UPDATE",
+	3: "DELETE",
+}
+var TableEvent_Type_value = map[string]int32{
+	"INVALID": 0,
+	"CREATE":  1,
+	"UPDATE":  2,
+	"DELETE":  3,
+}
+
+func (x TableEvent_Type) String() string {
+	return proto.EnumName(TableEvent_Type_name, int32(x))
+}
+func (TableEvent_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{4, 0} }
+
+// GossipMessage is a basic message header used by all messages types.
+type GossipMessage struct {
+	Type MessageType `protobuf:"varint,1,opt,name=type,proto3,enum=networkdb.MessageType" json:"type,omitempty"`
+	Data []byte      `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (m *GossipMessage) Reset()                    { *m = GossipMessage{} }
+func (*GossipMessage) ProtoMessage()               {}
+func (*GossipMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{0} }
+
+// NetworkEvent message payload definition.
+type NetworkEvent struct {
+	Type NetworkEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=networkdb.NetworkEvent_Type" json:"type,omitempty"`
+	// Lamport time using a network lamport clock indicating the
+	// time this event was generated on the node where it was
+	// generated.
+	LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,2,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"`
+	// Source node name.
+	NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
+	// ID of the network for which the event is generated.
+	NetworkID string `protobuf:"bytes,4,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"`
+}
+
+func (m *NetworkEvent) Reset()                    { *m = NetworkEvent{} }
+func (*NetworkEvent) ProtoMessage()               {}
+func (*NetworkEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{1} }
+
+// NetworkEntry for push pull of networks.
+type NetworkEntry struct {
+	// ID of the network
+	NetworkID string `protobuf:"bytes,1,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"`
+	// Latest lamport time of the network attachment when this
+	// network event was recorded.
+	LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,2,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"`
+	// Source node name where this network attachment happened.
+	NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
+	// Indicates if a leave from this network is in progress.
+	Leaving bool `protobuf:"varint,4,opt,name=leaving,proto3" json:"leaving,omitempty"`
+}
+
+func (m *NetworkEntry) Reset()                    { *m = NetworkEntry{} }
+func (*NetworkEntry) ProtoMessage()               {}
+func (*NetworkEntry) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{2} }
+
+// NetworkPushpull message payload definition.
+type NetworkPushPull struct {
+	// Lamport time when this push pull was initiated.
+	LTime    github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,1,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"`
+	Networks []*NetworkEntry                            `protobuf:"bytes,2,rep,name=networks" json:"networks,omitempty"`
+}
+
+func (m *NetworkPushPull) Reset()                    { *m = NetworkPushPull{} }
+func (*NetworkPushPull) ProtoMessage()               {}
+func (*NetworkPushPull) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{3} }
+
+func (m *NetworkPushPull) GetNetworks() []*NetworkEntry {
+	if m != nil {
+		return m.Networks
+	}
+	return nil
+}
+
+// TableEvent message payload definition.
+type TableEvent struct {
+	Type TableEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=networkdb.TableEvent_Type" json:"type,omitempty"`
+	// Lamport time when this event was generated.
+	LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,2,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"`
+	// Node name where this event originated.
+	NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
+	// ID of the network to which this table entry belongs.
+	NetworkID string `protobuf:"bytes,4,opt,name=network_id,json=networkId,proto3" json:"network_id,omitempty"`
+	// Name of the table to which this table entry belongs.
+	TableName string `protobuf:"bytes,5,opt,name=table_name,json=tableName,proto3" json:"table_name,omitempty"`
+	// Entry key.
+	Key string `protobuf:"bytes,6,opt,name=key,proto3" json:"key,omitempty"`
+	// Entry value.
+	Value []byte `protobuf:"bytes,7,opt,name=value,proto3" json:"value,omitempty"`
+}
+
+func (m *TableEvent) Reset()                    { *m = TableEvent{} }
+func (*TableEvent) ProtoMessage()               {}
+func (*TableEvent) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{4} }
+
+// BulkSync message payload definition.
+type BulkSyncMessage struct {
+	// Lamport time when this bulk sync was initiated.
+	LTime github_com_hashicorp_serf_serf.LamportTime `protobuf:"varint,1,opt,name=l_time,json=lTime,proto3,customtype=github.com/hashicorp/serf/serf.LamportTime" json:"l_time"`
+	// Indicates if this bulksync is a response to a bulk sync
+	// request from a peer node.
+	Unsolicited bool `protobuf:"varint,2,opt,name=unsolicited,proto3" json:"unsolicited,omitempty"`
+	// Name of the node which is producing this bulk sync message.
+	NodeName string `protobuf:"bytes,3,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
+	// List of network names whose table entries are getting
+	// bulksynced as part of the bulksync.
+	Networks []string `protobuf:"bytes,4,rep,name=networks" json:"networks,omitempty"`
+	// Bulksync payload
+	Payload []byte `protobuf:"bytes,5,opt,name=payload,proto3" json:"payload,omitempty"`
+}
+
+func (m *BulkSyncMessage) Reset()                    { *m = BulkSyncMessage{} }
+func (*BulkSyncMessage) ProtoMessage()               {}
+func (*BulkSyncMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{5} }
+
+// Compound message payload definition.
+type CompoundMessage struct {
+	// A list of simple messages.
+	Messages []*CompoundMessage_SimpleMessage `protobuf:"bytes,1,rep,name=messages" json:"messages,omitempty"`
+}
+
+func (m *CompoundMessage) Reset()                    { *m = CompoundMessage{} }
+func (*CompoundMessage) ProtoMessage()               {}
+func (*CompoundMessage) Descriptor() ([]byte, []int) { return fileDescriptorNetworkdb, []int{6} }
+
+func (m *CompoundMessage) GetMessages() []*CompoundMessage_SimpleMessage {
+	if m != nil {
+		return m.Messages
+	}
+	return nil
+}
+
+type CompoundMessage_SimpleMessage struct {
+	// Bytestring payload of a message constructed using
+	// other message type definitions.
+	Payload []byte `protobuf:"bytes,1,opt,name=Payload,json=payload,proto3" json:"Payload,omitempty"`
+}
+
+func (m *CompoundMessage_SimpleMessage) Reset()      { *m = CompoundMessage_SimpleMessage{} }
+func (*CompoundMessage_SimpleMessage) ProtoMessage() {}
+func (*CompoundMessage_SimpleMessage) Descriptor() ([]byte, []int) {
+	return fileDescriptorNetworkdb, []int{6, 0}
+}
+
+func init() {
+	proto.RegisterType((*GossipMessage)(nil), "networkdb.GossipMessage")
+	proto.RegisterType((*NetworkEvent)(nil), "networkdb.NetworkEvent")
+	proto.RegisterType((*NetworkEntry)(nil), "networkdb.NetworkEntry")
+	proto.RegisterType((*NetworkPushPull)(nil), "networkdb.NetworkPushPull")
+	proto.RegisterType((*TableEvent)(nil), "networkdb.TableEvent")
+	proto.RegisterType((*BulkSyncMessage)(nil), "networkdb.BulkSyncMessage")
+	proto.RegisterType((*CompoundMessage)(nil), "networkdb.CompoundMessage")
+	proto.RegisterType((*CompoundMessage_SimpleMessage)(nil), "networkdb.CompoundMessage.SimpleMessage")
+	proto.RegisterEnum("networkdb.MessageType", MessageType_name, MessageType_value)
+	proto.RegisterEnum("networkdb.NetworkEvent_Type", NetworkEvent_Type_name, NetworkEvent_Type_value)
+	proto.RegisterEnum("networkdb.TableEvent_Type", TableEvent_Type_name, TableEvent_Type_value)
+}
+func (this *GossipMessage) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 6)
+	s = append(s, "&networkdb.GossipMessage{")
+	s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n")
+	s = append(s, "Data: "+fmt.Sprintf("%#v", this.Data)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *NetworkEvent) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 8)
+	s = append(s, "&networkdb.NetworkEvent{")
+	s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n")
+	s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n")
+	s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n")
+	s = append(s, "NetworkID: "+fmt.Sprintf("%#v", this.NetworkID)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *NetworkEntry) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 8)
+	s = append(s, "&networkdb.NetworkEntry{")
+	s = append(s, "NetworkID: "+fmt.Sprintf("%#v", this.NetworkID)+",\n")
+	s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n")
+	s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n")
+	s = append(s, "Leaving: "+fmt.Sprintf("%#v", this.Leaving)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *NetworkPushPull) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 6)
+	s = append(s, "&networkdb.NetworkPushPull{")
+	s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n")
+	if this.Networks != nil {
+		s = append(s, "Networks: "+fmt.Sprintf("%#v", this.Networks)+",\n")
+	}
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *TableEvent) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 11)
+	s = append(s, "&networkdb.TableEvent{")
+	s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n")
+	s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n")
+	s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n")
+	s = append(s, "NetworkID: "+fmt.Sprintf("%#v", this.NetworkID)+",\n")
+	s = append(s, "TableName: "+fmt.Sprintf("%#v", this.TableName)+",\n")
+	s = append(s, "Key: "+fmt.Sprintf("%#v", this.Key)+",\n")
+	s = append(s, "Value: "+fmt.Sprintf("%#v", this.Value)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *BulkSyncMessage) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 9)
+	s = append(s, "&networkdb.BulkSyncMessage{")
+	s = append(s, "LTime: "+fmt.Sprintf("%#v", this.LTime)+",\n")
+	s = append(s, "Unsolicited: "+fmt.Sprintf("%#v", this.Unsolicited)+",\n")
+	s = append(s, "NodeName: "+fmt.Sprintf("%#v", this.NodeName)+",\n")
+	s = append(s, "Networks: "+fmt.Sprintf("%#v", this.Networks)+",\n")
+	s = append(s, "Payload: "+fmt.Sprintf("%#v", this.Payload)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *CompoundMessage) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 5)
+	s = append(s, "&networkdb.CompoundMessage{")
+	if this.Messages != nil {
+		s = append(s, "Messages: "+fmt.Sprintf("%#v", this.Messages)+",\n")
+	}
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func (this *CompoundMessage_SimpleMessage) GoString() string {
+	if this == nil {
+		return "nil"
+	}
+	s := make([]string, 0, 5)
+	s = append(s, "&networkdb.CompoundMessage_SimpleMessage{")
+	s = append(s, "Payload: "+fmt.Sprintf("%#v", this.Payload)+",\n")
+	s = append(s, "}")
+	return strings.Join(s, "")
+}
+func valueToGoStringNetworkdb(v interface{}, typ string) string {
+	rv := reflect.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect.Indirect(rv).Interface()
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
+}
+func extensionToGoStringNetworkdb(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
+	if e == nil {
+		return "nil"
+	}
+	s := "map[int32]proto.Extension{"
+	keys := make([]int, 0, len(e))
+	for k := range e {
+		keys = append(keys, int(k))
+	}
+	sort.Ints(keys)
+	ss := []string{}
+	for _, k := range keys {
+		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
+	}
+	s += strings.Join(ss, ",") + "}"
+	return s
+}
+func (m *GossipMessage) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *GossipMessage) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Type != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.Type))
+	}
+	if len(m.Data) > 0 {
+		data[i] = 0x12
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.Data)))
+		i += copy(data[i:], m.Data)
+	}
+	return i, nil
+}
+
+func (m *NetworkEvent) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *NetworkEvent) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Type != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.Type))
+	}
+	if m.LTime != 0 {
+		data[i] = 0x10
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.LTime))
+	}
+	if len(m.NodeName) > 0 {
+		data[i] = 0x1a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName)))
+		i += copy(data[i:], m.NodeName)
+	}
+	if len(m.NetworkID) > 0 {
+		data[i] = 0x22
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NetworkID)))
+		i += copy(data[i:], m.NetworkID)
+	}
+	return i, nil
+}
+
+func (m *NetworkEntry) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *NetworkEntry) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.NetworkID) > 0 {
+		data[i] = 0xa
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NetworkID)))
+		i += copy(data[i:], m.NetworkID)
+	}
+	if m.LTime != 0 {
+		data[i] = 0x10
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.LTime))
+	}
+	if len(m.NodeName) > 0 {
+		data[i] = 0x1a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName)))
+		i += copy(data[i:], m.NodeName)
+	}
+	if m.Leaving {
+		data[i] = 0x20
+		i++
+		if m.Leaving {
+			data[i] = 1
+		} else {
+			data[i] = 0
+		}
+		i++
+	}
+	return i, nil
+}
+
+func (m *NetworkPushPull) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *NetworkPushPull) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.LTime != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.LTime))
+	}
+	if len(m.Networks) > 0 {
+		for _, msg := range m.Networks {
+			data[i] = 0x12
+			i++
+			i = encodeVarintNetworkdb(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	return i, nil
+}
+
+func (m *TableEvent) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *TableEvent) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.Type != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.Type))
+	}
+	if m.LTime != 0 {
+		data[i] = 0x10
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.LTime))
+	}
+	if len(m.NodeName) > 0 {
+		data[i] = 0x1a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName)))
+		i += copy(data[i:], m.NodeName)
+	}
+	if len(m.NetworkID) > 0 {
+		data[i] = 0x22
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NetworkID)))
+		i += copy(data[i:], m.NetworkID)
+	}
+	if len(m.TableName) > 0 {
+		data[i] = 0x2a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.TableName)))
+		i += copy(data[i:], m.TableName)
+	}
+	if len(m.Key) > 0 {
+		data[i] = 0x32
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.Key)))
+		i += copy(data[i:], m.Key)
+	}
+	if len(m.Value) > 0 {
+		data[i] = 0x3a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.Value)))
+		i += copy(data[i:], m.Value)
+	}
+	return i, nil
+}
+
+func (m *BulkSyncMessage) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *BulkSyncMessage) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if m.LTime != 0 {
+		data[i] = 0x8
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(m.LTime))
+	}
+	if m.Unsolicited {
+		data[i] = 0x10
+		i++
+		if m.Unsolicited {
+			data[i] = 1
+		} else {
+			data[i] = 0
+		}
+		i++
+	}
+	if len(m.NodeName) > 0 {
+		data[i] = 0x1a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.NodeName)))
+		i += copy(data[i:], m.NodeName)
+	}
+	if len(m.Networks) > 0 {
+		for _, s := range m.Networks {
+			data[i] = 0x22
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				data[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			data[i] = uint8(l)
+			i++
+			i += copy(data[i:], s)
+		}
+	}
+	if len(m.Payload) > 0 {
+		data[i] = 0x2a
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.Payload)))
+		i += copy(data[i:], m.Payload)
+	}
+	return i, nil
+}
+
+func (m *CompoundMessage) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *CompoundMessage) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Messages) > 0 {
+		for _, msg := range m.Messages {
+			data[i] = 0xa
+			i++
+			i = encodeVarintNetworkdb(data, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(data[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
+	return i, nil
+}
+
+func (m *CompoundMessage_SimpleMessage) Marshal() (data []byte, err error) {
+	size := m.Size()
+	data = make([]byte, size)
+	n, err := m.MarshalTo(data)
+	if err != nil {
+		return nil, err
+	}
+	return data[:n], nil
+}
+
+func (m *CompoundMessage_SimpleMessage) MarshalTo(data []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Payload) > 0 {
+		data[i] = 0xa
+		i++
+		i = encodeVarintNetworkdb(data, i, uint64(len(m.Payload)))
+		i += copy(data[i:], m.Payload)
+	}
+	return i, nil
+}
+
+func encodeFixed64Networkdb(data []byte, offset int, v uint64) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	data[offset+4] = uint8(v >> 32)
+	data[offset+5] = uint8(v >> 40)
+	data[offset+6] = uint8(v >> 48)
+	data[offset+7] = uint8(v >> 56)
+	return offset + 8
+}
+func encodeFixed32Networkdb(data []byte, offset int, v uint32) int {
+	data[offset] = uint8(v)
+	data[offset+1] = uint8(v >> 8)
+	data[offset+2] = uint8(v >> 16)
+	data[offset+3] = uint8(v >> 24)
+	return offset + 4
+}
+func encodeVarintNetworkdb(data []byte, offset int, v uint64) int {
+	for v >= 1<<7 {
+		data[offset] = uint8(v&0x7f | 0x80)
+		v >>= 7
+		offset++
+	}
+	data[offset] = uint8(v)
+	return offset + 1
+}
+func (m *GossipMessage) Size() (n int) {
+	var l int
+	_ = l
+	if m.Type != 0 {
+		n += 1 + sovNetworkdb(uint64(m.Type))
+	}
+	l = len(m.Data)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	return n
+}
+
+func (m *NetworkEvent) Size() (n int) {
+	var l int
+	_ = l
+	if m.Type != 0 {
+		n += 1 + sovNetworkdb(uint64(m.Type))
+	}
+	if m.LTime != 0 {
+		n += 1 + sovNetworkdb(uint64(m.LTime))
+	}
+	l = len(m.NodeName)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	l = len(m.NetworkID)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	return n
+}
+
+func (m *NetworkEntry) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.NetworkID)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	if m.LTime != 0 {
+		n += 1 + sovNetworkdb(uint64(m.LTime))
+	}
+	l = len(m.NodeName)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	if m.Leaving {
+		n += 2
+	}
+	return n
+}
+
+func (m *NetworkPushPull) Size() (n int) {
+	var l int
+	_ = l
+	if m.LTime != 0 {
+		n += 1 + sovNetworkdb(uint64(m.LTime))
+	}
+	if len(m.Networks) > 0 {
+		for _, e := range m.Networks {
+			l = e.Size()
+			n += 1 + l + sovNetworkdb(uint64(l))
+		}
+	}
+	return n
+}
+
+func (m *TableEvent) Size() (n int) {
+	var l int
+	_ = l
+	if m.Type != 0 {
+		n += 1 + sovNetworkdb(uint64(m.Type))
+	}
+	if m.LTime != 0 {
+		n += 1 + sovNetworkdb(uint64(m.LTime))
+	}
+	l = len(m.NodeName)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	l = len(m.NetworkID)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	l = len(m.TableName)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	l = len(m.Key)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	l = len(m.Value)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	return n
+}
+
+func (m *BulkSyncMessage) Size() (n int) {
+	var l int
+	_ = l
+	if m.LTime != 0 {
+		n += 1 + sovNetworkdb(uint64(m.LTime))
+	}
+	if m.Unsolicited {
+		n += 2
+	}
+	l = len(m.NodeName)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	if len(m.Networks) > 0 {
+		for _, s := range m.Networks {
+			l = len(s)
+			n += 1 + l + sovNetworkdb(uint64(l))
+		}
+	}
+	l = len(m.Payload)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	return n
+}
+
+func (m *CompoundMessage) Size() (n int) {
+	var l int
+	_ = l
+	if len(m.Messages) > 0 {
+		for _, e := range m.Messages {
+			l = e.Size()
+			n += 1 + l + sovNetworkdb(uint64(l))
+		}
+	}
+	return n
+}
+
+func (m *CompoundMessage_SimpleMessage) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.Payload)
+	if l > 0 {
+		n += 1 + l + sovNetworkdb(uint64(l))
+	}
+	return n
+}
+
+func sovNetworkdb(x uint64) (n int) {
+	for {
+		n++
+		x >>= 7
+		if x == 0 {
+			break
+		}
+	}
+	return n
+}
+func sozNetworkdb(x uint64) (n int) {
+	return sovNetworkdb(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+func (this *GossipMessage) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&GossipMessage{`,
+		`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
+		`Data:` + fmt.Sprintf("%v", this.Data) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *NetworkEvent) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&NetworkEvent{`,
+		`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
+		`LTime:` + fmt.Sprintf("%v", this.LTime) + `,`,
+		`NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`,
+		`NetworkID:` + fmt.Sprintf("%v", this.NetworkID) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *NetworkEntry) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&NetworkEntry{`,
+		`NetworkID:` + fmt.Sprintf("%v", this.NetworkID) + `,`,
+		`LTime:` + fmt.Sprintf("%v", this.LTime) + `,`,
+		`NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`,
+		`Leaving:` + fmt.Sprintf("%v", this.Leaving) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *NetworkPushPull) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&NetworkPushPull{`,
+		`LTime:` + fmt.Sprintf("%v", this.LTime) + `,`,
+		`Networks:` + strings.Replace(fmt.Sprintf("%v", this.Networks), "NetworkEntry", "NetworkEntry", 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *TableEvent) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&TableEvent{`,
+		`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
+		`LTime:` + fmt.Sprintf("%v", this.LTime) + `,`,
+		`NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`,
+		`NetworkID:` + fmt.Sprintf("%v", this.NetworkID) + `,`,
+		`TableName:` + fmt.Sprintf("%v", this.TableName) + `,`,
+		`Key:` + fmt.Sprintf("%v", this.Key) + `,`,
+		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *BulkSyncMessage) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&BulkSyncMessage{`,
+		`LTime:` + fmt.Sprintf("%v", this.LTime) + `,`,
+		`Unsolicited:` + fmt.Sprintf("%v", this.Unsolicited) + `,`,
+		`NodeName:` + fmt.Sprintf("%v", this.NodeName) + `,`,
+		`Networks:` + fmt.Sprintf("%v", this.Networks) + `,`,
+		`Payload:` + fmt.Sprintf("%v", this.Payload) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *CompoundMessage) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&CompoundMessage{`,
+		`Messages:` + strings.Replace(fmt.Sprintf("%v", this.Messages), "CompoundMessage_SimpleMessage", "CompoundMessage_SimpleMessage", 1) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func (this *CompoundMessage_SimpleMessage) String() string {
+	if this == nil {
+		return "nil"
+	}
+	s := strings.Join([]string{`&CompoundMessage_SimpleMessage{`,
+		`Payload:` + fmt.Sprintf("%v", this.Payload) + `,`,
+		`}`,
+	}, "")
+	return s
+}
+func valueToStringNetworkdb(v interface{}) string {
+	rv := reflect.ValueOf(v)
+	if rv.IsNil() {
+		return "nil"
+	}
+	pv := reflect.Indirect(rv).Interface()
+	return fmt.Sprintf("*%v", pv)
+}
+func (m *GossipMessage) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: GossipMessage: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: GossipMessage: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
+			}
+			m.Type = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Type |= (MessageType(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Data = append(m.Data[:0], data[iNdEx:postIndex]...)
+			if m.Data == nil {
+				m.Data = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *NetworkEvent) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: NetworkEvent: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: NetworkEvent: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
+			}
+			m.Type = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Type |= (NetworkEvent_Type(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType)
+			}
+			m.LTime = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NodeName = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NetworkID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NetworkID = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *NetworkEntry) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: NetworkEntry: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: NetworkEntry: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NetworkID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NetworkID = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType)
+			}
+			m.LTime = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NodeName = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Leaving", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				v |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Leaving = bool(v != 0)
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *NetworkPushPull) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: NetworkPushPull: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: NetworkPushPull: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType)
+			}
+			m.LTime = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Networks", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Networks = append(m.Networks, &NetworkEntry{})
+			if err := m.Networks[len(m.Networks)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *TableEvent) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: TableEvent: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: TableEvent: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
+			}
+			m.Type = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.Type |= (TableEvent_Type(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType)
+			}
+			m.LTime = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NodeName = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NetworkID", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NetworkID = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field TableName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.TableName = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Key = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 7:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Value = append(m.Value[:0], data[iNdEx:postIndex]...)
+			if m.Value == nil {
+				m.Value = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *BulkSyncMessage) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: BulkSyncMessage: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: BulkSyncMessage: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LTime", wireType)
+			}
+			m.LTime = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				m.LTime |= (github_com_hashicorp_serf_serf.LamportTime(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Unsolicited", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				v |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Unsolicited = bool(v != 0)
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field NodeName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.NodeName = string(data[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Networks", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Networks = append(m.Networks, string(data[iNdEx:postIndex]))
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Payload = append(m.Payload[:0], data[iNdEx:postIndex]...)
+			if m.Payload == nil {
+				m.Payload = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *CompoundMessage) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: CompoundMessage: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: CompoundMessage: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Messages = append(m.Messages, &CompoundMessage_SimpleMessage{})
+			if err := m.Messages[len(m.Messages)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *CompoundMessage_SimpleMessage) Unmarshal(data []byte) error {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: SimpleMessage: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: SimpleMessage: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Payload", wireType)
+			}
+			var byteLen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				byteLen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if byteLen < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			postIndex := iNdEx + byteLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Payload = append(m.Payload[:0], data[iNdEx:postIndex]...)
+			if m.Payload == nil {
+				m.Payload = []byte{}
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipNetworkdb(data[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthNetworkdb
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func skipNetworkdb(data []byte) (n int, err error) {
+	l := len(data)
+	iNdEx := 0
+	for iNdEx < l {
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return 0, ErrIntOverflowNetworkdb
+			}
+			if iNdEx >= l {
+				return 0, io.ErrUnexpectedEOF
+			}
+			b := data[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		wireType := int(wire & 0x7)
+		switch wireType {
+		case 0:
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				iNdEx++
+				if data[iNdEx-1] < 0x80 {
+					break
+				}
+			}
+			return iNdEx, nil
+		case 1:
+			iNdEx += 8
+			return iNdEx, nil
+		case 2:
+			var length int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return 0, ErrIntOverflowNetworkdb
+				}
+				if iNdEx >= l {
+					return 0, io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				length |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			iNdEx += length
+			if length < 0 {
+				return 0, ErrInvalidLengthNetworkdb
+			}
+			return iNdEx, nil
+		case 3:
+			for {
+				var innerWire uint64
+				var start int = iNdEx
+				for shift := uint(0); ; shift += 7 {
+					if shift >= 64 {
+						return 0, ErrIntOverflowNetworkdb
+					}
+					if iNdEx >= l {
+						return 0, io.ErrUnexpectedEOF
+					}
+					b := data[iNdEx]
+					iNdEx++
+					innerWire |= (uint64(b) & 0x7F) << shift
+					if b < 0x80 {
+						break
+					}
+				}
+				innerWireType := int(innerWire & 0x7)
+				if innerWireType == 4 {
+					break
+				}
+				next, err := skipNetworkdb(data[start:])
+				if err != nil {
+					return 0, err
+				}
+				iNdEx = start + next
+			}
+			return iNdEx, nil
+		case 4:
+			return iNdEx, nil
+		case 5:
+			iNdEx += 4
+			return iNdEx, nil
+		default:
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
+		}
+	}
+	panic("unreachable")
+}
+
+var (
+	ErrInvalidLengthNetworkdb = fmt.Errorf("proto: negative length found during unmarshaling")
+	ErrIntOverflowNetworkdb   = fmt.Errorf("proto: integer overflow")
+)
+
+var fileDescriptorNetworkdb = []byte{
+	// 812 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x95, 0x4d, 0x6f, 0xe2, 0x46,
+	0x18, 0xc7, 0x31, 0x18, 0x02, 0x0f, 0xd0, 0x20, 0x27, 0x4d, 0x5c, 0xa7, 0x25, 0x91, 0x9b, 0x46,
+	0x14, 0x55, 0x4e, 0x95, 0x7c, 0x02, 0x5e, 0xac, 0x96, 0xc4, 0x31, 0xc8, 0x40, 0xaa, 0x9e, 0x90,
+	0xc1, 0x53, 0xb0, 0x62, 0x6c, 0x0b, 0x9b, 0x54, 0xdc, 0xaa, 0x9e, 0xa2, 0xde, 0x7a, 0xad, 0xd4,
+	0x53, 0x7b, 0xee, 0x07, 0xe8, 0xa1, 0xe7, 0xa8, 0xa7, 0xf6, 0xb6, 0xda, 0x43, 0xb4, 0xc9, 0x27,
+	0xd8, 0x8f, 0xb0, 0xe3, 0xc1, 0x86, 0x81, 0x44, 0xb9, 0xec, 0x6a, 0xb5, 0x07, 0xc3, 0xbc, 0xfc,
+	0xe6, 0xd1, 0xff, 0x79, 0xe6, 0x3f, 0x33, 0xb0, 0x69, 0x23, 0xff, 0x47, 0x67, 0x72, 0x65, 0xf4,
+	0x25, 0x77, 0xe2, 0xf8, 0x0e, 0x97, 0x59, 0x0c, 0x08, 0xdb, 0x43, 0x67, 0xe8, 0x90, 0xd1, 0xe3,
+	0xa0, 0x35, 0x07, 0xc4, 0x26, 0xe4, 0xbf, 0x71, 0x3c, 0xcf, 0x74, 0x2f, 0x90, 0xe7, 0xe9, 0x43,
+	0xc4, 0x95, 0x81, 0xf5, 0x67, 0x2e, 0xe2, 0x99, 0x03, 0xa6, 0xf4, 0xd1, 0xc9, 0x8e, 0xb4, 0x8c,
+	0x18, 0x12, 0x1d, 0x3c, 0xab, 0x11, 0x86, 0xe3, 0x80, 0x35, 0x74, 0x5f, 0xe7, 0xe3, 0x98, 0xcd,
+	0x69, 0xa4, 0x2d, 0xde, 0xc7, 0x21, 0xa7, 0xce, 0xd7, 0xc8, 0xd7, 0xc8, 0xf6, 0xb9, 0xaf, 0x57,
+	0x02, 0x7e, 0x4a, 0x05, 0xa4, 0x31, 0x89, 0x0a, 0xdb, 0x80, 0x94, 0xd5, 0xf3, 0xcd, 0x31, 0x22,
+	0x81, 0xd9, 0xea, 0xc9, 0xed, 0xdd, 0x7e, 0xec, 0xe5, 0xdd, 0x7e, 0x79, 0x68, 0xfa, 0xa3, 0x69,
+	0x5f, 0x1a, 0x38, 0xe3, 0xe3, 0x91, 0xee, 0x8d, 0xcc, 0x81, 0x33, 0x71, 0x8f, 0x3d, 0x34, 0xf9,
+	0x81, 0xfc, 0x48, 0x8a, 0x3e, 0x76, 0x9d, 0x89, 0xdf, 0xc1, 0x2b, 0xb5, 0xa4, 0x15, 0xfc, 0x71,
+	0x7b, 0x90, 0xb1, 0x1d, 0x03, 0xf5, 0x6c, 0x1d, 0x47, 0x4b, 0xe0, 0x68, 0x19, 0x2d, 0x1d, 0x0c,
+	0xa8, 0xb8, 0xcf, 0x7d, 0x05, 0x10, 0x8a, 0xe9, 0x99, 0x06, 0xcf, 0x06, 0xb3, 0xd5, 0xfc, 0xc3,
+	0xdd, 0x7e, 0x26, 0x14, 0xd6, 0xa8, 0x6b, 0x51, 0xfd, 0x1a, 0x86, 0x78, 0xc3, 0x00, 0x1b, 0x88,
+	0xe4, 0x4a, 0xb0, 0xd1, 0x50, 0x2f, 0x2b, 0x4a, 0xa3, 0x5e, 0x88, 0x09, 0x7b, 0xbf, 0xfc, 0x7e,
+	0xb0, 0x4b, 0x27, 0x12, 0x20, 0x0d, 0xfb, 0x5a, 0xb7, 0x4c, 0x83, 0x13, 0x81, 0x3d, 0x6b, 0x36,
+	0xd4, 0x02, 0x23, 0xf0, 0x18, 0xdb, 0x5e, 0xc7, 0xce, 0x1c, 0xd3, 0xe6, 0x0e, 0x21, 0xa9, 0xc8,
+	0x95, 0x4b, 0xb9, 0x10, 0x17, 0x3e, 0xc1, 0xd0, 0xc7, 0xeb, 0x90, 0x82, 0xf4, 0x6b, 0x24, 0xe4,
+	0x6e, 0xfe, 0x28, 0xc6, 0xfe, 0xfe, 0xb3, 0x48, 0x14, 0x88, 0xff, 0x30, 0xcb, 0x1a, 0xdb, 0xfe,
+	0x64, 0xb6, 0x96, 0x09, 0xf3, 0x7c, 0x26, 0xef, 0xad, 0xbe, 0x3c, 0x6c, 0x58, 0x58, 0xbd, 0x69,
+	0x0f, 0x49, 0x71, 0xd3, 0x5a, 0xd4, 0x15, 0x7f, 0x65, 0x60, 0x33, 0x94, 0xd6, 0x9a, 0x7a, 0xa3,
+	0xd6, 0xd4, 0xb2, 0x28, 0x55, 0xcc, 0xdb, 0xaa, 0x3a, 0x85, 0x74, 0x98, 0xad, 0x87, 0x53, 0x4c,
+	0x94, 0xb2, 0x27, 0xbb, 0x4f, 0xd8, 0x2e, 0xa8, 0x9c, 0xb6, 0x00, 0xc5, 0x7f, 0x13, 0x00, 0x1d,
+	0xbd, 0x6f, 0xa1, 0xb9, 0x6d, 0xa5, 0x15, 0xdb, 0x0a, 0xd4, 0xfa, 0x25, 0xf4, 0xc1, 0x9b, 0x96,
+	0xfb, 0x0c, 0xc0, 0x0f, 0xe4, 0xce, 0x63, 0x25, 0x49, 0xac, 0x0c, 0x19, 0x21, 0xc1, 0x0a, 0x90,
+	0xb8, 0x42, 0x33, 0x3e, 0x45, 0xc6, 0x83, 0x26, 0xb7, 0x0d, 0x49, 0xec, 0xdd, 0x29, 0xe2, 0x37,
+	0xc8, 0x99, 0x9e, 0x77, 0xc4, 0xbf, 0x22, 0xef, 0x1f, 0xd1, 0xde, 0x27, 0x7e, 0x5d, 0x56, 0x83,
+	0x76, 0xfe, 0x21, 0xa4, 0x6a, 0x9a, 0x5c, 0xe9, 0xc8, 0x91, 0xf7, 0x57, 0xb1, 0xda, 0x04, 0xe9,
+	0x3e, 0x0a, 0xa8, 0x6e, 0xab, 0x1e, 0x50, 0xf1, 0xa7, 0xa8, 0xae, 0x6b, 0x84, 0x54, 0x5d, 0x56,
+	0x64, 0x4c, 0x25, 0x9e, 0xa2, 0xea, 0xc8, 0x42, 0xfe, 0xfa, 0x09, 0xf9, 0x1f, 0x1b, 0xac, 0x3a,
+	0xb5, 0xae, 0xda, 0x33, 0x7b, 0x10, 0xdd, 0x6c, 0xef, 0xd0, 0x60, 0x07, 0x90, 0x9d, 0xda, 0x9e,
+	0x63, 0x99, 0x03, 0xd3, 0x47, 0x06, 0xd9, 0xf1, 0xb4, 0x46, 0x0f, 0x3d, 0xbf, 0x87, 0x02, 0xe5,
+	0x4f, 0x16, 0xfb, 0x33, 0xb3, 0xb4, 0x61, 0x70, 0x68, 0x5c, 0x7d, 0x66, 0x39, 0xba, 0x41, 0xb6,
+	0x2b, 0xa7, 0x45, 0x5d, 0xf1, 0x67, 0x9c, 0x53, 0xcd, 0xc1, 0x5a, 0xa6, 0xb6, 0x11, 0xe5, 0x54,
+	0x87, 0xf4, 0x78, 0xde, 0xf4, 0x70, 0x56, 0x81, 0xd3, 0x4b, 0x94, 0x53, 0xd7, 0x68, 0xa9, 0x6d,
+	0x8e, 0x5d, 0x0b, 0x85, 0x3d, 0x6d, 0xb1, 0x52, 0xf8, 0x12, 0xf2, 0x2b, 0x53, 0x81, 0x88, 0x56,
+	0x28, 0x82, 0x59, 0x11, 0x51, 0xfe, 0x2d, 0x0e, 0x59, 0xea, 0x21, 0xe0, 0x3e, 0xa7, 0x0d, 0xb1,
+	0x83, 0x77, 0x87, 0xa3, 0x66, 0x23, 0x37, 0x48, 0x90, 0x57, 0xe5, 0xce, 0x77, 0x4d, 0xed, 0xbc,
+	0x27, 0x5f, 0xca, 0x6a, 0x07, 0x9b, 0x82, 0xdc, 0x9b, 0x14, 0xba, 0xf2, 0x64, 0x94, 0x21, 0xdb,
+	0xa9, 0x54, 0x15, 0x39, 0xa4, 0xc3, 0x9b, 0x91, 0xa2, 0xa9, 0x73, 0x7a, 0x04, 0x99, 0x56, 0xb7,
+	0xfd, 0x6d, 0xaf, 0xd5, 0x55, 0x14, 0x6c, 0x90, 0x5d, 0x4c, 0x6e, 0x51, 0xe4, 0xe2, 0x7a, 0xc1,
+	0x5c, 0xb5, 0xab, 0x9c, 0xf7, 0xda, 0xdf, 0xab, 0xb5, 0x02, 0xfb, 0x88, 0x8b, 0xcc, 0xc2, 0x7d,
+	0x01, 0xe9, 0x5a, 0xf3, 0xa2, 0xd5, 0xec, 0xaa, 0xf5, 0x42, 0xf2, 0x11, 0x16, 0x55, 0x54, 0xd8,
+	0x0a, 0xed, 0x46, 0x17, 0xa3, 0xca, 0xbf, 0xb8, 0x2f, 0xc6, 0x5e, 0xdf, 0x17, 0x99, 0x9f, 0x1e,
+	0x8a, 0xcc, 0x2d, 0xfe, 0xfe, 0xc3, 0xdf, 0x2b, 0xfc, 0xf5, 0x53, 0xe4, 0xb5, 0x3d, 0x7d, 0x13,
+	0x00, 0x00, 0xff, 0xff, 0x7d, 0x9c, 0x5f, 0x56, 0xa1, 0x07, 0x00, 0x00,
+}

+ 156 - 0
libnetwork/networkdb/networkdb.proto

@@ -0,0 +1,156 @@
+syntax = "proto3";
+
+import "gogoproto/gogo.proto";
+
+package networkdb;
+
+option (gogoproto.marshaler_all) = true;
+option (gogoproto.unmarshaler_all) = true;
+option (gogoproto.stringer_all) = true;
+option (gogoproto.gostring_all) = true;
+option (gogoproto.sizer_all) = true;
+option (gogoproto.goproto_stringer_all) = false;
+
+// MessageType enum defines all the core message types that networkdb
+// uses to communicate to peers.
+enum MessageType {
+	option (gogoproto.goproto_enum_prefix) = false;
+	option (gogoproto.enum_customname) = "MessageType";
+
+	INVALID = 0 [(gogoproto.enumvalue_customname) = "MessageTypeInvalid"];
+
+	// NetworEvent message type is used to communicate network
+	// attachments on the node.
+	NETWORK_EVENT = 1 [(gogoproto.enumvalue_customname) = "MessageTypeNetworkEvent"];
+
+	// TableEvent message type is used to communicate any table
+	// CRUD event that happened on the node.
+	TABLE_EVENT = 2 [(gogoproto.enumvalue_customname) = "MessageTypeTableEvent"];
+
+	// PushPull message type is used to syncup all network
+	// attachments on a peer node either during startup of this
+	// node or with a random peer node periodically thereafter.
+	PUSH_PULL = 3 [(gogoproto.enumvalue_customname) = "MessageTypePushPull"];
+
+	// BulkSync message is used to bulksync the whole networkdb
+	// state with a peer node during startup of this node or with
+	// a random peer node periodically thereafter.
+	BULK_SYNC = 4 [(gogoproto.enumvalue_customname) = "MessageTypeBulkSync"];
+
+	// Compound message type is used to form a compound message
+	// which is a pack of many message of above types, packed into
+	// a single compound message.
+	COMPOUND = 5 [(gogoproto.enumvalue_customname) = "MessageTypeCompound"];
+}
+
+// GossipMessage is a basic message header used by all messages types.
+message GossipMessage {
+	MessageType type = 1; // type defines one of the message types defined above.
+	bytes data = 2; // Payload of the message of any type defined here.
+}
+
+// NetworkEvent message payload definition.
+message NetworkEvent {
+	enum Type {
+		option (gogoproto.goproto_enum_prefix) = false;
+		option (gogoproto.enum_customname) = "Type";
+
+		INVALID = 0 [(gogoproto.enumvalue_customname) = "NetworkEventTypeInvalid"];
+		// Join event is generated when this node joins a network.
+		JOIN = 1 [(gogoproto.enumvalue_customname) = "NetworkEventTypeJoin"];;
+		// Leave event is generated when this node leaves a network.
+		LEAVE = 2 [(gogoproto.enumvalue_customname) = "NetworkEventTypeLeave"];;
+	}
+
+	Type type = 1;
+
+	// Lamport time using a network lamport clock indicating the
+	// time this event was generated on the node where it was
+	// generated.
+	uint64 l_time = 2 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false];
+	// Source node name.
+	string node_name = 3;
+	// ID of the network for which the event is generated.
+	string network_id = 4 [(gogoproto.customname) = "NetworkID"];
+}
+
+// NetworkEntry for push pull of networks.
+message NetworkEntry {
+	// ID of the network
+	string network_id = 1 [(gogoproto.customname) = "NetworkID"];
+	// Latest lamport time of the network attachment when this
+	// network event was recorded.
+	uint64 l_time = 2 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false];
+	// Source node name where this network attachment happened.
+	string node_name = 3;
+	// Indicates if a leave from this network is in progress.
+	bool leaving = 4;
+}
+
+// NetworkPushpull message payload definition.
+message NetworkPushPull {
+	// Lamport time when this push pull was initiated.
+	uint64 l_time = 1 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false];
+	repeated NetworkEntry networks = 2;
+}
+
+// TableEvent message payload definition.
+message TableEvent {
+	enum Type {
+		option (gogoproto.goproto_enum_prefix) = false;
+		option (gogoproto.enum_customname) = "Type";
+
+		INVALID = 0 [(gogoproto.enumvalue_customname) = "TableEventTypeInvalid"];
+		// Create signifies that this table entry was just
+		// created.
+		CREATE = 1 [(gogoproto.enumvalue_customname) = "TableEventTypeCreate"];
+		// Update signifies that this table entry was just
+		// updated.
+		UPDATE = 2 [(gogoproto.enumvalue_customname) = "TableEventTypeUpdate"];
+		// Delete signifies that this table entry was just
+		// updated.
+		DELETE = 3 [(gogoproto.enumvalue_customname) = "TableEventTypeDelete"];
+	}
+
+	Type type = 1;
+	// Lamport time when this event was generated.
+	uint64 l_time = 2 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false];
+	// Node name where this event originated.
+	string node_name = 3;
+	// ID of the network to which this table entry belongs.
+	string network_id = 4 [(gogoproto.customname) = "NetworkID"];
+	// Name of the table to which this table entry belongs.
+	string table_name = 5;
+	// Entry key.
+	string key = 6;
+	// Entry value.
+	bytes value = 7;
+}
+
+// BulkSync message payload definition.
+message BulkSyncMessage {
+	// Lamport time when this bulk sync was initiated.
+	uint64 l_time = 1 [(gogoproto.customtype) = "github.com/hashicorp/serf/serf.LamportTime", (gogoproto.nullable) = false];
+	// Indicates if this bulksync is a response to a bulk sync
+	// request from a peer node.
+	bool unsolicited = 2;
+	// Name of the node which is producing this bulk sync message.
+	string node_name = 3;
+	// List of network names whose table entries are getting
+	// bulksynced as part of the bulksync.
+	repeated string networks = 4;
+	// Bulksync payload
+	bytes payload = 5;
+}
+
+// Compound message payload definition.
+message CompoundMessage {
+	message SimpleMessage {
+		// Bytestring payload of a message constructed using
+		// other message type definitions.
+		bytes Payload = 1;
+	}
+
+	// A list of simple messages.
+	repeated SimpleMessage messages = 1;
+}