Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af3fc82b77 | ||
|
|
3bb7036cfd | ||
|
|
d802eb485b | ||
|
|
b4dd9c2490 | ||
|
|
04ab198e95 | ||
|
|
c345700963 | ||
|
|
b21afcb78f | ||
|
|
7f65530b26 | ||
|
|
b1b03f3a97 | ||
|
|
36ef6d8da2 | ||
|
|
28bb0dd3b0 | ||
|
|
79f8a8f909 | ||
|
|
bfe2513540 | ||
|
|
2536aef737 | ||
|
|
0661ccdea9 | ||
|
|
29f7015e58 | ||
|
|
7dc1b50d3b | ||
|
|
682133a56a | ||
|
|
76db732f1b | ||
|
|
64aa2b5cc3 | ||
|
|
1eed5fd271 | ||
|
|
dd7ffa4501 | ||
|
|
5e79da0c9c | ||
|
|
65fe753a58 | ||
|
|
17c835e672 | ||
|
|
fa5bcd0457 | ||
|
|
499d6312b7 | ||
|
|
20d5903696 | ||
|
|
f039221ec9 | ||
|
|
dc9f8762ca | ||
|
|
e5c69801a7 | ||
|
|
ab458368de | ||
|
|
8eb680fcc9 | ||
|
|
71b05972f4 | ||
|
|
7deeb8dba5 | ||
|
|
daad190188 | ||
|
|
7cc0052451 | ||
|
|
18f8e29af8 | ||
|
|
d78f6614cc | ||
|
|
53ac43202a | ||
|
|
bfb050c9cc | ||
|
|
97622b961c | ||
|
|
b7e7c11a57 | ||
|
|
59e11e4e8a | ||
|
|
39b0357517 | ||
|
|
878a12002c | ||
|
|
d3d2863d52 | ||
|
|
f3f23b43b5 | ||
|
|
006262ed8f | ||
|
|
519aef86fa | ||
|
|
8bd77c0d47 | ||
|
|
7a5c910cd5 | ||
|
|
4e34f2001c | ||
|
|
54b7e2c874 | ||
|
|
19f89f7122 | ||
|
|
9f25d72a4a | ||
|
|
3e99b71e0f | ||
|
|
fb3b690c5f | ||
|
|
18fe553d23 | ||
|
|
e7ff6a2191 | ||
|
|
ad15e5a234 | ||
|
|
094c7aa438 | ||
|
|
472ed5a7d3 | ||
|
|
f284300870 | ||
|
|
a400a3dd09 | ||
|
|
c4855e8123 | ||
|
|
6c0bdec2c9 | ||
|
|
d6dd1f269a | ||
|
|
2bd23f3709 | ||
|
|
549fd5fe29 | ||
|
|
5f4753f881 | ||
|
|
e03a45f8c5 | ||
|
|
67c2d53e59 | ||
|
|
7b01dd9794 | ||
|
|
04e50ff02c | ||
|
|
781c805e10 | ||
|
|
60db57a41c | ||
|
|
df68f7dcb9 | ||
|
|
94984df047 | ||
|
|
cf9f715a28 | ||
|
|
4a6a46fd7b | ||
|
|
0eb7414f72 | ||
|
|
c02691a70c | ||
|
|
abc653c87d | ||
|
|
30a128c00b | ||
|
|
6a238818da | ||
|
|
7e1b7a2fcd | ||
|
|
c3a53a6ec5 | ||
|
|
b37d428726 | ||
|
|
12f5ec40b5 | ||
|
|
6a672cf8bc | ||
|
|
036b7d9f66 | ||
|
|
355c4bc58e | ||
|
|
203a3cfdd1 |
No files matched your search
+1
-1
@@ -48,7 +48,7 @@ releases
|
||||
.weaver.uptodate
|
||||
.weavedns.uptodate
|
||||
.weaveexec.uptodate
|
||||
weave.tar
|
||||
weave.tar.gz
|
||||
prog/weaveexec/weave
|
||||
prog/weaveexec/weavehosts
|
||||
prog/weaveexec/weaveproxy
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## Release 1.3.0
|
||||
|
||||
**Highlights**
|
||||
|
||||
This release includes a Docker Plugin, so you have the option to use
|
||||
Weave Net that way. More details in the
|
||||
[change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.3.0).
|
||||
|
||||
## Release 1.2.1
|
||||
|
||||
This release contains a number of bug fixes and minor
|
||||
|
||||
@@ -16,9 +16,9 @@ WEAVEWAIT_EXE=prog/weavewait/weavewait
|
||||
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
|
||||
NETCHECK_EXE=prog/netcheck/netcheck
|
||||
DOCKERTLSARGS_EXE=prog/docker_tls_args/docker_tls_args
|
||||
RUNNER_EXE=testing/runner/runner
|
||||
RUNNER_EXE=tools/runner/runner
|
||||
|
||||
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) $(RUNNER_EXE)
|
||||
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE)
|
||||
|
||||
WEAVER_UPTODATE=.weaver.uptodate
|
||||
WEAVEEXEC_UPTODATE=.weaveexec.uptodate
|
||||
@@ -30,7 +30,7 @@ WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec
|
||||
|
||||
IMAGES=$(WEAVER_IMAGE) $(WEAVEEXEC_IMAGE)
|
||||
|
||||
WEAVE_EXPORT=weave.tar
|
||||
WEAVE_EXPORT=weave.tar.gz
|
||||
|
||||
WEAVEEXEC_DOCKER_VERSION=1.3.1
|
||||
DOCKER_DISTRIB=prog/weaveexec/docker-$(WEAVEEXEC_DOCKER_VERSION).tgz
|
||||
@@ -70,7 +70,7 @@ $(NETCHECK_EXE): common/*.go common/*/*.go net/*.go
|
||||
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
||||
$(NETGO_CHECK)
|
||||
|
||||
$(WEAVER_EXE): router/*.go ipam/*.go ipam/*/*.go nameserver/*.go prog/weaver/*.go
|
||||
$(WEAVER_EXE): router/*.go mesh/*.go ipam/*.go ipam/*/*.go nameserver/*.go prog/weaver/*.go
|
||||
$(WEAVEPROXY_EXE): proxy/*.go prog/weaveproxy/main.go
|
||||
$(NETCHECK_EXE): prog/netcheck/netcheck.go
|
||||
|
||||
@@ -78,10 +78,9 @@ $(NETCHECK_EXE): prog/netcheck/netcheck.go
|
||||
# the main build stanza due to not importing net package
|
||||
$(SIGPROXY_EXE): prog/sigproxy/main.go
|
||||
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
|
||||
$(RUNNER_EXE): testing/runner/runner.go
|
||||
$(DOCKERTLSARGS_EXE): prog/docker_tls_args/*.go
|
||||
|
||||
$(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(RUNNER_EXE) $(DOCKERTLSARGS_EXE):
|
||||
$(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(DOCKERTLSARGS_EXE):
|
||||
go get -tags netgo ./$(@D)
|
||||
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
||||
|
||||
@@ -106,7 +105,7 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPR
|
||||
touch $@
|
||||
|
||||
$(WEAVE_EXPORT): $(IMAGES_UPTODATE)
|
||||
$(SUDO) docker save $(addsuffix :latest,$(IMAGES)) > $@
|
||||
$(SUDO) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
|
||||
|
||||
$(DOCKER_DISTRIB):
|
||||
curl -o $(DOCKER_DISTRIB) $(DOCKER_DISTRIB_URL)
|
||||
@@ -120,6 +119,9 @@ lint: tools/.git
|
||||
tools/.git:
|
||||
git submodule update --init
|
||||
|
||||
$(RUNNER_EXE): tools/.git
|
||||
make -C tools/runner
|
||||
|
||||
$(PUBLISH): publish_%: $(IMAGES_UPTODATE)
|
||||
$(SUDO) docker tag -f $(DOCKERHUB_USER)/$* $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
||||
$(SUDO) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
||||
|
||||
+3
-8
@@ -27,13 +27,10 @@ dependencies:
|
||||
docker save weaveworks/weave-test >$WEAVE_TEST;
|
||||
fi
|
||||
post:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install bc jq
|
||||
- pip install requests
|
||||
- sudo apt-get update && sudo apt-get install bc jq && pip install requests
|
||||
- curl https://sdk.cloud.google.com | bash
|
||||
- bin/setup-circleci-secrets "$SECRET_PASSWORD"
|
||||
- mkdir -p $(dirname $SRCDIR)
|
||||
- cp -r $(pwd)/ $SRCDIR
|
||||
- mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR
|
||||
- cd $SRCDIR/test; ./gce.sh make_template:
|
||||
parallel: false
|
||||
|
||||
@@ -45,9 +42,7 @@ test:
|
||||
parallel: true
|
||||
- docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go -e COVERAGE=true weaveworks/weave-build:
|
||||
parallel: true
|
||||
- cd $SRCDIR/test; ./gce.sh setup:
|
||||
parallel: true
|
||||
- cd $SRCDIR/test; eval $(./gce.sh hosts); ./setup.sh:
|
||||
- cd $SRCDIR/test; ./gce.sh setup && eval $(./gce.sh hosts) && ./setup.sh:
|
||||
parallel: true
|
||||
- cd $SRCDIR/test; eval $(./gce.sh hosts); export COVERAGE=true; ./run_all.sh:
|
||||
parallel: true
|
||||
|
||||
@@ -52,3 +52,15 @@ func SetLogLevel(levelname string) {
|
||||
}
|
||||
Log.Level = level
|
||||
}
|
||||
|
||||
func CheckFatal(e error) {
|
||||
if e != nil {
|
||||
Log.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func CheckWarn(e error) {
|
||||
if e != nil {
|
||||
Log.Warnln(e)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package odp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
+40
-40
@@ -11,8 +11,8 @@ import (
|
||||
"github.com/weaveworks/weave/ipam/paxos"
|
||||
"github.com/weaveworks/weave/ipam/ring"
|
||||
"github.com/weaveworks/weave/ipam/space"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
// Kinds of message we can unicast to other peers
|
||||
@@ -43,31 +43,31 @@ type operation interface {
|
||||
// are used around data structures.
|
||||
type Allocator struct {
|
||||
actionChan chan<- func()
|
||||
ourName router.PeerName
|
||||
ourName mesh.PeerName
|
||||
universe address.Range // superset of all ranges
|
||||
ring *ring.Ring // information on ranges owned by all peers
|
||||
space space.Space // more detail on ranges owned by us
|
||||
owned map[string][]address.Address // who owns what addresses, indexed by container-ID
|
||||
nicknames map[router.PeerName]string // so we can map nicknames for rmpeer
|
||||
nicknames map[mesh.PeerName]string // so we can map nicknames for rmpeer
|
||||
pendingAllocates []operation // held until we get some free space
|
||||
pendingClaims []operation // held until we know who owns the space
|
||||
gossip router.Gossip // our link to the outside world for sending messages
|
||||
gossip mesh.Gossip // our link to the outside world for sending messages
|
||||
paxos *paxos.Node
|
||||
paxosTicker *time.Ticker
|
||||
shuttingDown bool // to avoid doing any requests while trying to shut down
|
||||
isKnownPeer func(router.PeerName) bool
|
||||
isKnownPeer func(mesh.PeerName) bool
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// NewAllocator creates and initialises a new Allocator
|
||||
func NewAllocator(ourName router.PeerName, ourUID router.PeerUID, ourNickname string, universe address.Range, quorum uint, isKnownPeer func(name router.PeerName) bool) *Allocator {
|
||||
func NewAllocator(ourName mesh.PeerName, ourUID mesh.PeerUID, ourNickname string, universe address.Range, quorum uint, isKnownPeer func(name mesh.PeerName) bool) *Allocator {
|
||||
return &Allocator{
|
||||
ourName: ourName,
|
||||
universe: universe,
|
||||
ring: ring.New(universe.Start, universe.End, ourName),
|
||||
owned: make(map[string][]address.Address),
|
||||
paxos: paxos.NewNode(ourName, ourUID, quorum),
|
||||
nicknames: map[router.PeerName]string{ourName: ourNickname},
|
||||
nicknames: map[mesh.PeerName]string{ourName: ourNickname},
|
||||
isKnownPeer: isKnownPeer,
|
||||
now: time.Now,
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func NewAllocator(ourName router.PeerName, ourUID router.PeerUID, ourNickname st
|
||||
|
||||
// Start runs the allocator goroutine
|
||||
func (alloc *Allocator) Start() {
|
||||
actionChan := make(chan func(), router.ChannelSize)
|
||||
actionChan := make(chan func(), mesh.ChannelSize)
|
||||
alloc.actionChan = actionChan
|
||||
go alloc.actorLoop(actionChan)
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func (alloc *Allocator) tryPendingOps() {
|
||||
}
|
||||
}
|
||||
|
||||
func (alloc *Allocator) spaceRequestDenied(sender router.PeerName, r address.Range) {
|
||||
func (alloc *Allocator) spaceRequestDenied(sender mesh.PeerName, r address.Range) {
|
||||
for i := 0; i < len(alloc.pendingClaims); {
|
||||
claim := alloc.pendingClaims[i].(*claim)
|
||||
if r.Contains(claim.addr) {
|
||||
@@ -276,27 +276,27 @@ func (alloc *Allocator) Free(ident string, addrToFree address.Address) error {
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
func (alloc *Allocator) pickPeerFromNicknames(isValid func(router.PeerName) bool) router.PeerName {
|
||||
func (alloc *Allocator) pickPeerFromNicknames(isValid func(mesh.PeerName) bool) mesh.PeerName {
|
||||
for name := range alloc.nicknames {
|
||||
if name != alloc.ourName && isValid(name) {
|
||||
return name
|
||||
}
|
||||
}
|
||||
return router.UnknownPeerName
|
||||
return mesh.UnknownPeerName
|
||||
}
|
||||
|
||||
func (alloc *Allocator) pickPeerForTransfer() router.PeerName {
|
||||
func (alloc *Allocator) pickPeerForTransfer() mesh.PeerName {
|
||||
// first try alive peers that actively participate in IPAM (i.e. have entries)
|
||||
if heir := alloc.ring.PickPeerForTransfer(alloc.isKnownPeer); heir != router.UnknownPeerName {
|
||||
if heir := alloc.ring.PickPeerForTransfer(alloc.isKnownPeer); heir != mesh.UnknownPeerName {
|
||||
return heir
|
||||
}
|
||||
// next try alive peers that have IPAM enabled but have no entries
|
||||
if heir := alloc.pickPeerFromNicknames(alloc.isKnownPeer); heir != router.UnknownPeerName {
|
||||
if heir := alloc.pickPeerFromNicknames(alloc.isKnownPeer); heir != mesh.UnknownPeerName {
|
||||
return heir
|
||||
}
|
||||
// next try disappeared peers that still have entries
|
||||
t := func(router.PeerName) bool { return true }
|
||||
if heir := alloc.ring.PickPeerForTransfer(t); heir != router.UnknownPeerName {
|
||||
t := func(mesh.PeerName) bool { return true }
|
||||
if heir := alloc.ring.PickPeerForTransfer(t); heir != mesh.UnknownPeerName {
|
||||
return heir
|
||||
}
|
||||
// finally, disappeared peers that that passively participated in IPAM
|
||||
@@ -311,7 +311,7 @@ func (alloc *Allocator) Shutdown() {
|
||||
alloc.shuttingDown = true
|
||||
alloc.cancelOps(&alloc.pendingClaims)
|
||||
alloc.cancelOps(&alloc.pendingAllocates)
|
||||
if heir := alloc.pickPeerForTransfer(); heir != router.UnknownPeerName {
|
||||
if heir := alloc.pickPeerForTransfer(); heir != mesh.UnknownPeerName {
|
||||
alloc.ring.Transfer(alloc.ourName, heir)
|
||||
alloc.space.Clear()
|
||||
alloc.gossip.GossipBroadcast(alloc.Gossip())
|
||||
@@ -350,14 +350,14 @@ func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) error {
|
||||
// call into the router for this because we are interested in peers
|
||||
// that have gone away but are still in the ring, which is why we
|
||||
// maintain our own nicknames map.
|
||||
func (alloc *Allocator) lookupPeername(name string) (router.PeerName, error) {
|
||||
func (alloc *Allocator) lookupPeername(name string) (mesh.PeerName, error) {
|
||||
for peername, nickname := range alloc.nicknames {
|
||||
if nickname == name {
|
||||
return peername, nil
|
||||
}
|
||||
}
|
||||
|
||||
return router.PeerNameFromString(name)
|
||||
return mesh.PeerNameFromString(name)
|
||||
}
|
||||
|
||||
// Restrict the peers in "nicknames" to those in the ring plus peers known to the router
|
||||
@@ -370,7 +370,7 @@ func (alloc *Allocator) pruneNicknames() {
|
||||
}
|
||||
}
|
||||
|
||||
func (alloc *Allocator) annotatePeernames(names []router.PeerName) []string {
|
||||
func (alloc *Allocator) annotatePeernames(names []mesh.PeerName) []string {
|
||||
var res []string
|
||||
for _, name := range names {
|
||||
if nickname, found := alloc.nicknames[name]; found {
|
||||
@@ -388,7 +388,7 @@ func decodeRange(msg []byte) (r address.Range, err error) {
|
||||
}
|
||||
|
||||
// OnGossipUnicast (Sync)
|
||||
func (alloc *Allocator) OnGossipUnicast(sender router.PeerName, msg []byte) error {
|
||||
func (alloc *Allocator) OnGossipUnicast(sender mesh.PeerName, msg []byte) error {
|
||||
alloc.debugln("OnGossipUnicast from", sender, ": ", len(msg), "bytes")
|
||||
resultChan := make(chan error)
|
||||
alloc.actionChan <- func() {
|
||||
@@ -414,7 +414,7 @@ func (alloc *Allocator) OnGossipUnicast(sender router.PeerName, msg []byte) erro
|
||||
}
|
||||
|
||||
// OnGossipBroadcast (Sync)
|
||||
func (alloc *Allocator) OnGossipBroadcast(sender router.PeerName, msg []byte) (router.GossipData, error) {
|
||||
func (alloc *Allocator) OnGossipBroadcast(sender mesh.PeerName, msg []byte) (mesh.GossipData, error) {
|
||||
alloc.debugln("OnGossipBroadcast from", sender, ":", len(msg), "bytes")
|
||||
resultChan := make(chan error)
|
||||
alloc.actionChan <- func() {
|
||||
@@ -427,7 +427,7 @@ type gossipState struct {
|
||||
// We send a timstamp along with the information to be
|
||||
// gossipped in order to detect skewed clocks
|
||||
Now int64
|
||||
Nicknames map[router.PeerName]string
|
||||
Nicknames map[mesh.PeerName]string
|
||||
|
||||
Paxos paxos.GossipState
|
||||
Ring *ring.Ring
|
||||
@@ -463,11 +463,11 @@ func (alloc *Allocator) Encode() []byte {
|
||||
}
|
||||
|
||||
// OnGossip (Sync)
|
||||
func (alloc *Allocator) OnGossip(msg []byte) (router.GossipData, error) {
|
||||
func (alloc *Allocator) OnGossip(msg []byte) (mesh.GossipData, error) {
|
||||
alloc.debugln("Allocator.OnGossip:", len(msg), "bytes")
|
||||
resultChan := make(chan error)
|
||||
alloc.actionChan <- func() {
|
||||
resultChan <- alloc.update(router.UnknownPeerName, msg)
|
||||
resultChan <- alloc.update(mesh.UnknownPeerName, msg)
|
||||
}
|
||||
return nil, <-resultChan // for now, we never propagate updates. TBD
|
||||
}
|
||||
@@ -478,7 +478,7 @@ type ipamGossipData struct {
|
||||
alloc *Allocator
|
||||
}
|
||||
|
||||
func (d *ipamGossipData) Merge(other router.GossipData) {
|
||||
func (d *ipamGossipData) Merge(other mesh.GossipData) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -488,12 +488,12 @@ func (d *ipamGossipData) Encode() [][]byte {
|
||||
|
||||
// Gossip returns a GossipData implementation, which in this case always
|
||||
// returns the latest ring state (and does nothing on merge)
|
||||
func (alloc *Allocator) Gossip() router.GossipData {
|
||||
func (alloc *Allocator) Gossip() mesh.GossipData {
|
||||
return &ipamGossipData{alloc}
|
||||
}
|
||||
|
||||
// SetInterfaces gives the allocator two interfaces for talking to the outside world
|
||||
func (alloc *Allocator) SetInterfaces(gossip router.Gossip) {
|
||||
func (alloc *Allocator) SetInterfaces(gossip mesh.Gossip) {
|
||||
alloc.gossip = gossip
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ func (alloc *Allocator) establishRing() {
|
||||
}
|
||||
}
|
||||
|
||||
func (alloc *Allocator) createRing(peers []router.PeerName) {
|
||||
func (alloc *Allocator) createRing(peers []mesh.PeerName) {
|
||||
alloc.debugln("Paxos consensus:", peers)
|
||||
alloc.ring.ClaimForPeers(normalizeConsensus(peers))
|
||||
alloc.gossip.GossipBroadcast(alloc.Gossip())
|
||||
@@ -563,7 +563,7 @@ func (alloc *Allocator) ringUpdated() {
|
||||
}
|
||||
|
||||
// For compatibility with sort.Interface
|
||||
type peerNames []router.PeerName
|
||||
type peerNames []mesh.PeerName
|
||||
|
||||
func (a peerNames) Len() int { return len(a) }
|
||||
func (a peerNames) Less(i, j int) bool { return a[i] < a[j] }
|
||||
@@ -572,7 +572,7 @@ func (a peerNames) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
// When we get a consensus from Paxos, the peer names are not in a
|
||||
// defined order and may contain duplicates. This function sorts them
|
||||
// and de-dupes.
|
||||
func normalizeConsensus(consensus []router.PeerName) []router.PeerName {
|
||||
func normalizeConsensus(consensus []mesh.PeerName) []mesh.PeerName {
|
||||
if len(consensus) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -607,22 +607,22 @@ func encodeRange(r address.Range) []byte {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func (alloc *Allocator) sendSpaceRequest(dest router.PeerName, r address.Range) error {
|
||||
msg := router.Concat([]byte{msgSpaceRequest}, encodeRange(r))
|
||||
func (alloc *Allocator) sendSpaceRequest(dest mesh.PeerName, r address.Range) error {
|
||||
msg := append([]byte{msgSpaceRequest}, encodeRange(r)...)
|
||||
return alloc.gossip.GossipUnicast(dest, msg)
|
||||
}
|
||||
|
||||
func (alloc *Allocator) sendSpaceRequestDenied(dest router.PeerName, r address.Range) error {
|
||||
msg := router.Concat([]byte{msgSpaceRequestDenied}, encodeRange(r))
|
||||
func (alloc *Allocator) sendSpaceRequestDenied(dest mesh.PeerName, r address.Range) error {
|
||||
msg := append([]byte{msgSpaceRequestDenied}, encodeRange(r)...)
|
||||
return alloc.gossip.GossipUnicast(dest, msg)
|
||||
}
|
||||
|
||||
func (alloc *Allocator) sendRingUpdate(dest router.PeerName) {
|
||||
msg := router.Concat([]byte{msgRingUpdate}, alloc.encode())
|
||||
func (alloc *Allocator) sendRingUpdate(dest mesh.PeerName) {
|
||||
msg := append([]byte{msgRingUpdate}, alloc.encode()...)
|
||||
alloc.gossip.GossipUnicast(dest, msg)
|
||||
}
|
||||
|
||||
func (alloc *Allocator) update(sender router.PeerName, msg []byte) error {
|
||||
func (alloc *Allocator) update(sender mesh.PeerName, msg []byte) error {
|
||||
reader := bytes.NewReader(msg)
|
||||
decoder := gob.NewDecoder(reader)
|
||||
var data gossipState
|
||||
@@ -674,7 +674,7 @@ func (alloc *Allocator) update(sender router.PeerName, msg []byte) error {
|
||||
alloc.createRing(cons.Value)
|
||||
}
|
||||
}
|
||||
} else if sender != router.UnknownPeerName {
|
||||
} else if sender != mesh.UnknownPeerName {
|
||||
// Sender is trying to initialize a ring, but we have one
|
||||
// already - send it straight back
|
||||
alloc.sendRingUpdate(sender)
|
||||
@@ -684,7 +684,7 @@ func (alloc *Allocator) update(sender router.PeerName, msg []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (alloc *Allocator) donateSpace(r address.Range, to router.PeerName) {
|
||||
func (alloc *Allocator) donateSpace(r address.Range, to mesh.PeerName) {
|
||||
// No matter what we do, we'll send a unicast gossip
|
||||
// of our ring back to tha chap who asked for space.
|
||||
// This serves to both tell him of any space we might
|
||||
|
||||
+3
-3
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
type claim struct {
|
||||
@@ -43,7 +43,7 @@ func (c *claim) Try(alloc *Allocator) bool {
|
||||
switch owner := alloc.ring.Owner(c.addr); owner {
|
||||
case alloc.ourName:
|
||||
// success
|
||||
case router.UnknownPeerName:
|
||||
case mesh.UnknownPeerName:
|
||||
// If our ring doesn't know, it must be empty.
|
||||
if c.noErrorOnUnknown {
|
||||
alloc.infof("Claim %s for %s: address allocator still initializing; will try later.", c.addr, c.ident)
|
||||
@@ -86,7 +86,7 @@ func (c *claim) Try(alloc *Allocator) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *claim) deniedBy(alloc *Allocator, owner router.PeerName) {
|
||||
func (c *claim) deniedBy(alloc *Allocator, owner mesh.PeerName) {
|
||||
name, found := alloc.nicknames[owner]
|
||||
if found {
|
||||
name = " (" + name + ")"
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
package paxos
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/weave/router"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// The node identifier. The use of the UID here is important: Paxos
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
// node does not restart and lose its Paxos state but claim to have
|
||||
// the same ID.
|
||||
type NodeID struct {
|
||||
Name router.PeerName
|
||||
UID router.PeerUID
|
||||
Name mesh.PeerName
|
||||
UID mesh.PeerUID
|
||||
}
|
||||
|
||||
// note all fields exported in structs so we can Gob them
|
||||
@@ -39,7 +39,7 @@ func (a ProposalID) valid() bool {
|
||||
}
|
||||
|
||||
// For seeding IPAM, the value we want consensus on is a set of peer names
|
||||
type Value []router.PeerName
|
||||
type Value []mesh.PeerName
|
||||
|
||||
// An AcceptedValue is a Value plus the proposal which originated that
|
||||
// Value. The origin is not essential, but makes comparing
|
||||
@@ -72,7 +72,7 @@ type Node struct {
|
||||
knows GossipState
|
||||
}
|
||||
|
||||
func NewNode(name router.PeerName, uid router.PeerUID, quorum uint) *Node {
|
||||
func NewNode(name mesh.PeerName, uid mesh.PeerUID, quorum uint) *Node {
|
||||
return &Node{
|
||||
id: NodeID{name, uid},
|
||||
quorum: quorum,
|
||||
@@ -223,7 +223,7 @@ func (node *Node) Think() bool {
|
||||
// about. This is not necessarily all peer names, but it is at least
|
||||
// a quorum, and so good enough for seeding the ring.
|
||||
func (node *Node) pickValue() Value {
|
||||
val := make([]router.PeerName, len(node.knows))
|
||||
val := make([]mesh.PeerName, len(node.knows))
|
||||
i := 0
|
||||
for id := range node.knows {
|
||||
val[i] = id.Name
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/router"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
@@ -97,8 +97,8 @@ func makeRandomModel(params *TestParams, r *rand.Rand, t *testing.T) *Model {
|
||||
}
|
||||
|
||||
for i := range m.nodes {
|
||||
m.nodes[i].Node = NewNode(router.PeerName(i/2+1),
|
||||
router.PeerUID(r.Int63()), m.quorum)
|
||||
m.nodes[i].Node = NewNode(mesh.PeerName(i/2+1),
|
||||
mesh.PeerUID(r.Int63()), m.quorum)
|
||||
m.nodes[i].Propose()
|
||||
}
|
||||
|
||||
@@ -172,8 +172,8 @@ func (m *Model) isolateNode(node *TestNode) {
|
||||
|
||||
// Restart a node
|
||||
func (m *Model) restart(node *TestNode) {
|
||||
node.Node = NewNode(router.PeerName(m.nextID),
|
||||
router.PeerUID(m.r.Int63()), m.quorum)
|
||||
node.Node = NewNode(mesh.PeerName(m.nextID),
|
||||
mesh.PeerUID(m.r.Int63()), m.quorum)
|
||||
m.nextID++
|
||||
node.Propose()
|
||||
|
||||
|
||||
+3
-3
@@ -4,14 +4,14 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
// Entry represents entries around the ring
|
||||
type entry struct {
|
||||
Token address.Address // The start of this range
|
||||
Peer router.PeerName // Who owns this range
|
||||
Peer mesh.PeerName // Who owns this range
|
||||
Version uint32 // Version of this range
|
||||
Free address.Offset // Number of free IPs in this range
|
||||
}
|
||||
@@ -21,7 +21,7 @@ func (e *entry) Equal(e2 *entry) bool {
|
||||
e.Version == e2.Version
|
||||
}
|
||||
|
||||
func (e *entry) update(peername router.PeerName, free address.Offset) {
|
||||
func (e *entry) update(peername mesh.PeerName, free address.Offset) {
|
||||
e.Peer = peername
|
||||
e.Version++
|
||||
e.Free = free
|
||||
|
||||
+22
-22
@@ -13,16 +13,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
// Ring represents the ring itself
|
||||
type Ring struct {
|
||||
Start, End address.Address // [min, max) tokens in this ring. Due to wrapping, min == max (effectively)
|
||||
Peer router.PeerName // name of peer owning this ring instance
|
||||
Entries entries // list of entries sorted by token
|
||||
Seeds []router.PeerName // peers with which the ring was seeded
|
||||
Start, End address.Address // [min, max) tokens in this ring. Due to wrapping, min == max (effectively)
|
||||
Peer mesh.PeerName // name of peer owning this ring instance
|
||||
Entries entries // list of entries sorted by token
|
||||
Seeds []mesh.PeerName // peers with which the ring was seeded
|
||||
}
|
||||
|
||||
func (r *Ring) assertInvariants() {
|
||||
@@ -84,7 +84,7 @@ func (r *Ring) checkInvariants() error {
|
||||
}
|
||||
|
||||
// New creates an empty ring belonging to peer.
|
||||
func New(start, end address.Address, peer router.PeerName) *Ring {
|
||||
func New(start, end address.Address, peer mesh.PeerName) *Ring {
|
||||
common.Assert(start < end)
|
||||
|
||||
ring := &Ring{Start: start, End: end, Peer: peer, Entries: make([]*entry, 0)}
|
||||
@@ -111,7 +111,7 @@ func (r *Ring) distance(start, end address.Address) address.Offset {
|
||||
// Preconditions:
|
||||
// - start < end
|
||||
// - [start, end) must be owned by the calling peer
|
||||
func (r *Ring) GrantRangeToHost(start, end address.Address, peer router.PeerName) {
|
||||
func (r *Ring) GrantRangeToHost(start, end address.Address, peer mesh.PeerName) {
|
||||
//fmt.Printf("%s GrantRangeToHost [%v,%v) -> %s\n", r.Peer, start, end, peer)
|
||||
|
||||
r.assertInvariants()
|
||||
@@ -210,7 +210,7 @@ func (r *Ring) Merge(gossip Ring) error {
|
||||
addToResult := func(e entry) { result = append(result, &e) }
|
||||
|
||||
var mine, theirs *entry
|
||||
var previousOwner *router.PeerName
|
||||
var previousOwner *mesh.PeerName
|
||||
// i is index into r.Entries; j is index into gossip.Entries
|
||||
var i, j int
|
||||
for i < len(r.Entries) && j < len(gossip.Entries) {
|
||||
@@ -318,7 +318,7 @@ func (r *Ring) OwnedRanges() (result []address.Range) {
|
||||
|
||||
// ClaimForPeers claims the entire ring for the array of peers passed
|
||||
// in. Only works for empty rings.
|
||||
func (r *Ring) ClaimForPeers(peers []router.PeerName) {
|
||||
func (r *Ring) ClaimForPeers(peers []mesh.PeerName) {
|
||||
common.Assert(r.Empty())
|
||||
defer r.assertInvariants()
|
||||
defer r.updateExportedVariables()
|
||||
@@ -350,7 +350,7 @@ func (r *Ring) ClaimForPeers(peers []router.PeerName) {
|
||||
r.Seeds = peers
|
||||
}
|
||||
|
||||
func (r *Ring) FprintWithNicknames(w io.Writer, m map[router.PeerName]string) {
|
||||
func (r *Ring) FprintWithNicknames(w io.Writer, m map[mesh.PeerName]string) {
|
||||
for _, entry := range r.Entries {
|
||||
nickname, found := m[entry.Peer]
|
||||
if found {
|
||||
@@ -365,7 +365,7 @@ func (r *Ring) FprintWithNicknames(w io.Writer, m map[router.PeerName]string) {
|
||||
func (r *Ring) String() string {
|
||||
var buffer bytes.Buffer
|
||||
fmt.Fprintf(&buffer, "Ring [%s, %s)", r.Start, r.End)
|
||||
r.FprintWithNicknames(&buffer, make(map[router.PeerName]string))
|
||||
r.FprintWithNicknames(&buffer, make(map[mesh.PeerName]string))
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
@@ -415,7 +415,7 @@ func (r *Ring) ReportFree(freespace map[address.Address]address.Offset) {
|
||||
|
||||
type weightedPeer struct {
|
||||
weight float64
|
||||
peername router.PeerName
|
||||
peername mesh.PeerName
|
||||
}
|
||||
type weightedPeers []weightedPeer
|
||||
|
||||
@@ -426,10 +426,10 @@ func (ws weightedPeers) Swap(i, j int) { ws[i], ws[j] = ws[j], ws[i] }
|
||||
|
||||
// ChoosePeersToAskForSpace returns all peers we can ask for space in
|
||||
// the range [start, end), in weighted-random order. Assumes start<end.
|
||||
func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []router.PeerName {
|
||||
func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []mesh.PeerName {
|
||||
var (
|
||||
sum address.Offset
|
||||
totalSpacePerPeer = make(map[router.PeerName]address.Offset) // Compute total free space per peer
|
||||
totalSpacePerPeer = make(map[mesh.PeerName]address.Offset) // Compute total free space per peer
|
||||
)
|
||||
|
||||
// iterate through tokens
|
||||
@@ -463,25 +463,25 @@ func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []router.Pee
|
||||
ws = append(ws, weightedPeer{weight: float64(space) * rand.Float64(), peername: peername})
|
||||
}
|
||||
sort.Sort(ws)
|
||||
result := make([]router.PeerName, len(ws))
|
||||
result := make([]mesh.PeerName, len(ws))
|
||||
for i, wp := range ws {
|
||||
result[i] = wp.peername
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *Ring) PickPeerForTransfer(isValid func(router.PeerName) bool) router.PeerName {
|
||||
func (r *Ring) PickPeerForTransfer(isValid func(mesh.PeerName) bool) mesh.PeerName {
|
||||
for _, entry := range r.Entries {
|
||||
if entry.Peer != r.Peer && isValid(entry.Peer) {
|
||||
return entry.Peer
|
||||
}
|
||||
}
|
||||
return router.UnknownPeerName
|
||||
return mesh.UnknownPeerName
|
||||
}
|
||||
|
||||
// Transfer will mark all entries associated with 'from' peer as owned by 'to' peer
|
||||
// and return ranges indicating the new space we picked up
|
||||
func (r *Ring) Transfer(from, to router.PeerName) ([]address.Range, error) {
|
||||
func (r *Ring) Transfer(from, to mesh.PeerName) ([]address.Range, error) {
|
||||
r.assertInvariants()
|
||||
defer r.assertInvariants()
|
||||
defer r.updateExportedVariables()
|
||||
@@ -511,13 +511,13 @@ func (r *Ring) Contains(addr address.Address) bool {
|
||||
}
|
||||
|
||||
// Owner returns the peername which owns the range containing addr
|
||||
func (r *Ring) Owner(token address.Address) router.PeerName {
|
||||
func (r *Ring) Owner(token address.Address) mesh.PeerName {
|
||||
common.Assert(r.Start <= token && token < r.End)
|
||||
|
||||
r.assertInvariants()
|
||||
// There can be no owners on an empty ring
|
||||
if r.Empty() {
|
||||
return router.UnknownPeerName
|
||||
return mesh.UnknownPeerName
|
||||
}
|
||||
|
||||
// Look for the right-most entry, less than or equal to token
|
||||
@@ -530,8 +530,8 @@ func (r *Ring) Owner(token address.Address) router.PeerName {
|
||||
}
|
||||
|
||||
// Get the set of PeerNames mentioned in the ring
|
||||
func (r *Ring) PeerNames() map[router.PeerName]struct{} {
|
||||
res := make(map[router.PeerName]struct{})
|
||||
func (r *Ring) PeerNames() map[mesh.PeerName]struct{} {
|
||||
res := make(map[mesh.PeerName]struct{})
|
||||
|
||||
for _, entry := range r.Entries {
|
||||
res[entry.Peer] = struct{}{}
|
||||
|
||||
+13
-13
@@ -9,14 +9,14 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
var (
|
||||
peer1name, _ = router.PeerNameFromString("01:00:00:00:02:00")
|
||||
peer2name, _ = router.PeerNameFromString("02:00:00:00:02:00")
|
||||
peer3name, _ = router.PeerNameFromString("03:00:00:00:02:00")
|
||||
peer1name, _ = mesh.PeerNameFromString("01:00:00:00:02:00")
|
||||
peer2name, _ = mesh.PeerNameFromString("02:00:00:00:02:00")
|
||||
peer3name, _ = mesh.PeerNameFromString("03:00:00:00:02:00")
|
||||
|
||||
start, end = ParseIP("10.0.0.0"), ParseIP("10.0.0.255")
|
||||
dot10, dot245 = ParseIP("10.0.0.10"), ParseIP("10.0.0.245")
|
||||
@@ -351,7 +351,7 @@ func TestGossip(t *testing.T) {
|
||||
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
||||
}
|
||||
|
||||
func assertPeersWithSpace(t *testing.T, ring *Ring, start, end address.Address, expected int) []router.PeerName {
|
||||
func assertPeersWithSpace(t *testing.T, ring *Ring, start, end address.Address, expected int) []mesh.PeerName {
|
||||
peers := ring.ChoosePeersToAskForSpace(start, end)
|
||||
require.Equal(t, expected, len(peers))
|
||||
return peers
|
||||
@@ -375,7 +375,7 @@ func TestFindFree(t *testing.T) {
|
||||
ring1.assertInvariants()
|
||||
|
||||
// We should return others
|
||||
var peers []router.PeerName
|
||||
var peers []mesh.PeerName
|
||||
|
||||
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 1}}
|
||||
peers = assertPeersWithSpace(t, ring1, start, end, 1)
|
||||
@@ -493,7 +493,7 @@ func TestOwner(t *testing.T) {
|
||||
require.True(t, ring1.Contains(start), "start should be in ring")
|
||||
require.False(t, ring1.Contains(end), "end should not be in ring")
|
||||
|
||||
require.Equal(t, router.UnknownPeerName, ring1.Owner(start))
|
||||
require.Equal(t, mesh.UnknownPeerName, ring1.Owner(start))
|
||||
|
||||
ring1.ClaimItAll()
|
||||
ring1.GrantRangeToHost(middle, end, peer2name)
|
||||
@@ -517,9 +517,9 @@ func TestFuzzRing(t *testing.T) {
|
||||
iterations = 1000
|
||||
)
|
||||
|
||||
peers := make([]router.PeerName, numPeers)
|
||||
peers := make([]mesh.PeerName, numPeers)
|
||||
for i := 0; i < numPeers; i++ {
|
||||
peer, _ := router.PeerNameFromString(fmt.Sprintf("%02d:00:00:00:02:00", i))
|
||||
peer, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:00:00:00:02:00", i))
|
||||
peers[i] = peer
|
||||
}
|
||||
|
||||
@@ -601,13 +601,13 @@ func TestFuzzRingHard(t *testing.T) {
|
||||
var (
|
||||
numPeers = 100
|
||||
iterations = 3000
|
||||
peers []router.PeerName
|
||||
peers []mesh.PeerName
|
||||
rings []*Ring
|
||||
nextPeerID = 0
|
||||
)
|
||||
|
||||
addPeer := func() {
|
||||
peer, _ := router.PeerNameFromString(fmt.Sprintf("%02d:%02d:00:00:00:00", nextPeerID/10, nextPeerID%10))
|
||||
peer, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:%02d:00:00:00:00", nextPeerID/10, nextPeerID%10))
|
||||
common.Log.Debugf("%s: Adding peer", peer)
|
||||
nextPeerID++
|
||||
peers = append(peers, peer)
|
||||
@@ -620,7 +620,7 @@ func TestFuzzRingHard(t *testing.T) {
|
||||
|
||||
rings[0].ClaimItAll()
|
||||
|
||||
randomPeer := func(exclude int) (int, router.PeerName, *Ring) {
|
||||
randomPeer := func(exclude int) (int, mesh.PeerName, *Ring) {
|
||||
var peerIndex int
|
||||
if exclude >= 0 {
|
||||
peerIndex = rand.Intn(len(peers) - 1)
|
||||
@@ -729,7 +729,7 @@ func TestFuzzRingHard(t *testing.T) {
|
||||
}
|
||||
|
||||
func (r *Ring) ClaimItAll() {
|
||||
r.ClaimForPeers([]router.PeerName{r.Peer})
|
||||
r.ClaimForPeers([]mesh.PeerName{r.Peer})
|
||||
}
|
||||
|
||||
func (es entries) String() string {
|
||||
|
||||
+12
-12
@@ -8,13 +8,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
"github.com/weaveworks/weave/testing/gossip"
|
||||
)
|
||||
|
||||
type mockMessage struct {
|
||||
dst router.PeerName
|
||||
dst mesh.PeerName
|
||||
msgType byte
|
||||
buf []byte
|
||||
}
|
||||
@@ -48,13 +48,13 @@ func (m *mockGossipComms) String() string {
|
||||
// that the contents of messages are never re-ordered. Which, for instance,
|
||||
// requires they are not based off iterating through a map.
|
||||
|
||||
func (m *mockGossipComms) GossipBroadcast(update router.GossipData) error {
|
||||
func (m *mockGossipComms) GossipBroadcast(update mesh.GossipData) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
buf := []byte{}
|
||||
if len(m.messages) == 0 {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Gossip broadcast message unexpected: \n%x", m.name, buf))
|
||||
} else if msg := m.messages[0]; msg.dst != router.UnknownPeerName {
|
||||
} else if msg := m.messages[0]; msg.dst != mesh.UnknownPeerName {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Expected Gossip message to %s but got broadcast", m.name, msg.dst))
|
||||
} else if msg.buf != nil && !equalByteBuffer(msg.buf, buf) {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Gossip message not sent as expected: \nwant: %x\ngot : %x", m.name, msg.buf, buf))
|
||||
@@ -77,12 +77,12 @@ func equalByteBuffer(a, b []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *mockGossipComms) GossipUnicast(dstPeerName router.PeerName, buf []byte) error {
|
||||
func (m *mockGossipComms) GossipUnicast(dstPeerName mesh.PeerName, buf []byte) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if len(m.messages) == 0 {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Gossip message to %s unexpected: \n%s", m.name, dstPeerName, buf))
|
||||
} else if msg := m.messages[0]; msg.dst == router.UnknownPeerName {
|
||||
} else if msg := m.messages[0]; msg.dst == mesh.UnknownPeerName {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Expected Gossip broadcast message but got dest %s", m.name, dstPeerName))
|
||||
} else if msg.dst != dstPeerName {
|
||||
require.FailNow(m, fmt.Sprintf("%s: Expected Gossip message to %s but got dest %s", m.name, msg.dst, dstPeerName))
|
||||
@@ -99,7 +99,7 @@ func (m *mockGossipComms) GossipUnicast(dstPeerName router.PeerName, buf []byte)
|
||||
|
||||
func ExpectMessage(alloc *Allocator, dst string, msgType byte, buf []byte) {
|
||||
m := alloc.gossip.(*mockGossipComms)
|
||||
dstPeerName, _ := router.PeerNameFromString(dst)
|
||||
dstPeerName, _ := mesh.PeerNameFromString(dst)
|
||||
m.Lock()
|
||||
m.messages = append(m.messages, mockMessage{dstPeerName, msgType, buf})
|
||||
m.Unlock()
|
||||
@@ -108,7 +108,7 @@ func ExpectMessage(alloc *Allocator, dst string, msgType byte, buf []byte) {
|
||||
func ExpectBroadcastMessage(alloc *Allocator, buf []byte) {
|
||||
m := alloc.gossip.(*mockGossipComms)
|
||||
m.Lock()
|
||||
m.messages = append(m.messages, mockMessage{router.UnknownPeerName, 0, buf})
|
||||
m.messages = append(m.messages, mockMessage{mesh.UnknownPeerName, 0, buf})
|
||||
m.Unlock()
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ func CheckAllExpectedMessagesSent(allocs ...*Allocator) {
|
||||
}
|
||||
|
||||
func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, address.Range) {
|
||||
peername, err := router.PeerNameFromString(name)
|
||||
peername, err := mesh.PeerNameFromString(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -134,8 +134,8 @@ func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, addres
|
||||
panic(err)
|
||||
}
|
||||
|
||||
alloc := NewAllocator(peername, router.PeerUID(rand.Int63()),
|
||||
"nick-"+name, cidr.Range(), quorum, func(router.PeerName) bool { return true })
|
||||
alloc := NewAllocator(peername, mesh.PeerUID(rand.Int63()),
|
||||
"nick-"+name, cidr.Range(), quorum, func(mesh.PeerName) bool { return true })
|
||||
|
||||
return alloc, cidr.HostRange()
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func makeAllocatorWithMockGossip(t *testing.T, name string, universeCIDR string,
|
||||
}
|
||||
|
||||
func (alloc *Allocator) claimRingForTesting(allocs ...*Allocator) {
|
||||
peers := []router.PeerName{alloc.ourName}
|
||||
peers := []mesh.PeerName{alloc.ourName}
|
||||
for _, alloc2 := range allocs {
|
||||
peers = append(peers, alloc2.ourName)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -40,17 +40,16 @@ type RemoteConnection struct {
|
||||
type LocalConnection struct {
|
||||
sync.RWMutex
|
||||
RemoteConnection
|
||||
TCPConn *net.TCPConn
|
||||
version byte
|
||||
tcpSender TCPSender
|
||||
remoteUDPAddr *net.UDPAddr
|
||||
SessionKey *[32]byte
|
||||
heartbeatTCP *time.Ticker
|
||||
Router *Router
|
||||
uid uint64
|
||||
actionChan chan<- ConnectionAction
|
||||
finished <-chan struct{} // closed to signal that actorLoop has finished
|
||||
forwarder OverlayForwarder
|
||||
TCPConn *net.TCPConn
|
||||
version byte
|
||||
tcpSender TCPSender
|
||||
SessionKey *[32]byte
|
||||
heartbeatTCP *time.Ticker
|
||||
Router *Router
|
||||
uid uint64
|
||||
actionChan chan<- ConnectionAction
|
||||
finished <-chan struct{} // closed to signal that actorLoop has finished
|
||||
OverlayConn OverlayConnection
|
||||
}
|
||||
|
||||
type ConnectionAction func() error
|
||||
@@ -83,7 +82,7 @@ func (conn *RemoteConnection) ErrorLog(args ...interface{}) {
|
||||
|
||||
// Does not return anything. If the connection is successful, it will
|
||||
// end up in the local peer's connections map.
|
||||
func StartLocalConnection(connRemote *RemoteConnection, tcpConn *net.TCPConn, udpAddr *net.UDPAddr, router *Router, acceptNewPeer bool) {
|
||||
func StartLocalConnection(connRemote *RemoteConnection, tcpConn *net.TCPConn, router *Router, acceptNewPeer bool) {
|
||||
if connRemote.local != router.Ourself.Peer {
|
||||
log.Fatal("Attempt to create local connection from a peer which is not ourself")
|
||||
}
|
||||
@@ -94,7 +93,6 @@ func StartLocalConnection(connRemote *RemoteConnection, tcpConn *net.TCPConn, ud
|
||||
RemoteConnection: *connRemote,
|
||||
Router: router,
|
||||
TCPConn: tcpConn,
|
||||
remoteUDPAddr: udpAddr,
|
||||
uid: randUint64(),
|
||||
actionChan: actionChan,
|
||||
finished: finished}
|
||||
@@ -192,37 +190,37 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch
|
||||
|
||||
conn.Log("connection ready; using protocol version", conn.version)
|
||||
|
||||
params := ForwarderParams{
|
||||
params := OverlayConnectionParams{
|
||||
RemotePeer: conn.remote,
|
||||
LocalIP: conn.TCPConn.LocalAddr().(*net.TCPAddr).IP,
|
||||
RemoteAddr: conn.remoteUDPAddr,
|
||||
LocalAddr: conn.TCPConn.LocalAddr().(*net.TCPAddr),
|
||||
RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr),
|
||||
Outbound: conn.outbound,
|
||||
ConnUID: conn.uid,
|
||||
Crypto: conn.forwarderCrypto(),
|
||||
SessionKey: conn.SessionKey,
|
||||
SendControlMessage: conn.sendOverlayControlMessage,
|
||||
Features: intro.Features,
|
||||
}
|
||||
if conn.forwarder, err = conn.Router.Overlay.MakeForwarder(params); err != nil {
|
||||
if conn.OverlayConn, err = conn.Router.Overlay.PrepareConnection(params); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// As soon as we do AddConnection, the new connection becomes
|
||||
// visible to the packet routing logic. So AddConnection must
|
||||
// come after MakeForwarder
|
||||
// come after PrepareConnection
|
||||
if err = conn.Router.Ourself.AddConnection(conn); err != nil {
|
||||
return
|
||||
}
|
||||
conn.Router.ConnectionMaker.ConnectionCreated(conn)
|
||||
|
||||
// Forwarder confirmation comes after AddConnection, because
|
||||
// only after that completes do we know the connection is
|
||||
// valid: in particular that it is not a duplicate connection
|
||||
// to the same peer. Sending heartbeats on a duplicate
|
||||
// connection can trip up crypto at the other end, since the
|
||||
// associated UDP packets may get decoded by the other
|
||||
// connection. It is also generally wasteful to engage in any
|
||||
// interaction with the remote on a connection that turns out
|
||||
// to be invalid.
|
||||
conn.forwarder.Confirm()
|
||||
// OverlayConnection confirmation comes after AddConnection,
|
||||
// because only after that completes do we know the connection is
|
||||
// valid: in particular that it is not a duplicate connection to
|
||||
// the same peer. Overlay communication on a duplicate connection
|
||||
// can cause problems such as tripping up overlay crypto at the
|
||||
// other end due to data being decoded by the other connection. It
|
||||
// is also generally wasteful to engage in any interaction with
|
||||
// the remote on a connection that turns out to be invalid.
|
||||
conn.OverlayConn.Confirm()
|
||||
|
||||
// receiveTCP must follow also AddConnection. In the absence
|
||||
// of any indirect connectivity to the remote peer, the first
|
||||
@@ -330,10 +328,6 @@ func (conn *LocalConnection) registerRemote(remote *Peer, acceptNewPeer bool) er
|
||||
}
|
||||
}
|
||||
|
||||
if conn.remote.UID != remote.UID {
|
||||
return fmt.Errorf("Connection appears to be with different version of a peer we already know of")
|
||||
}
|
||||
|
||||
if conn.remote == conn.local {
|
||||
return ErrConnectToSelf
|
||||
}
|
||||
@@ -342,8 +336,8 @@ func (conn *LocalConnection) registerRemote(remote *Peer, acceptNewPeer bool) er
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) actorLoop(actionChan <-chan ConnectionAction) (err error) {
|
||||
fwdErrorChan := conn.forwarder.ErrorChannel()
|
||||
fwdEstablishedChan := conn.forwarder.EstablishedChannel()
|
||||
fwdErrorChan := conn.OverlayConn.ErrorChannel()
|
||||
fwdEstablishedChan := conn.OverlayConn.EstablishedChannel()
|
||||
|
||||
for err == nil {
|
||||
select {
|
||||
@@ -380,28 +374,17 @@ func (conn *LocalConnection) shutdown(err error) {
|
||||
conn.Router.Ourself.DeleteConnection(conn)
|
||||
}
|
||||
|
||||
stopTicker(conn.heartbeatTCP)
|
||||
if conn.heartbeatTCP != nil {
|
||||
conn.heartbeatTCP.Stop()
|
||||
}
|
||||
|
||||
if conn.forwarder != nil {
|
||||
conn.forwarder.Stop()
|
||||
if conn.OverlayConn != nil {
|
||||
conn.OverlayConn.Stop()
|
||||
}
|
||||
|
||||
conn.Router.ConnectionMaker.ConnectionTerminated(conn, err)
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) forwarderCrypto() *OverlayCrypto {
|
||||
if !conn.Router.UsingPassword() {
|
||||
return nil
|
||||
}
|
||||
|
||||
name := conn.local.NameByte
|
||||
return &OverlayCrypto{
|
||||
Dec: NewNaClDecryptor(conn.SessionKey, conn.outbound),
|
||||
Enc: NewNaClEncryptor(name, conn.SessionKey, conn.outbound, false),
|
||||
EncDF: NewNaClEncryptor(name, conn.SessionKey, conn.outbound, true),
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) sendOverlayControlMessage(tag byte, msg []byte) error {
|
||||
return conn.sendProtocolMsg(ProtocolMsg{ProtocolTag(tag), msg})
|
||||
}
|
||||
@@ -413,7 +396,7 @@ func (conn *LocalConnection) sendSimpleProtocolMsg(tag ProtocolTag) error {
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) sendProtocolMsg(m ProtocolMsg) error {
|
||||
return conn.tcpSender.Send(Concat([]byte{byte(m.tag)}, m.msg))
|
||||
return conn.tcpSender.Send(append([]byte{byte(m.tag)}, m.msg...))
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) receiveTCP(receiver TCPReceiver) {
|
||||
@@ -439,8 +422,8 @@ func (conn *LocalConnection) receiveTCP(receiver TCPReceiver) {
|
||||
func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) error {
|
||||
switch tag {
|
||||
case ProtocolHeartbeat:
|
||||
case ProtocolConnectionEstablished, ProtocolFragmentationReceived, ProtocolPMTUVerified, ProtocolOverlayControlMsg:
|
||||
conn.forwarder.ControlMessage(byte(tag), payload)
|
||||
case ProtocolReserved1, ProtocolReserved2, ProtocolReserved3, ProtocolOverlayControlMsg:
|
||||
conn.OverlayConn.ControlMessage(byte(tag), payload)
|
||||
case ProtocolGossipUnicast, ProtocolGossipBroadcast, ProtocolGossip:
|
||||
return conn.Router.handleGossip(tag, payload)
|
||||
default:
|
||||
@@ -452,20 +435,3 @@ func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte)
|
||||
func (conn *LocalConnection) extendReadDeadline() {
|
||||
conn.TCPConn.SetReadDeadline(time.Now().Add(TCPHeartbeat * 2))
|
||||
}
|
||||
|
||||
func (conn *LocalConnection) Forward(key ForwardPacketKey) FlowOp {
|
||||
return conn.forwarder.Forward(key)
|
||||
}
|
||||
|
||||
func tickerChan(ticker *time.Ticker) <-chan time.Time {
|
||||
if ticker != nil {
|
||||
return ticker.C
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopTicker(ticker *time.Ticker) {
|
||||
if ticker != nil {
|
||||
ticker.Stop()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -239,3 +239,12 @@ func (c *GossipChannel) sendBroadcast(srcName PeerName, update GossipData) {
|
||||
func (c *GossipChannel) log(args ...interface{}) {
|
||||
log.Println(append(append([]interface{}{}, "[gossip "+c.name+"]:"), args...)...)
|
||||
}
|
||||
|
||||
func GobEncode(items ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
for _, i := range items {
|
||||
checkFatal(enc.Encode(i))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -20,7 +20,7 @@ type mockChannelConnection struct {
|
||||
|
||||
func NewTestRouter(name string) *Router {
|
||||
peerName, _ := PeerNameFromString(name)
|
||||
router := NewRouter(Config{}, peerName, "nick")
|
||||
router := NewRouter(Config{}, peerName, "nick", nil)
|
||||
router.Start()
|
||||
return router
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -19,8 +19,7 @@ type LocalPeerAction func()
|
||||
func NewLocalPeer(name PeerName, nickName string, router *Router) *LocalPeer {
|
||||
actionChan := make(chan LocalPeerAction, ChannelSize)
|
||||
peer := &LocalPeer{
|
||||
Peer: NewPeer(name, nickName, randomPeerUID(), 0,
|
||||
randomPeerShortID()),
|
||||
Peer: NewPeer(name, nickName, randomPeerUID(), 0, randomPeerShortID()),
|
||||
router: router,
|
||||
actionChan: actionChan,
|
||||
}
|
||||
@@ -63,21 +62,16 @@ func (peer *LocalPeer) CreateConnection(peerAddr string, acceptNewPeer bool) err
|
||||
if err := peer.checkConnectionLimit(); err != nil {
|
||||
return err
|
||||
}
|
||||
tcpAddr, tcpErr := net.ResolveTCPAddr("tcp4", peerAddr)
|
||||
udpAddr, udpErr := net.ResolveUDPAddr("udp4", peerAddr)
|
||||
if tcpErr != nil || udpErr != nil {
|
||||
// they really should have the same value, but just in case...
|
||||
if tcpErr == nil {
|
||||
return udpErr
|
||||
}
|
||||
return tcpErr
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp4", peerAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcpConn, err := net.DialTCP("tcp4", nil, tcpAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
connRemote := NewRemoteConnection(peer.Peer, nil, tcpConn.RemoteAddr().String(), true, false)
|
||||
StartLocalConnection(connRemote, tcpConn, udpAddr, peer.router, acceptNewPeer)
|
||||
StartLocalConnection(connRemote, tcpConn, peer.router, acceptNewPeer)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -255,3 +249,13 @@ func (peer *LocalPeer) setShortID(shortID PeerShortID) {
|
||||
peer.ShortID = shortID
|
||||
peer.Version++
|
||||
}
|
||||
|
||||
func (peer *LocalPeer) setVersionBeyond(version uint64) bool {
|
||||
peer.Lock()
|
||||
defer peer.Unlock()
|
||||
if version >= peer.Version {
|
||||
peer.Version = version + 1
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// It supplies some mock implementations to other unit tests, and is
|
||||
// named "...test.go" so it is only compiled under `go test`.
|
||||
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type Overlay interface {
|
||||
// Enhance a features map with overlay-related features
|
||||
AddFeaturesTo(map[string]string)
|
||||
|
||||
// Prepare on overlay connection. The connection should remain
|
||||
// passive until it has been Confirm()ed.
|
||||
PrepareConnection(OverlayConnectionParams) (OverlayConnection, error)
|
||||
|
||||
// Obtain diagnostic information specific to the overlay
|
||||
Diagnostics() interface{}
|
||||
}
|
||||
|
||||
type OverlayConnectionParams struct {
|
||||
RemotePeer *Peer
|
||||
|
||||
// The local address of the corresponding TCP connection. Used to
|
||||
// derive the local IP address for sending. May differ for
|
||||
// different overlay connections.
|
||||
LocalAddr *net.TCPAddr
|
||||
|
||||
// The remote address of the corresponding TCP connection. Used to
|
||||
// determine the address to send to, but only if the TCP
|
||||
// connection is outbound. Otherwise the Overlay needs to discover
|
||||
// it (e.g. from incoming datagrams).
|
||||
RemoteAddr *net.TCPAddr
|
||||
|
||||
// Is the corresponding TCP connection outbound?
|
||||
Outbound bool
|
||||
|
||||
// Unique identifier for this connection
|
||||
ConnUID uint64
|
||||
|
||||
// Session key, if connection is encrypted; nil otherwise.
|
||||
//
|
||||
// NB: overlay connections must take care not to use nonces which
|
||||
// may collide with those of the main connection. These nonces are
|
||||
// 192 bits, with the top most bit unspecified, the next bit set
|
||||
// to 1, followed by 126 zero bits, and a message sequence number
|
||||
// in the lowest 64 bits.
|
||||
SessionKey *[32]byte
|
||||
|
||||
// Function to send a control message to the counterpart
|
||||
// overlay connection.
|
||||
SendControlMessage func(tag byte, msg []byte) error
|
||||
|
||||
// Features passed at connection initiation
|
||||
Features map[string]string
|
||||
}
|
||||
|
||||
// All of the machinery to manage overlay connectivity to a particular
|
||||
// peer
|
||||
type OverlayConnection interface {
|
||||
// Confirm that the connection is really wanted, and so the
|
||||
// Overlay should begin heartbeats etc. to verify the operation of
|
||||
// the overlay connection.
|
||||
Confirm()
|
||||
|
||||
// A channel indicating that the overlay connection is
|
||||
// established, i.e. its operation has been confirmed.
|
||||
EstablishedChannel() <-chan struct{}
|
||||
|
||||
// A channel indicating an error from the overlay connection. The
|
||||
// overlay connection is not expected to be operational after the
|
||||
// first error, so the channel only needs to buffer a single
|
||||
// error.
|
||||
ErrorChannel() <-chan error
|
||||
|
||||
Stop()
|
||||
|
||||
// Handle a message from the peer. 'tag' exists for
|
||||
// compatibility, and should always be
|
||||
// ProtocolOverlayControlMessage for non-sleeve overlays.
|
||||
ControlMessage(tag byte, msg []byte)
|
||||
|
||||
// User facing overlay name
|
||||
DisplayName() string
|
||||
}
|
||||
|
||||
type NullOverlay struct{}
|
||||
|
||||
func (NullOverlay) AddFeaturesTo(map[string]string) {
|
||||
}
|
||||
|
||||
func (NullOverlay) PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) {
|
||||
return NullOverlay{}, nil
|
||||
}
|
||||
|
||||
func (NullOverlay) Diagnostics() interface{} {
|
||||
return nil
|
||||
}
|
||||
func (NullOverlay) Confirm() {
|
||||
}
|
||||
|
||||
func (NullOverlay) EstablishedChannel() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) ErrorChannel() <-chan error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) Stop() {
|
||||
}
|
||||
|
||||
func (NullOverlay) ControlMessage(byte, []byte) {
|
||||
}
|
||||
|
||||
func (NullOverlay) DisplayName() string {
|
||||
return "null"
|
||||
}
|
||||
@@ -1,11 +1,28 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func randBytes(n int) []byte {
|
||||
buf := make([]byte, n)
|
||||
_, err := rand.Read(buf)
|
||||
checkFatal(err)
|
||||
return buf
|
||||
}
|
||||
|
||||
func randUint64() (r uint64) {
|
||||
return binary.LittleEndian.Uint64(randBytes(8))
|
||||
}
|
||||
|
||||
func randUint16() (r uint16) {
|
||||
return binary.LittleEndian.Uint16(randBytes(2))
|
||||
}
|
||||
|
||||
type PeerUID uint64
|
||||
|
||||
func randomPeerUID() PeerUID {
|
||||
@@ -45,6 +62,18 @@ type Peer struct {
|
||||
connections map[PeerName]Connection
|
||||
}
|
||||
|
||||
type ListOfPeers []*Peer
|
||||
|
||||
func (lop ListOfPeers) Len() int {
|
||||
return len(lop)
|
||||
}
|
||||
func (lop ListOfPeers) Swap(i, j int) {
|
||||
lop[i], lop[j] = lop[j], lop[i]
|
||||
}
|
||||
func (lop ListOfPeers) Less(i, j int) bool {
|
||||
return lop[i].Name < lop[j].Name
|
||||
}
|
||||
|
||||
type ConnectionSet map[Connection]struct{}
|
||||
|
||||
func NewPeerFromSummary(summary PeerSummary) *Peer {
|
||||
@@ -3,7 +3,7 @@
|
||||
// Let peer names be sha256 hashes...of anything (as long as it's
|
||||
// unique).
|
||||
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
@@ -15,7 +15,7 @@
|
||||
// name. In particular it doesn't actually have to be the MAC of, say,
|
||||
// the network interface the peer is sniffing on.
|
||||
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -56,3 +56,20 @@ func (name PeerName) Bin() []byte {
|
||||
func (name PeerName) String() string {
|
||||
return intmac(uint64(name)).String()
|
||||
}
|
||||
|
||||
func macint(mac net.HardwareAddr) (r uint64) {
|
||||
for _, b := range mac {
|
||||
r <<= 8
|
||||
r |= uint64(b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intmac(key uint64) (r net.HardwareAddr) {
|
||||
r = make([]byte, 6)
|
||||
for i := 5; i >= 0; i-- {
|
||||
r[i] = byte(key)
|
||||
key >>= 8
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var void = struct{}{}
|
||||
|
||||
type Peers struct {
|
||||
sync.RWMutex
|
||||
ourself *LocalPeer
|
||||
@@ -33,8 +36,8 @@ type UnknownPeerError struct {
|
||||
Name PeerName
|
||||
}
|
||||
|
||||
type NameCollisionError struct {
|
||||
Name PeerName
|
||||
func (upe UnknownPeerError) Error() string {
|
||||
return fmt.Sprint("Reference to unknown peer ", upe.Name)
|
||||
}
|
||||
|
||||
type PeerNameSet map[PeerName]struct{}
|
||||
@@ -57,6 +60,9 @@ type PeersPendingNotifications struct {
|
||||
|
||||
// The local short ID needs reassigning due to a collision
|
||||
reassignLocalShortID bool
|
||||
|
||||
// The local peer was modified
|
||||
localPeerModified bool
|
||||
}
|
||||
|
||||
func NewPeers(ourself *LocalPeer) *Peers {
|
||||
@@ -89,7 +95,8 @@ func (peers *Peers) OnInvalidateShortIDs(callback func()) {
|
||||
}
|
||||
|
||||
func (peers *Peers) unlockAndNotify(pending *PeersPendingNotifications) {
|
||||
broadcastLocalPeer := pending.reassignLocalShortID && peers.reassignLocalShortID(pending)
|
||||
broadcastLocalPeer := (pending.reassignLocalShortID && peers.reassignLocalShortID(pending)) ||
|
||||
pending.localPeerModified
|
||||
onGC := peers.onGC
|
||||
onInvalidateShortIDs := peers.onInvalidateShortIDs
|
||||
peers.Unlock()
|
||||
@@ -425,12 +432,8 @@ func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, de
|
||||
newPeer := NewPeerFromSummary(peerSummary)
|
||||
decodedUpdate = append(decodedUpdate, newPeer)
|
||||
decodedConns = append(decodedConns, connSummaries)
|
||||
existingPeer, found := peers.byName[newPeer.Name]
|
||||
if !found {
|
||||
if _, found := peers.byName[newPeer.Name]; !found {
|
||||
newPeers[newPeer.Name] = newPeer
|
||||
} else if existingPeer.UID != newPeer.UID {
|
||||
err = NameCollisionError{Name: newPeer.Name}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,36 +461,36 @@ func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]Connecti
|
||||
connSummaries := decodedConns[idx]
|
||||
name := newPeer.Name
|
||||
// guaranteed to find peer in the peers.byName
|
||||
peer := peers.byName[name]
|
||||
if peer != newPeer &&
|
||||
(peer == peers.ourself.Peer || peer.Version >= newPeer.Version) {
|
||||
// Nobody but us updates us. And if we know more about a
|
||||
// peer than what's in the the update, we ignore the
|
||||
// latter.
|
||||
continue
|
||||
switch peer := peers.byName[name]; peer {
|
||||
case peers.ourself.Peer:
|
||||
if newPeer.UID != peer.UID {
|
||||
// The update contains information about an old
|
||||
// incarnation of ourselves. We increase our version
|
||||
// number beyond that which we received, so our
|
||||
// information supersedes the old one when it is
|
||||
// received by other peers.
|
||||
pending.localPeerModified = peers.ourself.setVersionBeyond(newPeer.Version)
|
||||
}
|
||||
case newPeer:
|
||||
peer.connections = makeConnsMap(peer, connSummaries, peers.byName)
|
||||
newUpdate[name] = void
|
||||
default: // existing peer
|
||||
if newPeer.Version < peer.Version ||
|
||||
(newPeer.Version == peer.Version && newPeer.UID <= peer.UID) {
|
||||
continue
|
||||
}
|
||||
peer.Version = newPeer.Version
|
||||
peer.UID = newPeer.UID
|
||||
peer.connections = makeConnsMap(peer, connSummaries, peers.byName)
|
||||
|
||||
if newPeer.ShortID != peer.ShortID {
|
||||
peers.deleteByShortID(peer, pending)
|
||||
peer.ShortID = newPeer.ShortID
|
||||
peers.addByShortID(peer, pending)
|
||||
}
|
||||
newUpdate[name] = void
|
||||
}
|
||||
// If we're here, either it was a new peer, or the update has
|
||||
// more info about the peer than we do. Either case, we need
|
||||
// to set version and conns and include the updated peer in
|
||||
// the outgoing update.
|
||||
|
||||
// Can peer have been updated by anyone else in the mean time?
|
||||
// No - we know that peer is not ourself, so the only prospect
|
||||
// for an update would be someone else calling
|
||||
// router.Peers.ApplyUpdate. But ApplyUpdate takes the Lock on
|
||||
// the router.Peers, so there can be no race here.
|
||||
peer.Version = newPeer.Version
|
||||
peer.connections = makeConnsMap(peer, connSummaries, peers.byName)
|
||||
|
||||
if newPeer.ShortID != peer.ShortID {
|
||||
peers.deleteByShortID(peer, pending)
|
||||
peer.ShortID = newPeer.ShortID
|
||||
peers.addByShortID(peer, pending)
|
||||
}
|
||||
|
||||
newUpdate[name] = void
|
||||
}
|
||||
|
||||
return newUpdate
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -329,9 +329,9 @@ type ProtocolTag byte
|
||||
|
||||
const (
|
||||
ProtocolHeartbeat = iota
|
||||
ProtocolConnectionEstablished
|
||||
ProtocolFragmentationReceived
|
||||
ProtocolPMTUVerified
|
||||
ProtocolReserved1 // legacy overlay control messages
|
||||
ProtocolReserved2 //
|
||||
ProtocolReserved3 //
|
||||
ProtocolGossip
|
||||
ProtocolGossipUnicast
|
||||
ProtocolGossipBroadcast
|
||||
@@ -0,0 +1,180 @@
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
)
|
||||
|
||||
const MaxTCPMsgSize = 10 * 1024 * 1024
|
||||
|
||||
func GenerateKeyPair() (publicKey, privateKey *[32]byte, err error) {
|
||||
return box.GenerateKey(rand.Reader)
|
||||
}
|
||||
|
||||
func FormSessionKey(remotePublicKey, localPrivateKey *[32]byte, secretKey []byte) *[32]byte {
|
||||
var sharedKey [32]byte
|
||||
box.Precompute(&sharedKey, remotePublicKey, localPrivateKey)
|
||||
sharedKeySlice := sharedKey[:]
|
||||
sharedKeySlice = append(sharedKeySlice, secretKey...)
|
||||
sessionKey := sha256.Sum256(sharedKeySlice)
|
||||
return &sessionKey
|
||||
}
|
||||
|
||||
// TCP Senders/Receivers
|
||||
|
||||
// The lowest 64 bits of the nonce contain the message sequence
|
||||
// number. The top most bit indicates the connection polarity at the
|
||||
// sender - '1' for outbound; the next indicates protocol type - '1'
|
||||
// for TCP. The remaining 126 bits are zero. The polarity is needed so
|
||||
// that the two ends of a connection do not use the same nonces; the
|
||||
// protocol type so that the TCP connection nonces are distinct from
|
||||
// nonces used by overlay connections, if they share the session key.
|
||||
// This is a requirement of the NaCl Security Model; see
|
||||
// http://nacl.cr.yp.to/box.html.
|
||||
type TCPCryptoState struct {
|
||||
sessionKey *[32]byte
|
||||
nonce [24]byte
|
||||
seqNo uint64
|
||||
}
|
||||
|
||||
func NewTCPCryptoState(sessionKey *[32]byte, outbound bool) *TCPCryptoState {
|
||||
s := &TCPCryptoState{sessionKey: sessionKey}
|
||||
if outbound {
|
||||
s.nonce[0] |= (1 << 7)
|
||||
}
|
||||
s.nonce[0] |= (1 << 6)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *TCPCryptoState) advance() {
|
||||
s.seqNo++
|
||||
binary.BigEndian.PutUint64(s.nonce[16:24], s.seqNo)
|
||||
}
|
||||
|
||||
type TCPSender interface {
|
||||
Send([]byte) error
|
||||
}
|
||||
|
||||
type GobTCPSender struct {
|
||||
encoder *gob.Encoder
|
||||
}
|
||||
|
||||
type LengthPrefixTCPSender struct {
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
type EncryptedTCPSender struct {
|
||||
sync.RWMutex
|
||||
sender TCPSender
|
||||
state *TCPCryptoState
|
||||
}
|
||||
|
||||
func NewGobTCPSender(encoder *gob.Encoder) *GobTCPSender {
|
||||
return &GobTCPSender{encoder: encoder}
|
||||
}
|
||||
|
||||
func (sender *GobTCPSender) Send(msg []byte) error {
|
||||
return sender.encoder.Encode(msg)
|
||||
}
|
||||
|
||||
func NewLengthPrefixTCPSender(writer io.Writer) *LengthPrefixTCPSender {
|
||||
return &LengthPrefixTCPSender{writer: writer}
|
||||
}
|
||||
|
||||
func (sender *LengthPrefixTCPSender) Send(msg []byte) error {
|
||||
l := len(msg)
|
||||
if l > MaxTCPMsgSize {
|
||||
return fmt.Errorf("outgoing message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
|
||||
}
|
||||
// We copy the message so we can send it in a single Write
|
||||
// operation, thus making this thread-safe without locking.
|
||||
prefixedMsg := make([]byte, 4+l)
|
||||
binary.BigEndian.PutUint32(prefixedMsg, uint32(l))
|
||||
copy(prefixedMsg[4:], msg)
|
||||
_, err := sender.writer.Write(prefixedMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
func NewEncryptedTCPSender(sender TCPSender, sessionKey *[32]byte, outbound bool) *EncryptedTCPSender {
|
||||
return &EncryptedTCPSender{sender: sender, state: NewTCPCryptoState(sessionKey, outbound)}
|
||||
}
|
||||
|
||||
func (sender *EncryptedTCPSender) Send(msg []byte) error {
|
||||
sender.Lock()
|
||||
defer sender.Unlock()
|
||||
encodedMsg := secretbox.Seal(nil, msg, &sender.state.nonce, sender.state.sessionKey)
|
||||
sender.state.advance()
|
||||
return sender.sender.Send(encodedMsg)
|
||||
}
|
||||
|
||||
type TCPReceiver interface {
|
||||
Receive() ([]byte, error)
|
||||
}
|
||||
|
||||
type GobTCPReceiver struct {
|
||||
decoder *gob.Decoder
|
||||
}
|
||||
|
||||
type LengthPrefixTCPReceiver struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
type EncryptedTCPReceiver struct {
|
||||
receiver TCPReceiver
|
||||
state *TCPCryptoState
|
||||
}
|
||||
|
||||
func NewGobTCPReceiver(decoder *gob.Decoder) *GobTCPReceiver {
|
||||
return &GobTCPReceiver{decoder: decoder}
|
||||
}
|
||||
|
||||
func (receiver *GobTCPReceiver) Receive() ([]byte, error) {
|
||||
var msg []byte
|
||||
err := receiver.decoder.Decode(&msg)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func NewLengthPrefixTCPReceiver(reader io.Reader) *LengthPrefixTCPReceiver {
|
||||
return &LengthPrefixTCPReceiver{reader: reader}
|
||||
}
|
||||
|
||||
func (receiver *LengthPrefixTCPReceiver) Receive() ([]byte, error) {
|
||||
lenPrefix := make([]byte, 4)
|
||||
if _, err := io.ReadFull(receiver.reader, lenPrefix); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := binary.BigEndian.Uint32(lenPrefix)
|
||||
if l > MaxTCPMsgSize {
|
||||
return nil, fmt.Errorf("incoming message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
|
||||
}
|
||||
msg := make([]byte, l)
|
||||
_, err := io.ReadFull(receiver.reader, msg)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func NewEncryptedTCPReceiver(receiver TCPReceiver, sessionKey *[32]byte, outbound bool) *EncryptedTCPReceiver {
|
||||
return &EncryptedTCPReceiver{receiver: receiver, state: NewTCPCryptoState(sessionKey, !outbound)}
|
||||
}
|
||||
|
||||
func (receiver *EncryptedTCPReceiver) Receive() ([]byte, error) {
|
||||
msg, err := receiver.receiver.Receive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decodedMsg, success := secretbox.Open(nil, msg, &receiver.state.nonce, receiver.state.sessionKey)
|
||||
if !success {
|
||||
return nil, fmt.Errorf("Unable to decrypt TCP msg")
|
||||
}
|
||||
|
||||
receiver.state.advance()
|
||||
return decodedMsg, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"io"
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
const (
|
||||
Port = 6783
|
||||
ChannelSize = 16
|
||||
TCPHeartbeat = 30 * time.Second
|
||||
GossipInterval = 30 * time.Second
|
||||
MaxDuration = time.Duration(math.MaxInt64)
|
||||
|
||||
acceptMaxTokens = 100 // [1]
|
||||
acceptTokenDelay = 100 * time.Millisecond // [2]
|
||||
)
|
||||
|
||||
// [1] capacity of token bucket for rate limiting accepts
|
||||
|
||||
// [2] control rate at which new tokens are added to the bucket
|
||||
|
||||
var (
|
||||
log = common.Log
|
||||
checkFatal = common.CheckFatal
|
||||
checkWarn = common.CheckWarn
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
ProtocolMinVersion byte
|
||||
Password []byte
|
||||
ConnLimit int
|
||||
PeerDiscovery bool
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
Config
|
||||
Overlay Overlay
|
||||
Ourself *LocalPeer
|
||||
Peers *Peers
|
||||
Routes *Routes
|
||||
ConnectionMaker *ConnectionMaker
|
||||
gossipLock sync.RWMutex
|
||||
gossipChannels GossipChannels
|
||||
TopologyGossip Gossip
|
||||
acceptLimiter *TokenBucket
|
||||
}
|
||||
|
||||
func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router {
|
||||
router := &Router{Config: config, gossipChannels: make(GossipChannels)}
|
||||
|
||||
if overlay == nil {
|
||||
overlay = NullOverlay{}
|
||||
}
|
||||
|
||||
router.Overlay = overlay
|
||||
router.Ourself = NewLocalPeer(name, nickName, router)
|
||||
router.Peers = NewPeers(router.Ourself)
|
||||
router.Peers.OnGC(func(peer *Peer) {
|
||||
log.Println("Removed unreachable peer", peer)
|
||||
})
|
||||
router.Routes = NewRoutes(router.Ourself, router.Peers)
|
||||
router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery)
|
||||
router.TopologyGossip = router.NewGossip("topology", router)
|
||||
router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay)
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
// Start listening for TCP connections. This is separate from
|
||||
// NewRouter so that gossipers can register before we start forming
|
||||
// connections.
|
||||
func (router *Router) Start() {
|
||||
router.listenTCP(router.Port)
|
||||
}
|
||||
|
||||
func (router *Router) Stop() error {
|
||||
// TODO: perform graceful shutdown...
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *Router) UsingPassword() bool {
|
||||
return router.Password != nil
|
||||
}
|
||||
|
||||
func (router *Router) listenTCP(localPort int) {
|
||||
localAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprint(":", localPort))
|
||||
checkFatal(err)
|
||||
ln, err := net.ListenTCP("tcp4", localAddr)
|
||||
checkFatal(err)
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
for {
|
||||
tcpConn, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
continue
|
||||
}
|
||||
router.acceptTCP(tcpConn)
|
||||
router.acceptLimiter.Wait()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (router *Router) acceptTCP(tcpConn *net.TCPConn) {
|
||||
remoteAddrStr := tcpConn.RemoteAddr().String()
|
||||
log.Printf("->[%s] connection accepted", remoteAddrStr)
|
||||
connRemote := NewRemoteConnection(router.Ourself.Peer, nil, remoteAddrStr, false, false)
|
||||
StartLocalConnection(connRemote, tcpConn, router, true)
|
||||
}
|
||||
|
||||
// Gossiper methods - the Router is the topology Gossiper
|
||||
|
||||
type TopologyGossipData struct {
|
||||
peers *Peers
|
||||
update PeerNameSet
|
||||
}
|
||||
|
||||
func (router *Router) BroadcastTopologyUpdate(update []*Peer) {
|
||||
names := make(PeerNameSet)
|
||||
for _, p := range update {
|
||||
names[p.Name] = void
|
||||
}
|
||||
|
||||
router.TopologyGossip.GossipBroadcast(&TopologyGossipData{
|
||||
peers: router.Peers,
|
||||
update: names,
|
||||
})
|
||||
}
|
||||
|
||||
func (d *TopologyGossipData) Merge(other GossipData) {
|
||||
for name := range other.(*TopologyGossipData).update {
|
||||
d.update[name] = void
|
||||
}
|
||||
}
|
||||
|
||||
func (d *TopologyGossipData) Encode() [][]byte {
|
||||
return [][]byte{d.peers.EncodePeers(d.update)}
|
||||
}
|
||||
|
||||
func (router *Router) OnGossipUnicast(sender PeerName, msg []byte) error {
|
||||
return fmt.Errorf("unexpected topology gossip unicast: %v", msg)
|
||||
}
|
||||
|
||||
func (router *Router) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
|
||||
origUpdate, _, err := router.applyTopologyUpdate(update)
|
||||
if err != nil || len(origUpdate) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &TopologyGossipData{peers: router.Peers, update: origUpdate}, nil
|
||||
}
|
||||
|
||||
func (router *Router) Gossip() GossipData {
|
||||
return &TopologyGossipData{peers: router.Peers, update: router.Peers.Names()}
|
||||
}
|
||||
|
||||
func (router *Router) OnGossip(update []byte) (GossipData, error) {
|
||||
_, newUpdate, err := router.applyTopologyUpdate(update)
|
||||
if err != nil || len(newUpdate) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &TopologyGossipData{peers: router.Peers, update: newUpdate}, nil
|
||||
}
|
||||
|
||||
func (router *Router) applyTopologyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
|
||||
origUpdate, newUpdate, err := router.Peers.ApplyUpdate(update)
|
||||
if _, ok := err.(UnknownPeerError); err != nil && ok {
|
||||
// That update contained a reference to a peer which wasn't
|
||||
// itself included in the update, and we didn't know about
|
||||
// already. We ignore this; eventually we should receive an
|
||||
// update containing a complete topology.
|
||||
log.Println("Topology gossip:", err)
|
||||
return nil, nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(newUpdate) > 0 {
|
||||
router.ConnectionMaker.Refresh()
|
||||
router.Routes.Recalculate()
|
||||
}
|
||||
return origUpdate, newUpdate, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"math"
|
||||
@@ -12,7 +12,7 @@ type Routes struct {
|
||||
sync.RWMutex
|
||||
ourself *LocalPeer
|
||||
peers *Peers
|
||||
onChange func()
|
||||
onChange []func()
|
||||
unicast unicastRoutes
|
||||
unicastAll unicastRoutes // [1]
|
||||
broadcast broadcastRoutes
|
||||
@@ -23,13 +23,12 @@ type Routes struct {
|
||||
// symmetric ones
|
||||
}
|
||||
|
||||
func NewRoutes(ourself *LocalPeer, peers *Peers, onChange func()) *Routes {
|
||||
func NewRoutes(ourself *LocalPeer, peers *Peers) *Routes {
|
||||
recalculate := make(chan *struct{}, 1)
|
||||
wait := make(chan chan struct{})
|
||||
routes := &Routes{
|
||||
ourself: ourself,
|
||||
peers: peers,
|
||||
onChange: onChange,
|
||||
unicast: make(unicastRoutes),
|
||||
unicastAll: make(unicastRoutes),
|
||||
broadcast: make(broadcastRoutes),
|
||||
@@ -44,6 +43,12 @@ func NewRoutes(ourself *LocalPeer, peers *Peers, onChange func()) *Routes {
|
||||
return routes
|
||||
}
|
||||
|
||||
func (routes *Routes) OnChange(callback func()) {
|
||||
routes.Lock()
|
||||
defer routes.Unlock()
|
||||
routes.onChange = append(routes.onChange, callback)
|
||||
}
|
||||
|
||||
func (routes *Routes) PeerNames() PeerNameSet {
|
||||
return routes.peers.Names()
|
||||
}
|
||||
@@ -159,10 +164,13 @@ func (routes *Routes) calculate() {
|
||||
routes.unicastAll = unicastAll
|
||||
routes.broadcast = broadcast
|
||||
routes.broadcastAll = broadcastAll
|
||||
onChange := routes.onChange
|
||||
routes.Unlock()
|
||||
|
||||
if !unicast.equals(oldUnicast) || !broadcast.equals(oldBroadcast) {
|
||||
routes.onChange()
|
||||
for _, callback := range onChange {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
@@ -14,9 +13,6 @@ type Status struct {
|
||||
Name string
|
||||
NickName string
|
||||
Port int
|
||||
Interface string
|
||||
CaptureStats map[string]int
|
||||
MACs []MACStatus
|
||||
Peers []PeerStatus
|
||||
UnicastRoutes []UnicastRouteStatus
|
||||
BroadcastRoutes []BroadcastRouteStatus
|
||||
@@ -25,13 +21,6 @@ type Status struct {
|
||||
OverlayDiagnostics interface{}
|
||||
}
|
||||
|
||||
type MACStatus struct {
|
||||
Mac string
|
||||
Name string
|
||||
NickName string
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
type PeerStatus struct {
|
||||
Name string
|
||||
NickName string
|
||||
@@ -75,9 +64,6 @@ func NewStatus(router *Router) *Status {
|
||||
router.Ourself.Name.String(),
|
||||
router.Ourself.NickName,
|
||||
router.Port,
|
||||
router.Bridge.String(),
|
||||
router.Bridge.Stats(),
|
||||
NewMACStatusSlice(router.Macs),
|
||||
NewPeerStatusSlice(router.Peers),
|
||||
NewUnicastRouteStatusSlice(router.Routes),
|
||||
NewBroadcastRouteStatusSlice(router.Routes),
|
||||
@@ -86,22 +72,6 @@ func NewStatus(router *Router) *Status {
|
||||
router.Overlay.Diagnostics()}
|
||||
}
|
||||
|
||||
func NewMACStatusSlice(cache *MacCache) []MACStatus {
|
||||
cache.RLock()
|
||||
defer cache.RUnlock()
|
||||
|
||||
var slice []MACStatus
|
||||
for key, entry := range cache.table {
|
||||
slice = append(slice, MACStatus{
|
||||
intmac(key).String(),
|
||||
entry.peer.Name.String(),
|
||||
entry.peer.NickName,
|
||||
entry.lastSeen})
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
func NewPeerStatusSlice(peers *Peers) []PeerStatus {
|
||||
var slice []PeerStatus
|
||||
|
||||
@@ -176,7 +146,7 @@ func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus
|
||||
state = "established"
|
||||
}
|
||||
lc, _ := conn.(*LocalConnection)
|
||||
info := fmt.Sprintf("%-6v %v", lc.forwarder.DisplayName(), conn.Remote())
|
||||
info := fmt.Sprintf("%-6v %v", lc.OverlayConn.DisplayName(), conn.Remote())
|
||||
slice = append(slice, LocalConnectionStatus{conn.RemoteTCPAddr(), conn.Outbound(), state, info})
|
||||
}
|
||||
for address, target := range cm.targets {
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
type SurrogateGossipData struct {
|
||||
messages [][]byte
|
||||
@@ -1,4 +1,4 @@
|
||||
package router
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"time"
|
||||
@@ -11,14 +11,14 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
func startServer(t *testing.T, upstream *dns.ClientConfig) (*DNSServer, *Nameserver, int, int) {
|
||||
peername, err := router.PeerNameFromString("00:00:00:02:00:00")
|
||||
peername, err := mesh.PeerNameFromString("00:00:00:02:00:00")
|
||||
require.Nil(t, err)
|
||||
nameserver := New(peername, nil, "")
|
||||
nameserver := New(peername, "", func(mesh.PeerName) bool { return true })
|
||||
dnsserver, err := NewDNSServer(nameserver, "weave.local.", "0.0.0.0:0", "", 30, 5*time.Second)
|
||||
require.Nil(t, err)
|
||||
udpPort := dnsserver.servers[0].PacketConn.LocalAddr().(*net.UDPAddr).Port
|
||||
@@ -39,7 +39,7 @@ func TestTruncation(t *testing.T) {
|
||||
addrs := []address.Address{}
|
||||
for i := address.Address(0); i < 100; i++ {
|
||||
addrs = append(addrs, i)
|
||||
nameserver.AddEntry("foo.weave.local.", "", router.UnknownPeerName, i)
|
||||
nameserver.AddEntry("foo.weave.local.", "", mesh.UnknownPeerName, i)
|
||||
}
|
||||
|
||||
doRequest := func(client *dns.Client, request *dns.Msg, port int, expectedErr error) *dns.Msg {
|
||||
|
||||
+5
-5
@@ -8,15 +8,15 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
var now = func() int64 { return time.Now().Unix() }
|
||||
|
||||
type Entry struct {
|
||||
ContainerID string
|
||||
Origin router.PeerName
|
||||
Origin mesh.PeerName
|
||||
Addr address.Address
|
||||
Hostname string // as supplied
|
||||
lHostname string // lowercased (not exported, so not encoded by gob)
|
||||
@@ -128,7 +128,7 @@ func (es *Entries) checkAndPanic() *Entries {
|
||||
return es
|
||||
}
|
||||
|
||||
func (es *Entries) add(hostname, containerid string, origin router.PeerName, addr address.Address) Entry {
|
||||
func (es *Entries) add(hostname, containerid string, origin mesh.PeerName, addr address.Address) Entry {
|
||||
defer es.checkAndPanic().checkAndPanic()
|
||||
|
||||
entry := Entry{Hostname: hostname, lHostname: strings.ToLower(hostname),
|
||||
@@ -176,7 +176,7 @@ func (es *Entries) merge(incoming Entries) Entries {
|
||||
}
|
||||
|
||||
// f returning true means keep the entry.
|
||||
func (es *Entries) tombstone(ourname router.PeerName, f func(*Entry) bool) Entries {
|
||||
func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries {
|
||||
defer es.checkAndPanic().checkAndPanic()
|
||||
|
||||
tombstoned := Entries{}
|
||||
@@ -245,7 +245,7 @@ type GossipData struct {
|
||||
Entries
|
||||
}
|
||||
|
||||
func (g *GossipData) Merge(o router.GossipData) {
|
||||
func (g *GossipData) Merge(o mesh.GossipData) {
|
||||
other := o.(*GossipData)
|
||||
g.Entries.merge(other.Entries)
|
||||
if g.Timestamp < other.Timestamp {
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
func l(es Entries) Entries {
|
||||
@@ -28,21 +28,21 @@ func TestAdd(t *testing.T) {
|
||||
now = func() int64 { return 1234 }
|
||||
|
||||
entries := Entries{}
|
||||
entries.add("A", "", router.UnknownPeerName, address.Address(0))
|
||||
entries.add("A", "", mesh.UnknownPeerName, address.Address(0))
|
||||
expected := l(Entries{
|
||||
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)},
|
||||
Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0)},
|
||||
})
|
||||
require.Equal(t, entries, expected)
|
||||
|
||||
entries.tombstone(router.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" })
|
||||
entries.tombstone(mesh.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" })
|
||||
expected = l(Entries{
|
||||
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234},
|
||||
Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234},
|
||||
})
|
||||
require.Equal(t, entries, expected)
|
||||
|
||||
entries.add("A", "", router.UnknownPeerName, address.Address(0))
|
||||
entries.add("A", "", mesh.UnknownPeerName, address.Address(0))
|
||||
expected = l(Entries{
|
||||
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 2},
|
||||
Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0), Version: 2},
|
||||
})
|
||||
require.Equal(t, entries, expected)
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func TestTombstone(t *testing.T) {
|
||||
|
||||
es := makeEntries("AB")
|
||||
|
||||
es.tombstone(router.UnknownPeerName, func(e *Entry) bool {
|
||||
es.tombstone(mesh.UnknownPeerName, func(e *Entry) bool {
|
||||
return e.Hostname == "B"
|
||||
})
|
||||
expected := l(Entries{
|
||||
|
||||
+25
-31
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/miekg/dns"
|
||||
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,28 +34,24 @@ const (
|
||||
// - Update is O(n) for now
|
||||
type Nameserver struct {
|
||||
sync.RWMutex
|
||||
ourName router.PeerName
|
||||
domain string
|
||||
gossip router.Gossip
|
||||
entries Entries
|
||||
peers *router.Peers
|
||||
quit chan struct{}
|
||||
ourName mesh.PeerName
|
||||
domain string
|
||||
gossip mesh.Gossip
|
||||
entries Entries
|
||||
isKnownPeer func(mesh.PeerName) bool
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
func New(ourName router.PeerName, peers *router.Peers, domain string) *Nameserver {
|
||||
ns := &Nameserver{
|
||||
ourName: ourName,
|
||||
domain: dns.Fqdn(domain),
|
||||
peers: peers,
|
||||
quit: make(chan struct{}),
|
||||
func New(ourName mesh.PeerName, domain string, isKnownPeer func(mesh.PeerName) bool) *Nameserver {
|
||||
return &Nameserver{
|
||||
ourName: ourName,
|
||||
domain: dns.Fqdn(domain),
|
||||
isKnownPeer: isKnownPeer,
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
if peers != nil {
|
||||
peers.OnGC(ns.PeerGone)
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (n *Nameserver) SetGossip(gossip router.Gossip) {
|
||||
func (n *Nameserver) SetGossip(gossip mesh.Gossip) {
|
||||
n.gossip = gossip
|
||||
}
|
||||
|
||||
@@ -87,7 +83,7 @@ func (n *Nameserver) broadcastEntries(es ...Entry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Nameserver) AddEntry(hostname, containerid string, origin router.PeerName, addr address.Address) error {
|
||||
func (n *Nameserver) AddEntry(hostname, containerid string, origin mesh.PeerName, addr address.Address) error {
|
||||
n.infof("adding entry %s -> %s", hostname, addr.String())
|
||||
n.Lock()
|
||||
entry := n.entries.add(hostname, containerid, origin, addr)
|
||||
@@ -144,12 +140,12 @@ func (n *Nameserver) ContainerDied(ident string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Nameserver) PeerGone(peer *router.Peer) {
|
||||
func (n *Nameserver) PeerGone(peer mesh.PeerName) {
|
||||
n.infof("peer %s gone", peer.String())
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
n.entries.filter(func(e *Entry) bool {
|
||||
return e.Origin != peer.Name
|
||||
return e.Origin != peer
|
||||
})
|
||||
}
|
||||
|
||||
@@ -185,7 +181,7 @@ func (n *Nameserver) deleteTombstones() {
|
||||
})
|
||||
}
|
||||
|
||||
func (n *Nameserver) Gossip() router.GossipData {
|
||||
func (n *Nameserver) Gossip() mesh.GossipData {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
gossip := &GossipData{
|
||||
@@ -196,11 +192,11 @@ func (n *Nameserver) Gossip() router.GossipData {
|
||||
return gossip
|
||||
}
|
||||
|
||||
func (n *Nameserver) OnGossipUnicast(sender router.PeerName, msg []byte) error {
|
||||
func (n *Nameserver) OnGossipUnicast(sender mesh.PeerName, msg []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Nameserver) receiveGossip(msg []byte) (router.GossipData, router.GossipData, error) {
|
||||
func (n *Nameserver) receiveGossip(msg []byte) (mesh.GossipData, mesh.GossipData, error) {
|
||||
var gossip GossipData
|
||||
if err := gossip.Decode(msg); err != nil {
|
||||
return nil, nil, err
|
||||
@@ -212,11 +208,9 @@ func (n *Nameserver) receiveGossip(msg []byte) (router.GossipData, router.Gossip
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if n.peers != nil {
|
||||
gossip.Entries.filter(func(e *Entry) bool {
|
||||
return n.peers.Fetch(e.Origin) != nil
|
||||
})
|
||||
}
|
||||
gossip.Entries.filter(func(e *Entry) bool {
|
||||
return n.isKnownPeer(e.Origin)
|
||||
})
|
||||
|
||||
newEntries := n.entries.merge(gossip.Entries)
|
||||
if len(newEntries) > 0 {
|
||||
@@ -227,14 +221,14 @@ func (n *Nameserver) receiveGossip(msg []byte) (router.GossipData, router.Gossip
|
||||
|
||||
// merge received data into state and return "everything new I've
|
||||
// just learnt", or nil if nothing in the received data was new
|
||||
func (n *Nameserver) OnGossip(msg []byte) (router.GossipData, error) {
|
||||
func (n *Nameserver) OnGossip(msg []byte) (mesh.GossipData, error) {
|
||||
newEntries, _, err := n.receiveGossip(msg)
|
||||
return newEntries, err
|
||||
}
|
||||
|
||||
// merge received data into state and return a representation of
|
||||
// the received data, for further propagation
|
||||
func (n *Nameserver) OnGossipBroadcast(_ router.PeerName, msg []byte) (router.GossipData, error) {
|
||||
func (n *Nameserver) OnGossipBroadcast(_ mesh.PeerName, msg []byte) (mesh.GossipData, error) {
|
||||
_, entries, err := n.receiveGossip(msg)
|
||||
return entries, err
|
||||
}
|
||||
|
||||
@@ -11,19 +11,23 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
"github.com/weaveworks/weave/testing/gossip"
|
||||
)
|
||||
|
||||
func makeNameserver(name mesh.PeerName) *Nameserver {
|
||||
return New(name, "", func(mesh.PeerName) bool { return true })
|
||||
}
|
||||
|
||||
func makeNetwork(size int) ([]*Nameserver, *gossip.TestRouter) {
|
||||
gossipRouter := gossip.NewTestRouter(0.0)
|
||||
nameservers := make([]*Nameserver, size)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
name, _ := router.PeerNameFromString(fmt.Sprintf("%02d:00:00:02:00:00", i))
|
||||
nameserver := New(name, nil, "")
|
||||
name, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:00:00:02:00:00", i))
|
||||
nameserver := makeNameserver(name)
|
||||
nameserver.SetGossip(gossipRouter.Connect(nameserver.ourName, nameserver))
|
||||
nameserver.Start()
|
||||
nameservers[i] = nameserver
|
||||
@@ -40,7 +44,7 @@ func stopNetwork(nameservers []*Nameserver, grouter *gossip.TestRouter) {
|
||||
}
|
||||
|
||||
type pair struct {
|
||||
origin router.PeerName
|
||||
origin mesh.PeerName
|
||||
addr address.Address
|
||||
}
|
||||
|
||||
@@ -87,7 +91,7 @@ func testNameservers(t *testing.T) {
|
||||
badNameservers := nameservers[25:]
|
||||
// This subset will remain well-connected, and we will deal mainly with them
|
||||
nameservers = nameservers[:25]
|
||||
nameserversByName := map[router.PeerName]*Nameserver{}
|
||||
nameserversByName := map[mesh.PeerName]*Nameserver{}
|
||||
for _, n := range nameservers {
|
||||
nameserversByName[n.ourName] = n
|
||||
}
|
||||
@@ -142,7 +146,7 @@ func testNameservers(t *testing.T) {
|
||||
loseConnection := func() {
|
||||
nameserver1 := badNameservers[rand.Intn(len(badNameservers))]
|
||||
nameserver2 := nameservers[rand.Intn(len(nameservers))]
|
||||
nameserver1.PeerGone(&router.Peer{Name: nameserver2.ourName})
|
||||
nameserver1.PeerGone(nameserver2.ourName)
|
||||
}
|
||||
|
||||
deleteMapping := func() {
|
||||
@@ -222,9 +226,9 @@ func testNameservers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestContainerAndPeerDeath(t *testing.T) {
|
||||
peername, err := router.PeerNameFromString("00:00:00:02:00:00")
|
||||
peername, err := mesh.PeerNameFromString("00:00:00:02:00:00")
|
||||
require.Nil(t, err)
|
||||
nameserver := New(peername, nil, "")
|
||||
nameserver := makeNameserver(peername)
|
||||
|
||||
err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
|
||||
require.Nil(t, err)
|
||||
@@ -237,7 +241,7 @@ func TestContainerAndPeerDeath(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname"))
|
||||
|
||||
nameserver.PeerGone(&router.Peer{Name: peername})
|
||||
nameserver.PeerGone(peername)
|
||||
require.Equal(t, []address.Address{}, nameserver.Lookup("hostname"))
|
||||
}
|
||||
|
||||
@@ -246,9 +250,9 @@ func TestTombstoneDeletion(t *testing.T) {
|
||||
defer func() { now = oldNow }()
|
||||
now = func() int64 { return 1234 }
|
||||
|
||||
peername, err := router.PeerNameFromString("00:00:00:02:00:00")
|
||||
peername, err := mesh.PeerNameFromString("00:00:00:02:00:00")
|
||||
require.Nil(t, err)
|
||||
nameserver := New(peername, nil, "")
|
||||
nameserver := makeNameserver(peername)
|
||||
|
||||
err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0))
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -19,7 +19,7 @@ func NewRange(start Address, size Offset) Range {
|
||||
return Range{Start: start, End: Add(start, size)}
|
||||
}
|
||||
func (r Range) Size() Offset { return Subtract(r.End, r.Start) }
|
||||
func (r Range) String() string { return fmt.Sprintf("[%s-%s)", r.Start, r.End) }
|
||||
func (r Range) String() string { return fmt.Sprintf("%s-%s", r.Start, r.End-1) }
|
||||
func (r Range) Overlaps(or Range) bool { return !(r.Start >= or.End || r.End <= or.Start) }
|
||||
func (r Range) Contains(addr Address) bool { return addr >= r.Start && addr < r.End }
|
||||
|
||||
|
||||
+8
-7
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/ipam"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
weave "github.com/weaveworks/weave/router"
|
||||
@@ -24,14 +25,14 @@ var rootTemplate = template.New("root").Funcs(map[string]interface{}{
|
||||
}
|
||||
return count
|
||||
},
|
||||
"printConnectionCounts": func(conns []weave.LocalConnectionStatus) string {
|
||||
"printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string {
|
||||
counts := make(map[string]int)
|
||||
for _, conn := range conns {
|
||||
counts[conn.State]++
|
||||
}
|
||||
return printCounts(counts, []string{"established", "pending", "retrying", "failed", "connecting"})
|
||||
},
|
||||
"printPeerConnectionCounts": func(peers []weave.PeerStatus) string {
|
||||
"printPeerConnectionCounts": func(peers []mesh.PeerStatus) string {
|
||||
counts := make(map[string]int)
|
||||
for _, peer := range peers {
|
||||
for _, conn := range peer.Connections {
|
||||
@@ -146,16 +147,16 @@ var dnsEntriesTemplate = defTemplate("dnsEntries", `\
|
||||
|
||||
type WeaveStatus struct {
|
||||
Version string
|
||||
Router *weave.Status `json:"Router,omitempty"`
|
||||
IPAM *ipam.Status `json:"IPAM,omitempty"`
|
||||
DNS *nameserver.Status `json:"DNS,omitempty"`
|
||||
Router *weave.NetworkRouterStatus `json:"Router,omitempty"`
|
||||
IPAM *ipam.Status `json:"IPAM,omitempty"`
|
||||
DNS *nameserver.Status `json:"DNS,omitempty"`
|
||||
}
|
||||
|
||||
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.Router, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
|
||||
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
|
||||
status := func() WeaveStatus {
|
||||
return WeaveStatus{
|
||||
version,
|
||||
weave.NewStatus(router),
|
||||
weave.NewNetworkRouterStatus(router),
|
||||
ipam.NewStatus(allocator, defaultSubnet),
|
||||
nameserver.NewStatus(ns, dnsserver)}
|
||||
}
|
||||
|
||||
+26
-21
@@ -16,7 +16,9 @@ import (
|
||||
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/common/docker"
|
||||
"github.com/weaveworks/weave/common/odp"
|
||||
"github.com/weaveworks/weave/ipam"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
weavenet "github.com/weaveworks/weave/net"
|
||||
"github.com/weaveworks/weave/net/address"
|
||||
@@ -41,7 +43,8 @@ func main() {
|
||||
deleteDatapath bool
|
||||
addDatapathInterface string
|
||||
|
||||
config weave.Config
|
||||
config mesh.Config
|
||||
networkConfig weave.NetworkConfig
|
||||
protocolMinVersion int
|
||||
ifaceName string
|
||||
routerName string
|
||||
@@ -73,8 +76,8 @@ func main() {
|
||||
mflag.BoolVar(&deleteDatapath, []string{"-delete-datapath"}, false, "delete ODP datapath and exit")
|
||||
mflag.StringVar(&addDatapathInterface, []string{"-add-datapath-iface"}, "", "add a network interface to the ODP datapath and exit")
|
||||
|
||||
mflag.IntVar(&config.Port, []string{"#port", "-port"}, weave.Port, "router port")
|
||||
mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, weave.ProtocolMinVersion, "minimum weave protocol version")
|
||||
mflag.IntVar(&config.Port, []string{"#port", "-port"}, mesh.Port, "router port")
|
||||
mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, mesh.ProtocolMinVersion, "minimum weave protocol version")
|
||||
mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)")
|
||||
mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)")
|
||||
mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)")
|
||||
@@ -85,7 +88,7 @@ func main() {
|
||||
mflag.IntVar(&config.ConnLimit, []string{"#connlimit", "#-connlimit", "-conn-limit"}, 30, "connection limit (0 for unlimited)")
|
||||
mflag.BoolVar(&noDiscovery, []string{"#nodiscovery", "#-nodiscovery", "-no-discovery"}, false, "disable peer discovery")
|
||||
mflag.IntVar(&bufSzMB, []string{"#bufsz", "-bufsz"}, 8, "capture buffer size in MB")
|
||||
mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, fmt.Sprintf(":%d", weave.HTTPPort), "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)")
|
||||
mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, "", "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)")
|
||||
mflag.StringVar(&iprangeCIDR, []string{"#iprange", "#-iprange", "-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation")
|
||||
mflag.StringVar(&ipsubnetCIDR, []string{"#ipsubnet", "#-ipsubnet", "-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation")
|
||||
mflag.IntVar(&peerCount, []string{"#initpeercount", "#-initpeercount", "-init-peer-count"}, 0, "number of peers in network (for IP address allocation)")
|
||||
@@ -118,7 +121,7 @@ func main() {
|
||||
os.Exit(0)
|
||||
|
||||
case createDatapath:
|
||||
err, odp_supported := weave.CreateDatapath(datapathName)
|
||||
err, odp_supported := odp.CreateDatapath(datapathName)
|
||||
if !odp_supported {
|
||||
if err != nil {
|
||||
Log.Error(err)
|
||||
@@ -134,23 +137,23 @@ func main() {
|
||||
os.Exit(0)
|
||||
|
||||
case deleteDatapath:
|
||||
checkFatal(weave.DeleteDatapath(datapathName))
|
||||
checkFatal(odp.DeleteDatapath(datapathName))
|
||||
os.Exit(0)
|
||||
|
||||
case addDatapathInterface != "":
|
||||
checkFatal(weave.AddDatapathInterface(datapathName, addDatapathInterface))
|
||||
checkFatal(odp.AddDatapathInterface(datapathName, addDatapathInterface))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
Log.Println("Command line options:", options())
|
||||
Log.Println("Command line peers:", peers)
|
||||
|
||||
if protocolMinVersion < weave.ProtocolMinVersion || protocolMinVersion > weave.ProtocolMaxVersion {
|
||||
Log.Fatalf("--min-protocol-version must be in range [%d,%d]", weave.ProtocolMinVersion, weave.ProtocolMaxVersion)
|
||||
if protocolMinVersion < mesh.ProtocolMinVersion || protocolMinVersion > mesh.ProtocolMaxVersion {
|
||||
Log.Fatalf("--min-protocol-version must be in range [%d,%d]", mesh.ProtocolMinVersion, mesh.ProtocolMaxVersion)
|
||||
}
|
||||
config.ProtocolMinVersion = byte(protocolMinVersion)
|
||||
|
||||
var fastDPOverlay weave.Overlay
|
||||
var fastDPOverlay weave.NetworkOverlay
|
||||
if datapathName != "" {
|
||||
// A datapath name implies that "Bridge" and "Overlay"
|
||||
// packet handling use fast datapath, although other
|
||||
@@ -163,7 +166,7 @@ func main() {
|
||||
})
|
||||
|
||||
checkFatal(err)
|
||||
config.Bridge = fastdp.Bridge()
|
||||
networkConfig.Bridge = fastdp.Bridge()
|
||||
fastDPOverlay = fastdp.Overlay()
|
||||
}
|
||||
|
||||
@@ -178,7 +181,7 @@ func main() {
|
||||
checkFatal(err)
|
||||
|
||||
// bufsz flag is in MB
|
||||
config.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024)
|
||||
networkConfig.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024)
|
||||
checkFatal(err)
|
||||
}
|
||||
|
||||
@@ -203,7 +206,6 @@ func main() {
|
||||
sleeve := weave.NewSleeveOverlay(config.Port)
|
||||
overlays.Add("sleeve", sleeve)
|
||||
overlays.SetCompatOverlay(sleeve)
|
||||
config.Overlay = overlays
|
||||
|
||||
if routerName == "" {
|
||||
if iface == nil {
|
||||
@@ -212,7 +214,7 @@ func main() {
|
||||
routerName = iface.HardwareAddr.String()
|
||||
}
|
||||
|
||||
name, err := weave.PeerNameFromUserInput(routerName)
|
||||
name, err := mesh.PeerNameFromUserInput(routerName)
|
||||
checkFatal(err)
|
||||
|
||||
if nickName == "" {
|
||||
@@ -230,12 +232,12 @@ func main() {
|
||||
config.PeerDiscovery = !noDiscovery
|
||||
|
||||
if pktdebug {
|
||||
config.PacketLogging = packetLogging{}
|
||||
networkConfig.PacketLogging = packetLogging{}
|
||||
} else {
|
||||
config.PacketLogging = nopPacketLogging{}
|
||||
networkConfig.PacketLogging = nopPacketLogging{}
|
||||
}
|
||||
|
||||
router := weave.NewRouter(config, name, nickName)
|
||||
router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlays)
|
||||
Log.Println("Our name is", router.Ourself)
|
||||
|
||||
var dockerCli *docker.Client
|
||||
@@ -253,10 +255,13 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
isKnownPeer := func(name mesh.PeerName) bool {
|
||||
return router.Peers.Fetch(name) != nil
|
||||
}
|
||||
var allocator *ipam.Allocator
|
||||
var defaultSubnet address.CIDR
|
||||
if iprangeCIDR != "" {
|
||||
allocator, defaultSubnet = createAllocator(router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers))
|
||||
allocator, defaultSubnet = createAllocator(router.Router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer)
|
||||
observeContainers(allocator)
|
||||
} else if peerCount > 0 {
|
||||
Log.Fatal("--init-peer-count flag specified without --ipalloc-range")
|
||||
@@ -267,7 +272,8 @@ func main() {
|
||||
dnsserver *nameserver.DNSServer
|
||||
)
|
||||
if !noDNS {
|
||||
ns = nameserver.New(router.Ourself.Peer.Name, router.Peers, dnsDomain)
|
||||
ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer)
|
||||
router.Peers.OnGC(func(peer *mesh.Peer) { ns.PeerGone(peer.Name) })
|
||||
ns.SetGossip(router.NewGossip("nameserver", ns))
|
||||
observeContainers(ns)
|
||||
ns.Start()
|
||||
@@ -362,7 +368,7 @@ func parseAndCheckCIDR(cidrStr string) address.CIDR {
|
||||
return cidr
|
||||
}
|
||||
|
||||
func createAllocator(router *weave.Router, ipRangeStr string, defaultSubnetStr string, quorum uint) (*ipam.Allocator, address.CIDR) {
|
||||
func createAllocator(router *mesh.Router, ipRangeStr string, defaultSubnetStr string, quorum uint, isKnownPeer func(mesh.PeerName) bool) (*ipam.Allocator, address.CIDR) {
|
||||
ipRange := parseAndCheckCIDR(ipRangeStr)
|
||||
defaultSubnet := ipRange
|
||||
if defaultSubnetStr != "" {
|
||||
@@ -371,7 +377,6 @@ func createAllocator(router *weave.Router, ipRangeStr string, defaultSubnetStr s
|
||||
Log.Fatalf("IP address allocation default subnet %s does not overlap with allocation range %s", defaultSubnet, ipRange)
|
||||
}
|
||||
}
|
||||
isKnownPeer := func(name weave.PeerName) bool { return router.Peers.Fetch(name) != nil }
|
||||
allocator := ipam.NewAllocator(router.Ourself.Peer.Name, router.Ourself.Peer.UID, router.Ourself.Peer.NickName, ipRange.Range(), quorum, isKnownPeer)
|
||||
|
||||
allocator.SetInterfaces(router.NewGossip("IPallocation", allocator))
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@ import (
|
||||
. "github.com/weaveworks/weave/common"
|
||||
weavedocker "github.com/weaveworks/weave/common/docker"
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -490,7 +489,7 @@ func (proxy *Proxy) getDNSDomain() (domain string) {
|
||||
weaveIP = "127.0.0.1"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/domain", weaveIP, router.HTTPPort)
|
||||
url := fmt.Sprintf("http://%s:6784/domain", weaveIP)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
Port = 6783
|
||||
HTTPPort = Port + 1
|
||||
MaxUDPPacketSize = 65535
|
||||
ChannelSize = 16
|
||||
TCPHeartbeat = 30 * time.Second
|
||||
GossipInterval = 30 * time.Second
|
||||
MaxDuration = time.Duration(math.MaxInt64)
|
||||
MaxTCPMsgSize = 10 * 1024 * 1024
|
||||
FastHeartbeat = 500 * time.Millisecond
|
||||
SlowHeartbeat = 10 * time.Second
|
||||
MaxMissedHeartbeats = 6
|
||||
HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat
|
||||
)
|
||||
+45
-66
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/go-odp/odp"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// The virtual bridge accepts packets from ODP vports and the router
|
||||
@@ -40,8 +41,8 @@ type FastDatapath struct {
|
||||
dp odp.DatapathHandle
|
||||
deleteFlowsCount uint64
|
||||
missHandlers map[odp.VportID]missHandler
|
||||
localPeer *Peer
|
||||
peers *Peers
|
||||
localPeer *mesh.Peer
|
||||
peers *mesh.Peers
|
||||
overlayConsumer OverlayConsumer
|
||||
|
||||
// Bridge state: How to send to the given bridge port
|
||||
@@ -62,7 +63,7 @@ type FastDatapath struct {
|
||||
dec *EthernetDecoder
|
||||
|
||||
// forwarders by remote peer
|
||||
forwarders map[PeerName]*fastDatapathForwarder
|
||||
forwarders map[mesh.PeerName]*fastDatapathForwarder
|
||||
}
|
||||
|
||||
type FastDatapathConfig struct {
|
||||
@@ -105,7 +106,7 @@ func NewFastDatapath(config FastDatapathConfig) (*FastDatapath, error) {
|
||||
sendToMAC: make(map[MAC]bridgeSender),
|
||||
seenMACs: make(map[MAC]struct{}),
|
||||
vxlanVportIDs: make(map[int]odp.VportID),
|
||||
forwarders: make(map[PeerName]*fastDatapathForwarder),
|
||||
forwarders: make(map[mesh.PeerName]*fastDatapathForwarder),
|
||||
}
|
||||
|
||||
if err := fastdp.deleteVxlanVports(); err != nil {
|
||||
@@ -248,8 +249,7 @@ func (fastdp fastDatapathBridge) InjectPacket(key PacketKey) FlowOp {
|
||||
|
||||
// Ethernet bridge implementation
|
||||
|
||||
func (fastdp *FastDatapath) bridge(ingress bridgePortID,
|
||||
key PacketKey, lock *fastDatapathLock) FlowOp {
|
||||
func (fastdp *FastDatapath) bridge(ingress bridgePortID, key PacketKey, lock *fastDatapathLock) FlowOp {
|
||||
lock.relock()
|
||||
if fastdp.sendToMAC[key.SrcMAC] == nil {
|
||||
// Learn the source MAC
|
||||
@@ -260,8 +260,7 @@ func (fastdp *FastDatapath) bridge(ingress bridgePortID,
|
||||
// If we know about the destination MAC, deliver it to the
|
||||
// associated port.
|
||||
if sender := fastdp.sendToMAC[key.DstMAC]; sender != nil {
|
||||
return NewMultiFlowOp(false, odpEthernetFlowKey(key),
|
||||
sender(key, lock))
|
||||
return NewMultiFlowOp(false, odpEthernetFlowKey(key), sender(key, lock))
|
||||
}
|
||||
|
||||
// Otherwise, it might be a real broadcast, or it might
|
||||
@@ -299,7 +298,7 @@ type fastDatapathOverlay struct {
|
||||
*FastDatapath
|
||||
}
|
||||
|
||||
func (fastdp *FastDatapath) Overlay() Overlay {
|
||||
func (fastdp *FastDatapath) Overlay() NetworkOverlay {
|
||||
return fastDatapathOverlay{fastdp}
|
||||
}
|
||||
|
||||
@@ -345,8 +344,7 @@ func (flowStatus *FlowStatus) MarshalJSON() ([]byte, error) {
|
||||
actions = append(actions, fmt.Sprint(action))
|
||||
}
|
||||
|
||||
return json.Marshal(&jsonFlowStatus{flowKeys, actions,
|
||||
flowStatus.Packets, flowStatus.Bytes, flowStatus.Used})
|
||||
return json.Marshal(&jsonFlowStatus{flowKeys, actions, flowStatus.Packets, flowStatus.Bytes, flowStatus.Used})
|
||||
}
|
||||
|
||||
type VportStatus odp.Vport
|
||||
@@ -358,8 +356,7 @@ func (vport *VportStatus) MarshalJSON() ([]byte, error) {
|
||||
TypeName string
|
||||
}
|
||||
|
||||
return json.Marshal(&jsonVportStatus{vport.ID, vport.Spec.Name(),
|
||||
vport.Spec.TypeName()})
|
||||
return json.Marshal(&jsonVportStatus{vport.ID, vport.Spec.Name(), vport.Spec.TypeName()})
|
||||
}
|
||||
|
||||
func (fastdp fastDatapathOverlay) Diagnostics() interface{} {
|
||||
@@ -367,18 +364,14 @@ func (fastdp fastDatapathOverlay) Diagnostics() interface{} {
|
||||
defer lock.unlock()
|
||||
|
||||
vports, err := fastdp.dp.EnumerateVports()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
checkWarn(err)
|
||||
vportStatuses := make([]VportStatus, 0, len(vports))
|
||||
for _, vport := range vports {
|
||||
vportStatuses = append(vportStatuses, VportStatus(vport))
|
||||
}
|
||||
|
||||
flows, err := fastdp.dp.EnumerateFlows()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
checkWarn(err)
|
||||
flowStatuses := make([]FlowStatus, 0, len(flows))
|
||||
for _, flow := range flows {
|
||||
flowStatuses = append(flowStatuses, FlowStatus(flow))
|
||||
@@ -393,8 +386,7 @@ func (fastdp fastDatapathOverlay) Diagnostics() interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func (fastdp fastDatapathOverlay) StartConsumingPackets(localPeer *Peer,
|
||||
peers *Peers, consumer OverlayConsumer) error {
|
||||
func (fastdp fastDatapathOverlay) StartConsumingPackets(localPeer *mesh.Peer, peers *mesh.Peers, consumer OverlayConsumer) error {
|
||||
fastdp.lock.Lock()
|
||||
defer fastdp.lock.Unlock()
|
||||
|
||||
@@ -417,8 +409,7 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
||||
}
|
||||
|
||||
vxlanVportID, err := fastdp.dp.CreateVport(
|
||||
odp.NewVxlanVportSpec(fmt.Sprintf("vxlan-%d", udpPort),
|
||||
uint16(udpPort)))
|
||||
odp.NewVxlanVportSpec(fmt.Sprintf("vxlan-%d", udpPort), uint16(udpPort)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -464,29 +455,27 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
||||
tunnelFlowKey.SetIpv4Src(tunKey.Ipv4Src)
|
||||
tunnelFlowKey.SetIpv4Dst(tunKey.Ipv4Dst)
|
||||
|
||||
return NewMultiFlowOp(false, odpFlowKey(tunnelFlowKey),
|
||||
consumer(key))
|
||||
return NewMultiFlowOp(false, odpFlowKey(tunnelFlowKey), consumer(key))
|
||||
}
|
||||
|
||||
return vxlanVportID, nil
|
||||
}
|
||||
|
||||
func (fastdp *FastDatapath) extractPeers(tunnelID [8]byte) (*Peer, *Peer) {
|
||||
func (fastdp *FastDatapath) extractPeers(tunnelID [8]byte) (*mesh.Peer, *mesh.Peer) {
|
||||
vni := binary.BigEndian.Uint64(tunnelID[:])
|
||||
srcPeer := fastdp.peers.FetchByShortID(PeerShortID(vni & 0xfff))
|
||||
dstPeer := fastdp.peers.FetchByShortID(PeerShortID((vni >> 12) & 0xfff))
|
||||
srcPeer := fastdp.peers.FetchByShortID(mesh.PeerShortID(vni & 0xfff))
|
||||
dstPeer := fastdp.peers.FetchByShortID(mesh.PeerShortID((vni >> 12) & 0xfff))
|
||||
return srcPeer, dstPeer
|
||||
}
|
||||
|
||||
type vxlanSpecialPacketFlowOp struct {
|
||||
NonDiscardingFlowOp
|
||||
fastdp *FastDatapath
|
||||
srcPeer *Peer
|
||||
srcPeer *mesh.Peer
|
||||
sender *net.UDPAddr
|
||||
}
|
||||
|
||||
func (op vxlanSpecialPacketFlowOp) Process(frame []byte, dec *EthernetDecoder,
|
||||
broadcast bool) {
|
||||
func (op vxlanSpecialPacketFlowOp) Process(frame []byte, dec *EthernetDecoder, broadcast bool) {
|
||||
op.fastdp.lock.Lock()
|
||||
fwd := op.fastdp.forwarders[op.srcPeer.Name]
|
||||
op.fastdp.lock.Unlock()
|
||||
@@ -498,7 +487,7 @@ func (op vxlanSpecialPacketFlowOp) Process(frame []byte, dec *EthernetDecoder,
|
||||
|
||||
type fastDatapathForwarder struct {
|
||||
fastdp *FastDatapath
|
||||
remotePeer *Peer
|
||||
remotePeer *mesh.Peer
|
||||
localIP [4]byte
|
||||
sendControlMsg func(byte, []byte) error
|
||||
connUID uint64
|
||||
@@ -518,24 +507,24 @@ type fastDatapathForwarder struct {
|
||||
errorChan chan error
|
||||
}
|
||||
|
||||
func (fastdp fastDatapathOverlay) MakeForwarder(
|
||||
params ForwarderParams) (OverlayForwarder, error) {
|
||||
if params.Crypto != nil {
|
||||
func (fastdp fastDatapathOverlay) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) {
|
||||
if params.SessionKey != nil {
|
||||
// No encryption suport in fastdp. The weaver main.go
|
||||
// is responsible for ensuring this doesn't happen.
|
||||
log.Fatal("Attempt to use FastDatapath with encryption")
|
||||
}
|
||||
|
||||
vxlanVportID := fastdp.mainVxlanVportID
|
||||
remoteAddr := params.RemoteAddr
|
||||
if remoteAddr != nil {
|
||||
var remoteAddr *net.UDPAddr
|
||||
|
||||
if params.Outbound {
|
||||
remoteAddr = makeUDPAddr(params.RemoteAddr)
|
||||
// The provided address contains the main weave port
|
||||
// number to connect to. We need to derive the vxlan
|
||||
// port number from that.
|
||||
vxlanRemoteAddr := *params.RemoteAddr
|
||||
vxlanRemoteAddr := *remoteAddr
|
||||
vxlanRemoteAddr.Port++
|
||||
remoteAddr = &vxlanRemoteAddr
|
||||
|
||||
var err error
|
||||
vxlanVportID, err = fastdp.getVxlanVportID(remoteAddr.Port)
|
||||
if err != nil {
|
||||
@@ -543,7 +532,7 @@ func (fastdp fastDatapathOverlay) MakeForwarder(
|
||||
}
|
||||
}
|
||||
|
||||
localIP, err := ipv4Bytes(params.LocalIP)
|
||||
localIP, err := ipv4Bytes(params.LocalAddr.IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -674,15 +663,17 @@ func (fwd *fastDatapathForwarder) sendHeartbeat() {
|
||||
DstPeer: fwd.remotePeer,
|
||||
}
|
||||
fwd.lock.RUnlock()
|
||||
fwd.Forward(pk).Process(buf, dec, false)
|
||||
|
||||
if fop := fwd.Forward(pk); fop != nil {
|
||||
fop.Process(buf, dec, false)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
FastDatapathHeartbeatAck = iota
|
||||
)
|
||||
|
||||
func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte,
|
||||
sender *net.UDPAddr) {
|
||||
func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte, sender *net.UDPAddr) {
|
||||
fwd.lock.Lock()
|
||||
defer fwd.lock.Unlock()
|
||||
|
||||
@@ -706,8 +697,7 @@ func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte,
|
||||
fwd.heartbeatTimer.Reset(0)
|
||||
}
|
||||
} else if !udpAddrsEqual(fwd.remoteAddr, sender) {
|
||||
log.Info(fwd.logPrefix(),
|
||||
"Peer IP address changed to ", sender)
|
||||
log.Info(fwd.logPrefix(), "Peer IP address changed to ", sender)
|
||||
fwd.remoteAddr = sender
|
||||
}
|
||||
|
||||
@@ -732,8 +722,7 @@ func (fwd *fastDatapathForwarder) ControlMessage(tag byte, msg []byte) {
|
||||
fwd.handleHeartbeatAck()
|
||||
|
||||
default:
|
||||
log.Info(fwd.logPrefix(),
|
||||
"Ignoring unknown control message: ", tag)
|
||||
log.Info(fwd.logPrefix(), "Ignoring unknown control message: ", tag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,8 +798,7 @@ func (fwd *fastDatapathForwarder) Stop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (fastdp *FastDatapath) addForwarder(peer PeerName,
|
||||
fwd *fastDatapathForwarder) {
|
||||
func (fastdp *FastDatapath) addForwarder(peer mesh.PeerName, fwd *fastDatapathForwarder) {
|
||||
fastdp.lock.Lock()
|
||||
defer fastdp.lock.Unlock()
|
||||
|
||||
@@ -819,8 +807,7 @@ func (fastdp *FastDatapath) addForwarder(peer PeerName,
|
||||
fastdp.forwarders[peer] = fwd
|
||||
}
|
||||
|
||||
func (fastdp *FastDatapath) removeForwarder(peer PeerName,
|
||||
fwd *fastDatapathForwarder) {
|
||||
func (fastdp *FastDatapath) removeForwarder(peer mesh.PeerName, fwd *fastDatapathForwarder) {
|
||||
fastdp.lock.Lock()
|
||||
defer fastdp.lock.Unlock()
|
||||
if fastdp.forwarders[peer] == fwd {
|
||||
@@ -899,9 +886,7 @@ func (fastdp *FastDatapath) expireFlows() {
|
||||
defer lock.unlock()
|
||||
|
||||
flows, err := fastdp.dp.EnumerateFlows()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
checkWarn(err)
|
||||
|
||||
for _, flow := range flows {
|
||||
if flow.Used == 0 {
|
||||
@@ -922,8 +907,7 @@ func (fastdp *FastDatapath) expireFlows() {
|
||||
// maintain its MAC->peer table. We do this by querying the router
|
||||
// without an actual packet being involved. Maybe it's
|
||||
// worth devising a more unified approach in the future.
|
||||
func (fastdp *FastDatapath) touchFlow(fks odp.FlowKeys,
|
||||
lock *fastDatapathLock) {
|
||||
func (fastdp *FastDatapath) touchFlow(fks odp.FlowKeys, lock *fastDatapathLock) {
|
||||
// All the flows we create should have an ingress key, but we
|
||||
// check here just in case we encounter one from somewhere
|
||||
// else.
|
||||
@@ -963,8 +947,7 @@ func (fastdp *FastDatapath) Miss(packet []byte, fks odp.FlowKeys) error {
|
||||
// delivery to a local netdev based on the dest MAC),
|
||||
// including the ingress in every flow makes things simpler
|
||||
// in touchFlow.
|
||||
mfop := NewMultiFlowOp(false, handler(fks, &lock),
|
||||
odpFlowKey(odp.NewInPortFlowKey(ingress)))
|
||||
mfop := NewMultiFlowOp(false, handler(fks, &lock), odpFlowKey(odp.NewInPortFlowKey(ingress)))
|
||||
fastdp.send(mfop, packet, &lock)
|
||||
return nil
|
||||
}
|
||||
@@ -1032,8 +1015,7 @@ func (fastdp *FastDatapath) makeBridgeVport(vport odp.Vport) {
|
||||
|
||||
// Packets coming from the netdev are processed by the bridge
|
||||
fastdp.missHandlers[vportID] = func(flowKeys odp.FlowKeys, lock *fastDatapathLock) FlowOp {
|
||||
return fastdp.bridge(bridgePortID{vport: vportID},
|
||||
flowKeysToPacketKey(flowKeys), lock)
|
||||
return fastdp.bridge(bridgePortID{vport: vportID}, flowKeysToPacketKey(flowKeys), lock)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,8 +1026,7 @@ func flowKeysToPacketKey(fks odp.FlowKeys) PacketKey {
|
||||
|
||||
// The sendToPort map is read-only, so this method does the copy in
|
||||
// order to add an entry.
|
||||
func (fastdp *FastDatapath) addSendToPort(portID bridgePortID,
|
||||
sender bridgeSender) {
|
||||
func (fastdp *FastDatapath) addSendToPort(portID bridgePortID, sender bridgeSender) {
|
||||
sendToPort := map[bridgePortID]bridgeSender{portID: sender}
|
||||
for id, sender := range fastdp.sendToPort {
|
||||
sendToPort[id] = sender
|
||||
@@ -1064,8 +1045,7 @@ func (fastdp *FastDatapath) deleteSendToPort(portID bridgePortID) {
|
||||
}
|
||||
|
||||
// Send a packet, creating a corresponding ODP flow rule if possible
|
||||
func (fastdp *FastDatapath) send(fops FlowOp, frame []byte,
|
||||
lock *fastDatapathLock) {
|
||||
func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLock) {
|
||||
// Gather the actions from actionFlowOps, execute any others
|
||||
var dec *EthernetDecoder
|
||||
flow := odp.NewFlowSpec()
|
||||
@@ -1157,8 +1137,7 @@ func (fop odpActionsFlowOp) updateFlowSpec(flow *odp.FlowSpec) {
|
||||
flow.AddActions(fop.actions)
|
||||
}
|
||||
|
||||
func (fop odpActionsFlowOp) Process(frame []byte, dec *EthernetDecoder,
|
||||
broadcast bool) {
|
||||
func (fop odpActionsFlowOp) Process(frame []byte, dec *EthernetDecoder, broadcast bool) {
|
||||
fastdp := fop.fastdp
|
||||
fastdp.lock.Lock()
|
||||
defer fastdp.lock.Unlock()
|
||||
|
||||
+8
-5
@@ -1,6 +1,10 @@
|
||||
package router
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// Just enough flow machinery for the weave router
|
||||
|
||||
@@ -16,8 +20,8 @@ type PacketKey struct {
|
||||
}
|
||||
|
||||
type ForwardPacketKey struct {
|
||||
SrcPeer *Peer
|
||||
DstPeer *Peer
|
||||
SrcPeer *mesh.Peer
|
||||
DstPeer *mesh.Peer
|
||||
PacketKey
|
||||
}
|
||||
|
||||
@@ -64,8 +68,7 @@ func (mfop *MultiFlowOp) Add(op FlowOp) {
|
||||
mfop.ops = append(mfop.ops, op)
|
||||
}
|
||||
|
||||
func (mfop *MultiFlowOp) Process(frame []byte, dec *EthernetDecoder,
|
||||
broadcast bool) {
|
||||
func (mfop *MultiFlowOp) Process(frame []byte, dec *EthernetDecoder, broadcast bool) {
|
||||
for _, op := range mfop.ops {
|
||||
op.Process(frame, dec, mfop.broadcast)
|
||||
}
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/andybalholm/go-bit"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (publicKey, privateKey *[32]byte, err error) {
|
||||
return box.GenerateKey(rand.Reader)
|
||||
}
|
||||
|
||||
func FormSessionKey(remotePublicKey, localPrivateKey *[32]byte, secretKey []byte) *[32]byte {
|
||||
var sharedKey [32]byte
|
||||
box.Precompute(&sharedKey, remotePublicKey, localPrivateKey)
|
||||
sharedKeySlice := sharedKey[:]
|
||||
sharedKeySlice = append(sharedKeySlice, secretKey...)
|
||||
sessionKey := sha256.Sum256(sharedKeySlice)
|
||||
return &sessionKey
|
||||
}
|
||||
|
||||
// Frame Encryptors
|
||||
|
||||
type Encryptor interface {
|
||||
@@ -180,6 +161,10 @@ type PacketDecodingError struct {
|
||||
Desc string
|
||||
}
|
||||
|
||||
func (pde PacketDecodingError) Error() string {
|
||||
return fmt.Sprint("Failed to decode packet: ", pde.Desc)
|
||||
}
|
||||
|
||||
func NewNonDecryptor() *NonDecryptor {
|
||||
return &NonDecryptor{}
|
||||
}
|
||||
@@ -297,154 +282,3 @@ func (di *NaClDecryptorInstance) advanceState(seqNo uint64) (int, *bit.Set) {
|
||||
return offset, di.usedOffsets
|
||||
}
|
||||
}
|
||||
|
||||
// TCP Senders/Receivers
|
||||
|
||||
// The lowest 64 bits of the nonce contain the message sequence
|
||||
// number. The top most bit indicates the connection polarity at the
|
||||
// sender - '1' for outbound; the next indicates protocol type - '1'
|
||||
// for TCP. The remaining 126 bits are zero. The polarity is needed so
|
||||
// that the two ends of a connection do not use the same nonces; the
|
||||
// protocol type so that the TCP and UDP sender nonces are disjoint.
|
||||
// This is a requirement of the NaCl Security Model; see
|
||||
// http://nacl.cr.yp.to/box.html.
|
||||
type TCPCryptoState struct {
|
||||
sessionKey *[32]byte
|
||||
nonce [24]byte
|
||||
seqNo uint64
|
||||
}
|
||||
|
||||
func NewTCPCryptoState(sessionKey *[32]byte, outbound bool) *TCPCryptoState {
|
||||
s := &TCPCryptoState{sessionKey: sessionKey}
|
||||
if outbound {
|
||||
s.nonce[0] |= (1 << 7)
|
||||
}
|
||||
// Ensure that TCP and UDP sequences are disjoint
|
||||
s.nonce[0] |= (1 << 6)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *TCPCryptoState) advance() {
|
||||
s.seqNo++
|
||||
binary.BigEndian.PutUint64(s.nonce[16:24], s.seqNo)
|
||||
}
|
||||
|
||||
type TCPSender interface {
|
||||
Send([]byte) error
|
||||
}
|
||||
|
||||
type GobTCPSender struct {
|
||||
encoder *gob.Encoder
|
||||
}
|
||||
|
||||
type LengthPrefixTCPSender struct {
|
||||
writer io.Writer
|
||||
}
|
||||
|
||||
type EncryptedTCPSender struct {
|
||||
sync.RWMutex
|
||||
sender TCPSender
|
||||
state *TCPCryptoState
|
||||
}
|
||||
|
||||
func NewGobTCPSender(encoder *gob.Encoder) *GobTCPSender {
|
||||
return &GobTCPSender{encoder: encoder}
|
||||
}
|
||||
|
||||
func (sender *GobTCPSender) Send(msg []byte) error {
|
||||
return sender.encoder.Encode(msg)
|
||||
}
|
||||
|
||||
func NewLengthPrefixTCPSender(writer io.Writer) *LengthPrefixTCPSender {
|
||||
return &LengthPrefixTCPSender{writer: writer}
|
||||
}
|
||||
|
||||
func (sender *LengthPrefixTCPSender) Send(msg []byte) error {
|
||||
l := len(msg)
|
||||
if l > MaxTCPMsgSize {
|
||||
return fmt.Errorf("outgoing message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
|
||||
}
|
||||
// We copy the message so we can send it in a single Write
|
||||
// operation, thus making this thread-safe without locking.
|
||||
prefixedMsg := make([]byte, 4+l)
|
||||
binary.BigEndian.PutUint32(prefixedMsg, uint32(l))
|
||||
copy(prefixedMsg[4:], msg)
|
||||
_, err := sender.writer.Write(prefixedMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
func NewEncryptedTCPSender(sender TCPSender, sessionKey *[32]byte, outbound bool) *EncryptedTCPSender {
|
||||
return &EncryptedTCPSender{sender: sender, state: NewTCPCryptoState(sessionKey, outbound)}
|
||||
}
|
||||
|
||||
func (sender *EncryptedTCPSender) Send(msg []byte) error {
|
||||
sender.Lock()
|
||||
defer sender.Unlock()
|
||||
encodedMsg := secretbox.Seal(nil, msg, &sender.state.nonce, sender.state.sessionKey)
|
||||
sender.state.advance()
|
||||
return sender.sender.Send(encodedMsg)
|
||||
}
|
||||
|
||||
type TCPReceiver interface {
|
||||
Receive() ([]byte, error)
|
||||
}
|
||||
|
||||
type GobTCPReceiver struct {
|
||||
decoder *gob.Decoder
|
||||
}
|
||||
|
||||
type LengthPrefixTCPReceiver struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
type EncryptedTCPReceiver struct {
|
||||
receiver TCPReceiver
|
||||
state *TCPCryptoState
|
||||
}
|
||||
|
||||
func NewGobTCPReceiver(decoder *gob.Decoder) *GobTCPReceiver {
|
||||
return &GobTCPReceiver{decoder: decoder}
|
||||
}
|
||||
|
||||
func (receiver *GobTCPReceiver) Receive() ([]byte, error) {
|
||||
var msg []byte
|
||||
err := receiver.decoder.Decode(&msg)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func NewLengthPrefixTCPReceiver(reader io.Reader) *LengthPrefixTCPReceiver {
|
||||
return &LengthPrefixTCPReceiver{reader: reader}
|
||||
}
|
||||
|
||||
func (receiver *LengthPrefixTCPReceiver) Receive() ([]byte, error) {
|
||||
lenPrefix := make([]byte, 4)
|
||||
if _, err := io.ReadFull(receiver.reader, lenPrefix); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := binary.BigEndian.Uint32(lenPrefix)
|
||||
if l > MaxTCPMsgSize {
|
||||
return nil, fmt.Errorf("incoming message exceeds maximum size: %d > %d", l, MaxTCPMsgSize)
|
||||
}
|
||||
msg := make([]byte, l)
|
||||
_, err := io.ReadFull(receiver.reader, msg)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func NewEncryptedTCPReceiver(receiver TCPReceiver, sessionKey *[32]byte, outbound bool) *EncryptedTCPReceiver {
|
||||
return &EncryptedTCPReceiver{receiver: receiver, state: NewTCPCryptoState(sessionKey, !outbound)}
|
||||
}
|
||||
|
||||
func (receiver *EncryptedTCPReceiver) Receive() ([]byte, error) {
|
||||
msg, err := receiver.receiver.Receive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
decodedMsg, success := secretbox.Open(nil, msg, &receiver.state.nonce, receiver.state.sessionKey)
|
||||
if !success {
|
||||
return nil, fmt.Errorf("Unable to decrypt TCP msg")
|
||||
}
|
||||
|
||||
receiver.state.advance()
|
||||
return decodedMsg, nil
|
||||
}
|
||||
+3
-2
@@ -2,12 +2,13 @@ package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/weaveworks/weave/common"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (router *Router) HandleHTTP(muxRouter *mux.Router) {
|
||||
func (router *NetworkRouter) HandleHTTP(muxRouter *mux.Router) {
|
||||
|
||||
muxRouter.Methods("POST").Path("/connect").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
||||
+27
-8
@@ -4,11 +4,13 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
type MacCacheEntry struct {
|
||||
lastSeen time.Time
|
||||
peer *Peer
|
||||
peer *mesh.Peer
|
||||
}
|
||||
|
||||
type MacCache struct {
|
||||
@@ -16,10 +18,10 @@ type MacCache struct {
|
||||
table map[uint64]*MacCacheEntry
|
||||
maxAge time.Duration
|
||||
expiryTimer *time.Timer
|
||||
onExpiry func(net.HardwareAddr, *Peer)
|
||||
onExpiry func(net.HardwareAddr, *mesh.Peer)
|
||||
}
|
||||
|
||||
func NewMacCache(maxAge time.Duration, onExpiry func(net.HardwareAddr, *Peer)) *MacCache {
|
||||
func NewMacCache(maxAge time.Duration, onExpiry func(net.HardwareAddr, *mesh.Peer)) *MacCache {
|
||||
cache := &MacCache{
|
||||
table: make(map[uint64]*MacCacheEntry),
|
||||
maxAge: maxAge,
|
||||
@@ -28,7 +30,7 @@ func NewMacCache(maxAge time.Duration, onExpiry func(net.HardwareAddr, *Peer)) *
|
||||
return cache
|
||||
}
|
||||
|
||||
func (cache *MacCache) add(mac net.HardwareAddr, peer *Peer, force bool) (bool, *Peer) {
|
||||
func (cache *MacCache) add(mac net.HardwareAddr, peer *mesh.Peer, force bool) (bool, *mesh.Peer) {
|
||||
key := macint(mac)
|
||||
now := time.Now()
|
||||
|
||||
@@ -64,15 +66,15 @@ func (cache *MacCache) add(mac net.HardwareAddr, peer *Peer, force bool) (bool,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (cache *MacCache) Add(mac net.HardwareAddr, peer *Peer) (bool, *Peer) {
|
||||
func (cache *MacCache) Add(mac net.HardwareAddr, peer *mesh.Peer) (bool, *mesh.Peer) {
|
||||
return cache.add(mac, peer, false)
|
||||
}
|
||||
|
||||
func (cache *MacCache) AddForced(mac net.HardwareAddr, peer *Peer) (bool, *Peer) {
|
||||
func (cache *MacCache) AddForced(mac net.HardwareAddr, peer *mesh.Peer) (bool, *mesh.Peer) {
|
||||
return cache.add(mac, peer, true)
|
||||
}
|
||||
|
||||
func (cache *MacCache) Lookup(mac net.HardwareAddr) *Peer {
|
||||
func (cache *MacCache) Lookup(mac net.HardwareAddr) *mesh.Peer {
|
||||
key := macint(mac)
|
||||
cache.RLock()
|
||||
defer cache.RUnlock()
|
||||
@@ -83,7 +85,7 @@ func (cache *MacCache) Lookup(mac net.HardwareAddr) *Peer {
|
||||
return entry.peer
|
||||
}
|
||||
|
||||
func (cache *MacCache) Delete(peer *Peer) bool {
|
||||
func (cache *MacCache) Delete(peer *mesh.Peer) bool {
|
||||
found := false
|
||||
cache.Lock()
|
||||
defer cache.Unlock()
|
||||
@@ -112,3 +114,20 @@ func (cache *MacCache) expire() {
|
||||
}
|
||||
cache.setExpiryTimer()
|
||||
}
|
||||
|
||||
func macint(mac net.HardwareAddr) (r uint64) {
|
||||
for _, b := range mac {
|
||||
r <<= 8
|
||||
r |= uint64(b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intmac(key uint64) (r net.HardwareAddr) {
|
||||
r = make([]byte, 6)
|
||||
for i := 5; i >= 0; i-- {
|
||||
r[i] = byte(key)
|
||||
key >>= 8
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// Interface to overlay network packet handling
|
||||
type NetworkOverlay interface {
|
||||
mesh.Overlay
|
||||
|
||||
// The routes have changed, so any cached information should
|
||||
// be discarded.
|
||||
InvalidateRoutes()
|
||||
|
||||
// A mapping of a short id to a peer has changed
|
||||
InvalidateShortIDs()
|
||||
|
||||
// Start consuming forwarded packets.
|
||||
StartConsumingPackets(*mesh.Peer, *mesh.Peers, OverlayConsumer) error
|
||||
}
|
||||
|
||||
// When a consumer is called, the decoder will already have been used
|
||||
// to decode the frame.
|
||||
type OverlayConsumer func(ForwardPacketKey) FlowOp
|
||||
|
||||
// All of the machinery to forward packets to a particular peer
|
||||
type OverlayForwarder interface {
|
||||
mesh.OverlayConnection
|
||||
// Forward a packet across the connection. May be called as soon
|
||||
// as the overlay connection is created, in particular before
|
||||
// Confirm(). The return value nil means the key could not be
|
||||
// handled by this forwarder.
|
||||
Forward(ForwardPacketKey) FlowOp
|
||||
}
|
||||
|
||||
type NullNetworkOverlay struct{ mesh.NullOverlay }
|
||||
|
||||
func (NullNetworkOverlay) InvalidateRoutes() {
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) InvalidateShortIDs() {
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) StartConsumingPackets(*mesh.Peer, *mesh.Peers, OverlayConsumer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullNetworkOverlay) Forward(ForwardPacketKey) FlowOp {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelSize = 16
|
||||
MaxUDPPacketSize = 65535
|
||||
FastHeartbeat = 500 * time.Millisecond
|
||||
SlowHeartbeat = 10 * time.Second
|
||||
MaxMissedHeartbeats = 6
|
||||
HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat
|
||||
MaxDuration = time.Duration(math.MaxInt64)
|
||||
NameSize = mesh.NameSize
|
||||
// should be greater than typical ARP cache expiries, i.e. > 3/2 *
|
||||
// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux
|
||||
macMaxAge = 10 * time.Minute
|
||||
)
|
||||
|
||||
var (
|
||||
log = common.Log
|
||||
checkFatal = common.CheckFatal
|
||||
checkWarn = common.CheckWarn
|
||||
)
|
||||
|
||||
type NetworkConfig struct {
|
||||
BufSz int
|
||||
PacketLogging PacketLogging
|
||||
Bridge Bridge
|
||||
}
|
||||
|
||||
type PacketLogging interface {
|
||||
LogPacket(string, PacketKey)
|
||||
LogForwardPacket(string, ForwardPacketKey)
|
||||
}
|
||||
|
||||
type NetworkRouter struct {
|
||||
*mesh.Router
|
||||
NetworkConfig
|
||||
Macs *MacCache
|
||||
}
|
||||
|
||||
func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, name mesh.PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter {
|
||||
if overlay == nil {
|
||||
overlay = NullNetworkOverlay{}
|
||||
}
|
||||
if networkConfig.Bridge == nil {
|
||||
networkConfig.Bridge = NullBridge{}
|
||||
}
|
||||
|
||||
router := &NetworkRouter{Router: mesh.NewRouter(config, name, nickName, overlay), NetworkConfig: networkConfig}
|
||||
router.Peers.OnInvalidateShortIDs(overlay.InvalidateShortIDs)
|
||||
router.Routes.OnChange(overlay.InvalidateRoutes)
|
||||
router.Macs = NewMacCache(macMaxAge,
|
||||
func(mac net.HardwareAddr, peer *mesh.Peer) {
|
||||
log.Println("Expired MAC", mac, "at", peer)
|
||||
})
|
||||
router.Peers.OnGC(func(peer *mesh.Peer) { router.Macs.Delete(peer) })
|
||||
return router
|
||||
}
|
||||
|
||||
// Start listening for TCP connections, locally captured packets, and
|
||||
// forwarded packets.
|
||||
func (router *NetworkRouter) Start() {
|
||||
log.Println("Sniffing traffic on", router.Bridge)
|
||||
checkFatal(router.Bridge.StartConsumingPackets(router.handleCapturedPacket))
|
||||
checkFatal(router.Overlay.(NetworkOverlay).StartConsumingPackets(router.Ourself.Peer, router.Peers, router.handleForwardedPacket))
|
||||
router.Router.Start()
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
|
||||
router.PacketLogging.LogPacket("Captured", key)
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
||||
case newSrcMac:
|
||||
log.Println("Discovered local MAC", srcMac)
|
||||
|
||||
case conflictPeer != nil:
|
||||
// The MAC cache has an entry for the source MAC
|
||||
// associated with another peer. This probably means
|
||||
// we are seeing a frame we injected ourself. That
|
||||
// shouldn't happen, but discard it just in case.
|
||||
log.Error("Captured frame from MAC (", srcMac, ") associated with another peer ", conflictPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
// Discard STP broadcasts
|
||||
if key.DstMAC == [...]byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00} {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
switch dstPeer := router.Macs.Lookup(dstMac); dstPeer {
|
||||
case router.Ourself.Peer:
|
||||
// The packet is destined for a local MAC. The bridge
|
||||
// won't normally send us such packets, and if it does
|
||||
// it's likely to be broadcasting the packet to all
|
||||
// ports. So if it happens, just drop the packet to
|
||||
// avoid warnings if we try to forward it.
|
||||
return DiscardingFlowOp{}
|
||||
case nil:
|
||||
// If we don't know which peer corresponds to the dest
|
||||
// MAC, broadcast it.
|
||||
router.PacketLogging.LogPacket("Broadcasting", key)
|
||||
return router.relayBroadcast(router.Ourself.Peer, key)
|
||||
default:
|
||||
router.PacketLogging.LogPacket("Forwarding", key)
|
||||
return router.relay(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: router.Ourself.Peer,
|
||||
DstPeer: dstPeer})
|
||||
}
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||
if key.DstPeer != router.Ourself.Peer {
|
||||
// it's not for us, we're just relaying it
|
||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||
return router.relay(key)
|
||||
}
|
||||
|
||||
// At this point, it's either unicast to us, or a broadcast
|
||||
// (because the DstPeer on a forwarded broadcast packet is
|
||||
// always set to the peer being forwarded to)
|
||||
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.AddForced(srcMac, key.SrcPeer); {
|
||||
case newSrcMac:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
||||
|
||||
case conflictPeer != nil:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer, " (was at ", conflictPeer, ")")
|
||||
|
||||
// We need to clear out any flows destined to the MAC
|
||||
// that forward to the old peer.
|
||||
router.Overlay.(NetworkOverlay).InvalidateRoutes()
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Injecting", key)
|
||||
injectFop := router.Bridge.InjectPacket(key.PacketKey)
|
||||
dstPeer := router.Macs.Lookup(dstMac)
|
||||
if dstPeer == router.Ourself.Peer {
|
||||
return injectFop
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Relaying broadcast", key)
|
||||
relayFop := router.relayBroadcast(key.SrcPeer, key.PacketKey)
|
||||
switch {
|
||||
case injectFop == nil:
|
||||
return relayFop
|
||||
|
||||
case relayFop == nil:
|
||||
return injectFop
|
||||
|
||||
default:
|
||||
mfop := NewMultiFlowOp(false)
|
||||
mfop.Add(injectFop)
|
||||
mfop.Add(relayFop)
|
||||
return mfop
|
||||
}
|
||||
}
|
||||
|
||||
// Routing
|
||||
|
||||
func (router *NetworkRouter) relay(key ForwardPacketKey) FlowOp {
|
||||
relayPeerName, found := router.Routes.Unicast(key.DstPeer.Name)
|
||||
if !found {
|
||||
// Not necessarily an error as there could be a race with the
|
||||
// dst disappearing whilst the frame is in flight
|
||||
log.Println("Received packet for unknown destination:", key.DstPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
conn, found := router.Ourself.ConnectionTo(relayPeerName)
|
||||
if !found {
|
||||
// Again, could just be a race, not necessarily an error
|
||||
log.Println("Unable to find connection to relay peer", relayPeerName)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
return conn.(*mesh.LocalConnection).OverlayConn.(OverlayForwarder).Forward(key)
|
||||
}
|
||||
|
||||
func (router *NetworkRouter) relayBroadcast(srcPeer *mesh.Peer, key PacketKey) FlowOp {
|
||||
nextHops := router.Routes.Broadcast(srcPeer.Name)
|
||||
if len(nextHops) == 0 {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
op := NewMultiFlowOp(true)
|
||||
|
||||
for _, conn := range router.Ourself.ConnectionsTo(nextHops) {
|
||||
op.Add(conn.(*mesh.LocalConnection).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: srcPeer,
|
||||
DstPeer: conn.Remote()}))
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
type NetworkRouterStatus struct {
|
||||
*mesh.Status
|
||||
Interface string
|
||||
CaptureStats map[string]int
|
||||
MACs []MACStatus
|
||||
}
|
||||
|
||||
type MACStatus struct {
|
||||
Mac string
|
||||
Name string
|
||||
NickName string
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
func NewNetworkRouterStatus(router *NetworkRouter) *NetworkRouterStatus {
|
||||
return &NetworkRouterStatus{
|
||||
mesh.NewStatus(router.Router),
|
||||
router.Bridge.String(),
|
||||
router.Bridge.Stats(),
|
||||
NewMACStatusSlice(router.Macs)}
|
||||
}
|
||||
|
||||
func NewMACStatusSlice(cache *MacCache) []MACStatus {
|
||||
cache.RLock()
|
||||
defer cache.RUnlock()
|
||||
|
||||
var slice []MACStatus
|
||||
for key, entry := range cache.table {
|
||||
slice = append(slice, MACStatus{
|
||||
intmac(key).String(),
|
||||
entry.peer.Name.String(),
|
||||
entry.peer.NickName,
|
||||
entry.lastSeen})
|
||||
}
|
||||
|
||||
return slice
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// Interface to overlay network packet handling
|
||||
type Overlay interface {
|
||||
// Start consuming forwarded packets.
|
||||
StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error
|
||||
|
||||
// Form a packet-forwarding connection.
|
||||
MakeForwarder(ForwarderParams) (OverlayForwarder, error)
|
||||
|
||||
// The routes have changed, so any cached information should
|
||||
// be discarded.
|
||||
InvalidateRoutes()
|
||||
|
||||
// A mapping of a short id to a peer has changed
|
||||
InvalidateShortIDs()
|
||||
|
||||
// Enhance a features map with overlay-related features
|
||||
AddFeaturesTo(map[string]string)
|
||||
|
||||
// Obtain diagnostic information specific to the overlay
|
||||
Diagnostics() interface{}
|
||||
}
|
||||
|
||||
type ForwarderParams struct {
|
||||
RemotePeer *Peer
|
||||
|
||||
// The local IP address to use for sending. Derived from the
|
||||
// local address of the corresponding TCP socket, so may
|
||||
// differ for different forwarders.
|
||||
LocalIP net.IP
|
||||
|
||||
// The remote address to send to. nil if unknown, i.e. an
|
||||
// incoming connection, in which case the Overlay needs to
|
||||
// discover it (e.g. from incoming datagrams).
|
||||
RemoteAddr *net.UDPAddr
|
||||
|
||||
// Unique identifier for this connection
|
||||
ConnUID uint64
|
||||
|
||||
// Crypto bits. Nil if not encrypting
|
||||
Crypto *OverlayCrypto
|
||||
|
||||
// Function to send a control message to the counterpart
|
||||
// forwarder.
|
||||
SendControlMessage func(tag byte, msg []byte) error
|
||||
|
||||
// Features passed at connection initiation
|
||||
Features map[string]string
|
||||
}
|
||||
|
||||
// When a consumer is called, the decoder will already have been used
|
||||
// to decode the frame.
|
||||
type OverlayConsumer func(ForwardPacketKey) FlowOp
|
||||
|
||||
// Crypto settings for a forwarder.
|
||||
type OverlayCrypto struct {
|
||||
Dec Decryptor
|
||||
Enc Encryptor
|
||||
EncDF Encryptor
|
||||
}
|
||||
|
||||
// All of the machinery to forward packets to a particular peer
|
||||
type OverlayForwarder interface {
|
||||
// Forward a packet across the connection. May be called as
|
||||
// soon as the forwarder is created, in particular before
|
||||
// Confirm(). The return value nil means the key could not be
|
||||
// handled by this forwarder.
|
||||
Forward(ForwardPacketKey) FlowOp
|
||||
|
||||
// Confirm that the connection is really wanted, and so the
|
||||
// Overlay should begin heartbeats etc. to verify the
|
||||
// operation of the forwarder.
|
||||
Confirm()
|
||||
|
||||
// A channel indicating that the forwarder is established,
|
||||
// i.e. its operation has been confirmed.
|
||||
EstablishedChannel() <-chan struct{}
|
||||
|
||||
// A channel indicating an error from the forwarder. The
|
||||
// forwarder is not expected to be operational after the first
|
||||
// error, so the channel only needs to buffer a single error.
|
||||
ErrorChannel() <-chan error
|
||||
|
||||
Stop()
|
||||
|
||||
// Handle a message from the peer. 'tag' exists for
|
||||
// compatibility, and should always be
|
||||
// ProtocolOverlayControlMessage for non-sleeve overlays.
|
||||
ControlMessage(tag byte, msg []byte)
|
||||
|
||||
// User facing overlay name
|
||||
DisplayName() string
|
||||
}
|
||||
|
||||
type NullOverlay struct{}
|
||||
|
||||
func (NullOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) MakeForwarder(ForwarderParams) (OverlayForwarder, error) {
|
||||
return NullOverlay{}, nil
|
||||
}
|
||||
|
||||
func (NullOverlay) InvalidateRoutes() {
|
||||
}
|
||||
|
||||
func (NullOverlay) InvalidateShortIDs() {
|
||||
}
|
||||
|
||||
func (NullOverlay) Confirm() {
|
||||
}
|
||||
|
||||
func (NullOverlay) EstablishedChannel() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) ErrorChannel() <-chan error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (NullOverlay) AddFeaturesTo(map[string]string) {
|
||||
}
|
||||
|
||||
func (NullOverlay) Forward(ForwardPacketKey) FlowOp {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
func (NullOverlay) Stop() {
|
||||
}
|
||||
|
||||
func (NullOverlay) ControlMessage(byte, []byte) {
|
||||
}
|
||||
|
||||
func (NullOverlay) DisplayName() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
func (NullOverlay) Diagnostics() interface{} {
|
||||
return nil
|
||||
}
|
||||
+21
-25
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// OverlaySwitch selects which overlay to use, from a set of
|
||||
@@ -13,16 +15,16 @@ import (
|
||||
// uses the best one that seems to be working.
|
||||
|
||||
type OverlaySwitch struct {
|
||||
overlays map[string]Overlay
|
||||
overlays map[string]NetworkOverlay
|
||||
overlayNames []string
|
||||
compatOverlay Overlay
|
||||
compatOverlay NetworkOverlay
|
||||
}
|
||||
|
||||
func NewOverlaySwitch() *OverlaySwitch {
|
||||
return &OverlaySwitch{overlays: make(map[string]Overlay)}
|
||||
return &OverlaySwitch{overlays: make(map[string]NetworkOverlay)}
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) Add(name string, overlay Overlay) {
|
||||
func (osw *OverlaySwitch) Add(name string, overlay NetworkOverlay) {
|
||||
// check for repeated names
|
||||
if _, present := osw.overlays[name]; present {
|
||||
log.Fatal("OverlaySwitch: repeated overlay name")
|
||||
@@ -32,7 +34,7 @@ func (osw *OverlaySwitch) Add(name string, overlay Overlay) {
|
||||
osw.overlayNames = append(osw.overlayNames, name)
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) SetCompatOverlay(overlay Overlay) {
|
||||
func (osw *OverlaySwitch) SetCompatOverlay(overlay NetworkOverlay) {
|
||||
osw.compatOverlay = overlay
|
||||
}
|
||||
|
||||
@@ -60,11 +62,9 @@ func (osw *OverlaySwitch) InvalidateShortIDs() {
|
||||
}
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers,
|
||||
consumer OverlayConsumer) error {
|
||||
func (osw *OverlaySwitch) StartConsumingPackets(localPeer *mesh.Peer, peers *mesh.Peers, consumer OverlayConsumer) error {
|
||||
for _, overlay := range osw.overlays {
|
||||
if err := overlay.StartConsumingPackets(localPeer, peers,
|
||||
consumer); err != nil {
|
||||
if err := overlay.StartConsumingPackets(localPeer, peers, consumer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -72,19 +72,19 @@ func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers,
|
||||
}
|
||||
|
||||
type namedOverlay struct {
|
||||
Overlay
|
||||
NetworkOverlay
|
||||
name string
|
||||
}
|
||||
|
||||
// Find the common set of overlays supported by both sides, with the
|
||||
// ordering being the same on both sides too.
|
||||
func (osw *OverlaySwitch) commonOverlays(params ForwarderParams) ([]namedOverlay, error) {
|
||||
func (osw *OverlaySwitch) commonOverlays(params mesh.OverlayConnectionParams) ([]namedOverlay, error) {
|
||||
var peerOverlays []string
|
||||
if overlaysFeature, present := params.Features["Overlays"]; present {
|
||||
peerOverlays = strings.Split(overlaysFeature, " ")
|
||||
}
|
||||
|
||||
common := make(map[string]Overlay)
|
||||
common := make(map[string]NetworkOverlay)
|
||||
for _, name := range peerOverlays {
|
||||
if overlay := osw.overlays[name]; overlay != nil {
|
||||
common[name] = overlay
|
||||
@@ -120,7 +120,7 @@ func (osw *OverlaySwitch) commonOverlays(params ForwarderParams) ([]namedOverlay
|
||||
}
|
||||
|
||||
type overlaySwitchForwarder struct {
|
||||
remotePeer *Peer
|
||||
remotePeer *mesh.Peer
|
||||
|
||||
lock sync.Mutex
|
||||
|
||||
@@ -162,10 +162,9 @@ type subForwarderEvent struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (osw *OverlaySwitch) MakeForwarder(
|
||||
params ForwarderParams) (OverlayForwarder, error) {
|
||||
func (osw *OverlaySwitch) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) {
|
||||
if _, present := params.Features["Overlays"]; !present && osw.compatOverlay != nil {
|
||||
return osw.compatOverlay.MakeForwarder(params)
|
||||
return osw.compatOverlay.PrepareConnection(params)
|
||||
}
|
||||
|
||||
overlays, err := osw.commonOverlays(params)
|
||||
@@ -200,15 +199,15 @@ func (osw *OverlaySwitch) MakeForwarder(
|
||||
xmsg[0] = byte(index)
|
||||
xmsg[1] = tag
|
||||
copy(xmsg[2:], msg)
|
||||
return origSendControlMessage(ProtocolOverlayControlMsg,
|
||||
xmsg)
|
||||
return origSendControlMessage(mesh.ProtocolOverlayControlMsg, xmsg)
|
||||
}
|
||||
|
||||
subFwd, err := overlay.MakeForwarder(params)
|
||||
subConn, err := overlay.PrepareConnection(params)
|
||||
if err != nil {
|
||||
fwd.stopFrom(0)
|
||||
return nil, err
|
||||
}
|
||||
subFwd := subConn.(OverlayForwarder)
|
||||
|
||||
subStopChan := make(chan struct{})
|
||||
go monitorForwarder(i, eventsChan, subStopChan, subFwd)
|
||||
@@ -224,8 +223,7 @@ func (osw *OverlaySwitch) MakeForwarder(
|
||||
return fwd, nil
|
||||
}
|
||||
|
||||
func monitorForwarder(index int, eventsChan chan<- subForwarderEvent,
|
||||
stopChan <-chan struct{}, fwd OverlayForwarder) {
|
||||
func monitorForwarder(index int, eventsChan chan<- subForwarderEvent, stopChan <-chan struct{}, fwd OverlayForwarder) {
|
||||
establishedChan := fwd.EstablishedChannel()
|
||||
loop:
|
||||
for {
|
||||
@@ -257,8 +255,7 @@ loop:
|
||||
fwd.Stop()
|
||||
}
|
||||
|
||||
func (fwd *overlaySwitchForwarder) run(eventsChan <-chan subForwarderEvent,
|
||||
stopChan <-chan struct{}) {
|
||||
func (fwd *overlaySwitchForwarder) run(eventsChan <-chan subForwarderEvent, stopChan <-chan struct{}) {
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
@@ -355,8 +352,7 @@ func (fwd *overlaySwitchForwarder) chooseBest() {
|
||||
|
||||
if fwd.best != best {
|
||||
fwd.best = best
|
||||
log.Info(fwd.logPrefix(),
|
||||
"using ", fwd.forwarders[best].overlayName)
|
||||
log.Info(fwd.logPrefix(), "using ", fwd.forwarders[best].overlayName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,337 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
macMaxAge = 10 * time.Minute // [1]
|
||||
acceptMaxTokens = 100 // [2]
|
||||
acceptTokenDelay = 100 * time.Millisecond // [3]
|
||||
)
|
||||
|
||||
// [1] should be greater than typical ARP cache expiries, i.e. > 3/2 *
|
||||
// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux
|
||||
|
||||
// [2] capacity of token bucket for rate limiting accepts
|
||||
|
||||
// [3] control rate at which new tokens are added to the bucket
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
ProtocolMinVersion byte
|
||||
Password []byte
|
||||
ConnLimit int
|
||||
PeerDiscovery bool
|
||||
BufSz int
|
||||
PacketLogging PacketLogging
|
||||
Bridge Bridge
|
||||
Overlay Overlay
|
||||
}
|
||||
|
||||
type PacketLogging interface {
|
||||
LogPacket(string, PacketKey)
|
||||
LogForwardPacket(string, ForwardPacketKey)
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
Config
|
||||
Ourself *LocalPeer
|
||||
Macs *MacCache
|
||||
Peers *Peers
|
||||
Routes *Routes
|
||||
ConnectionMaker *ConnectionMaker
|
||||
gossipLock sync.RWMutex
|
||||
gossipChannels GossipChannels
|
||||
TopologyGossip Gossip
|
||||
UDPListener *net.UDPConn
|
||||
acceptLimiter *TokenBucket
|
||||
}
|
||||
|
||||
func NewRouter(config Config, name PeerName, nickName string) *Router {
|
||||
router := &Router{Config: config, gossipChannels: make(GossipChannels)}
|
||||
|
||||
if router.Bridge == nil {
|
||||
router.Bridge = NullBridge{}
|
||||
}
|
||||
|
||||
if router.Overlay == nil {
|
||||
router.Overlay = NullOverlay{}
|
||||
}
|
||||
|
||||
router.Ourself = NewLocalPeer(name, nickName, router)
|
||||
router.Macs = NewMacCache(macMaxAge,
|
||||
func(mac net.HardwareAddr, peer *Peer) {
|
||||
log.Println("Expired MAC", mac, "at", peer)
|
||||
})
|
||||
router.Peers = NewPeers(router.Ourself)
|
||||
router.Peers.OnGC(func(peer *Peer) {
|
||||
router.Macs.Delete(peer)
|
||||
log.Println("Removed unreachable peer", peer)
|
||||
})
|
||||
router.Peers.OnInvalidateShortIDs(router.Overlay.InvalidateShortIDs)
|
||||
|
||||
router.Routes = NewRoutes(router.Ourself, router.Peers, router.Overlay.InvalidateRoutes)
|
||||
router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery)
|
||||
router.TopologyGossip = router.NewGossip("topology", router)
|
||||
router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay)
|
||||
return router
|
||||
}
|
||||
|
||||
// Start listening for TCP connections, locally captured packets, and
|
||||
// forwarded packets. This is separate from NewRouter so
|
||||
// that gossipers can register before we start forming connections.
|
||||
func (router *Router) Start() {
|
||||
log.Println("Sniffing traffic on", router.Bridge)
|
||||
checkFatal(router.Bridge.StartConsumingPackets(router.handleCapturedPacket))
|
||||
checkFatal(router.Overlay.StartConsumingPackets(router.Ourself.Peer, router.Peers, router.handleForwardedPacket))
|
||||
router.listenTCP(router.Port)
|
||||
}
|
||||
|
||||
func (router *Router) Stop() error {
|
||||
// TODO: perform graceful shutdown...
|
||||
return nil
|
||||
}
|
||||
|
||||
func (router *Router) UsingPassword() bool {
|
||||
return router.Password != nil
|
||||
}
|
||||
|
||||
func (router *Router) handleCapturedPacket(key PacketKey) FlowOp {
|
||||
router.PacketLogging.LogPacket("Captured", key)
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.Add(srcMac, router.Ourself.Peer); {
|
||||
case newSrcMac:
|
||||
log.Println("Discovered local MAC", srcMac)
|
||||
|
||||
case conflictPeer != nil:
|
||||
// The MAC cache has an entry for the source MAC
|
||||
// associated with another peer. This probably means
|
||||
// we are seeing a frame we injected ourself. That
|
||||
// shouldn't happen, but discard it just in case.
|
||||
log.Error("Captured frame from MAC (", srcMac, ") associated with another peer ", conflictPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
// Discard STP broadcasts
|
||||
if key.DstMAC == [...]byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00} {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
switch dstPeer := router.Macs.Lookup(dstMac); dstPeer {
|
||||
case router.Ourself.Peer:
|
||||
// The packet is destined for a local MAC. The bridge
|
||||
// won't normally send us such packets, and if it does
|
||||
// it's likely to be broadcasting the packet to all
|
||||
// ports. So if it happens, just drop the packet to
|
||||
// avoid warnings if we try to forward it.
|
||||
return DiscardingFlowOp{}
|
||||
case nil:
|
||||
// If we don't know which peer corresponds to the dest
|
||||
// MAC, broadcast it.
|
||||
router.PacketLogging.LogPacket("Broadcasting", key)
|
||||
return router.relayBroadcast(router.Ourself.Peer, key)
|
||||
default:
|
||||
router.PacketLogging.LogPacket("Forwarding", key)
|
||||
return router.relay(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: router.Ourself.Peer,
|
||||
DstPeer: dstPeer})
|
||||
}
|
||||
}
|
||||
|
||||
func (router *Router) listenTCP(localPort int) {
|
||||
localAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprint(":", localPort))
|
||||
checkFatal(err)
|
||||
ln, err := net.ListenTCP("tcp4", localAddr)
|
||||
checkFatal(err)
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
for {
|
||||
tcpConn, err := ln.AcceptTCP()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
continue
|
||||
}
|
||||
router.acceptTCP(tcpConn)
|
||||
router.acceptLimiter.Wait()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (router *Router) acceptTCP(tcpConn *net.TCPConn) {
|
||||
// someone else is dialing us, so our udp sender is the conn
|
||||
// on router.Port and we wait for them to send us something on UDP to
|
||||
// start.
|
||||
remoteAddrStr := tcpConn.RemoteAddr().String()
|
||||
log.Printf("->[%s] connection accepted", remoteAddrStr)
|
||||
connRemote := NewRemoteConnection(router.Ourself.Peer, nil, remoteAddrStr, false, false)
|
||||
StartLocalConnection(connRemote, tcpConn, nil, router, true)
|
||||
}
|
||||
|
||||
func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||
if key.DstPeer != router.Ourself.Peer {
|
||||
// it's not for us, we're just relaying it
|
||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||
return router.relay(key)
|
||||
}
|
||||
|
||||
// At this point, it's either unicast to us, or a broadcast
|
||||
// (because the DstPeer on a forwarded broadcast packet is
|
||||
// always set to the peer being forwarded to)
|
||||
|
||||
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||
|
||||
switch newSrcMac, conflictPeer := router.Macs.AddForced(srcMac, key.SrcPeer); {
|
||||
case newSrcMac:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
||||
|
||||
case conflictPeer != nil:
|
||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer, " (was at ", conflictPeer, ")")
|
||||
|
||||
// We need to clear out any flows destined to the MAC
|
||||
// that forward to the old peer.
|
||||
router.Overlay.InvalidateRoutes()
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Injecting", key)
|
||||
injectFop := router.Bridge.InjectPacket(key.PacketKey)
|
||||
dstPeer := router.Macs.Lookup(dstMac)
|
||||
if dstPeer == router.Ourself.Peer {
|
||||
return injectFop
|
||||
}
|
||||
|
||||
router.PacketLogging.LogForwardPacket("Relaying broadcast", key)
|
||||
relayFop := router.relayBroadcast(key.SrcPeer, key.PacketKey)
|
||||
switch {
|
||||
case injectFop == nil:
|
||||
return relayFop
|
||||
|
||||
case relayFop == nil:
|
||||
return injectFop
|
||||
|
||||
default:
|
||||
mfop := NewMultiFlowOp(false)
|
||||
mfop.Add(injectFop)
|
||||
mfop.Add(relayFop)
|
||||
return mfop
|
||||
}
|
||||
}
|
||||
|
||||
// Routing
|
||||
|
||||
func (router *Router) relay(key ForwardPacketKey) FlowOp {
|
||||
relayPeerName, found := router.Routes.Unicast(key.DstPeer.Name)
|
||||
if !found {
|
||||
// Not necessarily an error as there could be a race with the
|
||||
// dst disappearing whilst the frame is in flight
|
||||
log.Println("Received packet for unknown destination:", key.DstPeer)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
conn, found := router.Ourself.ConnectionTo(relayPeerName)
|
||||
if !found {
|
||||
// Again, could just be a race, not necessarily an error
|
||||
log.Println("Unable to find connection to relay peer", relayPeerName)
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
return conn.(*LocalConnection).Forward(key)
|
||||
}
|
||||
|
||||
func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp {
|
||||
nextHops := router.Routes.Broadcast(srcPeer.Name)
|
||||
if len(nextHops) == 0 {
|
||||
return DiscardingFlowOp{}
|
||||
}
|
||||
|
||||
op := NewMultiFlowOp(true)
|
||||
|
||||
for _, conn := range router.Ourself.ConnectionsTo(nextHops) {
|
||||
op.Add(conn.(*LocalConnection).Forward(ForwardPacketKey{
|
||||
PacketKey: key,
|
||||
SrcPeer: srcPeer,
|
||||
DstPeer: conn.Remote()}))
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
// Gossiper methods - the Router is the topology Gossiper
|
||||
|
||||
type TopologyGossipData struct {
|
||||
peers *Peers
|
||||
update PeerNameSet
|
||||
}
|
||||
|
||||
func (router *Router) BroadcastTopologyUpdate(update []*Peer) {
|
||||
names := make(PeerNameSet)
|
||||
for _, p := range update {
|
||||
names[p.Name] = void
|
||||
}
|
||||
|
||||
router.TopologyGossip.GossipBroadcast(&TopologyGossipData{
|
||||
peers: router.Peers,
|
||||
update: names,
|
||||
})
|
||||
}
|
||||
|
||||
func (d *TopologyGossipData) Merge(other GossipData) {
|
||||
for name := range other.(*TopologyGossipData).update {
|
||||
d.update[name] = void
|
||||
}
|
||||
}
|
||||
|
||||
func (d *TopologyGossipData) Encode() [][]byte {
|
||||
return [][]byte{d.peers.EncodePeers(d.update)}
|
||||
}
|
||||
|
||||
func (router *Router) OnGossipUnicast(sender PeerName, msg []byte) error {
|
||||
return fmt.Errorf("unexpected topology gossip unicast: %v", msg)
|
||||
}
|
||||
|
||||
func (router *Router) OnGossipBroadcast(_ PeerName, update []byte) (GossipData, error) {
|
||||
origUpdate, _, err := router.applyTopologyUpdate(update)
|
||||
if err != nil || len(origUpdate) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &TopologyGossipData{peers: router.Peers, update: origUpdate}, nil
|
||||
}
|
||||
|
||||
func (router *Router) Gossip() GossipData {
|
||||
return &TopologyGossipData{peers: router.Peers, update: router.Peers.Names()}
|
||||
}
|
||||
|
||||
func (router *Router) OnGossip(update []byte) (GossipData, error) {
|
||||
_, newUpdate, err := router.applyTopologyUpdate(update)
|
||||
if err != nil || len(newUpdate) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &TopologyGossipData{peers: router.Peers, update: newUpdate}, nil
|
||||
}
|
||||
|
||||
func (router *Router) applyTopologyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
|
||||
origUpdate, newUpdate, err := router.Peers.ApplyUpdate(update)
|
||||
if _, ok := err.(UnknownPeerError); err != nil && ok {
|
||||
// That update contained a reference to a peer which wasn't
|
||||
// itself included in the update, and we didn't know about
|
||||
// already. We ignore this; eventually we should receive an
|
||||
// update containing a complete topology.
|
||||
log.Println("Topology gossip:", err)
|
||||
return nil, nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(newUpdate) > 0 {
|
||||
router.ConnectionMaker.Refresh()
|
||||
router.Routes.Recalculate()
|
||||
}
|
||||
return origUpdate, newUpdate, nil
|
||||
}
|
||||
+91
-68
@@ -11,12 +11,15 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// This diagram explains the various arithmetic and variables related
|
||||
@@ -53,6 +56,10 @@ const (
|
||||
FragTestInterval = 5 * time.Minute
|
||||
MTUVerifyAttempts = 8
|
||||
MTUVerifyTimeout = 10 * time.Millisecond // doubled with each attempt
|
||||
|
||||
ProtocolConnectionEstablished = mesh.ProtocolReserved1
|
||||
ProtocolFragmentationReceived = mesh.ProtocolReserved2
|
||||
ProtocolPMTUVerified = mesh.ProtocolReserved3
|
||||
)
|
||||
|
||||
type SleeveOverlay struct {
|
||||
@@ -60,24 +67,22 @@ type SleeveOverlay struct {
|
||||
|
||||
// These fields are set in StartConsumingPackets, and not
|
||||
// subsequently modified
|
||||
localPeer *Peer
|
||||
localPeer *mesh.Peer
|
||||
localPeerBin []byte
|
||||
consumer OverlayConsumer
|
||||
peers *Peers
|
||||
peers *mesh.Peers
|
||||
conn *net.UDPConn
|
||||
|
||||
lock sync.Mutex
|
||||
forwarders map[PeerName]*sleeveForwarder
|
||||
forwarders map[mesh.PeerName]*sleeveForwarder
|
||||
}
|
||||
|
||||
func NewSleeveOverlay(localPort int) Overlay {
|
||||
func NewSleeveOverlay(localPort int) NetworkOverlay {
|
||||
return &SleeveOverlay{localPort: localPort}
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers,
|
||||
consumer OverlayConsumer) error {
|
||||
localAddr, err := net.ResolveUDPAddr("udp4",
|
||||
fmt.Sprint(":", sleeve.localPort))
|
||||
func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *mesh.Peer, peers *mesh.Peers, consumer OverlayConsumer) error {
|
||||
localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(":", sleeve.localPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -97,8 +102,7 @@ func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers
|
||||
|
||||
// This makes sure all packets we send out do not have DF set
|
||||
// on them.
|
||||
err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP,
|
||||
syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DONT)
|
||||
err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DONT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,7 +120,7 @@ func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers
|
||||
sleeve.consumer = consumer
|
||||
sleeve.peers = peers
|
||||
sleeve.conn = conn
|
||||
sleeve.forwarders = make(map[PeerName]*sleeveForwarder)
|
||||
sleeve.forwarders = make(map[mesh.PeerName]*sleeveForwarder)
|
||||
go sleeve.readUDP()
|
||||
return nil
|
||||
}
|
||||
@@ -137,20 +141,19 @@ func (*SleeveOverlay) Diagnostics() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) lookupForwarder(peer PeerName) *sleeveForwarder {
|
||||
func (sleeve *SleeveOverlay) lookupForwarder(peer mesh.PeerName) *sleeveForwarder {
|
||||
sleeve.lock.Lock()
|
||||
defer sleeve.lock.Unlock()
|
||||
return sleeve.forwarders[peer]
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) addForwarder(peer PeerName, fwd *sleeveForwarder) {
|
||||
func (sleeve *SleeveOverlay) addForwarder(peer mesh.PeerName, fwd *sleeveForwarder) {
|
||||
sleeve.lock.Lock()
|
||||
defer sleeve.lock.Unlock()
|
||||
sleeve.forwarders[peer] = fwd
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) removeForwarder(peer PeerName,
|
||||
fwd *sleeveForwarder) {
|
||||
func (sleeve *SleeveOverlay) removeForwarder(peer mesh.PeerName, fwd *sleeveForwarder) {
|
||||
sleeve.lock.Lock()
|
||||
defer sleeve.lock.Unlock()
|
||||
if sleeve.forwarders[peer] == fwd {
|
||||
@@ -175,7 +178,7 @@ func (sleeve *SleeveOverlay) readUDP() {
|
||||
continue
|
||||
}
|
||||
|
||||
fwdName := PeerNameFromBin(buf[:NameSize])
|
||||
fwdName := mesh.PeerNameFromBin(buf[:NameSize])
|
||||
fwd := sleeve.lookupForwarder(fwdName)
|
||||
if fwd == nil {
|
||||
continue
|
||||
@@ -186,8 +189,7 @@ func (sleeve *SleeveOverlay) readUDP() {
|
||||
|
||||
err = fwd.crypto.Dec.IterateFrames(packet,
|
||||
func(src []byte, dst []byte, frame []byte) {
|
||||
sleeve.handleFrame(sender, fwd,
|
||||
src, dst, frame, dec)
|
||||
sleeve.handleFrame(sender, fwd, src, dst, frame, dec)
|
||||
})
|
||||
if err != nil {
|
||||
// Errors during UDP packet decoding /
|
||||
@@ -209,17 +211,15 @@ func (sleeve *SleeveOverlay) readUDP() {
|
||||
}
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) handleFrame(sender *net.UDPAddr,
|
||||
fwd *sleeveForwarder, src []byte, dst []byte, frame []byte,
|
||||
dec *EthernetDecoder) {
|
||||
func (sleeve *SleeveOverlay) handleFrame(sender *net.UDPAddr, fwd *sleeveForwarder, src []byte, dst []byte, frame []byte, dec *EthernetDecoder) {
|
||||
dec.DecodeLayers(frame)
|
||||
decodedLen := len(dec.decoded)
|
||||
if decodedLen == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
srcPeer := sleeve.peers.Fetch(PeerNameFromBin(src))
|
||||
dstPeer := sleeve.peers.Fetch(PeerNameFromBin(dst))
|
||||
srcPeer := sleeve.peers.Fetch(mesh.PeerNameFromBin(src))
|
||||
dstPeer := sleeve.peers.Fetch(mesh.PeerNameFromBin(dst))
|
||||
if srcPeer == nil || dstPeer == nil {
|
||||
return
|
||||
}
|
||||
@@ -246,8 +246,7 @@ func (sleeve *SleeveOverlay) handleFrame(sender *net.UDPAddr,
|
||||
sleeve.sendToConsumer(srcPeer, dstPeer, frame, dec)
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) sendToConsumer(srcPeer, dstPeer *Peer,
|
||||
frame []byte, dec *EthernetDecoder) {
|
||||
func (sleeve *SleeveOverlay) sendToConsumer(srcPeer, dstPeer *mesh.Peer, frame []byte, dec *EthernetDecoder) {
|
||||
if sleeve.consumer == nil {
|
||||
return
|
||||
}
|
||||
@@ -280,10 +279,16 @@ func (sleeve *SleeveOverlay) send(msg []byte, raddr *net.UDPAddr) error {
|
||||
return err
|
||||
}
|
||||
|
||||
type sleeveCrypto struct {
|
||||
Dec Decryptor
|
||||
Enc Encryptor
|
||||
EncDF Encryptor
|
||||
}
|
||||
|
||||
type sleeveForwarder struct {
|
||||
// Immutable
|
||||
sleeve *SleeveOverlay
|
||||
remotePeer *Peer
|
||||
remotePeer *mesh.Peer
|
||||
remotePeerBin []byte
|
||||
sendControlMsg func(byte, []byte) error
|
||||
connUID uint64
|
||||
@@ -310,7 +315,7 @@ type sleeveForwarder struct {
|
||||
stackFrag bool
|
||||
|
||||
// State only used within the forwarder goroutine
|
||||
crypto OverlayCrypto
|
||||
crypto sleeveCrypto
|
||||
senderDF *udpSenderDF
|
||||
maxPayload int
|
||||
|
||||
@@ -350,13 +355,17 @@ type controlMessage struct {
|
||||
msg []byte
|
||||
}
|
||||
|
||||
func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) {
|
||||
var crypto OverlayCrypto
|
||||
if params.Crypto != nil {
|
||||
crypto = *params.Crypto
|
||||
func (sleeve *SleeveOverlay) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) {
|
||||
name := sleeve.localPeer.NameByte
|
||||
var crypto sleeveCrypto
|
||||
if params.SessionKey != nil {
|
||||
crypto = sleeveCrypto{
|
||||
Dec: NewNaClDecryptor(params.SessionKey, params.Outbound),
|
||||
Enc: NewNaClEncryptor(name, params.SessionKey, params.Outbound, false),
|
||||
EncDF: NewNaClEncryptor(name, params.SessionKey, params.Outbound, true),
|
||||
}
|
||||
} else {
|
||||
name := sleeve.localPeer.NameByte
|
||||
crypto = OverlayCrypto{
|
||||
crypto = sleeveCrypto{
|
||||
Dec: NewNonDecryptor(),
|
||||
Enc: NewNonEncryptor(name),
|
||||
EncDF: NewNonEncryptor(name),
|
||||
@@ -370,6 +379,11 @@ func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwa
|
||||
confirmedChan := make(chan struct{})
|
||||
finishedChan := make(chan struct{})
|
||||
|
||||
var remoteAddr *net.UDPAddr
|
||||
if params.Outbound {
|
||||
remoteAddr = makeUDPAddr(params.RemoteAddr)
|
||||
}
|
||||
|
||||
fwd := &sleeveForwarder{
|
||||
sleeve: sleeve,
|
||||
remotePeer: params.RemotePeer,
|
||||
@@ -384,17 +398,16 @@ func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwa
|
||||
finishedChan: finishedChan,
|
||||
establishedChan: make(chan struct{}),
|
||||
errorChan: make(chan error, 1),
|
||||
remoteAddr: params.RemoteAddr,
|
||||
remoteAddr: remoteAddr,
|
||||
mtu: DefaultMTU,
|
||||
crypto: crypto,
|
||||
maxPayload: DefaultMTU - UDPOverhead,
|
||||
overheadDF: UDPOverhead + crypto.EncDF.PacketOverhead() +
|
||||
crypto.EncDF.FrameOverhead() + EthernetOverhead,
|
||||
senderDF: newUDPSenderDF(params.LocalIP, sleeve.localPort),
|
||||
senderDF: newUDPSenderDF(params.LocalAddr.IP, sleeve.localPort),
|
||||
}
|
||||
|
||||
go fwd.run(aggChan, aggDFChan, specialChan, controlMsgChan,
|
||||
confirmedChan, finishedChan)
|
||||
go fwd.run(aggChan, aggDFChan, specialChan, controlMsgChan, confirmedChan, finishedChan)
|
||||
return fwd, nil
|
||||
}
|
||||
|
||||
@@ -436,8 +449,7 @@ func (fwd *sleeveForwarder) Forward(key ForwardPacketKey) FlowOp {
|
||||
return curriedForward{fwd: fwd, key: key}
|
||||
}
|
||||
|
||||
func (f curriedForward) Process(frame []byte, dec *EthernetDecoder,
|
||||
broadcast bool) {
|
||||
func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bool) {
|
||||
fwd := f.fwd
|
||||
fwd.lock.RLock()
|
||||
haveContact := (fwd.remoteAddr != nil)
|
||||
@@ -446,8 +458,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder,
|
||||
fwd.lock.RUnlock()
|
||||
|
||||
if !haveContact {
|
||||
log.Print(fwd.logPrefix(),
|
||||
"Cannot forward frame yet - awaiting contact")
|
||||
log.Print(fwd.logPrefix(), "Cannot forward frame yet - awaiting contact")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -466,8 +477,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder,
|
||||
// of our pipeline.
|
||||
if dec.DF() {
|
||||
if !frameTooBig(frame, mtu) {
|
||||
fwd.aggregate(fwd.aggregatorDFChan, srcName, dstName,
|
||||
frame)
|
||||
fwd.aggregate(fwd.aggregatorDFChan, srcName, dstName, frame)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -492,8 +502,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder,
|
||||
|
||||
// The frag-needed packet does not have DF set, so the
|
||||
// potential recursion here is bounded.
|
||||
fwd.sleeve.sendToConsumer(f.key.DstPeer, f.key.SrcPeer,
|
||||
fragNeededPacket, dec)
|
||||
fwd.sleeve.sendToConsumer(f.key.DstPeer, f.key.SrcPeer, fragNeededPacket, dec)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -514,21 +523,18 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder,
|
||||
// fragment it ourself.
|
||||
checkWarn(fragment(dec.Eth, dec.IP, mtu,
|
||||
func(segFrame []byte) {
|
||||
fwd.aggregate(fwd.aggregatorDFChan, srcName, dstName,
|
||||
segFrame)
|
||||
fwd.aggregate(fwd.aggregatorDFChan, srcName, dstName, segFrame)
|
||||
}))
|
||||
}
|
||||
|
||||
func (fwd *sleeveForwarder) aggregate(ch chan<- aggregatorFrame, src []byte,
|
||||
dst []byte, frame []byte) {
|
||||
func (fwd *sleeveForwarder) aggregate(ch chan<- aggregatorFrame, src []byte, dst []byte, frame []byte) {
|
||||
select {
|
||||
case ch <- aggregatorFrame{src, dst, frame}:
|
||||
case <-fwd.finishedChan:
|
||||
}
|
||||
}
|
||||
|
||||
func fragment(eth layers.Ethernet, ip layers.IPv4, mtu int,
|
||||
forward func([]byte)) error {
|
||||
func fragment(eth layers.Ethernet, ip layers.IPv4, mtu int, forward func([]byte)) error {
|
||||
// We are not doing any sort of NAT, so we don't need to worry
|
||||
// about checksums of IP payload (eg UDP checksum).
|
||||
headerSize := int(ip.IHL) * 4
|
||||
@@ -570,8 +576,7 @@ func fragment(eth layers.Ethernet, ip layers.IPv4, mtu int,
|
||||
ip.FragOffset = uint16((offset + offsetBase) >> 3)
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
segPayload := gopacket.Payload(segmentPayload)
|
||||
err := gopacket.SerializeLayers(buf, opts, ð, &ip,
|
||||
&segPayload)
|
||||
err := gopacket.SerializeLayers(buf, opts, ð, &ip, &segPayload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -623,13 +628,10 @@ loop:
|
||||
for err == nil {
|
||||
select {
|
||||
case frame := <-aggChan:
|
||||
err = fwd.aggregateAndSend(frame, aggChan,
|
||||
fwd.crypto.Enc, fwd.sleeve,
|
||||
MaxUDPPacketSize-UDPOverhead)
|
||||
err = fwd.aggregateAndSend(frame, aggChan, fwd.crypto.Enc, fwd.sleeve, MaxUDPPacketSize-UDPOverhead)
|
||||
|
||||
case frame := <-aggDFChan:
|
||||
err = fwd.aggregateAndSend(frame, aggDFChan,
|
||||
fwd.crypto.EncDF, fwd.senderDF, fwd.maxPayload)
|
||||
err = fwd.aggregateAndSend(frame, aggDFChan, fwd.crypto.EncDF, fwd.senderDF, fwd.maxPayload)
|
||||
|
||||
case sf := <-specialChan:
|
||||
err = fwd.handleSpecialFrame(sf)
|
||||
@@ -683,8 +685,7 @@ loop:
|
||||
}
|
||||
|
||||
func (fwd *sleeveForwarder) aggregateAndSend(frame aggregatorFrame,
|
||||
aggChan <-chan aggregatorFrame, enc Encryptor, sender udpSender,
|
||||
limit int) error {
|
||||
aggChan <-chan aggregatorFrame, enc Encryptor, sender udpSender, limit int) error {
|
||||
// Give up after processing N frames, to avoid starving the
|
||||
// other activities of the forwarder goroutine.
|
||||
i := 0
|
||||
@@ -734,8 +735,7 @@ func fits(frame aggregatorFrame, enc Encryptor, limit int) bool {
|
||||
return enc.TotalLen()+enc.FrameOverhead()+len(frame.frame) <= limit
|
||||
}
|
||||
|
||||
func (fwd *sleeveForwarder) flushEncryptor(enc Encryptor,
|
||||
sender udpSender) error {
|
||||
func (fwd *sleeveForwarder) flushEncryptor(enc Encryptor, sender udpSender) error {
|
||||
msg, err := enc.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -744,8 +744,7 @@ func (fwd *sleeveForwarder) flushEncryptor(enc Encryptor,
|
||||
return fwd.processSendError(sender.send(msg, fwd.remoteAddr))
|
||||
}
|
||||
|
||||
func (fwd *sleeveForwarder) sendSpecial(enc Encryptor, sender udpSender,
|
||||
data []byte) error {
|
||||
func (fwd *sleeveForwarder) sendSpecial(enc Encryptor, sender udpSender, data []byte) error {
|
||||
enc.AppendFrame(fwd.sleeve.localPeerBin, fwd.remotePeerBin, data)
|
||||
return fwd.flushEncryptor(enc, sender)
|
||||
}
|
||||
@@ -776,8 +775,7 @@ func (fwd *sleeveForwarder) handleControlMessage(cm controlMessage) error {
|
||||
return fwd.handleMTUTestAck(cm.msg)
|
||||
|
||||
default:
|
||||
log.Print(fwd.logPrefix(),
|
||||
"Ignoring unknown control message tag: ", cm.tag)
|
||||
log.Print(fwd.logPrefix(), "Ignoring unknown control message tag: ", cm.tag)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -836,8 +834,7 @@ func (fwd *sleeveForwarder) handleHeartbeat(special specialFrame) error {
|
||||
}
|
||||
}
|
||||
} else if !udpAddrsEqual(fwd.remoteAddr, special.sender) {
|
||||
log.Print(fwd.logPrefix(),
|
||||
"Peer UDP address changed to ", special.sender)
|
||||
log.Print(fwd.logPrefix(), "Peer UDP address changed to ", special.sender)
|
||||
fwd.setRemoteAddr(special.sender)
|
||||
}
|
||||
|
||||
@@ -1146,3 +1143,29 @@ func timerChan(timer *time.Timer) <-chan time.Time {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tickerChan(ticker *time.Ticker) <-chan time.Time {
|
||||
if ticker != nil {
|
||||
return ticker.C
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeUDPAddr(addr *net.TCPAddr) *net.UDPAddr {
|
||||
return &net.UDPAddr{IP: addr.IP, Port: addr.Port, Zone: addr.Zone}
|
||||
}
|
||||
|
||||
// Look inside an error produced by the net package to get to the
|
||||
// syscall.Errno at the root of the problem.
|
||||
func PosixError(err error) error {
|
||||
if operr, ok := err.(*net.OpError); ok {
|
||||
err = operr.Err
|
||||
}
|
||||
|
||||
// go1.5 wraps an Errno inside a SyscallError inside an OpError
|
||||
if scerr, ok := err.(*os.SyscallError); ok {
|
||||
err = scerr.Err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
var log = common.Log
|
||||
|
||||
var void = struct{}{}
|
||||
|
||||
func checkFatal(e error) {
|
||||
if e != nil {
|
||||
log.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func checkWarn(e error) {
|
||||
if e != nil {
|
||||
log.Warnln(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Look inside an error produced by the net package to get to the
|
||||
// syscall.Errno at the root of the problem.
|
||||
func PosixError(err error) error {
|
||||
if operr, ok := err.(*net.OpError); ok {
|
||||
err = operr.Err
|
||||
}
|
||||
|
||||
// go1.5 wraps an Errno inside a SyscallError inside an OpError
|
||||
if scerr, ok := err.(*os.SyscallError); ok {
|
||||
err = scerr.Err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (upe UnknownPeerError) Error() string {
|
||||
return fmt.Sprint("Reference to unknown peer ", upe.Name)
|
||||
}
|
||||
|
||||
func (nce NameCollisionError) Error() string {
|
||||
return fmt.Sprint("Multiple peers found with same name: ", nce.Name)
|
||||
}
|
||||
|
||||
func (pde PacketDecodingError) Error() string {
|
||||
return fmt.Sprint("Failed to decode packet: ", pde.Desc)
|
||||
}
|
||||
|
||||
func Concat(elems ...[]byte) []byte {
|
||||
res := []byte{}
|
||||
for _, e := range elems {
|
||||
res = append(res, e...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func randBytes(n int) []byte {
|
||||
buf := make([]byte, n)
|
||||
_, err := rand.Read(buf)
|
||||
checkFatal(err)
|
||||
return buf
|
||||
}
|
||||
|
||||
func randUint64() (r uint64) {
|
||||
return binary.LittleEndian.Uint64(randBytes(8))
|
||||
}
|
||||
|
||||
func randUint16() (r uint16) {
|
||||
return binary.LittleEndian.Uint16(randBytes(2))
|
||||
}
|
||||
|
||||
func GobEncode(items ...interface{}) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
for _, i := range items {
|
||||
checkFatal(enc.Encode(i))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func macint(mac net.HardwareAddr) (r uint64) {
|
||||
for _, b := range mac {
|
||||
r <<= 8
|
||||
r |= uint64(b)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func intmac(key uint64) (r net.HardwareAddr) {
|
||||
r = make([]byte, 6)
|
||||
for i := 5; i >= 0; i-- {
|
||||
r[i] = byte(key)
|
||||
key >>= 8
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type ListOfPeers []*Peer
|
||||
|
||||
func (lop ListOfPeers) Len() int {
|
||||
return len(lop)
|
||||
}
|
||||
func (lop ListOfPeers) Swap(i, j int) {
|
||||
lop[i], lop[j] = lop[j], lop[i]
|
||||
}
|
||||
func (lop ListOfPeers) Less(i, j int) bool {
|
||||
return lop[i].Name < lop[j].Name
|
||||
}
|
||||
+3
-3
@@ -54,7 +54,7 @@ $ make
|
||||
|
||||
This will build the weave components and package them into three
|
||||
Docker images (`weaveworks/weave`, `weaveworks/weavedns`, and
|
||||
`weaveworks/weaveexec`). These are then exported as `weave.tar`.
|
||||
`weaveworks/weaveexec`). These are then exported as `weave.tar.gz`.
|
||||
|
||||
## Building in a Docker container
|
||||
|
||||
@@ -167,13 +167,13 @@ you can do so with
|
||||
$ vagrant ssh -c 'make -C src/github.com/weaveworks/weave'
|
||||
```
|
||||
|
||||
you should then find a `weave.tar` container snapshot tarball in the
|
||||
you should then find a `weave.tar.gz` container snapshot tarball in the
|
||||
top-level directory. You can use that snapshot with `docker load`
|
||||
against a different host, e.g.
|
||||
|
||||
```bash
|
||||
$ export DOCKER_HOST=tcp://<HOST:PORT>
|
||||
$ docker load < weave.tar
|
||||
$ docker load < weave.tar.gz
|
||||
```
|
||||
|
||||
You can provide extra Vagrant configuration by putting a file
|
||||
|
||||
@@ -11,6 +11,7 @@ example](https://github.com/weaveworks/weave#example):
|
||||
* [Virtual ethernet switch](#virtual-ethernet-switch)
|
||||
* [Fast data path](#fast-data-path)
|
||||
* [Seamless Docker integration](#docker)
|
||||
* [Docker network plugin](#plugin)
|
||||
* [Address allocation](#addressing)
|
||||
* [Naming and discovery](#naming-and-discovery)
|
||||
* [Application isolation](#application-isolation)
|
||||
@@ -88,6 +89,24 @@ Containers started in this way that subsequently restart, either by an
|
||||
explicit `docker restart` command or by Docker restart policy, are
|
||||
re-attached to the weave network by the weave Docker API proxy.
|
||||
|
||||
### <a name="plugin"></a>Docker network plugin
|
||||
|
||||
Alternatively, you can use weave as a Docker plugin. First you must
|
||||
configure the Docker daemon to use a cluster store as documented
|
||||
[here](https://docs.docker.com/engine/userguide/networking/dockernetworks/#an-overlay-network);
|
||||
you can then launch weave and create a network:
|
||||
|
||||
$ weave launch
|
||||
$ weave launch-plugin
|
||||
$ docker network create --driver=weave weave
|
||||
|
||||
and then start a container:
|
||||
|
||||
$ docker run --net=weave -ti ubuntu
|
||||
|
||||
For more details see the
|
||||
[plugin README](https://github.com/weaveworks/docker-plugin).
|
||||
|
||||
### <a name="addressing"></a>Address allocation
|
||||
|
||||
Containers are automatically allocated an IP address that is unique
|
||||
|
||||
+1
-5
@@ -214,7 +214,7 @@ reports on the current status of the weave router and IP allocator:
|
||||
|
||||
Service: ipam
|
||||
Consensus: waiting(quorum: 2, known: 0)
|
||||
Range: [10.32.0.0-10.48.0.0)
|
||||
Range: 10.32.0.0-10.47.255.255
|
||||
DefaultSubnet: 10.32.0.0/12
|
||||
|
||||
...
|
||||
@@ -225,7 +225,3 @@ guide](troubleshooting.html#weave-status) for full details.
|
||||
|
||||
The 'Service: ipam' section displays the consensus state as well as
|
||||
the total allocation range and default subnet.
|
||||
|
||||
Note that the 'Range' is written using interval notation - '[' means
|
||||
the start of the range is included and ')' means the end of the range
|
||||
is not included.
|
||||
@@ -81,7 +81,7 @@ $ weave status
|
||||
|
||||
Service: ipam
|
||||
Consensus: achieved
|
||||
Range: [10.32.0.0-10.48.0.0)
|
||||
Range: 10.32.0.0-10.47.255.255
|
||||
DefaultSubnet: 10.32.0.0/12
|
||||
|
||||
Service: dns
|
||||
|
||||
@@ -7,8 +7,8 @@ C2=10.2.1.47
|
||||
|
||||
start_suite "WEAVE_NO_FASTDP operation"
|
||||
|
||||
WEAVE_NO_FASTDP=1 weave_on $HOST1 launch
|
||||
WEAVE_NO_FASTDP=1 weave_on $HOST2 launch $HOST1
|
||||
WEAVE_NO_FASTDP=1 WEAVE_DOCKER_ARGS=$ADD_HOST_ARGS weave_on $HOST1 launch
|
||||
WEAVE_NO_FASTDP=1 WEAVE_DOCKER_ARGS=$ADD_HOST_ARGS weave_on $HOST2 launch $HOST1
|
||||
|
||||
start_container $HOST1 $C1/24 --name=c1
|
||||
start_container $HOST2 $C2/24 --name=c2
|
||||
|
||||
@@ -72,6 +72,5 @@ start_container $HOST2 --name=c4 -h $NAME4
|
||||
start_container_with_dns $HOST1 --name=c3
|
||||
C4=$(container_ip $HOST2 c4)
|
||||
assert_dns_record $HOST1 c3 $NAME4 $C4
|
||||
assert_raises "exec_on $HOST1 c3 getent hosts 8.8.8.8 | grep google"
|
||||
|
||||
end_suite
|
||||
@@ -42,10 +42,11 @@ run_on $HOST1 sudo kill -KILL $(docker_on $HOST1 inspect --format='{{.State.Pid}
|
||||
sleep 1
|
||||
check_attached
|
||||
|
||||
# Disabled because Docker 1.8 often fails to restart weave or weaveproxy
|
||||
# Restart docker itself, using different commands for systemd- and upstart-managed.
|
||||
run_on $HOST1 sh -c "command -v systemctl >/dev/null && sudo systemctl restart docker || sudo service docker restart"
|
||||
wait_for_proxy $HOST1
|
||||
check_attached
|
||||
#run_on $HOST1 sh -c "command -v systemctl >/dev/null && sudo systemctl restart docker || sudo service docker restart"
|
||||
#wait_for_proxy $HOST1
|
||||
#check_attached
|
||||
|
||||
# Restarting proxy shouldn't kill unattachable containers
|
||||
proxy_start_container $HOST1 -di --name=c3 --restart=always # Use ipam, so it won't be attachable w/o weave
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ set -e
|
||||
: ${SSH_KEY_FILE:=$HOME/.ssh/gce_ssh_key}
|
||||
: ${PROJECT:=positive-cocoa-90213}
|
||||
: ${IMAGE:=ubuntu-14-04}
|
||||
: ${TEMPLATE_NAME:=test-template-6}
|
||||
: ${TEMPLATE_NAME:=test-template-8}
|
||||
: ${ZONE:=us-central1-a}
|
||||
: ${NUM_HOSTS:=5}
|
||||
SUFFIX=""
|
||||
@@ -73,7 +73,7 @@ curl -sSL https://get.docker.com/ | sh
|
||||
apt-get update -qq;
|
||||
apt-get install -q -y --force-yes --no-install-recommends ethtool;
|
||||
usermod -a -G docker vagrant;
|
||||
echo 'DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375"' >> /etc/default/docker;
|
||||
echo 'DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375 -s overlay"' >> /etc/default/docker;
|
||||
service docker restart
|
||||
EOF
|
||||
# It seems we need a short delay for docker to start up, so I put this in
|
||||
@@ -142,7 +142,7 @@ function hosts {
|
||||
done
|
||||
echo export SSH=ssh
|
||||
echo export HOSTS=\"$hosts\"
|
||||
echo export WEAVE_DOCKER_ARGS=\"$args\"
|
||||
echo export ADD_HOST_ARGS=\"$args\"
|
||||
rm $json
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,4 +23,4 @@ if [ -n "$CIRCLECI" -o -n "$PARALLEL" ]; then
|
||||
RUNNER_ARGS="$RUNNER_ARGS -parallel"
|
||||
fi
|
||||
|
||||
HOSTS="$HOSTS" "${DIR}/../testing/runner/runner" $RUNNER_ARGS $TESTS
|
||||
HOSTS="$HOSTS" "${DIR}/../tools/runner/runner" $RUNNER_ARGS $TESTS
|
||||
@@ -1 +0,0 @@
|
||||
lib
|
||||
@@ -1,6 +0,0 @@
|
||||
To upload newer version:
|
||||
|
||||
```
|
||||
pip install -r requirements.txt -t lib
|
||||
appcfg.py update .
|
||||
```
|
||||
@@ -1,13 +0,0 @@
|
||||
application: positive-cocoa-90213
|
||||
version: 1
|
||||
runtime: python27
|
||||
api_version: 1
|
||||
threadsafe: true
|
||||
|
||||
handlers:
|
||||
- url: .*
|
||||
script: main.app
|
||||
|
||||
libraries:
|
||||
- name: webapp2
|
||||
version: latest
|
||||
@@ -1,3 +0,0 @@
|
||||
from google.appengine.ext import vendor
|
||||
|
||||
vendor.add('lib')
|
||||
@@ -1,4 +0,0 @@
|
||||
cron:
|
||||
- description: periodic gc
|
||||
url: /tasks/gc
|
||||
schedule: every 5 minutes
|
||||
@@ -1,112 +0,0 @@
|
||||
import collections
|
||||
import json
|
||||
import logging
|
||||
import operator
|
||||
import re
|
||||
|
||||
import flask
|
||||
from oauth2client.client import GoogleCredentials
|
||||
from googleapiclient import discovery
|
||||
|
||||
from google.appengine.api import urlfetch
|
||||
from google.appengine.ext import ndb
|
||||
|
||||
app = flask.Flask('scheduler')
|
||||
app.debug = True
|
||||
|
||||
# We use exponential moving average to record
|
||||
# test run times. Higher alpha discounts historic
|
||||
# observations faster.
|
||||
alpha = 0.3
|
||||
|
||||
PROJECT = 'positive-cocoa-90213'
|
||||
ZONE = 'us-central1-a'
|
||||
|
||||
class Test(ndb.Model):
|
||||
total_run_time = ndb.FloatProperty(default=0.) # Not total, but a EWMA
|
||||
total_runs = ndb.IntegerProperty(default=0)
|
||||
|
||||
class Schedule(ndb.Model):
|
||||
shards = ndb.JsonProperty()
|
||||
|
||||
@app.route('/record/<path:test_name>/<runtime>', methods=['POST'])
|
||||
@ndb.transactional
|
||||
def record(test_name, runtime):
|
||||
test = Test.get_by_id(test_name)
|
||||
if test is None:
|
||||
test = Test(id=test_name)
|
||||
test.total_run_time = (test.total_run_time * (1-alpha)) + (float(runtime) * alpha)
|
||||
test.total_runs += 1
|
||||
test.put()
|
||||
return ('', 204)
|
||||
|
||||
@app.route('/schedule/<test_run>/<int:shard_count>/<int:shard>', methods=['POST'])
|
||||
def schedule(test_run, shard_count, shard):
|
||||
# read tests from body
|
||||
test_names = flask.request.get_json(force=True)['tests']
|
||||
|
||||
# first see if we have a scedule already
|
||||
schedule_id = "%s-%d" % (test_run, shard_count)
|
||||
schedule = Schedule.get_by_id(schedule_id)
|
||||
if schedule is not None:
|
||||
return flask.json.jsonify(tests=schedule.shards[str(shard)])
|
||||
|
||||
# if not, do simple greedy algorithm
|
||||
test_times = ndb.get_multi(ndb.Key(Test, test_name) for test_name in test_names)
|
||||
def avg(test):
|
||||
if test is not None:
|
||||
return test.total_run_time
|
||||
return 1
|
||||
test_times = [(test_name, avg(test)) for test_name, test in zip(test_names, test_times)]
|
||||
test_times_dict = dict(test_times)
|
||||
test_times.sort(key=operator.itemgetter(1))
|
||||
|
||||
shards = {i: [] for i in xrange(shard_count)}
|
||||
while test_times:
|
||||
test_name, time = test_times.pop()
|
||||
|
||||
# find shortest shard and put it in that
|
||||
s, _ = min(((i, sum(test_times_dict[t] for t in shards[i]))
|
||||
for i in xrange(shard_count)), key=operator.itemgetter(1))
|
||||
|
||||
shards[s].append(test_name)
|
||||
|
||||
# atomically insert or retrieve existing schedule
|
||||
schedule = Schedule.get_or_insert(schedule_id, shards=shards)
|
||||
return flask.json.jsonify(tests=schedule.shards[str(shard)])
|
||||
|
||||
NAME_RE = re.compile(r'^host(?P<index>\d+)-(?P<build>\d+)-(?P<shard>\d+)$')
|
||||
|
||||
@app.route('/tasks/gc')
|
||||
def gc():
|
||||
# Get list of running VMs, pick build id out of VM name
|
||||
credentials = GoogleCredentials.get_application_default()
|
||||
compute = discovery.build('compute', 'v1', credentials=credentials)
|
||||
instances = compute.instances().list(project=PROJECT, zone=ZONE).execute()
|
||||
host_by_build = collections.defaultdict(list)
|
||||
for instance in instances['items']:
|
||||
matches = NAME_RE.match(instance['name'])
|
||||
if matches is None:
|
||||
continue
|
||||
host_by_build[int(matches.group('build'))].append(instance['name'])
|
||||
logging.info("Running VMs by build: %r", host_by_build)
|
||||
|
||||
# Get list of builds, filter down to runnning builds
|
||||
result = urlfetch.fetch('https://circleci.com/api/v1/project/weaveworks/weave',
|
||||
headers={'Accept': 'application/json'})
|
||||
assert result.status_code == 200
|
||||
builds = json.loads(result.content)
|
||||
running = {build['build_num'] for build in builds if build['status'] == 'running'}
|
||||
logging.info("Runnings builds: %r", running)
|
||||
|
||||
# Stop VMs for builds that aren't running
|
||||
stopped = []
|
||||
for build, names in host_by_build.iteritems():
|
||||
if build in running:
|
||||
continue
|
||||
for name in names:
|
||||
stopped.append(name)
|
||||
logging.info("Stopping VM %s", name)
|
||||
compute.instances().delete(project=PROJECT, zone=ZONE, instance=name).execute()
|
||||
|
||||
return (flask.json.jsonify(running=list(running), stopped=stopped), 200)
|
||||
@@ -1,2 +0,0 @@
|
||||
flask
|
||||
google-api-python-client
|
||||
+1
-1
@@ -13,7 +13,7 @@ echo " prefetch test images"
|
||||
|
||||
setup_host() {
|
||||
HOST=$1
|
||||
docker_on $HOST load -i ../weave.tar
|
||||
docker_on $HOST load -i ../weave.tar.gz
|
||||
DANGLING_IMAGES="$(docker_on $HOST images -q -f dangling=true)"
|
||||
[ -n "$DANGLING_IMAGES" ] && docker_on $HOST rmi $DANGLING_IMAGES 1>/dev/null 2>&1 || true
|
||||
run_on $HOST mkdir -p bin
|
||||
|
||||
+16
-16
@@ -7,21 +7,21 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/router"
|
||||
"github.com/weaveworks/weave/mesh"
|
||||
)
|
||||
|
||||
// Router to convey gossip from one gossiper to another, for testing
|
||||
type unicastMessage struct {
|
||||
sender router.PeerName
|
||||
sender mesh.PeerName
|
||||
buf []byte
|
||||
}
|
||||
type broadcastMessage struct {
|
||||
sender router.PeerName
|
||||
data router.GossipData
|
||||
sender mesh.PeerName
|
||||
data mesh.GossipData
|
||||
}
|
||||
type gossipMessage struct {
|
||||
sender router.PeerName
|
||||
data router.GossipData
|
||||
sender mesh.PeerName
|
||||
data mesh.GossipData
|
||||
}
|
||||
type exitMessage struct {
|
||||
exitChan chan struct{}
|
||||
@@ -31,12 +31,12 @@ type flushMessage struct {
|
||||
}
|
||||
|
||||
type TestRouter struct {
|
||||
gossipChans map[router.PeerName]chan interface{}
|
||||
gossipChans map[mesh.PeerName]chan interface{}
|
||||
loss float32 // 0.0 means no loss
|
||||
}
|
||||
|
||||
func NewTestRouter(loss float32) *TestRouter {
|
||||
return &TestRouter{make(map[router.PeerName]chan interface{}, 100), loss}
|
||||
return &TestRouter{make(map[mesh.PeerName]chan interface{}, 100), loss}
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) Stop() {
|
||||
@@ -45,7 +45,7 @@ func (grouter *TestRouter) Stop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) gossipBroadcast(sender router.PeerName, update router.GossipData) error {
|
||||
func (grouter *TestRouter) gossipBroadcast(sender mesh.PeerName, update mesh.GossipData) error {
|
||||
for _, gossipChan := range grouter.gossipChans {
|
||||
select {
|
||||
case gossipChan <- broadcastMessage{sender: sender, data: update}:
|
||||
@@ -56,7 +56,7 @@ func (grouter *TestRouter) gossipBroadcast(sender router.PeerName, update router
|
||||
return nil
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) gossip(sender router.PeerName, update router.GossipData) error {
|
||||
func (grouter *TestRouter) gossip(sender mesh.PeerName, update mesh.GossipData) error {
|
||||
count := int(math.Log2(float64(len(grouter.gossipChans))))
|
||||
for dest, gossipChan := range grouter.gossipChans {
|
||||
if dest == sender {
|
||||
@@ -83,7 +83,7 @@ func (grouter *TestRouter) Flush() {
|
||||
}
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) RemovePeer(peer router.PeerName) {
|
||||
func (grouter *TestRouter) RemovePeer(peer mesh.PeerName) {
|
||||
gossipChan := grouter.gossipChans[peer]
|
||||
resultChan := make(chan struct{})
|
||||
gossipChan <- exitMessage{exitChan: resultChan}
|
||||
@@ -93,10 +93,10 @@ func (grouter *TestRouter) RemovePeer(peer router.PeerName) {
|
||||
|
||||
type TestRouterClient struct {
|
||||
router *TestRouter
|
||||
sender router.PeerName
|
||||
sender mesh.PeerName
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper, gossipChan chan interface{}) {
|
||||
func (grouter *TestRouter) run(sender mesh.PeerName, gossiper mesh.Gossiper, gossipChan chan interface{}) {
|
||||
gossipTimer := time.Tick(2 * time.Second)
|
||||
for {
|
||||
select {
|
||||
@@ -155,7 +155,7 @@ func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper,
|
||||
}
|
||||
}
|
||||
|
||||
func (grouter *TestRouter) Connect(sender router.PeerName, gossiper router.Gossiper) router.Gossip {
|
||||
func (grouter *TestRouter) Connect(sender mesh.PeerName, gossiper mesh.Gossiper) mesh.Gossip {
|
||||
gossipChan := make(chan interface{}, 100)
|
||||
|
||||
go grouter.run(sender, gossiper, gossipChan)
|
||||
@@ -164,7 +164,7 @@ func (grouter *TestRouter) Connect(sender router.PeerName, gossiper router.Gossi
|
||||
return TestRouterClient{grouter, sender}
|
||||
}
|
||||
|
||||
func (client TestRouterClient) GossipUnicast(dstPeerName router.PeerName, buf []byte) error {
|
||||
func (client TestRouterClient) GossipUnicast(dstPeerName mesh.PeerName, buf []byte) error {
|
||||
select {
|
||||
case client.router.gossipChans[dstPeerName] <- unicastMessage{sender: client.sender, buf: buf}:
|
||||
default: // drop the message if we cannot send it
|
||||
@@ -173,6 +173,6 @@ func (client TestRouterClient) GossipUnicast(dstPeerName router.PeerName, buf []
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client TestRouterClient) GossipBroadcast(update router.GossipData) error {
|
||||
func (client TestRouterClient) GossipBroadcast(update mesh.GossipData) error {
|
||||
return client.router.gossipBroadcast(client.sender, update)
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/mflag"
|
||||
"github.com/mgutz/ansi"
|
||||
)
|
||||
|
||||
const (
|
||||
schedulerHost = "positive-cocoa-90213.appspot.com"
|
||||
JSON = "application/json"
|
||||
)
|
||||
|
||||
var (
|
||||
start = ansi.ColorCode("black+ub")
|
||||
fail = ansi.ColorCode("red+b")
|
||||
succ = ansi.ColorCode("green+b")
|
||||
reset = ansi.ColorCode("reset")
|
||||
|
||||
useScheduler = false
|
||||
runParallel = false
|
||||
verbose = false
|
||||
|
||||
consoleLock = sync.Mutex{}
|
||||
)
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
hosts int
|
||||
}
|
||||
|
||||
type schedule struct {
|
||||
Tests []string `json:"tests"`
|
||||
}
|
||||
|
||||
type result struct {
|
||||
test
|
||||
errored bool
|
||||
hosts []string
|
||||
}
|
||||
|
||||
type tests []test
|
||||
|
||||
func (ts tests) Len() int { return len(ts) }
|
||||
func (ts tests) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] }
|
||||
func (ts tests) Less(i, j int) bool {
|
||||
if ts[i].hosts != ts[j].hosts {
|
||||
return ts[i].hosts < ts[j].hosts
|
||||
}
|
||||
return ts[i].name < ts[j].name
|
||||
}
|
||||
|
||||
func (ts *tests) pick(availible int) (test, bool) {
|
||||
// pick the first test that fits in the availible hosts
|
||||
for i, test := range *ts {
|
||||
if test.hosts <= availible {
|
||||
*ts = append((*ts)[:i], (*ts)[i+1:]...)
|
||||
return test, true
|
||||
}
|
||||
}
|
||||
|
||||
return test{}, false
|
||||
}
|
||||
|
||||
func (t test) run(hosts []string) bool {
|
||||
consoleLock.Lock()
|
||||
fmt.Printf("%s>>> Running %s on %s%s\n", start, t.name, hosts, reset)
|
||||
consoleLock.Unlock()
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
cmd := exec.Command(t.name)
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Stdout = &out
|
||||
cmd.Stderr = &out
|
||||
|
||||
// replace HOSTS in env
|
||||
for i, env := range cmd.Env {
|
||||
if strings.HasPrefix(env, "HOSTS") {
|
||||
cmd.Env[i] = fmt.Sprintf("HOSTS=%s", strings.Join(hosts, " "))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
err := cmd.Run()
|
||||
duration := float64(time.Now().Sub(start)) / float64(time.Second)
|
||||
|
||||
consoleLock.Lock()
|
||||
if err != nil {
|
||||
fmt.Printf("%s>>> Test %s finished after %0.1f secs with error: %v%s\n", fail, t.name, duration, err, reset)
|
||||
} else {
|
||||
fmt.Printf("%s>>> Test %s finished with success after %0.1f secs%s\n", succ, t.name, duration, reset)
|
||||
}
|
||||
if err != nil || verbose {
|
||||
fmt.Print(out.String())
|
||||
fmt.Println()
|
||||
}
|
||||
consoleLock.Unlock()
|
||||
|
||||
if err != nil && useScheduler {
|
||||
updateScheduler(t.name, duration)
|
||||
}
|
||||
|
||||
return err != nil
|
||||
}
|
||||
|
||||
func updateScheduler(test string, duration float64) {
|
||||
req := &http.Request{
|
||||
Method: "POST",
|
||||
Host: schedulerHost,
|
||||
URL: &url.URL{
|
||||
Opaque: fmt.Sprintf("/record/%s/%0.2f", url.QueryEscape(test), duration),
|
||||
Scheme: "http",
|
||||
Host: schedulerHost,
|
||||
},
|
||||
Close: true,
|
||||
}
|
||||
if resp, err := http.DefaultClient.Do(req); err != nil {
|
||||
fmt.Printf("Error updating scheduler: %v\n", err)
|
||||
} else {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func getSchedule(tests []string) ([]string, error) {
|
||||
var (
|
||||
testRun = "integration-" + os.Getenv("CIRCLE_BUILD_NUM")
|
||||
shardCount = os.Getenv("CIRCLE_NODE_TOTAL")
|
||||
shardID = os.Getenv("CIRCLE_NODE_INDEX")
|
||||
requestBody = &bytes.Buffer{}
|
||||
)
|
||||
if err := json.NewEncoder(requestBody).Encode(schedule{tests}); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
url := fmt.Sprintf("http://%s/schedule/%s/%s/%s", schedulerHost, testRun, shardCount, shardID)
|
||||
resp, err := http.Post(url, JSON, requestBody)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
var sched schedule
|
||||
if err := json.NewDecoder(resp.Body).Decode(&sched); err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return sched.Tests, nil
|
||||
}
|
||||
|
||||
func getTests(testNames []string) (tests, error) {
|
||||
var err error
|
||||
if useScheduler {
|
||||
testNames, err = getSchedule(testNames)
|
||||
if err != nil {
|
||||
return tests{}, err
|
||||
}
|
||||
}
|
||||
tests := tests{}
|
||||
for _, name := range testNames {
|
||||
parts := strings.Split(strings.TrimSuffix(name, "_test.sh"), "_")
|
||||
numHosts, err := strconv.Atoi(parts[len(parts)-1])
|
||||
if err != nil {
|
||||
numHosts = 1
|
||||
}
|
||||
tests = append(tests, test{name, numHosts})
|
||||
fmt.Printf("Test %s needs %d hosts\n", name, numHosts)
|
||||
}
|
||||
return tests, nil
|
||||
}
|
||||
|
||||
func summary(tests, failed tests) {
|
||||
if len(failed) > 0 {
|
||||
fmt.Printf("%s>>> Ran %d tests, %d failed%s\n", fail, len(tests), len(failed), reset)
|
||||
for _, test := range failed {
|
||||
fmt.Printf("%s>>> Fail %s%s\n", fail, test.name, reset)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%s>>> Ran %d tests, all succeeded%s\n", succ, len(tests), reset)
|
||||
}
|
||||
}
|
||||
|
||||
func parallel(ts tests, hosts []string) bool {
|
||||
testsCopy := ts
|
||||
sort.Sort(sort.Reverse(ts))
|
||||
resultsChan := make(chan result)
|
||||
outstanding := 0
|
||||
failed := tests{}
|
||||
for len(ts) > 0 || outstanding > 0 {
|
||||
// While we have some free hosts, try and schedule
|
||||
// a test on them
|
||||
for len(hosts) > 0 {
|
||||
test, ok := ts.pick(len(hosts))
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
testHosts := hosts[:test.hosts]
|
||||
hosts = hosts[test.hosts:]
|
||||
|
||||
go func() {
|
||||
errored := test.run(testHosts)
|
||||
resultsChan <- result{test, errored, testHosts}
|
||||
}()
|
||||
outstanding++
|
||||
}
|
||||
|
||||
// Otherwise, wait for the test to finish and return
|
||||
// the hosts to the pool
|
||||
result := <-resultsChan
|
||||
hosts = append(hosts, result.hosts...)
|
||||
outstanding--
|
||||
if result.errored {
|
||||
failed = append(failed, result.test)
|
||||
}
|
||||
}
|
||||
summary(testsCopy, failed)
|
||||
return len(failed) > 0
|
||||
}
|
||||
|
||||
func sequential(ts tests, hosts []string) bool {
|
||||
failed := tests{}
|
||||
for _, test := range ts {
|
||||
if test.run(hosts) {
|
||||
failed = append(failed, test)
|
||||
}
|
||||
}
|
||||
summary(ts, failed)
|
||||
return len(failed) > 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
mflag.BoolVar(&useScheduler, []string{"scheduler"}, false, "Use scheduler to distribute tests across shards")
|
||||
mflag.BoolVar(&runParallel, []string{"parallel"}, false, "Run tests in parallel on hosts where possible")
|
||||
mflag.BoolVar(&verbose, []string{"v"}, false, "Print output from all tests (Also enabled via DEBUG=1)")
|
||||
mflag.Parse()
|
||||
|
||||
if len(os.Getenv("DEBUG")) > 0 {
|
||||
verbose = true
|
||||
}
|
||||
|
||||
tests, err := getTests(mflag.Args())
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing tests: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
hosts := strings.Fields(os.Getenv("HOSTS"))
|
||||
maxHosts := len(hosts)
|
||||
if maxHosts == 0 {
|
||||
fmt.Print("No HOSTS specified.\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var errored bool
|
||||
if runParallel {
|
||||
errored = parallel(tests, hosts)
|
||||
} else {
|
||||
errored = sequential(tests, hosts)
|
||||
}
|
||||
|
||||
if errored {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
+1
-1
Submodule tools updated: a286ddade0...452f2b7de1.
@@ -58,6 +58,7 @@ weave launch-proxy [-H <endpoint>] [--with-dns | --without-dns]
|
||||
[--hostname-match <regexp>]
|
||||
[--hostname-replacement <replacement>]
|
||||
[--rewrite-inspect]
|
||||
weave launch-plugin
|
||||
weave env [--restore]
|
||||
weave config
|
||||
weave connect [--replace] [<peer> ...]
|
||||
@@ -80,6 +81,7 @@ weave ps [<container_id> ...]
|
||||
weave stop
|
||||
weave stop-router
|
||||
weave stop-proxy
|
||||
weave stop-plugin
|
||||
weave reset
|
||||
weave rmpeer <peer_id>
|
||||
|
||||
@@ -288,6 +290,10 @@ fi
|
||||
BASE_IMAGE=$DOCKERHUB_USER/weave
|
||||
IMAGE=$BASE_IMAGE:$IMAGE_VERSION
|
||||
|
||||
BASE_PLUGIN_IMAGE=$DOCKERHUB_USER/plugin
|
||||
PLUGIN_IMAGE=$BASE_PLUGIN_IMAGE:$IMAGE_VERSION
|
||||
PLUGIN_CONTAINER_NAME=weaveplugin
|
||||
|
||||
PROCFS=${PROCFS:-/proc}
|
||||
DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0}
|
||||
CONTAINER_NAME=${WEAVE_CONTAINER_NAME:-weave}
|
||||
@@ -703,7 +709,7 @@ setup_router_iface_bridge() {
|
||||
}
|
||||
|
||||
attach() {
|
||||
if [ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "/proc/$$/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink /proc/$$/ns/net)" ] ; then
|
||||
if [ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "/proc/self/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink /proc/self/ns/net)" ] ; then
|
||||
echo "Container is running in the host network namespace, and therefore cannot be" >&2
|
||||
echo "connected to weave. Perhaps the container was started with --net=host." >&2
|
||||
return 1
|
||||
@@ -1463,6 +1469,7 @@ launch_router() {
|
||||
|
||||
if [ "$BRIDGE_TYPE" = fastdp ] ; then
|
||||
NETHOST_OPT="--net=host"
|
||||
HTTP_IP=127.0.0.1
|
||||
# In case there is a lingering veth-weave netdev
|
||||
ip link del $ROUTER_HOSTNETNS_IFNAME >/dev/null 2>&1 || true
|
||||
fi
|
||||
@@ -1481,7 +1488,8 @@ launch_router() {
|
||||
$(router_opts_$BRIDGE_TYPE) \
|
||||
--ipalloc-range "$IPRANGE" \
|
||||
--dns-effective-listen-address $DOCKER_BRIDGE_IP \
|
||||
${NETHOST_OPT:+$DNS_ROUTER_OPTS --http-addr 127.0.0.1:$HTTP_PORT} $NO_DNS_OPT \
|
||||
${NETHOST_OPT:+$DNS_ROUTER_OPTS} $NO_DNS_OPT \
|
||||
--http-addr $HTTP_IP:$HTTP_PORT \
|
||||
--docker-api "unix:///var/run/docker.sock" "$@")
|
||||
with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE
|
||||
attach_router
|
||||
@@ -1527,14 +1535,8 @@ launch_proxy() {
|
||||
# when launching the weaveproxy container.
|
||||
docker_client_args $DOCKER_CLIENT_ARGS
|
||||
proxy_args "$@"
|
||||
HOSTS_PATH=$(docker run --rm --net=none \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--entrypoint=/bin/sh \
|
||||
$EXEC_IMAGE -c 'docker inspect -f {{.HostsPath}} $(hostname)')
|
||||
CONTAINERS_PATH="$(dirname $(dirname "$HOSTS_PATH"))"
|
||||
PROXY_CONTAINER=$(docker run --privileged -d --name=$PROXY_CONTAINER_NAME --net=host \
|
||||
$PROXY_VOLUMES \
|
||||
-v "$CONTAINERS_PATH":"$CONTAINERS_PATH" \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/run/weave:/var/run/weave \
|
||||
-v /proc:/hostproc \
|
||||
@@ -1553,6 +1555,19 @@ stop_proxy() {
|
||||
stop $PROXY_CONTAINER_NAME "Proxy"
|
||||
}
|
||||
|
||||
launch_plugin() {
|
||||
PLUGIN_CONTAINER=$(docker run --privileged -d --name=$PLUGIN_CONTAINER_NAME \
|
||||
--restart=always \
|
||||
--net=host \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /run/docker/plugins:/run/docker/plugins \
|
||||
$PLUGIN_IMAGE "$@")
|
||||
}
|
||||
|
||||
stop_plugin() {
|
||||
stop $PLUGIN_CONTAINER_NAME "Plugin"
|
||||
}
|
||||
|
||||
##########################################################################################
|
||||
|
||||
[ $(id -u) = 0 ] || {
|
||||
@@ -1651,7 +1666,7 @@ shift 1
|
||||
|
||||
case "$COMMAND" in
|
||||
setup)
|
||||
for img in $IMAGE $EXEC_IMAGE ; do
|
||||
for img in $IMAGE $EXEC_IMAGE $PLUGIN_IMAGE ; do
|
||||
docker pull $img
|
||||
done
|
||||
;;
|
||||
@@ -1703,6 +1718,11 @@ EOF
|
||||
launch_proxy "$@"
|
||||
echo $PROXY_CONTAINER
|
||||
;;
|
||||
launch-plugin)
|
||||
check_not_running $PLUGIN_CONTAINER_NAME $BASE_PLUGIN_IMAGE
|
||||
launch_plugin "$@"
|
||||
echo $PLUGIN_CONTAINER
|
||||
;;
|
||||
env|proxy-env)
|
||||
[ "$COMMAND" = "env" ] || deprecation_warning "$COMMAND" "'weave env'"
|
||||
if PROXY_ADDR=$(proxy_addr) ; then
|
||||
@@ -1758,6 +1778,11 @@ EOF
|
||||
echo " Service: proxy"
|
||||
echo " Address: $PROXY_ADDRS"
|
||||
fi
|
||||
if [ -z "$SUB_STATUS" ] && check_running $PLUGIN_CONTAINER_NAME 2>/dev/null ; then
|
||||
echo
|
||||
echo " Service: plugin"
|
||||
echo " DriverName: weave"
|
||||
fi
|
||||
[ -n "$SUB_STATUS" ] || echo
|
||||
[ $res -eq 0 ]
|
||||
;;
|
||||
@@ -1944,6 +1969,10 @@ EOF
|
||||
[ $# -eq 0 ] || usage
|
||||
stop_proxy
|
||||
;;
|
||||
stop-plugin)
|
||||
[ $# -eq 0 ] || usage
|
||||
stop_plugin
|
||||
;;
|
||||
reset)
|
||||
[ $# -eq 0 ] || usage
|
||||
warn_if_stopping_proxy_in_env
|
||||
|
||||
Reference in new issue
Block a user