From 203a3cfdd1d8827b5be5b64d8428385ea0409dc8 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Fri, 23 Oct 2015 13:02:00 +0000 Subject: [PATCH 01/67] Remove test runner; it now live in build-tools.git --- Makefile | 10 +- test/run_all.sh | 2 +- testing/runner/runner.go | 273 --------------------------------------- tools | 2 +- 4 files changed, 8 insertions(+), 279 deletions(-) delete mode 100644 testing/runner/runner.go diff --git a/Makefile b/Makefile index e1ff2156..2335594b 100644 --- a/Makefile +++ b/Makefile @@ -15,9 +15,9 @@ SIGPROXY_EXE=prog/sigproxy/sigproxy WEAVEWAIT_EXE=prog/weavewait/weavewait 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) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) $(RUNNER_EXE) +EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) WEAVER_UPTODATE=.weaver.uptodate WEAVEEXEC_UPTODATE=.weaveexec.uptodate @@ -77,10 +77,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/main.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) @@ -114,6 +113,9 @@ lint: tools/.git tools/.git: git submodule update --init +$(RUNNER_EXE): + 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) diff --git a/test/run_all.sh b/test/run_all.sh index d73c5b1c..78cc7f74 100755 --- a/test/run_all.sh +++ b/test/run_all.sh @@ -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 diff --git a/testing/runner/runner.go b/testing/runner/runner.go deleted file mode 100644 index fe4f7efe..00000000 --- a/testing/runner/runner.go +++ /dev/null @@ -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) - } -} diff --git a/tools b/tools index a286ddad..58c9a390 160000 --- a/tools +++ b/tools @@ -1 +1 @@ -Subproject commit a286ddade02b98e429a8f65d52a825405a9efcf3 +Subproject commit 58c9a390c54860547254fa3a66e0acd8916f889c From 6a672cf8bc8da414952039d5a07a6c42f55f658c Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Wed, 28 Oct 2015 18:23:15 +0000 Subject: [PATCH 02/67] tiny refactor: more idiomatic referal to process' /proc --- weave | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weave b/weave index 3e954067..3e5de581 100755 --- a/weave +++ b/weave @@ -697,7 +697,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 From 12f5ec40b5212886d325bdcdd9866c3c9f766691 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 29 Oct 2015 23:21:07 +0000 Subject: [PATCH 03/67] refactor: reduce coupling of nameserver to router The nameserver no longer knows anything about router.Peers and router.Peer. That only leaves PeerName, Gossip and GossipData. --- nameserver/dns_test.go | 2 +- nameserver/nameserver.go | 40 +++++++++++++++-------------------- nameserver/nameserver_test.go | 12 +++++++---- prog/weaver/main.go | 6 +++++- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/nameserver/dns_test.go b/nameserver/dns_test.go index 74768715..74187f27 100644 --- a/nameserver/dns_test.go +++ b/nameserver/dns_test.go @@ -18,7 +18,7 @@ import ( func startServer(t *testing.T, upstream *dns.ClientConfig) (*DNSServer, *Nameserver, int, int) { peername, err := router.PeerNameFromString("00:00:00:02:00:00") require.Nil(t, err) - nameserver := New(peername, nil, "") + nameserver := New(peername, "", func(router.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 diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index 19037804..48501db6 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -37,25 +37,21 @@ 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 router.PeerName + domain string + gossip router.Gossip + entries Entries + isKnownPeer func(router.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 router.PeerName, domain string, isKnownPeer func(router.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) { @@ -147,12 +143,12 @@ func (n *Nameserver) ContainerDied(ident string) { } } -func (n *Nameserver) PeerGone(peer *router.Peer) { +func (n *Nameserver) PeerGone(peer router.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 }) } @@ -219,11 +215,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 { diff --git a/nameserver/nameserver_test.go b/nameserver/nameserver_test.go index 581fe321..dda9f1e5 100644 --- a/nameserver/nameserver_test.go +++ b/nameserver/nameserver_test.go @@ -17,13 +17,17 @@ import ( "github.com/weaveworks/weave/testing/gossip" ) +func makeNameserver(name router.PeerName) *Nameserver { + return New(name, "", func(router.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, "") + nameserver := makeNameserver(name) nameserver.SetGossip(gossipRouter.Connect(nameserver.ourName, nameserver)) nameserver.Start() nameservers[i] = nameserver @@ -205,7 +209,7 @@ func testNameservers(t *testing.T) { func TestContainerAndPeerDeath(t *testing.T) { peername, err := router.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) @@ -218,7 +222,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")) } @@ -229,7 +233,7 @@ func TestTombstoneDeletion(t *testing.T) { peername, err := router.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) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index bf85b916..32c7a40f 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -264,7 +264,11 @@ func main() { dnsserver *nameserver.DNSServer ) if !noDNS { - ns = nameserver.New(router.Ourself.Peer.Name, router.Peers, dnsDomain) + isKnownPeer := func(name weave.PeerName) bool { + return router.Peers.Fetch(name) != nil + } + ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer) + router.Peers.OnGC(func(peer *weave.Peer) { ns.PeerGone(peer.Name) }) ns.SetGossip(router.NewGossip("nameserver", ns)) observeContainers(ns) ns.Start() From abc653c87d4e6b00b890dd1b4b4bf920cdaced77 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 3 Nov 2015 10:13:43 +0000 Subject: [PATCH 04/67] Fix merge breakage --- nameserver/nameserver_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nameserver/nameserver_test.go b/nameserver/nameserver_test.go index ccb4857c..5beaf87e 100644 --- a/nameserver/nameserver_test.go +++ b/nameserver/nameserver_test.go @@ -146,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() { From c02691a70cb426587a688b586c8474c9fa001f9b Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Tue, 3 Nov 2015 14:38:42 +0000 Subject: [PATCH 05/67] Move scheduler to build-tools. --- test/scheduler/.gitignore | 1 - test/scheduler/README.md | 6 -- test/scheduler/app.yaml | 13 ---- test/scheduler/appengine_config.py | 3 - test/scheduler/cron.yaml | 4 -- test/scheduler/main.py | 112 ----------------------------- test/scheduler/requirements.txt | 2 - 7 files changed, 141 deletions(-) delete mode 100644 test/scheduler/.gitignore delete mode 100644 test/scheduler/README.md delete mode 100644 test/scheduler/app.yaml delete mode 100644 test/scheduler/appengine_config.py delete mode 100644 test/scheduler/cron.yaml delete mode 100644 test/scheduler/main.py delete mode 100644 test/scheduler/requirements.txt diff --git a/test/scheduler/.gitignore b/test/scheduler/.gitignore deleted file mode 100644 index a65b4177..00000000 --- a/test/scheduler/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lib diff --git a/test/scheduler/README.md b/test/scheduler/README.md deleted file mode 100644 index 8489d787..00000000 --- a/test/scheduler/README.md +++ /dev/null @@ -1,6 +0,0 @@ -To upload newer version: - -``` -pip install -r requirements.txt -t lib -appcfg.py update . -``` diff --git a/test/scheduler/app.yaml b/test/scheduler/app.yaml deleted file mode 100644 index 8bc59f00..00000000 --- a/test/scheduler/app.yaml +++ /dev/null @@ -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 diff --git a/test/scheduler/appengine_config.py b/test/scheduler/appengine_config.py deleted file mode 100644 index f4489ff9..00000000 --- a/test/scheduler/appengine_config.py +++ /dev/null @@ -1,3 +0,0 @@ -from google.appengine.ext import vendor - -vendor.add('lib') diff --git a/test/scheduler/cron.yaml b/test/scheduler/cron.yaml deleted file mode 100644 index 652aed80..00000000 --- a/test/scheduler/cron.yaml +++ /dev/null @@ -1,4 +0,0 @@ -cron: -- description: periodic gc - url: /tasks/gc - schedule: every 5 minutes diff --git a/test/scheduler/main.py b/test/scheduler/main.py deleted file mode 100644 index ed0c78e3..00000000 --- a/test/scheduler/main.py +++ /dev/null @@ -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//', 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///', 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\d+)-(?P\d+)-(?P\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) diff --git a/test/scheduler/requirements.txt b/test/scheduler/requirements.txt deleted file mode 100644 index d4d47e6e..00000000 --- a/test/scheduler/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -flask -google-api-python-client From 6b9e8816d19c3e3f7c19c08a94319b6d91b30bee Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 3 Nov 2015 15:31:17 +0000 Subject: [PATCH 06/67] Wait for proxy to become available after docker is restarted --- test/640_proxy_restart_reattaches_test.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index fc1df46c..c3e163fd 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -11,6 +11,18 @@ check_attached() { assert_dns_record $HOST1 c1 $NAME $C2 } +wait_for_proxy() { + for i in $(seq 1 120); do + echo "Waiting for proxy to start" + if proxy docker_on $1 info > /dev/null 2>&1 ; then + return + fi + sleep 1 + done + echo "Timed out waiting for proxy to start" >&2 + exit 1 +} + start_suite "Proxy restart reattaches networking to containers" WEAVE_DOCKER_ARGS=--restart=always WEAVEPROXY_DOCKER_ARGS=--restart=always weave_on $HOST1 launch @@ -32,7 +44,7 @@ check_attached # 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" -sleep 10 +wait_for_proxy $HOST1 check_attached # Restarting proxy shouldn't kill unattachable containers From 06eaac8690e5374cb724179003b924cbb6562f4b Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 3 Nov 2015 15:38:14 +0000 Subject: [PATCH 07/67] Don't assert ethwe carrier via the proxy The test script runs commands inside containers via docker exec to ensure the ethwe carrier is up. We must not run these commands via the proxy because it will interpose weavewait, which will block forever if attachment has failed (e.g. due to #1556). --- test/640_proxy_restart_reattaches_test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index c3e163fd..59bc91f8 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -7,7 +7,7 @@ C2=10.2.0.34 NAME=seetwo.weave.local check_attached() { - assert_raises "proxy exec_on $HOST1 c2 $CHECK_ETHWE_UP" + assert_raises "exec_on $HOST1 c2 $CHECK_ETHWE_UP" assert_dns_record $HOST1 c1 $NAME $C2 } @@ -51,6 +51,6 @@ check_attached proxy_start_container $HOST1 -di --name=c3 --restart=always # Use ipam, so it won't be attachable w/o weave weave_on $HOST1 stop weave_on $HOST1 launch-proxy -assert_raises "proxy exec_on $HOST1 c3 $CHECK_ETHWE_UP" +assert_raises "exec_on $HOST1 c3 $CHECK_ETHWE_UP" end_suite From 60db57a41cb7c690ec55c4b51654a0f50a3baa55 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Tue, 3 Nov 2015 18:11:53 +0000 Subject: [PATCH 08/67] refactor: remove duplicate isKnownPeer function --- prog/weaver/main.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 453584b3..c12f8e28 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -253,10 +253,13 @@ func main() { } } } + isKnownPeer := func(name weave.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, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer) observeContainers(allocator) } else if peerCount > 0 { Log.Fatal("--init-peer-count flag specified without --ipalloc-range") @@ -267,9 +270,6 @@ func main() { dnsserver *nameserver.DNSServer ) if !noDNS { - isKnownPeer := func(name weave.PeerName) bool { - return router.Peers.Fetch(name) != nil - } ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer) router.Peers.OnGC(func(peer *weave.Peer) { ns.PeerGone(peer.Name) }) ns.SetGossip(router.NewGossip("nameserver", ns)) @@ -366,7 +366,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 *weave.Router, ipRangeStr string, defaultSubnetStr string, quorum uint, isKnownPeer func(weave.PeerName) bool) (*ipam.Allocator, address.CIDR) { ipRange := parseAndCheckCIDR(ipRangeStr) defaultSubnet := ipRange if defaultSubnetStr != "" { @@ -375,7 +375,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)) From 7b01dd979493698f6ab7c9b8f7455cc91cabb857 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 4 Nov 2015 16:45:16 +0000 Subject: [PATCH 09/67] Drop use of interval notation --- net/address/address.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/address/address.go b/net/address/address.go index 291a3227..71e00716 100644 --- a/net/address/address.go +++ b/net/address/address.go @@ -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 } From 67c2d53e59b8c33765abca0a7642af290bfb01a3 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 4 Nov 2015 17:42:24 +0000 Subject: [PATCH 10/67] Bind the HTTP listener to localhost when fastdp enabled Prevent containers from accessing the weave router control port when fast datapath is in use. --- weave | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weave b/weave index 41e84ebe..2da34e83 100755 --- a/weave +++ b/weave @@ -1481,7 +1481,7 @@ launch_router() { $(router_opts_$BRIDGE_TYPE) \ --ipalloc-range "$IPRANGE" \ --dns-effective-listen-address $DOCKER_BRIDGE_IP \ - ${NETHOST_OPT:+$DNS_ROUTER_OPTS} $NO_DNS_OPT \ + ${NETHOST_OPT:+$DNS_ROUTER_OPTS --http-addr 127.0.0.1:$HTTP_PORT} $NO_DNS_OPT \ --docker-api "unix:///var/run/docker.sock" "$@") with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE attach_router From e03a45f8c57fd6c10537494b5db9110e04a757e7 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 4 Nov 2015 16:55:01 +0000 Subject: [PATCH 11/67] Update docs to match loss of interval notation --- site/ipam.md | 6 +----- site/troubleshooting.md | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/site/ipam.md b/site/ipam.md index f06e4106..f63ad873 100644 --- a/site/ipam.md +++ b/site/ipam.md @@ -208,7 +208,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 ... @@ -219,7 +219,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. diff --git a/site/troubleshooting.md b/site/troubleshooting.md index 9f691c1f..bc5bbb2b 100644 --- a/site/troubleshooting.md +++ b/site/troubleshooting.md @@ -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 From 5f4753f88100d4808aad702240f55028a6ed8f45 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 5 Nov 2015 10:13:06 +0000 Subject: [PATCH 12/67] Segregate discussion of range and subnet, and explain subnet a bit --- site/ipam.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/site/ipam.md b/site/ipam.md index f63ad873..7f19ffc5 100644 --- a/site/ipam.md +++ b/site/ipam.md @@ -109,9 +109,7 @@ The range parameter is written in [CIDR notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) - in this example "/16" means the first 16 bits of the address form the network address and the allocator is to allocate container addresses -that all start 10.2. The ".0" and ".-1" addresses in a subnet are not -used, as required by -[RFC 1122](https://tools.ietf.org/html/rfc1122#page-29). +that all start 10.2. Weave shares the IP address range across all peers, dynamically according to their needs. If a group of peers becomes isolated from @@ -121,11 +119,16 @@ to the rest of the network without any conflicts arising. ## Automatic allocation across multiple subnets -When -[running containers on different subnets](features.html#application-isolation), -you may wish to request the allocation of an address from a particular -subnet. This is done by specifying the subnet with `net:`, in -CIDR notation, e.g. +IP subnets are used to define or restrict routing. By default, weave +puts all containers in a subnet that spans the entire allocation +range, so every weave-attached container can talk to every other +weave-attached container. + +If you want some [isolation](features.html#application-isolation), you +can choose to run containers on different subnets. To request the +allocation of an address from a particular subnet, set the +`WEAVE_CIDR` environment variable to `net:` when creating the +container, e.g. host1$ docker run -e WEAVE_CIDR=net:10.2.7.0/24 -ti ubuntu @@ -135,6 +138,9 @@ for instance: host1$ docker run -e WEAVE_CIDR="net:10.2.7.0/24 net:10.2.8.0/24 ip:10.3.9.1/24" -ti ubuntu +(Note the ".0" and ".-1" addresses in a subnet are not used, as required by +[RFC 1122](https://tools.ietf.org/html/rfc1122#page-29)). + When working with multiple subnets in this way, it is usually desirable to constrain the default subnet - i.e. the one chosen by the allocator when no subnet is supplied - so that it does not overlap From d6dd1f269a0f596bfd4b5d03c6f5913190bb201b Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 5 Nov 2015 12:16:57 +0000 Subject: [PATCH 13/67] Document port security --- site/features.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/site/features.md b/site/features.md index f2d4bf44..baa580a4 100644 --- a/site/features.md +++ b/site/features.md @@ -219,7 +219,7 @@ NB: By default docker permits communication between containers on the same host, via their docker-assigned IP addresses. For complete isolation between application containers, that feature needs to be disabled by -[setting `--icc=false`](https://docs.docker.com/articles/networking/#between-containers) +[setting `--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers) in the docker daemon configuration. Furthermore, containers should be prevented from capturing and injecting raw network packets - this can be accomplished by starting them with the `--cap-drop net_raw` option. @@ -307,6 +307,14 @@ supplying a password will [cause weave to fall back to a slower method](#fast-data-path) for transporting data between peers. +Be aware that: + +* Containers will be able to access the router REST API if you have + disabled fast datapath. You can prevent this by setting + [`--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers) +* Containers are able to access the router control and data plane + ports, but you can mitigate this by enabling encryption + ### Host network integration Weave application networks can be integrated with a host's network, From 4dd63d8f72c247513bf6e20c04394ced35023add Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 4 Nov 2015 17:42:24 +0000 Subject: [PATCH 14/67] Bind the HTTP listener to localhost when fastdp enabled Prevent containers from accessing the weave router control port when fast datapath is in use. --- weave | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weave b/weave index 77c28d91..ec2cc4fb 100755 --- a/weave +++ b/weave @@ -1481,7 +1481,7 @@ launch_router() { $(router_opts_$BRIDGE_TYPE) \ --ipalloc-range "$IPRANGE" \ --dns-effective-listen-address $DOCKER_BRIDGE_IP \ - ${NETHOST_OPT:+$DNS_ROUTER_OPTS} $NO_DNS_OPT \ + ${NETHOST_OPT:+$DNS_ROUTER_OPTS --http-addr 127.0.0.1:$HTTP_PORT} $NO_DNS_OPT \ --docker-api "unix:///var/run/docker.sock" "$@") with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE attach_router From 3abb657777be0c8bb67b6979fbdfef3a6bbea0a8 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 5 Nov 2015 12:16:57 +0000 Subject: [PATCH 15/67] Document port security --- site/features.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/site/features.md b/site/features.md index f2d4bf44..baa580a4 100644 --- a/site/features.md +++ b/site/features.md @@ -219,7 +219,7 @@ NB: By default docker permits communication between containers on the same host, via their docker-assigned IP addresses. For complete isolation between application containers, that feature needs to be disabled by -[setting `--icc=false`](https://docs.docker.com/articles/networking/#between-containers) +[setting `--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers) in the docker daemon configuration. Furthermore, containers should be prevented from capturing and injecting raw network packets - this can be accomplished by starting them with the `--cap-drop net_raw` option. @@ -307,6 +307,14 @@ supplying a password will [cause weave to fall back to a slower method](#fast-data-path) for transporting data between peers. +Be aware that: + +* Containers will be able to access the router REST API if you have + disabled fast datapath. You can prevent this by setting + [`--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers) +* Containers are able to access the router control and data plane + ports, but you can mitigate this by enabling encryption + ### Host network integration Weave application networks can be integrated with a host's network, From a400a3dd098265dc85c24f060e43a494460f3772 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 5 Nov 2015 14:20:38 +0000 Subject: [PATCH 16/67] Disable restart of docker --- test/640_proxy_restart_reattaches_test.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index 59bc91f8..034d4704 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -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 From ab5f4410b6902020af64d596cd51c3fcd2f706bc Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 5 Nov 2015 14:34:13 +0000 Subject: [PATCH 17/67] Add release v1.2.1 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f442b7d..de063202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## Release 1.2.1 + +This release contains a number of bug fixes and minor +enhancements. More details in the +[change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.2.1). + +The release is fully compatible with 1.2.0 versions, so existing +clusters can be upgraded incrementally. + ## Release 1.2.0 **Highlights** From 094c7aa43877e3b47e419f109bc77d58b73db348 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 5 Nov 2015 17:24:38 +0000 Subject: [PATCH 18/67] cosmetic --- router/local_peer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/router/local_peer.go b/router/local_peer.go index 1d159221..f0047486 100644 --- a/router/local_peer.go +++ b/router/local_peer.go @@ -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, } From ad15e5a234fd14f3474c9166c65c30d14e62a7ef Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 5 Nov 2015 19:01:34 +0000 Subject: [PATCH 19/67] cosmetic --- router/fastdp.go | 33 +++++++++++---------------------- router/flow.go | 3 +-- router/overlay_switch.go | 12 ++++-------- router/sleeve.go | 31 ++++++++++--------------------- 4 files changed, 26 insertions(+), 53 deletions(-) diff --git a/router/fastdp.go b/router/fastdp.go index 5e9b6ce0..2a8ca06a 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -248,8 +248,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 @@ -393,8 +392,7 @@ func (fastdp fastDatapathOverlay) Diagnostics() interface{} { } } -func (fastdp fastDatapathOverlay) StartConsumingPackets(localPeer *Peer, - peers *Peers, consumer OverlayConsumer) error { +func (fastdp fastDatapathOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers, consumer OverlayConsumer) error { fastdp.lock.Lock() defer fastdp.lock.Unlock() @@ -485,8 +483,7 @@ type vxlanSpecialPacketFlowOp struct { 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() @@ -518,8 +515,7 @@ type fastDatapathForwarder struct { errorChan chan error } -func (fastdp fastDatapathOverlay) MakeForwarder( - params ForwarderParams) (OverlayForwarder, error) { +func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { if params.Crypto != nil { // No encryption suport in fastdp. The weaver main.go // is responsible for ensuring this doesn't happen. @@ -681,8 +677,7 @@ 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() @@ -809,8 +804,7 @@ func (fwd *fastDatapathForwarder) Stop() { } } -func (fastdp *FastDatapath) addForwarder(peer PeerName, - fwd *fastDatapathForwarder) { +func (fastdp *FastDatapath) addForwarder(peer PeerName, fwd *fastDatapathForwarder) { fastdp.lock.Lock() defer fastdp.lock.Unlock() @@ -819,8 +813,7 @@ func (fastdp *FastDatapath) addForwarder(peer PeerName, fastdp.forwarders[peer] = fwd } -func (fastdp *FastDatapath) removeForwarder(peer PeerName, - fwd *fastDatapathForwarder) { +func (fastdp *FastDatapath) removeForwarder(peer PeerName, fwd *fastDatapathForwarder) { fastdp.lock.Lock() defer fastdp.lock.Unlock() if fastdp.forwarders[peer] == fwd { @@ -922,8 +915,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. @@ -1044,8 +1036,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 +1055,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 +1147,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() diff --git a/router/flow.go b/router/flow.go index 7ca1caa2..4992b044 100644 --- a/router/flow.go +++ b/router/flow.go @@ -64,8 +64,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) } diff --git a/router/overlay_switch.go b/router/overlay_switch.go index 61f4202e..612e6bde 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -60,8 +60,7 @@ func (osw *OverlaySwitch) InvalidateShortIDs() { } } -func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers, - consumer OverlayConsumer) error { +func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers, consumer OverlayConsumer) error { for _, overlay := range osw.overlays { if err := overlay.StartConsumingPackets(localPeer, peers, consumer); err != nil { @@ -162,8 +161,7 @@ type subForwarderEvent struct { err error } -func (osw *OverlaySwitch) MakeForwarder( - params ForwarderParams) (OverlayForwarder, error) { +func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { if _, present := params.Features["Overlays"]; !present && osw.compatOverlay != nil { return osw.compatOverlay.MakeForwarder(params) } @@ -224,8 +222,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 +254,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 { diff --git a/router/sleeve.go b/router/sleeve.go index 676d73c7..82f9bc39 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -74,8 +74,7 @@ func NewSleeveOverlay(localPort int) Overlay { return &SleeveOverlay{localPort: localPort} } -func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers, - consumer OverlayConsumer) error { +func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers, consumer OverlayConsumer) error { localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(":", sleeve.localPort)) if err != nil { @@ -149,8 +148,7 @@ func (sleeve *SleeveOverlay) addForwarder(peer PeerName, fwd *sleeveForwarder) { sleeve.forwarders[peer] = fwd } -func (sleeve *SleeveOverlay) removeForwarder(peer PeerName, - fwd *sleeveForwarder) { +func (sleeve *SleeveOverlay) removeForwarder(peer PeerName, fwd *sleeveForwarder) { sleeve.lock.Lock() defer sleeve.lock.Unlock() if sleeve.forwarders[peer] == fwd { @@ -209,9 +207,7 @@ 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 { @@ -246,8 +242,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 *Peer, frame []byte, dec *EthernetDecoder) { if sleeve.consumer == nil { return } @@ -436,8 +431,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) @@ -519,16 +513,14 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, })) } -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 @@ -683,8 +675,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 +725,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 +734,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) } From e7ff6a21918a39b717c6ff596d3a3b2cff3f1b7f Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 5 Nov 2015 19:32:49 +0000 Subject: [PATCH 20/67] LocalPeer shouldn't have to know about remote UDP address ...and LocalConnection shouldn't have to remember it --- router/connection.go | 32 ++++++++++++++++++-------------- router/local_peer.go | 13 ++++--------- router/router.go | 2 +- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/router/connection.go b/router/connection.go index 9f047159..699a12de 100644 --- a/router/connection.go +++ b/router/connection.go @@ -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 + forwarder OverlayForwarder } 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,10 +190,16 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch conn.Log("connection ready; using protocol version", conn.version) + var remoteAddr *net.UDPAddr + if conn.outbound { + tcpAddr := conn.TCPConn.RemoteAddr().(*net.TCPAddr) + remoteAddr = &net.UDPAddr{IP: tcpAddr.IP, Port: tcpAddr.Port, Zone: tcpAddr.Zone} + } + params := ForwarderParams{ RemotePeer: conn.remote, LocalIP: conn.TCPConn.LocalAddr().(*net.TCPAddr).IP, - RemoteAddr: conn.remoteUDPAddr, + RemoteAddr: remoteAddr, ConnUID: conn.uid, Crypto: conn.forwarderCrypto(), SendControlMessage: conn.sendOverlayControlMessage, diff --git a/router/local_peer.go b/router/local_peer.go index f0047486..80c5abcc 100644 --- a/router/local_peer.go +++ b/router/local_peer.go @@ -62,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 } diff --git a/router/router.go b/router/router.go index 5e135a6d..7e8cf346 100644 --- a/router/router.go +++ b/router/router.go @@ -171,7 +171,7 @@ 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, nil, router, true) + StartLocalConnection(connRemote, tcpConn, router, true) } func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp { From 18fe553d232cf008260db79778f0d7c56c3c6a61 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 5 Nov 2015 20:43:52 +0000 Subject: [PATCH 21/67] LocalConnection shouldn't have to know about remote UDP address ...and generally know less about how overlays establish connectivity. --- router/connection.go | 11 +++-------- router/fastdp.go | 11 ++++++----- router/overlay.go | 20 ++++++++++++-------- router/sleeve.go | 9 +++++++-- router/utils.go | 4 ++++ 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/router/connection.go b/router/connection.go index 699a12de..ed8d4848 100644 --- a/router/connection.go +++ b/router/connection.go @@ -190,16 +190,11 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch conn.Log("connection ready; using protocol version", conn.version) - var remoteAddr *net.UDPAddr - if conn.outbound { - tcpAddr := conn.TCPConn.RemoteAddr().(*net.TCPAddr) - remoteAddr = &net.UDPAddr{IP: tcpAddr.IP, Port: tcpAddr.Port, Zone: tcpAddr.Zone} - } - params := ForwarderParams{ RemotePeer: conn.remote, - LocalIP: conn.TCPConn.LocalAddr().(*net.TCPAddr).IP, - RemoteAddr: remoteAddr, + LocalAddr: conn.TCPConn.LocalAddr().(*net.TCPAddr), + RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr), + Outbound: conn.outbound, ConnUID: conn.uid, Crypto: conn.forwarderCrypto(), SendControlMessage: conn.sendOverlayControlMessage, diff --git a/router/fastdp.go b/router/fastdp.go index 2a8ca06a..e7149fcd 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -523,15 +523,16 @@ func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (Overlay } 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 { @@ -539,7 +540,7 @@ func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (Overlay } } - localIP, err := ipv4Bytes(params.LocalIP) + localIP, err := ipv4Bytes(params.LocalAddr.IP) if err != nil { return nil, err } diff --git a/router/overlay.go b/router/overlay.go index 3ab9f88d..914f40dd 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -29,15 +29,19 @@ type Overlay 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 local address of the corresponding TCP connection. Used to + // derive the local IP address for sending. May differ for + // different forwarders. + LocalAddr *net.TCPAddr - // 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 + // 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 diff --git a/router/sleeve.go b/router/sleeve.go index 82f9bc39..bc46fb7a 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -365,6 +365,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, @@ -379,13 +384,13 @@ 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, diff --git a/router/utils.go b/router/utils.go index 3530abd2..3da6f747 100644 --- a/router/utils.go +++ b/router/utils.go @@ -104,6 +104,10 @@ func intmac(key uint64) (r net.HardwareAddr) { return } +func makeUDPAddr(addr *net.TCPAddr) *net.UDPAddr { + return &net.UDPAddr{IP: addr.IP, Port: addr.Port, Zone: addr.Zone} +} + type ListOfPeers []*Peer func (lop ListOfPeers) Len() int { From fb3b690c5fdd6d1381e6b7e151b7f2901343ded4 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 5 Nov 2015 21:27:14 +0000 Subject: [PATCH 22/67] refactor: reduce coupling between LocalConnection and Forwarder --- router/connection.go | 4 ---- router/router.go | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/router/connection.go b/router/connection.go index 9f047159..cfb41897 100644 --- a/router/connection.go +++ b/router/connection.go @@ -453,10 +453,6 @@ 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 diff --git a/router/router.go b/router/router.go index 5e135a6d..d1e2bb5c 100644 --- a/router/router.go +++ b/router/router.go @@ -242,7 +242,7 @@ func (router *Router) relay(key ForwardPacketKey) FlowOp { return DiscardingFlowOp{} } - return conn.(*LocalConnection).Forward(key) + return conn.(*LocalConnection).forwarder.Forward(key) } func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { @@ -254,7 +254,7 @@ func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { op := NewMultiFlowOp(true) for _, conn := range router.Ourself.ConnectionsTo(nextHops) { - op.Add(conn.(*LocalConnection).Forward(ForwardPacketKey{ + op.Add(conn.(*LocalConnection).forwarder.Forward(ForwardPacketKey{ PacketKey: key, SrcPeer: srcPeer, DstPeer: conn.Remote()})) From 9f25d72a4a7a6b1ba75e7830a8bc672f4c67f580 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 05:43:20 +0000 Subject: [PATCH 23/67] cosmetic --- router/overlay_switch.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/router/overlay_switch.go b/router/overlay_switch.go index 612e6bde..aa18d174 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -62,8 +62,7 @@ func (osw *OverlaySwitch) InvalidateShortIDs() { func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *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 } } @@ -198,8 +197,7 @@ func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarde xmsg[0] = byte(index) xmsg[1] = tag copy(xmsg[2:], msg) - return origSendControlMessage(ProtocolOverlayControlMsg, - xmsg) + return origSendControlMessage(ProtocolOverlayControlMsg, xmsg) } subFwd, err := overlay.MakeForwarder(params) @@ -351,8 +349,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) } } From 19f89f7122f15cc6a8d5cc426e2b9f729dfbd9df Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 07:30:53 +0000 Subject: [PATCH 24/67] remove duplicate test this is already covered in dns_fallback_test --- test/210_dns_cross_hosts_3_test.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/210_dns_cross_hosts_3_test.sh b/test/210_dns_cross_hosts_3_test.sh index 813d621f..23a2d42f 100755 --- a/test/210_dns_cross_hosts_3_test.sh +++ b/test/210_dns_cross_hosts_3_test.sh @@ -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 From 54b7e2c874065710ecb687cb377a0c90587a2533 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 11:08:44 +0000 Subject: [PATCH 25/67] tiny refactor: use checkWarn in a few more places --- router/fastdp.go | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/router/fastdp.go b/router/fastdp.go index e7149fcd..fbd09d0b 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -366,18 +366,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)) @@ -893,9 +889,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 { From 4e34f2001ca4c86e6d4749f7d58e4789be46d580 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 11:14:11 +0000 Subject: [PATCH 26/67] cosmetic --- router/fastdp.go | 27 +++++++++------------------ router/sleeve.go | 40 +++++++++++++--------------------------- 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/router/fastdp.go b/router/fastdp.go index fbd09d0b..f0a76e22 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -259,8 +259,7 @@ func (fastdp *FastDatapath) bridge(ingress bridgePortID, key PacketKey, lock *fa // 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 @@ -344,8 +343,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 @@ -357,8 +355,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{} { @@ -411,8 +408,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 } @@ -458,8 +454,7 @@ 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 @@ -698,8 +693,7 @@ func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte, sender 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 } @@ -724,8 +718,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) } } @@ -950,8 +943,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 } @@ -1019,8 +1011,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) } } diff --git a/router/sleeve.go b/router/sleeve.go index bc46fb7a..4dd22340 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -75,8 +75,7 @@ func NewSleeveOverlay(localPort int) Overlay { } func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers, consumer OverlayConsumer) error { - localAddr, err := net.ResolveUDPAddr("udp4", - fmt.Sprint(":", sleeve.localPort)) + localAddr, err := net.ResolveUDPAddr("udp4", fmt.Sprint(":", sleeve.localPort)) if err != nil { return err } @@ -96,8 +95,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 } @@ -184,8 +182,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 / @@ -393,8 +390,7 @@ func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwa 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 } @@ -445,8 +441,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bo 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 } @@ -465,8 +460,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bo // 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 } @@ -491,8 +485,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bo // 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 } @@ -513,8 +506,7 @@ func (f curriedForward) Process(frame []byte, dec *EthernetDecoder, broadcast bo // 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) })) } @@ -567,8 +559,7 @@ func fragment(eth layers.Ethernet, ip layers.IPv4, mtu int, forward func([]byte) 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 } @@ -620,13 +611,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) @@ -770,8 +758,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 } } @@ -830,8 +817,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) } From 7a5c910cd5fa58ecf5e78d2f244e6476de4baec4 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 12:44:13 +0000 Subject: [PATCH 27/67] tiny refactor: inline a tiny single-use fun and move another --- router/connection.go | 17 +++-------------- router/sleeve.go | 7 +++++++ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/router/connection.go b/router/connection.go index 6c6de9e5..6c9fb962 100644 --- a/router/connection.go +++ b/router/connection.go @@ -379,7 +379,9 @@ 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() @@ -451,16 +453,3 @@ func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) func (conn *LocalConnection) extendReadDeadline() { conn.TCPConn.SetReadDeadline(time.Now().Add(TCPHeartbeat * 2)) } - -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() - } -} diff --git a/router/sleeve.go b/router/sleeve.go index 4dd22340..ffc11f7f 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -1126,3 +1126,10 @@ 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 +} From 8bd77c0d47fb4120406b141f2bbac942b02de80a Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 09:25:40 +0000 Subject: [PATCH 28/67] refactor: get rid of router/utils.go most functions end up in other files in the router package, but a few land in common. --- common/logging.go | 12 ++++ ipam/allocator.go | 6 +- router/connection.go | 2 +- router/crypto.go | 4 ++ router/gossip_channel.go | 9 +++ router/mac_cache.go | 17 ++++++ router/peer.go | 29 ++++++++++ router/peers.go | 11 ++++ router/router.go | 8 +++ router/sleeve.go | 20 +++++++ router/utils.go | 121 --------------------------------------- 11 files changed, 114 insertions(+), 125 deletions(-) delete mode 100644 router/utils.go diff --git a/common/logging.go b/common/logging.go index 074eb850..d42ad44a 100644 --- a/common/logging.go +++ b/common/logging.go @@ -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) + } +} diff --git a/ipam/allocator.go b/ipam/allocator.go index 05fdcda1..4c32404e 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -608,17 +608,17 @@ func encodeRange(r address.Range) []byte { } func (alloc *Allocator) sendSpaceRequest(dest router.PeerName, r address.Range) error { - msg := router.Concat([]byte{msgSpaceRequest}, encodeRange(r)) + 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)) + 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()) + msg := append([]byte{msgRingUpdate}, alloc.encode()...) alloc.gossip.GossipUnicast(dest, msg) } diff --git a/router/connection.go b/router/connection.go index 6c9fb962..90f5f80f 100644 --- a/router/connection.go +++ b/router/connection.go @@ -414,7 +414,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) { diff --git a/router/crypto.go b/router/crypto.go index 939157af..160972fd 100644 --- a/router/crypto.go +++ b/router/crypto.go @@ -180,6 +180,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{} } diff --git a/router/gossip_channel.go b/router/gossip_channel.go index 11e8e8aa..dd817712 100644 --- a/router/gossip_channel.go +++ b/router/gossip_channel.go @@ -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() +} diff --git a/router/mac_cache.go b/router/mac_cache.go index ecc9afb3..0d0e77c7 100644 --- a/router/mac_cache.go +++ b/router/mac_cache.go @@ -112,3 +112,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 +} diff --git a/router/peer.go b/router/peer.go index e73d1592..a1114e4f 100644 --- a/router/peer.go +++ b/router/peer.go @@ -1,11 +1,28 @@ package router 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 { diff --git a/router/peers.go b/router/peers.go index f3d238d0..6082c754 100644 --- a/router/peers.go +++ b/router/peers.go @@ -3,11 +3,14 @@ package router import ( "bytes" "encoding/gob" + "fmt" "io" "math/rand" "sync" ) +var void = struct{}{} + type Peers struct { sync.RWMutex ourself *LocalPeer @@ -33,10 +36,18 @@ type UnknownPeerError struct { Name PeerName } +func (upe UnknownPeerError) Error() string { + return fmt.Sprint("Reference to unknown peer ", upe.Name) +} + type NameCollisionError struct { Name PeerName } +func (nce NameCollisionError) Error() string { + return fmt.Sprint("Multiple peers found with same name: ", nce.Name) +} + type PeerNameSet map[PeerName]struct{} type ConnectionSummary struct { diff --git a/router/router.go b/router/router.go index 31ff80d6..9ea3623f 100644 --- a/router/router.go +++ b/router/router.go @@ -5,6 +5,8 @@ import ( "net" "sync" "time" + + "github.com/weaveworks/weave/common" ) const ( @@ -20,6 +22,12 @@ const ( // [3] 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 diff --git a/router/sleeve.go b/router/sleeve.go index ffc11f7f..89dbb750 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "net" + "os" "sync" "syscall" "time" @@ -1133,3 +1134,22 @@ func tickerChan(ticker *time.Ticker) <-chan time.Time { } 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 +} diff --git a/router/utils.go b/router/utils.go deleted file mode 100644 index 3da6f747..00000000 --- a/router/utils.go +++ /dev/null @@ -1,121 +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 -} - -func makeUDPAddr(addr *net.TCPAddr) *net.UDPAddr { - return &net.UDPAddr{IP: addr.IP, Port: addr.Port, Zone: addr.Zone} -} - -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 -} From 519aef86fadf4efe5f213899f53219b1bd72beae Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Fri, 6 Nov 2015 20:08:09 +0000 Subject: [PATCH 29/67] refactor: split crypto code --- router/{crypto.go => frame_crypto.go} | 170 ------------------------ router/protocol_crypto.go | 178 ++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 170 deletions(-) rename router/{crypto.go => frame_crypto.go} (62%) create mode 100644 router/protocol_crypto.go diff --git a/router/crypto.go b/router/frame_crypto.go similarity index 62% rename from router/crypto.go rename to router/frame_crypto.go index 160972fd..71c75257 100644 --- a/router/crypto.go +++ b/router/frame_crypto.go @@ -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 { @@ -301,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 -} diff --git a/router/protocol_crypto.go b/router/protocol_crypto.go new file mode 100644 index 00000000..5fbb48e8 --- /dev/null +++ b/router/protocol_crypto.go @@ -0,0 +1,178 @@ +package router + +import ( + "crypto/rand" + "crypto/sha256" + "encoding/binary" + "encoding/gob" + "fmt" + "io" + "sync" + + "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 +} + +// 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 +} From 006262ed8f877b32ad185597419e94c103ce2eaa Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Fri, 6 Nov 2015 19:38:04 +0000 Subject: [PATCH 30/67] refactor: Connections don't need to know about overlay crypto --- router/connection.go | 15 +-------------- router/fastdp.go | 2 +- router/overlay.go | 4 ++-- router/sleeve.go | 10 +++++++--- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/router/connection.go b/router/connection.go index 90f5f80f..7a1f878f 100644 --- a/router/connection.go +++ b/router/connection.go @@ -196,7 +196,7 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr), Outbound: conn.outbound, ConnUID: conn.uid, - Crypto: conn.forwarderCrypto(), + SessionKey: conn.SessionKey, SendControlMessage: conn.sendOverlayControlMessage, Features: intro.Features, } @@ -390,19 +390,6 @@ func (conn *LocalConnection) shutdown(err error) { 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}) } diff --git a/router/fastdp.go b/router/fastdp.go index f0a76e22..440a93b8 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -507,7 +507,7 @@ type fastDatapathForwarder struct { } func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { - if params.Crypto != nil { + 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") diff --git a/router/overlay.go b/router/overlay.go index 914f40dd..1789f886 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -46,8 +46,8 @@ type ForwarderParams struct { // Unique identifier for this connection ConnUID uint64 - // Crypto bits. Nil if not encrypting - Crypto *OverlayCrypto + // Session key, if connection is encrypted; nil otherwise + SessionKey *[32]byte // Function to send a control message to the counterpart // forwarder. diff --git a/router/sleeve.go b/router/sleeve.go index 89dbb750..01001b3f 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -344,11 +344,15 @@ type controlMessage struct { } func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { + name := sleeve.localPeer.NameByte var crypto OverlayCrypto - if params.Crypto != nil { - crypto = *params.Crypto + if params.SessionKey != nil { + crypto = OverlayCrypto{ + 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{ Dec: NewNonDecryptor(), Enc: NewNonEncryptor(name), From f3f23b43b5c4870dbb4457dbd038a6457d08803f Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Fri, 6 Nov 2015 19:45:48 +0000 Subject: [PATCH 31/67] refactor: crypto doesn't need to be a generic overlay feature --- router/overlay.go | 7 ------- router/sleeve.go | 14 ++++++++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/router/overlay.go b/router/overlay.go index 1789f886..e0e95364 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -61,13 +61,6 @@ type ForwarderParams struct { // 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 diff --git a/router/sleeve.go b/router/sleeve.go index 01001b3f..cc6694ec 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -273,6 +273,12 @@ 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 @@ -303,7 +309,7 @@ type sleeveForwarder struct { stackFrag bool // State only used within the forwarder goroutine - crypto OverlayCrypto + crypto sleeveCrypto senderDF *udpSenderDF maxPayload int @@ -345,15 +351,15 @@ type controlMessage struct { func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { name := sleeve.localPeer.NameByte - var crypto OverlayCrypto + var crypto sleeveCrypto if params.SessionKey != nil { - crypto = OverlayCrypto{ + 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 { - crypto = OverlayCrypto{ + crypto = sleeveCrypto{ Dec: NewNonDecryptor(), Enc: NewNonEncryptor(name), EncDF: NewNonEncryptor(name), From d3d2863d52d9620bb4ce53207166c22b6385d482 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 16:32:23 +0000 Subject: [PATCH 32/67] refactor: get rid of const.go --- router/consts.go | 21 --------------------- router/protocol_crypto.go | 2 ++ router/router.go | 13 +++++++++++++ 3 files changed, 15 insertions(+), 21 deletions(-) delete mode 100644 router/consts.go diff --git a/router/consts.go b/router/consts.go deleted file mode 100644 index 6fd11588..00000000 --- a/router/consts.go +++ /dev/null @@ -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 -) diff --git a/router/protocol_crypto.go b/router/protocol_crypto.go index 5fbb48e8..f215a595 100644 --- a/router/protocol_crypto.go +++ b/router/protocol_crypto.go @@ -13,6 +13,8 @@ import ( "golang.org/x/crypto/nacl/secretbox" ) +const MaxTCPMsgSize = 10 * 1024 * 1024 + func GenerateKeyPair() (publicKey, privateKey *[32]byte, err error) { return box.GenerateKey(rand.Reader) } diff --git a/router/router.go b/router/router.go index 9ea3623f..44c3fbdc 100644 --- a/router/router.go +++ b/router/router.go @@ -2,6 +2,7 @@ package router import ( "fmt" + "math" "net" "sync" "time" @@ -10,6 +11,18 @@ import ( ) const ( + Port = 6783 + HTTPPort = Port + 1 + MaxUDPPacketSize = 65535 + ChannelSize = 16 + TCPHeartbeat = 30 * time.Second + GossipInterval = 30 * time.Second + MaxDuration = time.Duration(math.MaxInt64) + FastHeartbeat = 500 * time.Millisecond + SlowHeartbeat = 10 * time.Second + MaxMissedHeartbeats = 6 + HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat + macMaxAge = 10 * time.Minute // [1] acceptMaxTokens = 100 // [2] acceptTokenDelay = 100 * time.Millisecond // [3] From 878a12002c477f1daf1f4aea00e13ed490aec901 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 18:01:12 +0000 Subject: [PATCH 33/67] set http listen address solely through the weave script Previously it was set by the script only in fastdp mode; and in the router's main.go otherwise. Yet every interaction of the script with weave assumes the port is the script's HTTP_PORT=6784. By always starting the router with options to listen on that port we ensure that the router is in fact listening where the script expects it to. In doing this get rid of router.HTTPPort. We do need to hard-code the port in the proxy instead, but relying on router.HTTPPort was flawed anyway, for the above reasons. --- prog/weaver/main.go | 2 +- proxy/proxy.go | 3 +-- router/router.go | 1 - weave | 4 +++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index c12f8e28..6620efcc 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -85,7 +85,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)") diff --git a/proxy/proxy.go b/proxy/proxy.go index 6618fe51..778742d4 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -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 diff --git a/router/router.go b/router/router.go index 44c3fbdc..e02036bd 100644 --- a/router/router.go +++ b/router/router.go @@ -12,7 +12,6 @@ import ( const ( Port = 6783 - HTTPPort = Port + 1 MaxUDPPacketSize = 65535 ChannelSize = 16 TCPHeartbeat = 30 * time.Second diff --git a/weave b/weave index 2da34e83..80bcd57a 100755 --- a/weave +++ b/weave @@ -1463,6 +1463,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 +1482,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 From 59e11e4e8adde0097f7d1789576d72672ebe0ab9 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 11:15:31 +0000 Subject: [PATCH 34/67] refactor: more flexible Routes API --- router/router.go | 5 ++++- router/routes.go | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/router/router.go b/router/router.go index e02036bd..56a7c480 100644 --- a/router/router.go +++ b/router/router.go @@ -94,10 +94,13 @@ func NewRouter(config Config, name PeerName, nickName string) *Router { }) router.Peers.OnInvalidateShortIDs(router.Overlay.InvalidateShortIDs) - router.Routes = NewRoutes(router.Ourself, router.Peers, router.Overlay.InvalidateRoutes) + router.Routes = NewRoutes(router.Ourself, router.Peers) + router.Routes.OnChange(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 } diff --git a/router/routes.go b/router/routes.go index b7ef0f30..8ea756ef 100644 --- a/router/routes.go +++ b/router/routes.go @@ -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() + } } } From b7e7c11a57385720449d5ca8496cccd685c7707a Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 12:29:36 +0000 Subject: [PATCH 35/67] refactor: make Overlay setting more explicit --- prog/weaver/main.go | 3 +-- router/gossip_test.go | 2 +- router/router.go | 15 +++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 6620efcc..48bb26df 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -203,7 +203,6 @@ func main() { sleeve := weave.NewSleeveOverlay(config.Port) overlays.Add("sleeve", sleeve) overlays.SetCompatOverlay(sleeve) - config.Overlay = overlays if routerName == "" { if iface == nil { @@ -235,7 +234,7 @@ func main() { config.PacketLogging = nopPacketLogging{} } - router := weave.NewRouter(config, name, nickName) + router := weave.NewRouter(config, name, nickName, overlays) Log.Println("Our name is", router.Ourself) var dockerCli *docker.Client diff --git a/router/gossip_test.go b/router/gossip_test.go index b618561e..3429ed50 100644 --- a/router/gossip_test.go +++ b/router/gossip_test.go @@ -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 } diff --git a/router/router.go b/router/router.go index 56a7c480..49f15995 100644 --- a/router/router.go +++ b/router/router.go @@ -49,7 +49,6 @@ type Config struct { BufSz int PacketLogging PacketLogging Bridge Bridge - Overlay Overlay } type PacketLogging interface { @@ -59,6 +58,7 @@ type PacketLogging interface { type Router struct { Config + Overlay Overlay Ourself *LocalPeer Macs *MacCache Peers *Peers @@ -71,17 +71,18 @@ type Router struct { acceptLimiter *TokenBucket } -func NewRouter(config Config, name PeerName, nickName string) *Router { +func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router { router := &Router{Config: config, gossipChannels: make(GossipChannels)} if router.Bridge == nil { router.Bridge = NullBridge{} } - if router.Overlay == nil { - router.Overlay = NullOverlay{} + if overlay == nil { + overlay = NullOverlay{} } + router.Overlay = overlay router.Ourself = NewLocalPeer(name, nickName, router) router.Macs = NewMacCache(macMaxAge, func(mac net.HardwareAddr, peer *Peer) { @@ -92,11 +93,9 @@ func NewRouter(config Config, name PeerName, nickName string) *Router { router.Macs.Delete(peer) log.Println("Removed unreachable peer", peer) }) - router.Peers.OnInvalidateShortIDs(router.Overlay.InvalidateShortIDs) - + router.Peers.OnInvalidateShortIDs(overlay.InvalidateShortIDs) router.Routes = NewRoutes(router.Ourself, router.Peers) - router.Routes.OnChange(router.Overlay.InvalidateRoutes) - + router.Routes.OnChange(overlay.InvalidateRoutes) router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery) router.TopologyGossip = router.NewGossip("topology", router) router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay) From 97622b961c04a6a47e729f18d51ff991ca4fa4cc Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 13:06:29 +0000 Subject: [PATCH 36/67] remove cruft --- router/router.go | 1 - 1 file changed, 1 deletion(-) diff --git a/router/router.go b/router/router.go index 49f15995..6d70eb92 100644 --- a/router/router.go +++ b/router/router.go @@ -67,7 +67,6 @@ type Router struct { gossipLock sync.RWMutex gossipChannels GossipChannels TopologyGossip Gossip - UDPListener *net.UDPConn acceptLimiter *TokenBucket } From bfb050c9ccda64728fb9f751aa52c15ed2b44208 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 14:58:33 +0000 Subject: [PATCH 37/67] better convergence when peers restart Previously when a peer restarted, information about the new incarnation (i.e. with a different UID) was not accepted by other peers (and connections would be dropped) unless all knowledge of the previous incarnation had been purged. This could result in a lot of connection churn and hence connectivity disruption, and, in some pathological cases, very slow convergence and hence acceptance of the new incarnation into the network. We now no longer drop connections when encountering different incarnations of a peer. There are two situations when that can happen: 1) on connection establishment we simply proceed 2) on receipt of gossip to ensure convergence we a) treat the UID as an additional discriminator when deciding whether we should update our information about a peer with that which was gossiped. Specifically, we update the information we hold when a) the gossiped version is greater, or b) is the same and the UID is greater. b) include the UID in the information we update c) move our own version number beyond any we receive for ourselves, if the received UID differs from ours. With (a) we establishes a total order of peer information across several incarnations of the same peer. i.e. we consider information to be fresher if it has a higher version, or the same version and higher UID. This may seem somewhat counter intutive, since it will generally treat information about new incarnations as older than old incarnations, since incarnations always start life with version 1. But to do better we'd need to establish a total order of incarnations that matches their temporal occurrence. Which requires some sort of durable state. So instead we have (c). Through that we learn the highest version number of any old incarnation of ourselves that other peers still hold, and then make sure that our version is greater than that. Essentially we continue where the old incarnations left off. It's as if instead of restarting we had simply changed UIDs. And due to (a) and (b) the information about the new incarnation of ourselves, now with a higher version, will supersede that of the old incarnations. Fixes #1554. --- router/connection.go | 4 --- router/local_peer.go | 10 ++++++ router/peers.go | 76 ++++++++++++++++++++------------------------ 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/router/connection.go b/router/connection.go index 7a1f878f..77a539cc 100644 --- a/router/connection.go +++ b/router/connection.go @@ -329,10 +329,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 } diff --git a/router/local_peer.go b/router/local_peer.go index 80c5abcc..ab54745a 100644 --- a/router/local_peer.go +++ b/router/local_peer.go @@ -249,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 +} diff --git a/router/peers.go b/router/peers.go index 6082c754..9c30a4e2 100644 --- a/router/peers.go +++ b/router/peers.go @@ -40,14 +40,6 @@ func (upe UnknownPeerError) Error() string { return fmt.Sprint("Reference to unknown peer ", upe.Name) } -type NameCollisionError struct { - Name PeerName -} - -func (nce NameCollisionError) Error() string { - return fmt.Sprint("Multiple peers found with same name: ", nce.Name) -} - type PeerNameSet map[PeerName]struct{} type ConnectionSummary struct { @@ -68,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 { @@ -100,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() @@ -436,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 } } @@ -469,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 } From d78f6614cc9b3c22372f326be7cf4f6b44e199d3 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Fri, 6 Nov 2015 23:05:33 +0000 Subject: [PATCH 38/67] refactor: separate forwarder from overlay connection ...since the main connections only need to know about the former. We make LocalConnection.Overlay (formerly '.forwarder') public since the router needs access to it, and it shouldn't be doing that via a private field. --- router/connection.go | 37 +++++++++++++++--------------- router/fastdp.go | 2 +- router/overlay.go | 49 +++++++++++++++++++++++----------------- router/overlay_switch.go | 9 ++++---- router/router.go | 4 ++-- router/sleeve.go | 2 +- router/status.go | 2 +- 7 files changed, 56 insertions(+), 49 deletions(-) diff --git a/router/connection.go b/router/connection.go index 7a1f878f..a1877cfd 100644 --- a/router/connection.go +++ b/router/connection.go @@ -49,7 +49,7 @@ type LocalConnection struct { uid uint64 actionChan chan<- ConnectionAction finished <-chan struct{} // closed to signal that actorLoop has finished - forwarder OverlayForwarder + OverlayConn OverlayConnection } type ConnectionAction func() error @@ -190,7 +190,7 @@ 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, LocalAddr: conn.TCPConn.LocalAddr().(*net.TCPAddr), RemoteAddr: conn.TCPConn.RemoteAddr().(*net.TCPAddr), @@ -200,28 +200,27 @@ func (conn *LocalConnection) run(actionChan <-chan ConnectionAction, finished ch 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 @@ -341,8 +340,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 { @@ -383,8 +382,8 @@ func (conn *LocalConnection) shutdown(err error) { conn.heartbeatTCP.Stop() } - if conn.forwarder != nil { - conn.forwarder.Stop() + if conn.OverlayConn != nil { + conn.OverlayConn.Stop() } conn.Router.ConnectionMaker.ConnectionTerminated(conn, err) @@ -428,7 +427,7 @@ func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) switch tag { case ProtocolHeartbeat: case ProtocolConnectionEstablished, ProtocolFragmentationReceived, ProtocolPMTUVerified, ProtocolOverlayControlMsg: - conn.forwarder.ControlMessage(byte(tag), payload) + conn.OverlayConn.ControlMessage(byte(tag), payload) case ProtocolGossipUnicast, ProtocolGossipBroadcast, ProtocolGossip: return conn.Router.handleGossip(tag, payload) default: diff --git a/router/fastdp.go b/router/fastdp.go index 440a93b8..0c92bf9c 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -506,7 +506,7 @@ type fastDatapathForwarder struct { errorChan chan error } -func (fastdp fastDatapathOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { +func (fastdp fastDatapathOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) { if params.SessionKey != nil { // No encryption suport in fastdp. The weaver main.go // is responsible for ensuring this doesn't happen. diff --git a/router/overlay.go b/router/overlay.go index e0e95364..a219e631 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -9,8 +9,9 @@ type Overlay interface { // Start consuming forwarded packets. StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error - // Form a packet-forwarding connection. - MakeForwarder(ForwarderParams) (OverlayForwarder, error) + // Prepare on overlay connection. The connection should remain + // passive until it has been Confirm()ed. + PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) // The routes have changed, so any cached information should // be discarded. @@ -26,12 +27,12 @@ type Overlay interface { Diagnostics() interface{} } -type ForwarderParams struct { +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 forwarders. + // different overlay connections. LocalAddr *net.TCPAddr // The remote address of the corresponding TCP connection. Used to @@ -50,7 +51,7 @@ type ForwarderParams struct { SessionKey *[32]byte // Function to send a control message to the counterpart - // forwarder. + // overlay connection. SendControlMessage func(tag byte, msg []byte) error // Features passed at connection initiation @@ -61,26 +62,22 @@ type ForwarderParams struct { // to decode the frame. type OverlayConsumer func(ForwardPacketKey) FlowOp -// 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 - +// 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 forwarder. + // Overlay should begin heartbeats etc. to verify the operation of + // the overlay connection. Confirm() - // A channel indicating that the forwarder is established, - // i.e. its operation has been confirmed. + // 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 forwarder. The - // forwarder is not expected to be operational after the first - // error, so the channel only needs to buffer a single error. + // 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() @@ -94,13 +91,23 @@ type OverlayForwarder interface { DisplayName() string } +// All of the machinery to forward packets to a particular peer +type OverlayForwarder interface { + 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 NullOverlay struct{} func (NullOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { return nil } -func (NullOverlay) MakeForwarder(ForwarderParams) (OverlayForwarder, error) { +func (NullOverlay) PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) { return NullOverlay{}, nil } diff --git a/router/overlay_switch.go b/router/overlay_switch.go index aa18d174..8cf67922 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -76,7 +76,7 @@ type namedOverlay struct { // 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 OverlayConnectionParams) ([]namedOverlay, error) { var peerOverlays []string if overlaysFeature, present := params.Features["Overlays"]; present { peerOverlays = strings.Split(overlaysFeature, " ") @@ -160,9 +160,9 @@ type subForwarderEvent struct { err error } -func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { +func (osw *OverlaySwitch) PrepareConnection(params OverlayConnectionParams) (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,11 +200,12 @@ func (osw *OverlaySwitch) MakeForwarder(params ForwarderParams) (OverlayForwarde return origSendControlMessage(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) diff --git a/router/router.go b/router/router.go index 6d70eb92..014a19b4 100644 --- a/router/router.go +++ b/router/router.go @@ -263,7 +263,7 @@ func (router *Router) relay(key ForwardPacketKey) FlowOp { return DiscardingFlowOp{} } - return conn.(*LocalConnection).forwarder.Forward(key) + return conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) } func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { @@ -275,7 +275,7 @@ func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { op := NewMultiFlowOp(true) for _, conn := range router.Ourself.ConnectionsTo(nextHops) { - op.Add(conn.(*LocalConnection).forwarder.Forward(ForwardPacketKey{ + op.Add(conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{ PacketKey: key, SrcPeer: srcPeer, DstPeer: conn.Remote()})) diff --git a/router/sleeve.go b/router/sleeve.go index cc6694ec..bf4102f9 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -349,7 +349,7 @@ type controlMessage struct { msg []byte } -func (sleeve *SleeveOverlay) MakeForwarder(params ForwarderParams) (OverlayForwarder, error) { +func (sleeve *SleeveOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) { name := sleeve.localPeer.NameByte var crypto sleeveCrypto if params.SessionKey != nil { diff --git a/router/status.go b/router/status.go index 469f9329..64cbd6e0 100644 --- a/router/status.go +++ b/router/status.go @@ -176,7 +176,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 { From 18f8e29af8e886f49cb73aedf9a5aa46dfbdd598 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 12:34:17 +0000 Subject: [PATCH 39/67] refactor: separate NetworkOverlay from Overlay ...since connections only need to know about the latter. --- prog/weaver/main.go | 2 +- router/fastdp.go | 2 +- router/overlay.go | 20 ++++++++++++-------- router/overlay_switch.go | 14 +++++++------- router/router.go | 6 +++--- router/sleeve.go | 2 +- 6 files changed, 25 insertions(+), 21 deletions(-) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 48bb26df..bb13c7e2 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -150,7 +150,7 @@ func main() { } 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 diff --git a/router/fastdp.go b/router/fastdp.go index 0c92bf9c..b1765a94 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -297,7 +297,7 @@ type fastDatapathOverlay struct { *FastDatapath } -func (fastdp *FastDatapath) Overlay() Overlay { +func (fastdp *FastDatapath) Overlay() NetworkOverlay { return fastDatapathOverlay{fastdp} } diff --git a/router/overlay.go b/router/overlay.go index a219e631..ae5fb4a1 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -4,15 +4,22 @@ import ( "net" ) -// Interface to overlay network packet handling type Overlay interface { - // Start consuming forwarded packets. - StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error + // 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{} +} + +// Interface to overlay network packet handling +type NetworkOverlay interface { + Overlay + // The routes have changed, so any cached information should // be discarded. InvalidateRoutes() @@ -20,11 +27,8 @@ type Overlay interface { // 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{} + // Start consuming forwarded packets. + StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error } type OverlayConnectionParams struct { diff --git a/router/overlay_switch.go b/router/overlay_switch.go index 8cf67922..9ead7987 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -13,16 +13,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 +32,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 } @@ -70,7 +70,7 @@ func (osw *OverlaySwitch) StartConsumingPackets(localPeer *Peer, peers *Peers, c } type namedOverlay struct { - Overlay + NetworkOverlay name string } @@ -82,7 +82,7 @@ func (osw *OverlaySwitch) commonOverlays(params OverlayConnectionParams) ([]name 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 diff --git a/router/router.go b/router/router.go index 014a19b4..6b29d558 100644 --- a/router/router.go +++ b/router/router.go @@ -70,7 +70,7 @@ type Router struct { acceptLimiter *TokenBucket } -func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router { +func NewRouter(config Config, name PeerName, nickName string, overlay NetworkOverlay) *Router { router := &Router{Config: config, gossipChannels: make(GossipChannels)} if router.Bridge == nil { @@ -108,7 +108,7 @@ func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) * 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)) + checkFatal(router.Overlay.(NetworkOverlay).StartConsumingPackets(router.Ourself.Peer, router.Peers, router.handleForwardedPacket)) router.listenTCP(router.Port) } @@ -218,7 +218,7 @@ func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp { // We need to clear out any flows destined to the MAC // that forward to the old peer. - router.Overlay.InvalidateRoutes() + router.Overlay.(NetworkOverlay).InvalidateRoutes() } router.PacketLogging.LogForwardPacket("Injecting", key) diff --git a/router/sleeve.go b/router/sleeve.go index bf4102f9..3b329a1a 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -71,7 +71,7 @@ type SleeveOverlay struct { forwarders map[PeerName]*sleeveForwarder } -func NewSleeveOverlay(localPort int) Overlay { +func NewSleeveOverlay(localPort int) NetworkOverlay { return &SleeveOverlay{localPort: localPort} } From 7cc005245101be1ec4bb4e7706d937095ebd7aad Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 12:36:59 +0000 Subject: [PATCH 40/67] refactor: separate NullNetworkOverlay from NullOverlay --- router/overlay.go | 31 ++++++++++++++++--------------- router/router.go | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/router/overlay.go b/router/overlay.go index ae5fb4a1..27dd896d 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -107,20 +107,16 @@ type OverlayForwarder interface { type NullOverlay struct{} -func (NullOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { - return nil +func (NullOverlay) AddFeaturesTo(map[string]string) { } func (NullOverlay) PrepareConnection(OverlayConnectionParams) (OverlayConnection, error) { return NullOverlay{}, nil } -func (NullOverlay) InvalidateRoutes() { +func (NullOverlay) Diagnostics() interface{} { + return nil } - -func (NullOverlay) InvalidateShortIDs() { -} - func (NullOverlay) Confirm() { } @@ -132,13 +128,6 @@ func (NullOverlay) ErrorChannel() <-chan error { return nil } -func (NullOverlay) AddFeaturesTo(map[string]string) { -} - -func (NullOverlay) Forward(ForwardPacketKey) FlowOp { - return DiscardingFlowOp{} -} - func (NullOverlay) Stop() { } @@ -149,6 +138,18 @@ func (NullOverlay) DisplayName() string { return "null" } -func (NullOverlay) Diagnostics() interface{} { +type NullNetworkOverlay struct{ NullOverlay } + +func (NullNetworkOverlay) InvalidateRoutes() { +} + +func (NullNetworkOverlay) InvalidateShortIDs() { +} + +func (NullNetworkOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { return nil } + +func (NullNetworkOverlay) Forward(ForwardPacketKey) FlowOp { + return DiscardingFlowOp{} +} diff --git a/router/router.go b/router/router.go index 6b29d558..42b13dbd 100644 --- a/router/router.go +++ b/router/router.go @@ -78,7 +78,7 @@ func NewRouter(config Config, name PeerName, nickName string, overlay NetworkOve } if overlay == nil { - overlay = NullOverlay{} + overlay = NullNetworkOverlay{} } router.Overlay = overlay From daad19018825e7d32ad3be5c69a7608e31b2ebe5 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 11:33:01 +0000 Subject: [PATCH 41/67] refactor: split overlay.go to extract network overlay stuff --- router/network_overlay.go | 46 +++++++++++++++++++++++++++++++++++++++ router/overlay.go | 45 -------------------------------------- 2 files changed, 46 insertions(+), 45 deletions(-) create mode 100644 router/network_overlay.go diff --git a/router/network_overlay.go b/router/network_overlay.go new file mode 100644 index 00000000..8d80594b --- /dev/null +++ b/router/network_overlay.go @@ -0,0 +1,46 @@ +package router + +// Interface to overlay network packet handling +type NetworkOverlay interface { + 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(*Peer, *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 { + 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{ NullOverlay } + +func (NullNetworkOverlay) InvalidateRoutes() { +} + +func (NullNetworkOverlay) InvalidateShortIDs() { +} + +func (NullNetworkOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { + return nil +} + +func (NullNetworkOverlay) Forward(ForwardPacketKey) FlowOp { + return DiscardingFlowOp{} +} diff --git a/router/overlay.go b/router/overlay.go index 27dd896d..13fd0428 100644 --- a/router/overlay.go +++ b/router/overlay.go @@ -16,21 +16,6 @@ type Overlay interface { Diagnostics() interface{} } -// Interface to overlay network packet handling -type NetworkOverlay interface { - 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(*Peer, *Peers, OverlayConsumer) error -} - type OverlayConnectionParams struct { RemotePeer *Peer @@ -62,10 +47,6 @@ type OverlayConnectionParams struct { 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 - // All of the machinery to manage overlay connectivity to a particular // peer type OverlayConnection interface { @@ -95,16 +76,6 @@ type OverlayConnection interface { DisplayName() string } -// All of the machinery to forward packets to a particular peer -type OverlayForwarder interface { - 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 NullOverlay struct{} func (NullOverlay) AddFeaturesTo(map[string]string) { @@ -137,19 +108,3 @@ func (NullOverlay) ControlMessage(byte, []byte) { func (NullOverlay) DisplayName() string { return "null" } - -type NullNetworkOverlay struct{ NullOverlay } - -func (NullNetworkOverlay) InvalidateRoutes() { -} - -func (NullNetworkOverlay) InvalidateShortIDs() { -} - -func (NullNetworkOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { - return nil -} - -func (NullNetworkOverlay) Forward(ForwardPacketKey) FlowOp { - return DiscardingFlowOp{} -} From 7deeb8dba547a20fc56facd8d1d4b01bd83766e9 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 8 Nov 2015 12:50:55 +0000 Subject: [PATCH 42/67] refactor: separate NetworkRouter from Router --- prog/weaver/http.go | 2 +- prog/weaver/main.go | 13 ++++---- router/router.go | 72 +++++++++++++++++++++++++++++---------------- router/status.go | 2 +- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index a53f59c8..968ea227 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -151,7 +151,7 @@ type WeaveStatus struct { 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, diff --git a/prog/weaver/main.go b/prog/weaver/main.go index bb13c7e2..e925cb2e 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -42,6 +42,7 @@ func main() { addDatapathInterface string config weave.Config + networkConfig weave.NetworkConfig protocolMinVersion int ifaceName string routerName string @@ -163,7 +164,7 @@ func main() { }) checkFatal(err) - config.Bridge = fastdp.Bridge() + networkConfig.Bridge = fastdp.Bridge() fastDPOverlay = fastdp.Overlay() } @@ -178,7 +179,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) } @@ -229,12 +230,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, overlays) + router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlays) Log.Println("Our name is", router.Ourself) var dockerCli *docker.Client @@ -258,7 +259,7 @@ func main() { var allocator *ipam.Allocator var defaultSubnet address.CIDR if iprangeCIDR != "" { - allocator, defaultSubnet = createAllocator(router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer) + 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") diff --git a/router/router.go b/router/router.go index 42b13dbd..f3ae7136 100644 --- a/router/router.go +++ b/router/router.go @@ -46,9 +46,12 @@ type Config struct { Password []byte ConnLimit int PeerDiscovery bool - BufSz int - PacketLogging PacketLogging - Bridge Bridge +} + +type NetworkConfig struct { + BufSz int + PacketLogging PacketLogging + Bridge Bridge } type PacketLogging interface { @@ -60,7 +63,6 @@ type Router struct { Config Overlay Overlay Ourself *LocalPeer - Macs *MacCache Peers *Peers Routes *Routes ConnectionMaker *ConnectionMaker @@ -70,31 +72,20 @@ type Router struct { acceptLimiter *TokenBucket } -func NewRouter(config Config, name PeerName, nickName string, overlay NetworkOverlay) *Router { +func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) *Router { router := &Router{Config: config, gossipChannels: make(GossipChannels)} - if router.Bridge == nil { - router.Bridge = NullBridge{} - } - if overlay == nil { - overlay = NullNetworkOverlay{} + overlay = NullOverlay{} } router.Overlay = overlay 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(overlay.InvalidateShortIDs) router.Routes = NewRoutes(router.Ourself, router.Peers) - router.Routes.OnChange(overlay.InvalidateRoutes) router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery) router.TopologyGossip = router.NewGossip("topology", router) router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay) @@ -102,14 +93,45 @@ func NewRouter(config Config, name PeerName, nickName string, overlay NetworkOve 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. +type NetworkRouter struct { + *Router + NetworkConfig + Macs *MacCache +} + +func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter { + if overlay == nil { + overlay = NullNetworkOverlay{} + } + if networkConfig.Bridge == nil { + networkConfig.Bridge = NullBridge{} + } + + router := &NetworkRouter{Router: 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 *Peer) { + log.Println("Expired MAC", mac, "at", peer) + }) + router.Peers.OnGC(func(peer *Peer) { router.Macs.Delete(peer) }) + 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) +} + +// 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.listenTCP(router.Port) + router.Router.Start() } func (router *Router) Stop() error { @@ -121,7 +143,7 @@ func (router *Router) UsingPassword() bool { return router.Password != nil } -func (router *Router) handleCapturedPacket(key PacketKey) FlowOp { +func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp { router.PacketLogging.LogPacket("Captured", key) srcMac := net.HardwareAddr(key.SrcMAC[:]) @@ -195,7 +217,7 @@ func (router *Router) acceptTCP(tcpConn *net.TCPConn) { StartLocalConnection(connRemote, tcpConn, router, true) } -func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp { +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) @@ -247,7 +269,7 @@ func (router *Router) handleForwardedPacket(key ForwardPacketKey) FlowOp { // Routing -func (router *Router) relay(key ForwardPacketKey) FlowOp { +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 @@ -266,7 +288,7 @@ func (router *Router) relay(key ForwardPacketKey) FlowOp { return conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) } -func (router *Router) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { +func (router *NetworkRouter) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { nextHops := router.Routes.Broadcast(srcPeer.Name) if len(nextHops) == 0 { return DiscardingFlowOp{} diff --git a/router/status.go b/router/status.go index 64cbd6e0..f59d55d8 100644 --- a/router/status.go +++ b/router/status.go @@ -65,7 +65,7 @@ type LocalConnectionStatus struct { Info string } -func NewStatus(router *Router) *Status { +func NewStatus(router *NetworkRouter) *Status { return &Status{ Protocol, ProtocolMinVersion, From 71b05972f450f997af45790cec94bdb41d53279f Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 15:50:55 +0000 Subject: [PATCH 43/67] refactor: move NetworkRouter into its own file --- router/network_router.go | 196 +++++++++++++++++++++++++++++++++++++ router/router.go | 206 ++------------------------------------- 2 files changed, 205 insertions(+), 197 deletions(-) create mode 100644 router/network_router.go diff --git a/router/network_router.go b/router/network_router.go new file mode 100644 index 00000000..02bff759 --- /dev/null +++ b/router/network_router.go @@ -0,0 +1,196 @@ +package router + +import ( + "net" + "time" +) + +const ( + MaxUDPPacketSize = 65535 + FastHeartbeat = 500 * time.Millisecond + SlowHeartbeat = 10 * time.Second + MaxMissedHeartbeats = 6 + HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat + // 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 +) + +type NetworkConfig struct { + BufSz int + PacketLogging PacketLogging + Bridge Bridge +} + +type PacketLogging interface { + LogPacket(string, PacketKey) + LogForwardPacket(string, ForwardPacketKey) +} + +type NetworkRouter struct { + *Router + NetworkConfig + Macs *MacCache +} + +func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter { + if overlay == nil { + overlay = NullNetworkOverlay{} + } + if networkConfig.Bridge == nil { + networkConfig.Bridge = NullBridge{} + } + + router := &NetworkRouter{Router: 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 *Peer) { + log.Println("Expired MAC", mac, "at", peer) + }) + router.Peers.OnGC(func(peer *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.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) +} + +func (router *NetworkRouter) 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).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{ + PacketKey: key, + SrcPeer: srcPeer, + DstPeer: conn.Remote()})) + } + + return op +} diff --git a/router/router.go b/router/router.go index f3ae7136..d96b6fe2 100644 --- a/router/router.go +++ b/router/router.go @@ -11,28 +11,19 @@ import ( ) const ( - Port = 6783 - MaxUDPPacketSize = 65535 - ChannelSize = 16 - TCPHeartbeat = 30 * time.Second - GossipInterval = 30 * time.Second - MaxDuration = time.Duration(math.MaxInt64) - FastHeartbeat = 500 * time.Millisecond - SlowHeartbeat = 10 * time.Second - MaxMissedHeartbeats = 6 - HeartbeatTimeout = MaxMissedHeartbeats * SlowHeartbeat + Port = 6783 + ChannelSize = 16 + TCPHeartbeat = 30 * time.Second + GossipInterval = 30 * time.Second + MaxDuration = time.Duration(math.MaxInt64) - macMaxAge = 10 * time.Minute // [1] - acceptMaxTokens = 100 // [2] - acceptTokenDelay = 100 * time.Millisecond // [3] + acceptMaxTokens = 100 // [1] + acceptTokenDelay = 100 * time.Millisecond // [2] ) -// [1] should be greater than typical ARP cache expiries, i.e. > 3/2 * -// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux +// [1] capacity of token bucket for rate limiting accepts -// [2] capacity of token bucket for rate limiting accepts - -// [3] control rate at which new tokens are added to the bucket +// [2] control rate at which new tokens are added to the bucket var ( log = common.Log @@ -48,17 +39,6 @@ type Config struct { PeerDiscovery bool } -type NetworkConfig struct { - BufSz int - PacketLogging PacketLogging - Bridge Bridge -} - -type PacketLogging interface { - LogPacket(string, PacketKey) - LogForwardPacket(string, ForwardPacketKey) -} - type Router struct { Config Overlay Overlay @@ -93,31 +73,6 @@ func NewRouter(config Config, name PeerName, nickName string, overlay Overlay) * return router } -type NetworkRouter struct { - *Router - NetworkConfig - Macs *MacCache -} - -func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter { - if overlay == nil { - overlay = NullNetworkOverlay{} - } - if networkConfig.Bridge == nil { - networkConfig.Bridge = NullBridge{} - } - - router := &NetworkRouter{Router: 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 *Peer) { - log.Println("Expired MAC", mac, "at", peer) - }) - router.Peers.OnGC(func(peer *Peer) { router.Macs.Delete(peer) }) - return router -} - // Start listening for TCP connections. This is separate from // NewRouter so that gossipers can register before we start forming // connections. @@ -125,15 +80,6 @@ func (router *Router) Start() { router.listenTCP(router.Port) } -// 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 *Router) Stop() error { // TODO: perform graceful shutdown... return nil @@ -143,51 +89,6 @@ func (router *Router) UsingPassword() bool { return router.Password != nil } -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 *Router) listenTCP(localPort int) { localAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprint(":", localPort)) checkFatal(err) @@ -217,95 +118,6 @@ func (router *Router) acceptTCP(tcpConn *net.TCPConn) { StartLocalConnection(connRemote, tcpConn, router, true) } -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.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) -} - -func (router *NetworkRouter) 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).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{ - PacketKey: key, - SrcPeer: srcPeer, - DstPeer: conn.Remote()})) - } - - return op -} - // Gossiper methods - the Router is the topology Gossiper type TopologyGossipData struct { From 8eb680fcc925ed067b1b302d6692a73b75da0abf Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 08:08:03 +0000 Subject: [PATCH 44/67] refactor: separate out NetworkRouter-specific status --- prog/weaver/http.go | 8 ++++---- router/status.go | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 968ea227..8871468e 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -146,16 +146,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.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)} } diff --git a/router/status.go b/router/status.go index f59d55d8..776f359f 100644 --- a/router/status.go +++ b/router/status.go @@ -14,9 +14,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,6 +22,13 @@ type Status struct { OverlayDiagnostics interface{} } +type NetworkRouterStatus struct { + *Status + Interface string + CaptureStats map[string]int + MACs []MACStatus +} + type MACStatus struct { Mac string Name string @@ -65,7 +69,7 @@ type LocalConnectionStatus struct { Info string } -func NewStatus(router *NetworkRouter) *Status { +func NewStatus(router *Router) *Status { return &Status{ Protocol, ProtocolMinVersion, @@ -75,9 +79,6 @@ func NewStatus(router *NetworkRouter) *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,6 +87,14 @@ func NewStatus(router *NetworkRouter) *Status { router.Overlay.Diagnostics()} } +func NewNetworkRouterStatus(router *NetworkRouter) *NetworkRouterStatus { + return &NetworkRouterStatus{ + NewStatus(router.Router), + router.Bridge.String(), + router.Bridge.Stats(), + NewMACStatusSlice(router.Macs)} +} + func NewMACStatusSlice(cache *MacCache) []MACStatus { cache.RLock() defer cache.RUnlock() From ab458368de3c4d34dd8abbe70cc98c8be293770f Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sat, 7 Nov 2015 08:15:23 +0000 Subject: [PATCH 45/67] refactor: move NetworkRouterStatus into its own file --- router/network_router_status.go | 43 +++++++++++++++++++++++++++++++++ router/status.go | 39 ------------------------------ 2 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 router/network_router_status.go diff --git a/router/network_router_status.go b/router/network_router_status.go new file mode 100644 index 00000000..1b56d3e6 --- /dev/null +++ b/router/network_router_status.go @@ -0,0 +1,43 @@ +package router + +import ( + "time" +) + +type NetworkRouterStatus struct { + *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{ + 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 +} diff --git a/router/status.go b/router/status.go index 776f359f..bb418d65 100644 --- a/router/status.go +++ b/router/status.go @@ -2,7 +2,6 @@ package router import ( "fmt" - "time" ) type Status struct { @@ -22,20 +21,6 @@ type Status struct { OverlayDiagnostics interface{} } -type NetworkRouterStatus struct { - *Status - Interface string - CaptureStats map[string]int - MACs []MACStatus -} - -type MACStatus struct { - Mac string - Name string - NickName string - LastSeen time.Time -} - type PeerStatus struct { Name string NickName string @@ -87,30 +72,6 @@ func NewStatus(router *Router) *Status { router.Overlay.Diagnostics()} } -func NewNetworkRouterStatus(router *NetworkRouter) *NetworkRouterStatus { - return &NetworkRouterStatus{ - 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 -} - func NewPeerStatusSlice(peers *Peers) []PeerStatus { var slice []PeerStatus From dc9f8762ca74cc2845ca4208a22bf4e851c6a20d Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 16:37:39 +0000 Subject: [PATCH 46/67] move generic communication substrate into its own 'mesh' package This is mostly a matter of moving some files, changing package names, changing some imports, and changing some type references. We duplicate the odd constant & global var, and the intmac/macint functions, since neither 'router' or 'mesh' nor, really,' common' are a natural home for them. --- Makefile | 2 +- ipam/allocator.go | 74 +++++++++++++------------- ipam/claim.go | 6 +-- ipam/paxos/paxos.go | 12 ++--- ipam/paxos/paxos_test.go | 10 ++-- ipam/ring/entry.go | 6 +-- ipam/ring/ring.go | 44 +++++++-------- ipam/ring/ring_test.go | 26 ++++----- ipam/testutils_test.go | 24 ++++----- {router => mesh}/connection.go | 2 +- {router => mesh}/connection_maker.go | 2 +- {router => mesh}/gossip.go | 2 +- {router => mesh}/gossip_channel.go | 2 +- {router => mesh}/gossip_test.go | 2 +- {router => mesh}/local_peer.go | 2 +- {router => mesh}/mocks_test.go | 2 +- {router => mesh}/overlay.go | 2 +- {router => mesh}/peer.go | 2 +- {router => mesh}/peer_name_hash.go | 2 +- {router => mesh}/peer_name_mac.go | 19 ++++++- {router => mesh}/peers.go | 2 +- {router => mesh}/peers_test.go | 2 +- {router => mesh}/protocol.go | 2 +- {router => mesh}/protocol_crypto.go | 2 +- {router => mesh}/protocol_test.go | 2 +- {router => mesh}/router.go | 2 +- {router => mesh}/routes.go | 2 +- {router => mesh}/status.go | 2 +- {router => mesh}/surrogate_gossiper.go | 2 +- {router => mesh}/token_bucket.go | 2 +- nameserver/dns_test.go | 8 +-- nameserver/entry.go | 10 ++-- nameserver/entry_test.go | 16 +++--- nameserver/nameserver.go | 26 ++++----- nameserver/nameserver_test.go | 16 +++--- prog/weaver/http.go | 5 +- prog/weaver/main.go | 19 +++---- router/fastdp.go | 27 +++++----- router/flow.go | 10 ++-- router/http.go | 5 +- router/mac_cache.go | 18 ++++--- router/network_overlay.go | 14 +++-- router/network_router.go | 29 +++++++--- router/network_router_status.go | 6 ++- router/overlay_switch.go | 12 +++-- router/sleeve.go | 42 ++++++++------- testing/gossip/mocks.go | 32 +++++------ 47 files changed, 304 insertions(+), 254 deletions(-) rename {router => mesh}/connection.go (99%) rename {router => mesh}/connection_maker.go (99%) rename {router => mesh}/gossip.go (99%) rename {router => mesh}/gossip_channel.go (99%) rename {router => mesh}/gossip_test.go (99%) rename {router => mesh}/local_peer.go (99%) rename {router => mesh}/mocks_test.go (99%) rename {router => mesh}/overlay.go (99%) rename {router => mesh}/peer.go (99%) rename {router => mesh}/peer_name_hash.go (98%) rename {router => mesh}/peer_name_mac.go (85%) rename {router => mesh}/peers.go (99%) rename {router => mesh}/peers_test.go (99%) rename {router => mesh}/protocol.go (99%) rename {router => mesh}/protocol_crypto.go (99%) rename {router => mesh}/protocol_test.go (99%) rename {router => mesh}/router.go (99%) rename {router => mesh}/routes.go (99%) rename {router => mesh}/status.go (99%) rename {router => mesh}/surrogate_gossiper.go (98%) rename {router => mesh}/token_bucket.go (98%) diff --git a/Makefile b/Makefile index 1757de4a..0104e3ff 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/ipam/allocator.go b/ipam/allocator.go index 4c32404e..888b9433 100644 --- a/ipam/allocator.go +++ b/ipam/allocator.go @@ -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 { +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 { +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) { +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 diff --git a/ipam/claim.go b/ipam/claim.go index 2515afd2..20ec6519 100644 --- a/ipam/claim.go +++ b/ipam/claim.go @@ -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 + ")" diff --git a/ipam/paxos/paxos.go b/ipam/paxos/paxos.go index 18d3aeea..3466bb8c 100644 --- a/ipam/paxos/paxos.go +++ b/ipam/paxos/paxos.go @@ -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 diff --git a/ipam/paxos/paxos_test.go b/ipam/paxos/paxos_test.go index c1d5bfe0..c9dd1ff9 100644 --- a/ipam/paxos/paxos_test.go +++ b/ipam/paxos/paxos_test.go @@ -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() diff --git a/ipam/ring/entry.go b/ipam/ring/entry.go index d1d832ed..872a13ab 100644 --- a/ipam/ring/entry.go +++ b/ipam/ring/entry.go @@ -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 diff --git a/ipam/ring/ring.go b/ipam/ring/ring.go index fee7991e..30f32b8d 100644 --- a/ipam/ring/ring.go +++ b/ipam/ring/ring.go @@ -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= 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 { diff --git a/ipam/testutils_test.go b/ipam/testutils_test.go index 144e313f..3aac1cce 100644 --- a/ipam/testutils_test.go +++ b/ipam/testutils_test.go @@ -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) } diff --git a/router/connection.go b/mesh/connection.go similarity index 99% rename from router/connection.go rename to mesh/connection.go index 1cef75b9..e97d52bd 100644 --- a/router/connection.go +++ b/mesh/connection.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/connection_maker.go b/mesh/connection_maker.go similarity index 99% rename from router/connection_maker.go rename to mesh/connection_maker.go index 85775fd2..78edaf58 100644 --- a/router/connection_maker.go +++ b/mesh/connection_maker.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/gossip.go b/mesh/gossip.go similarity index 99% rename from router/gossip.go rename to mesh/gossip.go index 45db0e83..abfab8fa 100644 --- a/router/gossip.go +++ b/mesh/gossip.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/gossip_channel.go b/mesh/gossip_channel.go similarity index 99% rename from router/gossip_channel.go rename to mesh/gossip_channel.go index dd817712..098553e7 100644 --- a/router/gossip_channel.go +++ b/mesh/gossip_channel.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "bytes" diff --git a/router/gossip_test.go b/mesh/gossip_test.go similarity index 99% rename from router/gossip_test.go rename to mesh/gossip_test.go index 3429ed50..5f622826 100644 --- a/router/gossip_test.go +++ b/mesh/gossip_test.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/local_peer.go b/mesh/local_peer.go similarity index 99% rename from router/local_peer.go rename to mesh/local_peer.go index ab54745a..72262e59 100644 --- a/router/local_peer.go +++ b/mesh/local_peer.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/mocks_test.go b/mesh/mocks_test.go similarity index 99% rename from router/mocks_test.go rename to mesh/mocks_test.go index 064850df..08ae90aa 100644 --- a/router/mocks_test.go +++ b/mesh/mocks_test.go @@ -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" diff --git a/router/overlay.go b/mesh/overlay.go similarity index 99% rename from router/overlay.go rename to mesh/overlay.go index 13fd0428..2e794078 100644 --- a/router/overlay.go +++ b/mesh/overlay.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "net" diff --git a/router/peer.go b/mesh/peer.go similarity index 99% rename from router/peer.go rename to mesh/peer.go index a1114e4f..1846f352 100644 --- a/router/peer.go +++ b/mesh/peer.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "crypto/rand" diff --git a/router/peer_name_hash.go b/mesh/peer_name_hash.go similarity index 98% rename from router/peer_name_hash.go rename to mesh/peer_name_hash.go index 9bcd207e..ac76103e 100644 --- a/router/peer_name_hash.go +++ b/mesh/peer_name_hash.go @@ -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" diff --git a/router/peer_name_mac.go b/mesh/peer_name_mac.go similarity index 85% rename from router/peer_name_mac.go rename to mesh/peer_name_mac.go index 7bf868a0..c2b6cdbe 100644 --- a/router/peer_name_mac.go +++ b/mesh/peer_name_mac.go @@ -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 +} diff --git a/router/peers.go b/mesh/peers.go similarity index 99% rename from router/peers.go rename to mesh/peers.go index 9c30a4e2..70ec4c8d 100644 --- a/router/peers.go +++ b/mesh/peers.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "bytes" diff --git a/router/peers_test.go b/mesh/peers_test.go similarity index 99% rename from router/peers_test.go rename to mesh/peers_test.go index e5f328f9..5c2b0094 100644 --- a/router/peers_test.go +++ b/mesh/peers_test.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/protocol.go b/mesh/protocol.go similarity index 99% rename from router/protocol.go rename to mesh/protocol.go index add17a17..1863125a 100644 --- a/router/protocol.go +++ b/mesh/protocol.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "bytes" diff --git a/router/protocol_crypto.go b/mesh/protocol_crypto.go similarity index 99% rename from router/protocol_crypto.go rename to mesh/protocol_crypto.go index f215a595..db0b5f68 100644 --- a/router/protocol_crypto.go +++ b/mesh/protocol_crypto.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "crypto/rand" diff --git a/router/protocol_test.go b/mesh/protocol_test.go similarity index 99% rename from router/protocol_test.go rename to mesh/protocol_test.go index 1a56079a..1ea2ec41 100644 --- a/router/protocol_test.go +++ b/mesh/protocol_test.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "io" diff --git a/router/router.go b/mesh/router.go similarity index 99% rename from router/router.go rename to mesh/router.go index d96b6fe2..55c34c7d 100644 --- a/router/router.go +++ b/mesh/router.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/routes.go b/mesh/routes.go similarity index 99% rename from router/routes.go rename to mesh/routes.go index 8ea756ef..d7787af9 100644 --- a/router/routes.go +++ b/mesh/routes.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "math" diff --git a/router/status.go b/mesh/status.go similarity index 99% rename from router/status.go rename to mesh/status.go index bb418d65..0dce08bb 100644 --- a/router/status.go +++ b/mesh/status.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "fmt" diff --git a/router/surrogate_gossiper.go b/mesh/surrogate_gossiper.go similarity index 98% rename from router/surrogate_gossiper.go rename to mesh/surrogate_gossiper.go index 04059eb7..aef844a8 100644 --- a/router/surrogate_gossiper.go +++ b/mesh/surrogate_gossiper.go @@ -1,4 +1,4 @@ -package router +package mesh type SurrogateGossipData struct { messages [][]byte diff --git a/router/token_bucket.go b/mesh/token_bucket.go similarity index 98% rename from router/token_bucket.go rename to mesh/token_bucket.go index 254de6eb..e6daeb3b 100644 --- a/router/token_bucket.go +++ b/mesh/token_bucket.go @@ -1,4 +1,4 @@ -package router +package mesh import ( "time" diff --git a/nameserver/dns_test.go b/nameserver/dns_test.go index a1fad802..9712fe91 100644 --- a/nameserver/dns_test.go +++ b/nameserver/dns_test.go @@ -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, "", func(router.PeerName) bool { return true }) + 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 { diff --git a/nameserver/entry.go b/nameserver/entry.go index a3310423..524845a3 100644 --- a/nameserver/entry.go +++ b/nameserver/entry.go @@ -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 { diff --git a/nameserver/entry_test.go b/nameserver/entry_test.go index 1e350e64..1e794660 100644 --- a/nameserver/entry_test.go +++ b/nameserver/entry_test.go @@ -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{ diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index 5a87fb02..0d33d184 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -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,15 +34,15 @@ const ( // - Update is O(n) for now type Nameserver struct { sync.RWMutex - ourName router.PeerName + ourName mesh.PeerName domain string - gossip router.Gossip + gossip mesh.Gossip entries Entries - isKnownPeer func(router.PeerName) bool + isKnownPeer func(mesh.PeerName) bool quit chan struct{} } -func New(ourName router.PeerName, domain string, isKnownPeer func(router.PeerName) bool) *Nameserver { +func New(ourName mesh.PeerName, domain string, isKnownPeer func(mesh.PeerName) bool) *Nameserver { return &Nameserver{ ourName: ourName, domain: dns.Fqdn(domain), @@ -51,7 +51,7 @@ func New(ourName router.PeerName, domain string, isKnownPeer func(router.PeerNam } } -func (n *Nameserver) SetGossip(gossip router.Gossip) { +func (n *Nameserver) SetGossip(gossip mesh.Gossip) { n.gossip = gossip } @@ -83,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) @@ -140,7 +140,7 @@ func (n *Nameserver) ContainerDied(ident string) { } } -func (n *Nameserver) PeerGone(peer router.PeerName) { +func (n *Nameserver) PeerGone(peer mesh.PeerName) { n.infof("peer %s gone", peer.String()) n.Lock() defer n.Unlock() @@ -181,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{ @@ -192,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 @@ -221,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 } diff --git a/nameserver/nameserver_test.go b/nameserver/nameserver_test.go index 5beaf87e..f7b603b5 100644 --- a/nameserver/nameserver_test.go +++ b/nameserver/nameserver_test.go @@ -11,14 +11,14 @@ 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 router.PeerName) *Nameserver { - return New(name, "", func(router.PeerName) bool { return true }) +func makeNameserver(name mesh.PeerName) *Nameserver { + return New(name, "", func(mesh.PeerName) bool { return true }) } func makeNetwork(size int) ([]*Nameserver, *gossip.TestRouter) { @@ -26,7 +26,7 @@ func makeNetwork(size int) ([]*Nameserver, *gossip.TestRouter) { nameservers := make([]*Nameserver, size) for i := 0; i < size; i++ { - name, _ := router.PeerNameFromString(fmt.Sprintf("%02d:00:00:02:00:00", i)) + name, _ := mesh.PeerNameFromString(fmt.Sprintf("%02d:00:00:02:00:00", i)) nameserver := makeNameserver(name) nameserver.SetGossip(gossipRouter.Connect(nameserver.ourName, nameserver)) nameserver.Start() @@ -44,7 +44,7 @@ func stopNetwork(nameservers []*Nameserver, grouter *gossip.TestRouter) { } type pair struct { - origin router.PeerName + origin mesh.PeerName addr address.Address } @@ -91,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 } @@ -226,7 +226,7 @@ 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 := makeNameserver(peername) @@ -250,7 +250,7 @@ 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 := makeNameserver(peername) diff --git a/prog/weaver/http.go b/prog/weaver/http.go index 8871468e..cb828f47 100644 --- a/prog/weaver/http.go +++ b/prog/weaver/http.go @@ -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 { diff --git a/prog/weaver/main.go b/prog/weaver/main.go index e925cb2e..cbd3a0b9 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -17,6 +17,7 @@ import ( . "github.com/weaveworks/weave/common" "github.com/weaveworks/weave/common/docker" "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 +42,7 @@ func main() { deleteDatapath bool addDatapathInterface string - config weave.Config + config mesh.Config networkConfig weave.NetworkConfig protocolMinVersion int ifaceName string @@ -74,8 +75,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)") @@ -146,8 +147,8 @@ func main() { 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) @@ -212,7 +213,7 @@ func main() { routerName = iface.HardwareAddr.String() } - name, err := weave.PeerNameFromUserInput(routerName) + name, err := mesh.PeerNameFromUserInput(routerName) checkFatal(err) if nickName == "" { @@ -253,7 +254,7 @@ func main() { } } } - isKnownPeer := func(name weave.PeerName) bool { + isKnownPeer := func(name mesh.PeerName) bool { return router.Peers.Fetch(name) != nil } var allocator *ipam.Allocator @@ -271,7 +272,7 @@ func main() { ) if !noDNS { ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer) - router.Peers.OnGC(func(peer *weave.Peer) { ns.PeerGone(peer.Name) }) + router.Peers.OnGC(func(peer *mesh.Peer) { ns.PeerGone(peer.Name) }) ns.SetGossip(router.NewGossip("nameserver", ns)) observeContainers(ns) ns.Start() @@ -366,7 +367,7 @@ func parseAndCheckCIDR(cidrStr string) address.CIDR { return cidr } -func createAllocator(router *weave.Router, ipRangeStr string, defaultSubnetStr string, quorum uint, isKnownPeer func(weave.PeerName) bool) (*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 != "" { diff --git a/router/fastdp.go b/router/fastdp.go index b1765a94..6bed5a09 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -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 { @@ -385,7 +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() @@ -460,17 +461,17 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) { 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 } @@ -486,7 +487,7 @@ func (op vxlanSpecialPacketFlowOp) Process(frame []byte, dec *EthernetDecoder, b type fastDatapathForwarder struct { fastdp *FastDatapath - remotePeer *Peer + remotePeer *mesh.Peer localIP [4]byte sendControlMsg func(byte, []byte) error connUID uint64 @@ -506,7 +507,7 @@ type fastDatapathForwarder struct { errorChan chan error } -func (fastdp fastDatapathOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) { +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. @@ -794,7 +795,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() @@ -803,7 +804,7 @@ func (fastdp *FastDatapath) addForwarder(peer PeerName, fwd *fastDatapathForward 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 { diff --git a/router/flow.go b/router/flow.go index 4992b044..e523a255 100644 --- a/router/flow.go +++ b/router/flow.go @@ -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 } diff --git a/router/http.go b/router/http.go index 7ad552b8..c4057e87 100644 --- a/router/http.go +++ b/router/http.go @@ -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 { diff --git a/router/mac_cache.go b/router/mac_cache.go index 0d0e77c7..0d95d623 100644 --- a/router/mac_cache.go +++ b/router/mac_cache.go @@ -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() diff --git a/router/network_overlay.go b/router/network_overlay.go index 8d80594b..b09b720b 100644 --- a/router/network_overlay.go +++ b/router/network_overlay.go @@ -1,8 +1,12 @@ package router +import ( + "github.com/weaveworks/weave/mesh" +) + // Interface to overlay network packet handling type NetworkOverlay interface { - Overlay + mesh.Overlay // The routes have changed, so any cached information should // be discarded. @@ -12,7 +16,7 @@ type NetworkOverlay interface { InvalidateShortIDs() // Start consuming forwarded packets. - StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error + StartConsumingPackets(*mesh.Peer, *mesh.Peers, OverlayConsumer) error } // When a consumer is called, the decoder will already have been used @@ -21,7 +25,7 @@ type OverlayConsumer func(ForwardPacketKey) FlowOp // All of the machinery to forward packets to a particular peer type OverlayForwarder interface { - OverlayConnection + 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 @@ -29,7 +33,7 @@ type OverlayForwarder interface { Forward(ForwardPacketKey) FlowOp } -type NullNetworkOverlay struct{ NullOverlay } +type NullNetworkOverlay struct{ mesh.NullOverlay } func (NullNetworkOverlay) InvalidateRoutes() { } @@ -37,7 +41,7 @@ func (NullNetworkOverlay) InvalidateRoutes() { func (NullNetworkOverlay) InvalidateShortIDs() { } -func (NullNetworkOverlay) StartConsumingPackets(*Peer, *Peers, OverlayConsumer) error { +func (NullNetworkOverlay) StartConsumingPackets(*mesh.Peer, *mesh.Peers, OverlayConsumer) error { return nil } diff --git a/router/network_router.go b/router/network_router.go index 02bff759..20186de5 100644 --- a/router/network_router.go +++ b/router/network_router.go @@ -1,21 +1,34 @@ 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 @@ -28,12 +41,12 @@ type PacketLogging interface { } type NetworkRouter struct { - *Router + *mesh.Router NetworkConfig Macs *MacCache } -func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter { +func NewNetworkRouter(config mesh.Config, networkConfig NetworkConfig, name mesh.PeerName, nickName string, overlay NetworkOverlay) *NetworkRouter { if overlay == nil { overlay = NullNetworkOverlay{} } @@ -41,14 +54,14 @@ func NewNetworkRouter(config Config, networkConfig NetworkConfig, name PeerName, networkConfig.Bridge = NullBridge{} } - router := &NetworkRouter{Router: NewRouter(config, name, nickName, overlay), NetworkConfig: networkConfig} + 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 *Peer) { + func(mac net.HardwareAddr, peer *mesh.Peer) { log.Println("Expired MAC", mac, "at", peer) }) - router.Peers.OnGC(func(peer *Peer) { router.Macs.Delete(peer) }) + router.Peers.OnGC(func(peer *mesh.Peer) { router.Macs.Delete(peer) }) return router } @@ -174,10 +187,10 @@ func (router *NetworkRouter) relay(key ForwardPacketKey) FlowOp { return DiscardingFlowOp{} } - return conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) + return conn.(*mesh.LocalConnection).OverlayConn.(OverlayForwarder).Forward(key) } -func (router *NetworkRouter) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp { +func (router *NetworkRouter) relayBroadcast(srcPeer *mesh.Peer, key PacketKey) FlowOp { nextHops := router.Routes.Broadcast(srcPeer.Name) if len(nextHops) == 0 { return DiscardingFlowOp{} @@ -186,7 +199,7 @@ func (router *NetworkRouter) relayBroadcast(srcPeer *Peer, key PacketKey) FlowOp op := NewMultiFlowOp(true) for _, conn := range router.Ourself.ConnectionsTo(nextHops) { - op.Add(conn.(*LocalConnection).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{ + op.Add(conn.(*mesh.LocalConnection).OverlayConn.(OverlayForwarder).Forward(ForwardPacketKey{ PacketKey: key, SrcPeer: srcPeer, DstPeer: conn.Remote()})) diff --git a/router/network_router_status.go b/router/network_router_status.go index 1b56d3e6..e35267e9 100644 --- a/router/network_router_status.go +++ b/router/network_router_status.go @@ -2,10 +2,12 @@ package router import ( "time" + + "github.com/weaveworks/weave/mesh" ) type NetworkRouterStatus struct { - *Status + *mesh.Status Interface string CaptureStats map[string]int MACs []MACStatus @@ -20,7 +22,7 @@ type MACStatus struct { func NewNetworkRouterStatus(router *NetworkRouter) *NetworkRouterStatus { return &NetworkRouterStatus{ - NewStatus(router.Router), + mesh.NewStatus(router.Router), router.Bridge.String(), router.Bridge.Stats(), NewMACStatusSlice(router.Macs)} diff --git a/router/overlay_switch.go b/router/overlay_switch.go index 9ead7987..9e6efd00 100644 --- a/router/overlay_switch.go +++ b/router/overlay_switch.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" "sync" + + "github.com/weaveworks/weave/mesh" ) // OverlaySwitch selects which overlay to use, from a set of @@ -60,7 +62,7 @@ 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 { return err @@ -76,7 +78,7 @@ type namedOverlay struct { // 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 OverlayConnectionParams) ([]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, " ") @@ -118,7 +120,7 @@ func (osw *OverlaySwitch) commonOverlays(params OverlayConnectionParams) ([]name } type overlaySwitchForwarder struct { - remotePeer *Peer + remotePeer *mesh.Peer lock sync.Mutex @@ -160,7 +162,7 @@ type subForwarderEvent struct { err error } -func (osw *OverlaySwitch) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) { +func (osw *OverlaySwitch) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) { if _, present := params.Features["Overlays"]; !present && osw.compatOverlay != nil { return osw.compatOverlay.PrepareConnection(params) } @@ -197,7 +199,7 @@ func (osw *OverlaySwitch) PrepareConnection(params OverlayConnectionParams) (Ove xmsg[0] = byte(index) xmsg[1] = tag copy(xmsg[2:], msg) - return origSendControlMessage(ProtocolOverlayControlMsg, xmsg) + return origSendControlMessage(mesh.ProtocolOverlayControlMsg, xmsg) } subConn, err := overlay.PrepareConnection(params) diff --git a/router/sleeve.go b/router/sleeve.go index 3b329a1a..66cbe7cd 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -18,6 +18,8 @@ import ( "github.com/google/gopacket" "github.com/google/gopacket/layers" + + "github.com/weaveworks/weave/mesh" ) // This diagram explains the various arithmetic and variables related @@ -61,21 +63,21 @@ 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) NetworkOverlay { return &SleeveOverlay{localPort: localPort} } -func (sleeve *SleeveOverlay) StartConsumingPackets(localPeer *Peer, peers *Peers, consumer OverlayConsumer) error { +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 @@ -114,7 +116,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 } @@ -135,19 +137,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 { @@ -172,7 +174,7 @@ func (sleeve *SleeveOverlay) readUDP() { continue } - fwdName := PeerNameFromBin(buf[:NameSize]) + fwdName := mesh.PeerNameFromBin(buf[:NameSize]) fwd := sleeve.lookupForwarder(fwdName) if fwd == nil { continue @@ -212,8 +214,8 @@ func (sleeve *SleeveOverlay) handleFrame(sender *net.UDPAddr, fwd *sleeveForward 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 } @@ -240,7 +242,7 @@ func (sleeve *SleeveOverlay) handleFrame(sender *net.UDPAddr, fwd *sleeveForward 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 } @@ -282,7 +284,7 @@ type sleeveCrypto struct { type sleeveForwarder struct { // Immutable sleeve *SleeveOverlay - remotePeer *Peer + remotePeer *mesh.Peer remotePeerBin []byte sendControlMsg func(byte, []byte) error connUID uint64 @@ -349,7 +351,7 @@ type controlMessage struct { msg []byte } -func (sleeve *SleeveOverlay) PrepareConnection(params OverlayConnectionParams) (OverlayConnection, error) { +func (sleeve *SleeveOverlay) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) { name := sleeve.localPeer.NameByte var crypto sleeveCrypto if params.SessionKey != nil { @@ -759,13 +761,13 @@ func (fwd *sleeveForwarder) handleSpecialFrame(special specialFrame) error { func (fwd *sleeveForwarder) handleControlMessage(cm controlMessage) error { switch cm.tag { - case ProtocolConnectionEstablished: + case mesh.ProtocolConnectionEstablished: return fwd.handleHeartbeatAck() - case ProtocolFragmentationReceived: + case mesh.ProtocolFragmentationReceived: return fwd.handleFragTestAck() - case ProtocolPMTUVerified: + case mesh.ProtocolPMTUVerified: return fwd.handleMTUTestAck(cm.msg) default: @@ -834,7 +836,7 @@ func (fwd *sleeveForwarder) handleHeartbeat(special specialFrame) error { if !fwd.ackedHeartbeat { fwd.ackedHeartbeat = true - if err := fwd.sendControlMsg(ProtocolConnectionEstablished, nil); err != nil { + if err := fwd.sendControlMsg(mesh.ProtocolConnectionEstablished, nil); err != nil { return err } } @@ -895,7 +897,7 @@ func (fwd *sleeveForwarder) handleFragTest(frame []byte) error { return nil } - return fwd.sendControlMsg(ProtocolFragmentationReceived, nil) + return fwd.sendControlMsg(mesh.ProtocolFragmentationReceived, nil) } func (fwd *sleeveForwarder) handleFragTestAck() error { @@ -941,7 +943,7 @@ func (fwd *sleeveForwarder) sendMTUTest() error { func (fwd *sleeveForwarder) handleMTUTest(frame []byte) error { buf := make([]byte, 2) binary.BigEndian.PutUint16(buf, uint16(len(frame)-EthernetOverhead)) - return fwd.sendControlMsg(ProtocolPMTUVerified, buf) + return fwd.sendControlMsg(mesh.ProtocolPMTUVerified, buf) } func (fwd *sleeveForwarder) handleMTUTestAck(msg []byte) error { diff --git a/testing/gossip/mocks.go b/testing/gossip/mocks.go index ae5791f1..1a42b03d 100644 --- a/testing/gossip/mocks.go +++ b/testing/gossip/mocks.go @@ -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) } From 20d5903696bb5499eb88cec8c1621cfe263bf59c Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 5 Nov 2015 15:45:09 +0000 Subject: [PATCH 47/67] Update test template name to pull in new Docker version --- test/gce.sh | 4 ++-- tools | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/gce.sh b/test/gce.sh index 55a577de..b83f5198 100755 --- a/test/gce.sh +++ b/test/gce.sh @@ -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 diff --git a/tools b/tools index 58c9a390..452f2b7d 160000 --- a/tools +++ b/tools @@ -1 +1 @@ -Subproject commit 58c9a390c54860547254fa3a66e0acd8916f889c +Subproject commit 452f2b7de10dddb1bd8933ebb43bc8d8775e6658 From 499d6312b7e6159ab94c116127b9c020fe109118 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 6 Nov 2015 10:02:19 +0000 Subject: [PATCH 48/67] Don't need --add-host except in non-FDP case because we put the mappings in the outer /etc/hosts --- test/190_no_fastdp_2_test.sh | 4 ++-- test/gce.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/190_no_fastdp_2_test.sh b/test/190_no_fastdp_2_test.sh index fe793f2b..18d235fc 100755 --- a/test/190_no_fastdp_2_test.sh +++ b/test/190_no_fastdp_2_test.sh @@ -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 diff --git a/test/gce.sh b/test/gce.sh index b83f5198..b1cc7cca 100755 --- a/test/gce.sh +++ b/test/gce.sh @@ -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 } From fa5bcd045704dacca0504c4c183c7e6783c12fa5 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 6 Nov 2015 10:37:51 +0000 Subject: [PATCH 49/67] Lump some commands together to reduce CircleCI waiting overhead --- circle.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/circle.yml b/circle.yml index cd208015..32804c63 100644 --- a/circle.yml +++ b/circle.yml @@ -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 From 17c835e6720c9a437614758cd81dccd9aa4b0371 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 9 Nov 2015 09:25:27 +0000 Subject: [PATCH 50/67] Compress weave.tar to save upload time --- .gitignore | 2 +- Makefile | 4 ++-- site/building.md | 6 +++--- test/setup.sh | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 2cefdfb7..4506fcc5 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Makefile b/Makefile index 1757de4a..7431459e 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -105,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) diff --git a/site/building.md b/site/building.md index 2d7b713f..41b0bfe1 100644 --- a/site/building.md +++ b/site/building.md @@ -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:// -$ docker load < weave.tar +$ docker load < weave.tar.gz ``` You can provide extra Vagrant configuration by putting a file diff --git a/test/setup.sh b/test/setup.sh index 11280ce2..9312fc20 100755 --- a/test/setup.sh +++ b/test/setup.sh @@ -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 From 65fe753a58e577f956496e2b20df301264032e06 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 9 Nov 2015 12:24:18 +0000 Subject: [PATCH 51/67] Remove code coverage as temporary work-around to Docker 1.9 issue --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 32804c63..bdb710c7 100644 --- a/circle.yml +++ b/circle.yml @@ -40,11 +40,11 @@ test: parallel: true - docker run -v /home/ubuntu:/home/go -e COVERDIR=test/coverage -e SLOW=true -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX weaveworks/weave-test: parallel: true - - docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go -e COVERAGE=true weaveworks/weave-build: + - docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go weaveworks/weave-build: parallel: true - 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: + - cd $SRCDIR/test; eval $(./gce.sh hosts); ./run_all.sh: parallel: true timeout: 300 - cd $SRCDIR; make clean-bin: From dd7ffa450161f7a13ee2cd62f4b759813e92e033 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 19:46:53 +0000 Subject: [PATCH 52/67] code docs: warn against nonce re-use by overlay connection --- mesh/overlay.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mesh/overlay.go b/mesh/overlay.go index 2e794078..5c48c927 100644 --- a/mesh/overlay.go +++ b/mesh/overlay.go @@ -36,7 +36,13 @@ type OverlayConnectionParams struct { // Unique identifier for this connection ConnUID uint64 - // Session key, if connection is encrypted; nil otherwise + // 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 From 1eed5fd2716d06adfba2636bb4066127aa7570c4 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 19:47:27 +0000 Subject: [PATCH 53/67] cosmetic: don't mention UDP in mesh --- mesh/protocol_crypto.go | 4 ++-- mesh/router.go | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/mesh/protocol_crypto.go b/mesh/protocol_crypto.go index db0b5f68..2adb6921 100644 --- a/mesh/protocol_crypto.go +++ b/mesh/protocol_crypto.go @@ -35,7 +35,8 @@ func FormSessionKey(remotePublicKey, localPrivateKey *[32]byte, secretKey []byte // 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. +// 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 { @@ -49,7 +50,6 @@ func NewTCPCryptoState(sessionKey *[32]byte, outbound bool) *TCPCryptoState { if outbound { s.nonce[0] |= (1 << 7) } - // Ensure that TCP and UDP sequences are disjoint s.nonce[0] |= (1 << 6) return s } diff --git a/mesh/router.go b/mesh/router.go index 55c34c7d..916ea5b7 100644 --- a/mesh/router.go +++ b/mesh/router.go @@ -109,9 +109,6 @@ func (router *Router) listenTCP(localPort int) { } 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) From 64aa2b5cc363c7b50412a273246378c0c19cfe6d Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Mon, 9 Nov 2015 20:56:04 +0000 Subject: [PATCH 54/67] refactor: remove weave overlay-isms from mesh --- mesh/connection.go | 2 +- mesh/protocol.go | 6 +++--- router/sleeve.go | 16 ++++++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mesh/connection.go b/mesh/connection.go index e97d52bd..b19d2c2c 100644 --- a/mesh/connection.go +++ b/mesh/connection.go @@ -422,7 +422,7 @@ func (conn *LocalConnection) receiveTCP(receiver TCPReceiver) { func (conn *LocalConnection) handleProtocolMsg(tag ProtocolTag, payload []byte) error { switch tag { case ProtocolHeartbeat: - case ProtocolConnectionEstablished, ProtocolFragmentationReceived, ProtocolPMTUVerified, ProtocolOverlayControlMsg: + case ProtocolReserved1, ProtocolReserved2, ProtocolReserved3, ProtocolOverlayControlMsg: conn.OverlayConn.ControlMessage(byte(tag), payload) case ProtocolGossipUnicast, ProtocolGossipBroadcast, ProtocolGossip: return conn.Router.handleGossip(tag, payload) diff --git a/mesh/protocol.go b/mesh/protocol.go index 1863125a..7ac06050 100644 --- a/mesh/protocol.go +++ b/mesh/protocol.go @@ -329,9 +329,9 @@ type ProtocolTag byte const ( ProtocolHeartbeat = iota - ProtocolConnectionEstablished - ProtocolFragmentationReceived - ProtocolPMTUVerified + ProtocolReserved1 // legacy overlay control messages + ProtocolReserved2 // + ProtocolReserved3 // ProtocolGossip ProtocolGossipUnicast ProtocolGossipBroadcast diff --git a/router/sleeve.go b/router/sleeve.go index 66cbe7cd..0be92572 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -56,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 { @@ -761,13 +765,13 @@ func (fwd *sleeveForwarder) handleSpecialFrame(special specialFrame) error { func (fwd *sleeveForwarder) handleControlMessage(cm controlMessage) error { switch cm.tag { - case mesh.ProtocolConnectionEstablished: + case ProtocolConnectionEstablished: return fwd.handleHeartbeatAck() - case mesh.ProtocolFragmentationReceived: + case ProtocolFragmentationReceived: return fwd.handleFragTestAck() - case mesh.ProtocolPMTUVerified: + case ProtocolPMTUVerified: return fwd.handleMTUTestAck(cm.msg) default: @@ -836,7 +840,7 @@ func (fwd *sleeveForwarder) handleHeartbeat(special specialFrame) error { if !fwd.ackedHeartbeat { fwd.ackedHeartbeat = true - if err := fwd.sendControlMsg(mesh.ProtocolConnectionEstablished, nil); err != nil { + if err := fwd.sendControlMsg(ProtocolConnectionEstablished, nil); err != nil { return err } } @@ -897,7 +901,7 @@ func (fwd *sleeveForwarder) handleFragTest(frame []byte) error { return nil } - return fwd.sendControlMsg(mesh.ProtocolFragmentationReceived, nil) + return fwd.sendControlMsg(ProtocolFragmentationReceived, nil) } func (fwd *sleeveForwarder) handleFragTestAck() error { @@ -943,7 +947,7 @@ func (fwd *sleeveForwarder) sendMTUTest() error { func (fwd *sleeveForwarder) handleMTUTest(frame []byte) error { buf := make([]byte, 2) binary.BigEndian.PutUint16(buf, uint16(len(frame)-EthernetOverhead)) - return fwd.sendControlMsg(mesh.ProtocolPMTUVerified, buf) + return fwd.sendControlMsg(ProtocolPMTUVerified, buf) } func (fwd *sleeveForwarder) handleMTUTestAck(msg []byte) error { From 76db732f1b0e70b1d07bb44de372694201a2ad5e Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 10 Nov 2015 10:24:58 +0000 Subject: [PATCH 55/67] Revert "Disable restart of docker" This reverts commit a400a3dd098265dc85c24f060e43a494460f3772. --- test/640_proxy_restart_reattaches_test.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index 034d4704..59bc91f8 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -42,11 +42,10 @@ 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 From 682133a56aa2f7e9e5c3faa72fc7a81e96595099 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 10 Nov 2015 17:09:17 +0000 Subject: [PATCH 56/67] Move ODP helper functions out to their own package --- {router => common/odp}/odp.go | 2 +- prog/weaver/main.go | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) rename {router => common/odp}/odp.go (99%) diff --git a/router/odp.go b/common/odp/odp.go similarity index 99% rename from router/odp.go rename to common/odp/odp.go index d772d930..53b481ff 100644 --- a/router/odp.go +++ b/common/odp/odp.go @@ -1,4 +1,4 @@ -package router +package odp import ( "fmt" diff --git a/prog/weaver/main.go b/prog/weaver/main.go index cbd3a0b9..d5fb2553 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -16,6 +16,7 @@ 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" @@ -120,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) @@ -136,11 +137,11 @@ 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) } From 7dc1b50d3b1a87701d6496a6dfc95ff473eaa81b Mon Sep 17 00:00:00 2001 From: David Wragg Date: Tue, 10 Nov 2015 23:17:01 +0000 Subject: [PATCH 57/67] Handle the case where Forward returns nil Forward can return nil if the remote peer has HasShortID false. That can happen if we learn about a 1.2 peer from a 1.1 peer and attempt to connect to it. This change just fixes the panic. HasShortID will never be set, so we'll fall back to sleeve. But if that occurs, if can be fixed by a restart of the affected routers. --- router/fastdp.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/router/fastdp.go b/router/fastdp.go index 5e9b6ce0..250f0ac4 100644 --- a/router/fastdp.go +++ b/router/fastdp.go @@ -674,7 +674,10 @@ 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 ( From 0661ccdea9b410d771ce16d4dd38db32fbb24603 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 11 Nov 2015 10:10:17 +0000 Subject: [PATCH 58/67] Revert "Revert "Disable restart of docker"" This reverts commit 76db732f1b0e70b1d07bb44de372694201a2ad5e. --- test/640_proxy_restart_reattaches_test.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index 59bc91f8..034d4704 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -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 From 2536aef737f1238f34740d8711e6c54e97b89ef7 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 11 Nov 2015 14:47:15 +0000 Subject: [PATCH 59/67] Proxy doesn't need to mount the containers dir --- weave | 6 ------ 1 file changed, 6 deletions(-) diff --git a/weave b/weave index ec2cc4fb..ae989b41 100755 --- a/weave +++ b/weave @@ -1527,14 +1527,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 \ From b1b03f3a97a4888f52f6483e8eafc3ec7649ba10 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 12 Nov 2015 11:27:48 +0000 Subject: [PATCH 60/67] Revert "Remove code coverage as temporary work-around to Docker 1.9 issue" This reverts commit 65fe753a58e577f956496e2b20df301264032e06. --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index bdb710c7..32804c63 100644 --- a/circle.yml +++ b/circle.yml @@ -40,11 +40,11 @@ test: parallel: true - docker run -v /home/ubuntu:/home/go -e COVERDIR=test/coverage -e SLOW=true -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX weaveworks/weave-test: parallel: true - - docker run -v /var/run/docker.sock:/run/docker.sock -v /home/ubuntu:/home/go weaveworks/weave-build: + - 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 && eval $(./gce.sh hosts) && ./setup.sh: parallel: true - - cd $SRCDIR/test; eval $(./gce.sh hosts); ./run_all.sh: + - cd $SRCDIR/test; eval $(./gce.sh hosts); export COVERAGE=true; ./run_all.sh: parallel: true timeout: 300 - cd $SRCDIR; make clean-bin: From 7f65530b2654ccc7dd05258029d867b218d148e0 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 10 Nov 2015 15:59:11 +0000 Subject: [PATCH 61/67] `weave setup` fetches plugin --- weave | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/weave b/weave index 80bcd57a..49456ef3 100755 --- a/weave +++ b/weave @@ -288,6 +288,9 @@ fi BASE_IMAGE=$DOCKERHUB_USER/weave IMAGE=$BASE_IMAGE:$IMAGE_VERSION +BASE_PLUGIN_IMAGE=$DOCKERHUB_USER/plugin +PLUGIN_IMAGE=$BASE_PLUGIN_IMAGE:$IMAGE_VERSION + PROCFS=${PROCFS:-/proc} DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} CONTAINER_NAME=${WEAVE_CONTAINER_NAME:-weave} @@ -1653,7 +1656,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 ;; From b21afcb78f43da49ed2361c01c1575b68a2aee66 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 10 Nov 2015 16:42:58 +0000 Subject: [PATCH 62/67] Implement `weave launch-plugin` and `weave stop-plugin` --- weave | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/weave b/weave index 49456ef3..5acd9edc 100755 --- a/weave +++ b/weave @@ -58,6 +58,7 @@ weave launch-proxy [-H ] [--with-dns | --without-dns] [--hostname-match ] [--hostname-replacement ] [--rewrite-inspect] +weave launch-plugin weave env [--restore] weave config weave connect [--replace] [ ...] @@ -80,6 +81,7 @@ weave ps [ ...] weave stop weave stop-router weave stop-proxy +weave stop-plugin weave reset weave rmpeer @@ -290,6 +292,7 @@ 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} @@ -1558,6 +1561,18 @@ stop_proxy() { stop $PROXY_CONTAINER_NAME "Proxy" } +launch_plugin() { + PLUGIN_CONTAINER=$(docker run --privileged -d --name=$PLUGIN_CONTAINER_NAME \ + --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 ] || { @@ -1708,6 +1723,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 @@ -1949,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 From c345700963ec89936da4da06fc7ed09c526785ba Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Tue, 10 Nov 2015 17:28:49 +0000 Subject: [PATCH 63/67] Add plugin to `weave status` --- weave | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/weave b/weave index 5acd9edc..06afef92 100755 --- a/weave +++ b/weave @@ -1783,6 +1783,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 ] ;; From 04ab198e952e8811029a1686ee53b2ea3b2bd895 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 12 Nov 2015 13:07:14 +0000 Subject: [PATCH 64/67] Set restart policy to 'always' Docker attempts to recreate networks on startup which means the plugin container has to be started. If it isn't started automatically by Docker with a restart policy, it's not possible to start it manually because Docker is blocked. --- weave | 1 + 1 file changed, 1 insertion(+) diff --git a/weave b/weave index 06afef92..8e76b8fc 100755 --- a/weave +++ b/weave @@ -1563,6 +1563,7 @@ stop_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 \ From b4dd9c2490a70ed51fa1af780e8aa3fc23abdc44 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 12 Nov 2015 14:46:38 +0000 Subject: [PATCH 65/67] Add plugin to features doc --- site/features.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/site/features.md b/site/features.md index baa580a4..4dbbb7ab 100644 --- a/site/features.md +++ b/site/features.md @@ -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. +### 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). + ### Address allocation Containers are automatically allocated an IP address that is unique From 3bb7036cfdff6844702e36ec0c953b54600d3cc3 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 12 Nov 2015 16:48:56 +0000 Subject: [PATCH 66/67] Runner depends on tools --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 335da1b0..b13b3454 100644 --- a/Makefile +++ b/Makefile @@ -119,7 +119,7 @@ lint: tools/.git tools/.git: git submodule update --init -$(RUNNER_EXE): +$(RUNNER_EXE): tools/.git make -C tools/runner $(PUBLISH): publish_%: $(IMAGES_UPTODATE) From af3fc82b7768150b547402ff258617a5636cb608 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Thu, 12 Nov 2015 16:49:33 +0000 Subject: [PATCH 67/67] Add release v1.3.0 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de063202..1136390a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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