Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
851b58cca8 | ||
|
|
cb48ebc399 | ||
|
|
5278eb7ebc | ||
|
|
418c256689 | ||
|
|
4eeb846507 | ||
|
|
7529f5f9af | ||
|
|
8506e57482 | ||
|
|
b1d09305e4 | ||
|
|
07892bff7d | ||
|
|
50985dee90 | ||
|
|
60323d0960 | ||
|
|
a9cef6327f | ||
|
|
fdeb9010ba | ||
|
|
ee659d4033 | ||
|
|
8f9b2a36c0 | ||
|
|
6a83130685 | ||
|
|
77e6c6f886 | ||
|
|
8a5a15d5e9 | ||
|
|
bcc8c73f59 | ||
|
|
e22c6375c9 | ||
|
|
22ae0d200c | ||
|
|
7231bd00f8 | ||
|
|
590a151bde | ||
|
|
f5dfefef75 | ||
|
|
8e6cb5e24d | ||
|
|
ed629d420d | ||
|
|
fd568682c3 | ||
|
|
dbb9849b8c | ||
|
|
776af44782 | ||
|
|
69dacd0594 | ||
|
|
f17a2a00b1 | ||
|
|
1a64420e01 | ||
|
|
49b9a2c8df | ||
|
|
6c251417d5 | ||
|
|
8c0c38c8b3 | ||
|
|
29eee4e858 | ||
|
|
454c6f713d | ||
|
|
dd715e18ec | ||
|
|
f067c7d44e | ||
|
|
c1023eaf18 | ||
|
|
b091f59311 | ||
|
|
f98ad822e3 | ||
|
|
917c1ddbad | ||
|
|
d81d2f691d | ||
|
|
1ad118a38f | ||
|
|
9d1648cee7 | ||
|
|
929167366a | ||
|
|
353ccf5e6c | ||
|
|
cfc1fa4fae | ||
|
|
d881f47088 | ||
|
|
84013c4452 | ||
|
|
d9dc1a988c | ||
|
|
5fd14348aa | ||
|
|
57a250a20b | ||
|
|
81add75258 | ||
|
|
0145282a10 | ||
|
|
ae0cb5d483 | ||
|
|
e7eeecd762 | ||
|
|
7d308a4ac5 | ||
|
|
ebcb7f6108 | ||
|
|
e03c7b1b7c | ||
|
|
70a20b4d26 | ||
|
|
d143470d77 | ||
|
|
30d6639a98 | ||
|
|
92cfd3b4f9 | ||
|
|
7659ea21c7 | ||
|
|
4e740736e7 | ||
|
|
4f44d9e25a | ||
|
|
2ae2d52289 | ||
|
|
635191970f | ||
|
|
e370443a3f | ||
|
|
738ff2b65f | ||
|
|
cef8c908d0 | ||
|
|
edc0cdbc10 | ||
|
|
89e116961c | ||
|
|
71180f97e7 | ||
|
|
be8d9d88d8 | ||
|
|
35de3720e9 | ||
|
|
4a7e2054db | ||
|
|
fe75047988 | ||
|
|
f73fb5307f | ||
|
|
172597a68d | ||
|
|
f05169e457 | ||
|
|
b171497466 | ||
|
|
61375fb785 | ||
|
|
04cc4edf26 | ||
|
|
0101a12fba | ||
|
|
e094fb1547 | ||
|
|
e0a44a901a | ||
|
|
d4f9abeefd | ||
|
|
0338d4595b | ||
|
|
7328c3fe86 | ||
|
|
bf288ff6f5 | ||
|
|
ef4c4024bc | ||
|
|
6f24cca4b1 | ||
|
|
bf59a003bb | ||
|
|
2298a40327 | ||
|
|
61d22bb8b4 | ||
|
|
eb3bbff883 | ||
|
|
03c1379d1b | ||
|
|
1635093341 | ||
|
|
93dcc4550a | ||
|
|
ab55da47b6 | ||
|
|
17971a5a3a | ||
|
|
e0b90e8f02 | ||
|
|
ea014d1362 | ||
|
|
6ef302b8a1 | ||
|
|
1e7afe3bec | ||
|
|
48508044d6 | ||
|
|
a4ad66f1c8 | ||
|
|
0f85a959bb | ||
|
|
d9a8adda1d | ||
|
|
ef4a8648a9 | ||
|
|
8bb72aa175 | ||
|
|
fa05dcf6ee | ||
|
|
8affa26858 | ||
|
|
856cb48170 | ||
|
|
1239fca567 | ||
|
|
6592a9afc7 | ||
|
|
7ffd96f425 | ||
|
|
906d9a47b1 | ||
|
|
0dff07dc8b | ||
|
|
9261d17dbe | ||
|
|
7d8a18bd20 | ||
|
|
29cb13cba6 | ||
|
|
52f375ac1e | ||
|
|
73f184df7e | ||
|
|
bbd631f08f | ||
|
|
cf315fb6ba | ||
|
|
c03a2caac2 | ||
|
|
9c2bc0b825 | ||
|
|
fcda8985fb | ||
|
|
14082f9332 | ||
|
|
83401eb245 | ||
|
|
022a98d4a4 | ||
|
|
bb1cca713d | ||
|
|
1d80a8d676 | ||
|
|
aa9c032176 | ||
|
|
baa8f229f7 | ||
|
|
ab1b99a4d9 | ||
|
|
11ff1880e5 | ||
|
|
71bf040715 | ||
|
|
6a04c6c7bd | ||
|
|
8530528dd5 | ||
|
|
e1d8992ec5 | ||
|
|
b03311e99d | ||
|
|
0c1138ee60 | ||
|
|
8a45292e24 | ||
|
|
d1712e9589 | ||
|
|
ec21afb426 | ||
|
|
882bff292e | ||
|
|
f3843a6b18 | ||
|
|
597c6c111d | ||
|
|
ac4957e15c | ||
|
|
f3915592b2 | ||
|
|
8a292fd9f3 | ||
|
|
f34936d9be | ||
|
|
d4367457a9 | ||
|
|
b4a43f1b85 | ||
|
|
3674808244 | ||
|
|
44cc978a94 | ||
|
|
f441ec2644 | ||
|
|
0ae13a2650 | ||
|
|
ee6596e21c | ||
|
|
a63147beda | ||
|
|
cdcf5808db | ||
|
|
d501c78795 | ||
|
|
e61ddc59c4 | ||
|
|
46e4f047de | ||
|
|
9cff5f2c5e | ||
|
|
5f031453d3 | ||
|
|
028216021f | ||
|
|
d6544302d3 | ||
|
|
bc529c5d09 | ||
|
|
354d1ddd5c | ||
|
|
28bf4e6e95 | ||
|
|
33b7faa17d | ||
|
|
ac731c0ff7 | ||
|
|
fd34dda6c1 | ||
|
|
16fca913de | ||
|
|
f989a82eb0 | ||
|
|
d410ecd34c | ||
|
|
48569265e2 | ||
|
|
ad43acf843 | ||
|
|
71782a6aa5 | ||
|
|
6df24d1a40 | ||
|
|
e283b0a1ce | ||
|
|
fa15193011 | ||
|
|
dff14c19f8 | ||
|
|
6103595b9c | ||
|
|
01c436ae15 | ||
|
|
c3a2539445 | ||
|
|
664ba8735f | ||
|
|
937036aa64 | ||
|
|
47cdf2b755 | ||
|
|
ef270764f3 | ||
|
|
a6edd40de3 | ||
|
|
4219c2c2ab | ||
|
|
4785de1a34 | ||
|
|
cbec624cd8 | ||
|
|
e7bde18f71 | ||
|
|
e9eeaee520 | ||
|
|
d5ec9fb38d | ||
|
|
233a776c41 | ||
|
|
d5f1c233bf | ||
|
|
af732d0495 | ||
|
|
04a87f951b | ||
|
|
9cc98919fa | ||
|
|
e42600632f | ||
|
|
93aa3fed16 | ||
|
|
49e76d1486 | ||
|
|
965bed7c4f | ||
|
|
317c6ba04c | ||
|
|
41d127934b | ||
|
|
915638d17a | ||
|
|
f73355abcc | ||
|
|
8f9da95e5e | ||
|
|
0935aa9221 | ||
|
|
aaa073afed | ||
|
|
9b606fb823 | ||
|
|
15d91c558b | ||
|
|
ffc5a78139 | ||
|
|
f8693074a3 | ||
|
|
1629f4f3f0 | ||
|
|
10baab38d3 | ||
|
|
e458c11e66 | ||
|
|
a07e3301b1 | ||
|
|
2b4d13c5b1 | ||
|
|
755e42836c | ||
|
|
ad743b0e96 | ||
|
|
0544901357 | ||
|
|
bc94633180 | ||
|
|
16415404c7 | ||
|
|
702d12d801 | ||
|
|
46eb01604c | ||
|
|
af36682a7e | ||
|
|
03d9e3db69 | ||
|
|
b03b3fccc7 | ||
|
|
9414e2979d | ||
|
|
865664425b |
No files matched your search
+3
-2
@@ -52,7 +52,7 @@ testing/cover/cover
|
|||||||
testing/runner/runner
|
testing/runner/runner
|
||||||
releases
|
releases
|
||||||
.*.uptodate
|
.*.uptodate
|
||||||
weave.tar.gz
|
weave*.tar.gz
|
||||||
prog/weaveexec/weave
|
prog/weaveexec/weave
|
||||||
prog/weaveexec/weavehosts
|
prog/weaveexec/weavehosts
|
||||||
prog/weaveexec/weaveproxy
|
prog/weaveexec/weaveproxy
|
||||||
@@ -61,9 +61,10 @@ prog/weaveexec/weavewait_noop
|
|||||||
prog/weaveexec/weavewait_nomcast
|
prog/weaveexec/weavewait_nomcast
|
||||||
prog/weaveexec/sigproxy
|
prog/weaveexec/sigproxy
|
||||||
prog/weaveexec/weaveutil
|
prog/weaveexec/weaveutil
|
||||||
prog/weaveexec/docker*.tgz
|
prog/weaveexec/docker*
|
||||||
Vagrantfile.local
|
Vagrantfile.local
|
||||||
test/tls/tls
|
test/tls/tls
|
||||||
test/tls/*.pem
|
test/tls/*.pem
|
||||||
test/coverage
|
test/coverage
|
||||||
test/coverage.*
|
test/coverage.*
|
||||||
|
*qemu-*-static
|
||||||
+10
-4
@@ -3,7 +3,7 @@
|
|||||||
url = https://github.com/weaveworks/build-tools
|
url = https://github.com/weaveworks/build-tools
|
||||||
[submodule "vendor/github.com/vishvananda/netlink"]
|
[submodule "vendor/github.com/vishvananda/netlink"]
|
||||||
path = vendor/github.com/vishvananda/netlink
|
path = vendor/github.com/vishvananda/netlink
|
||||||
url = https://github.com/vishvananda/netlink.git
|
url = https://github.com/weaveworks/netlink.git
|
||||||
[submodule "vendor/github.com/gorilla/mux"]
|
[submodule "vendor/github.com/gorilla/mux"]
|
||||||
path = vendor/github.com/gorilla/mux
|
path = vendor/github.com/gorilla/mux
|
||||||
url = https://github.com/gorilla/mux.git
|
url = https://github.com/gorilla/mux.git
|
||||||
@@ -79,9 +79,6 @@
|
|||||||
[submodule "vendor/golang.org/x/sys"]
|
[submodule "vendor/golang.org/x/sys"]
|
||||||
path = vendor/golang.org/x/sys
|
path = vendor/golang.org/x/sys
|
||||||
url = https://go.googlesource.com/sys
|
url = https://go.googlesource.com/sys
|
||||||
[submodule "vendor/github.com/weaveworks/docker"]
|
|
||||||
path = vendor/github.com/weaveworks/docker
|
|
||||||
url = https://github.com/weaveworks/docker
|
|
||||||
[submodule "vendor/github.com/beorn7/perks"]
|
[submodule "vendor/github.com/beorn7/perks"]
|
||||||
path = vendor/github.com/beorn7/perks
|
path = vendor/github.com/beorn7/perks
|
||||||
url = https://github.com/beorn7/perks
|
url = https://github.com/beorn7/perks
|
||||||
@@ -118,3 +115,12 @@
|
|||||||
[submodule "vendor/github.com/spf13/pflag"]
|
[submodule "vendor/github.com/spf13/pflag"]
|
||||||
path = vendor/github.com/spf13/pflag
|
path = vendor/github.com/spf13/pflag
|
||||||
url = https://github.com/spf13/pflag
|
url = https://github.com/spf13/pflag
|
||||||
|
[submodule "vendor/github.com/mgutz/ansi"]
|
||||||
|
path = vendor/github.com/mgutz/ansi
|
||||||
|
url = https://github.com/mgutz/ansi
|
||||||
|
[submodule "vendor/github.com/estesp/manifest-tool"]
|
||||||
|
path = vendor/github.com/estesp/manifest-tool
|
||||||
|
url = https://github.com/estesp/manifest-tool
|
||||||
|
[submodule "vendor/github.com/weaveworks/common"]
|
||||||
|
path = vendor/github.com/weaveworks/common
|
||||||
|
url = https://github.com/weaveworks/common
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# IMPORTANT: Please only use GLOBs to ignore files and directories.
|
||||||
|
|
||||||
|
# Do not lint any bash script in Weave Net, in order to
|
||||||
|
# avoid breaking the build on make lint:
|
||||||
|
*.sh
|
||||||
|
bin/*
|
||||||
|
prog/weaveexec/symlink
|
||||||
|
weave
|
||||||
@@ -1,3 +1,62 @@
|
|||||||
|
## Release 1.9.0
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
|
||||||
|
* Encryption is now available for Fast Datapath connections, which
|
||||||
|
greatly improves the performance. #1644,#2687
|
||||||
|
* We now build images for Intel/AMD 64-bit, ARM and ARM 64-bit. #2713
|
||||||
|
* Weave Net Docker images are now labelled with description, vendor, etc. #2712
|
||||||
|
* `weave status connections` now shows the MTU #2389,#2663
|
||||||
|
* CNI plugin is now a stand-alone binary that does not depend on Docker #2594,#2662
|
||||||
|
* Embedded docker client updated to version 1.10.3 #2395
|
||||||
|
|
||||||
|
**NOTE:** The move to multi-architecture required that we update the
|
||||||
|
embedded Docker client, and this has the effect that this release of
|
||||||
|
Weave Net will not work with Docker installations older than
|
||||||
|
1.10.
|
||||||
|
|
||||||
|
[Full list of changes](https://github.com/weaveworks/weave/issues?q=milestone%3A1.9.0).
|
||||||
|
|
||||||
|
## Release 1.8.2
|
||||||
|
|
||||||
|
Bug fixes and minor improvements
|
||||||
|
|
||||||
|
* Fixed a bug where looping flows were installed which caused high CPU
|
||||||
|
usage #2650, #2674
|
||||||
|
* Fixed a bug where Kubernetes master could not contact pods #2673, #2683
|
||||||
|
* Fixed a bug where weave-kube was crashing in a loop due to invalid
|
||||||
|
Weave bridge state #2657
|
||||||
|
* Fixed a bug where iptables NAT rules were not appended due to
|
||||||
|
"temporary unavailable" iptables error #2679
|
||||||
|
* Added a detection of enabling the hairpin mode on the Weave bridge port
|
||||||
|
which caused installation of looping flows #2674
|
||||||
|
* Added a detection of overlaps between Weave and the host IP address
|
||||||
|
ranges when launching weave-kube #2669, #2672
|
||||||
|
* Added logging of connections blocked by weave-npc #2546, #2573
|
||||||
|
|
||||||
|
More details in the [change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.8.2).
|
||||||
|
|
||||||
|
## Release 1.8.1
|
||||||
|
|
||||||
|
Bug fixes and minor improvements
|
||||||
|
|
||||||
|
* Fixed weave-npc crash from Succeeded/Failed pods #2632,#2658
|
||||||
|
* Fixed occasional failure to create Weave bridge on node reboot
|
||||||
|
#2617,#2637
|
||||||
|
* Fixed a bug where weave-kube would fail to install when run with
|
||||||
|
unrelease snapshot builds #2642
|
||||||
|
* Improved conformance to CNI spec by not releasing IP addresses when
|
||||||
|
a container dies #2643
|
||||||
|
* Improved troubleshooting of install failure by creating CNI config
|
||||||
|
after Weave Net is up #2570
|
||||||
|
* "up to date" shown even when the version check was blocked by
|
||||||
|
firewall #2537,#2565,#2645
|
||||||
|
* "Unable to claim" message on re-launching Weave after using CNI
|
||||||
|
#2548,#2577
|
||||||
|
* Eliminated spurious IP reclaim operations when IPAM was disabled
|
||||||
|
#2567,#2644
|
||||||
|
* Include `jq` tool in our build VM configuration #2656
|
||||||
|
|
||||||
## Release 1.8.0
|
## Release 1.8.0
|
||||||
|
|
||||||
Highlights:
|
Highlights:
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
PUBLISH=publish_weave publish_weaveexec publish_plugin publish_weave-kube publish_weave-npc
|
|
||||||
|
|
||||||
.DEFAULT: all
|
.DEFAULT: all
|
||||||
.PHONY: all exes testrunner update tests lint publish $(PUBLISH) clean clean-bin prerequisites build run-smoketests
|
.PHONY: all exes testrunner update tests lint publish-one-arch $(PUBLISH) clean clean-bin prerequisites build run-smoketests
|
||||||
|
|
||||||
# If you can use docker without being root, you can do "make SUDO="
|
# If you can use docker without being root, you can do "make SUDO="
|
||||||
SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E")
|
SUDO=$(shell docker info >/dev/null 2>&1 || echo "sudo -E")
|
||||||
@@ -10,9 +8,82 @@ RM=--rm
|
|||||||
RUN_FLAGS=-ti
|
RUN_FLAGS=-ti
|
||||||
COVERAGE=
|
COVERAGE=
|
||||||
|
|
||||||
DOCKERHUB_USER=weaveworks
|
# This specifies the architecture we're building for
|
||||||
WEAVE_VERSION=git-$(shell git rev-parse --short=12 HEAD)
|
ARCH?=amd64
|
||||||
|
|
||||||
|
# We're using QEMU to be able to build Docker images for other architectures
|
||||||
|
# from amd64 machines.
|
||||||
|
QEMU_VERSION=v2.7.0
|
||||||
|
|
||||||
|
# A list of all supported architectures here. Should be named as Go is naming platforms
|
||||||
|
# All supported architectures must have an "ifeq" block below that customizes the parameters
|
||||||
|
ALL_ARCHITECTURES=amd64 arm arm64
|
||||||
|
ML_PLATFORMS=linux/amd64,linux/arm,linux/arm64
|
||||||
|
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
# The architecture to use when downloading the docker binary
|
||||||
|
WEAVEEXEC_DOCKER_ARCH?=x86_64
|
||||||
|
|
||||||
|
# The name of the alpine baseimage to use as the base for weave images
|
||||||
|
ALPINE_BASEIMAGE?=alpine:3.4
|
||||||
|
|
||||||
|
# The extension for the made images
|
||||||
|
# Specifying none means for example weaveworks/weave:latest
|
||||||
|
ARCH_EXT?=
|
||||||
|
|
||||||
|
# The name of the gcc we're using for compiling C code
|
||||||
|
CC=gcc
|
||||||
|
|
||||||
|
# Optional parameters that can be passed when linking C code into the Go binary
|
||||||
|
CGO_LDFLAGS=
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),arm)
|
||||||
|
# The architecture to use when downloading the docker binary
|
||||||
|
WEAVEEXEC_DOCKER_ARCH?=armel
|
||||||
|
|
||||||
|
# Using the (semi-)official alpine image
|
||||||
|
ALPINE_BASEIMAGE?=armhf/alpine:3.4
|
||||||
|
|
||||||
|
# arm images have the -arm suffix, for instance weaveworks/weave-arm:latest
|
||||||
|
ARCH_EXT?=-arm
|
||||||
|
|
||||||
|
# The name of the gcc binary
|
||||||
|
CC=arm-linux-gnueabihf-gcc
|
||||||
|
|
||||||
|
# The architecture name to use when downloading a prebuilt QEMU binary
|
||||||
|
QEMUARCH=arm
|
||||||
|
|
||||||
|
# In the weaveworks/build image; libpcap libraries for arm are placed here
|
||||||
|
# Tell the gcc linker to search for libpcap here
|
||||||
|
CGO_LDFLAGS="-L/usr/local/lib/$(CC)"
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),arm64)
|
||||||
|
# Use the arm 32-bit docker client variant
|
||||||
|
WEAVEEXEC_DOCKER_ARCH?=armel
|
||||||
|
|
||||||
|
# Using the (semi-)official alpine image
|
||||||
|
ALPINE_BASEIMAGE?=aarch64/alpine:3.5
|
||||||
|
|
||||||
|
# arm64 images have the -arm64 suffix, for instance weaveworks/weave-arm64:latest
|
||||||
|
ARCH_EXT?=-arm64
|
||||||
|
|
||||||
|
# The name of the gcc binary
|
||||||
|
CC=aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
# The architecture name to use when downloading a prebuilt QEMU binary
|
||||||
|
QEMUARCH=aarch64
|
||||||
|
|
||||||
|
# In the weaveworks/build image; libpcap libraries for arm64 are placed here
|
||||||
|
# Tell the gcc linker to search for libpcap here
|
||||||
|
CGO_LDFLAGS="-L/usr/local/lib/$(CC)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
# The name of the user that this Makefile should produce image artifacts for. Can/should be overridden
|
||||||
|
DOCKERHUB_USER?=weaveworks
|
||||||
|
# The default version that's chosen when pushing the images. Can/should be overridden
|
||||||
|
WEAVE_VERSION?=git-$(shell git rev-parse --short=12 HEAD)
|
||||||
|
|
||||||
|
# Paths to all relevant binaries that should be compiled
|
||||||
WEAVER_EXE=prog/weaver/weaver
|
WEAVER_EXE=prog/weaver/weaver
|
||||||
WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy
|
WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy
|
||||||
SIGPROXY_EXE=prog/sigproxy/sigproxy
|
SIGPROXY_EXE=prog/sigproxy/sigproxy
|
||||||
@@ -24,35 +95,43 @@ WEAVEWAIT_NOMCAST_EXE=prog/weavewait/weavewait_nomcast
|
|||||||
WEAVEUTIL_EXE=prog/weaveutil/weaveutil
|
WEAVEUTIL_EXE=prog/weaveutil/weaveutil
|
||||||
PLUGIN_EXE=prog/plugin/plugin
|
PLUGIN_EXE=prog/plugin/plugin
|
||||||
RUNNER_EXE=tools/runner/runner
|
RUNNER_EXE=tools/runner/runner
|
||||||
|
MANIFEST_TOOL_DIR=vendor/github.com/estesp/manifest-tool
|
||||||
|
MANIFEST_TOOL_EXE=$(MANIFEST_TOOL_DIR)/manifest-tool
|
||||||
TEST_TLS_EXE=test/tls/tls
|
TEST_TLS_EXE=test/tls/tls
|
||||||
|
|
||||||
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(PLUGIN_EXE) $(TEST_TLS_EXE)
|
# All binaries together in a list
|
||||||
|
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(KUBEPEERS_EXE) $(WEAVENPC_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE) $(PLUGIN_EXE) $(RUNNER_EXE) $(TEST_TLS_EXE) $(MANIFEST_TOOL_EXE)
|
||||||
|
|
||||||
|
# These stamp files are used to mark the current state of the build; whether an image has been built or not
|
||||||
BUILD_UPTODATE=.build.uptodate
|
BUILD_UPTODATE=.build.uptodate
|
||||||
WEAVER_UPTODATE=.weaver.uptodate
|
WEAVER_UPTODATE=.weaver$(ARCH_EXT).uptodate
|
||||||
WEAVEEXEC_UPTODATE=.weaveexec.uptodate
|
WEAVEEXEC_UPTODATE=.weaveexec$(ARCH_EXT).uptodate
|
||||||
PLUGIN_UPTODATE=.plugin.uptodate
|
PLUGIN_UPTODATE=.plugin$(ARCH_EXT).uptodate
|
||||||
WEAVEKUBE_UPTODATE=.weavekube.uptodate
|
WEAVEKUBE_UPTODATE=.weavekube$(ARCH_EXT).uptodate
|
||||||
WEAVENPC_UPTODATE=.weavenpc.uptodate
|
WEAVENPC_UPTODATE=.weavenpc$(ARCH_EXT).uptodate
|
||||||
WEAVEDB_UPTODATE=.weavedb.uptodate
|
WEAVEDB_UPTODATE=.weavedb.uptodate
|
||||||
|
|
||||||
IMAGES_UPTODATE=$(WEAVER_UPTODATE) $(WEAVEEXEC_UPTODATE) $(PLUGIN_UPTODATE) $(WEAVEKUBE_UPTODATE) $(WEAVENPC_UPTODATE) $(WEAVEDB_UPTODATE)
|
IMAGES_UPTODATE=$(WEAVER_UPTODATE) $(WEAVEEXEC_UPTODATE) $(PLUGIN_UPTODATE) $(WEAVEKUBE_UPTODATE) $(WEAVENPC_UPTODATE)
|
||||||
|
|
||||||
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave
|
# The names of the images. Note that the images for other architectures than amd64 have a suffix in the image name.
|
||||||
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec
|
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave$(ARCH_EXT)
|
||||||
PLUGIN_IMAGE=$(DOCKERHUB_USER)/plugin
|
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec$(ARCH_EXT)
|
||||||
WEAVEKUBE_IMAGE=$(DOCKERHUB_USER)/weave-kube
|
PLUGIN_IMAGE=$(DOCKERHUB_USER)/plugin$(ARCH_EXT)
|
||||||
WEAVENPC_IMAGE=$(DOCKERHUB_USER)/weave-npc
|
WEAVEKUBE_IMAGE=$(DOCKERHUB_USER)/weave-kube$(ARCH_EXT)
|
||||||
BUILD_IMAGE=$(DOCKERHUB_USER)/weavebuild
|
WEAVENPC_IMAGE=$(DOCKERHUB_USER)/weave-npc$(ARCH_EXT)
|
||||||
|
BUILD_IMAGE=weaveworks/weavebuild
|
||||||
WEAVEDB_IMAGE=$(DOCKERHUB_USER)/weavedb
|
WEAVEDB_IMAGE=$(DOCKERHUB_USER)/weavedb
|
||||||
|
|
||||||
IMAGES=$(WEAVER_IMAGE) $(WEAVEEXEC_IMAGE) $(PLUGIN_IMAGE) $(WEAVEKUBE_IMAGE) $(WEAVENPC_IMAGE) $(WEAVEDB_IMAGE)
|
IMAGES=$(WEAVER_IMAGE) $(WEAVEEXEC_IMAGE) $(PLUGIN_IMAGE) $(WEAVEKUBE_IMAGE) $(WEAVENPC_IMAGE) $(WEAVEDB_IMAGE)
|
||||||
|
|
||||||
WEAVE_EXPORT=weave.tar.gz
|
PUBLISH=publish_weave publish_weaveexec publish_plugin publish_weave-kube publish_weave-npc
|
||||||
|
PUSH_ML=push_ml_weave push_ml_weaveexec push_ml_plugin push_ml_weave-kube push_ml_weave-npc
|
||||||
|
|
||||||
WEAVEEXEC_DOCKER_VERSION=1.6.2
|
WEAVE_EXPORT=weave$(ARCH_EXT).tar.gz
|
||||||
DOCKER_DISTRIB=prog/weaveexec/docker-$(WEAVEEXEC_DOCKER_VERSION).tgz
|
|
||||||
DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/x86_64/docker-$(WEAVEEXEC_DOCKER_VERSION).tgz
|
DOCKER_VERSION=1.10.3
|
||||||
|
DOCKER_DISTRIB=prog/weaveexec/docker-$(DOCKER_VERSION).tgz
|
||||||
|
DOCKER_DISTRIB_URL=https://get.docker.com/builds/Linux/$(WEAVEEXEC_DOCKER_ARCH)/docker-$(DOCKER_VERSION).tgz
|
||||||
NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
|
NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
|
||||||
rm $@; \
|
rm $@; \
|
||||||
echo "\nYour go standard library was built without the 'netgo' build tag."; \
|
echo "\nYour go standard library was built without the 'netgo' build tag."; \
|
||||||
@@ -61,6 +140,9 @@ NETGO_CHECK=@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
|
|||||||
echo " sudo go install -tags netgo std"; \
|
echo " sudo go install -tags netgo std"; \
|
||||||
false; \
|
false; \
|
||||||
}
|
}
|
||||||
|
# The flags we are passing to go build. -extldflags -static for making a static binary,
|
||||||
|
# -linkmode external for linking external C libraries into the binary, -X main.version for telling the
|
||||||
|
# Go binary which version it is, -tags netgo for enforcing the native Go DNS resolver
|
||||||
BUILD_FLAGS=-i -ldflags "-linkmode external -extldflags -static -X main.version=$(WEAVE_VERSION)" -tags netgo
|
BUILD_FLAGS=-i -ldflags "-linkmode external -extldflags -static -X main.version=$(WEAVE_VERSION)" -tags netgo
|
||||||
|
|
||||||
PACKAGE_BASE=$(shell go list -e ./)
|
PACKAGE_BASE=$(shell go list -e ./)
|
||||||
@@ -71,12 +153,14 @@ testrunner: $(RUNNER_EXE) $(TEST_TLS_EXE)
|
|||||||
$(WEAVER_EXE) $(WEAVEPROXY_EXE) $(WEAVEUTIL_EXE): common/*.go common/*/*.go net/*.go net/*/*.go
|
$(WEAVER_EXE) $(WEAVEPROXY_EXE) $(WEAVEUTIL_EXE): common/*.go common/*/*.go net/*.go net/*/*.go
|
||||||
$(WEAVER_EXE): router/*.go ipam/*.go ipam/*/*.go db/*.go nameserver/*.go prog/weaver/*.go
|
$(WEAVER_EXE): router/*.go ipam/*.go ipam/*/*.go db/*.go nameserver/*.go prog/weaver/*.go
|
||||||
$(WEAVEPROXY_EXE): proxy/*.go prog/weaveproxy/*.go
|
$(WEAVEPROXY_EXE): proxy/*.go prog/weaveproxy/*.go
|
||||||
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go
|
$(WEAVEUTIL_EXE): prog/weaveutil/*.go net/*.go plugin/net/*.go plugin/ipam/*.go db/*.go
|
||||||
$(SIGPROXY_EXE): prog/sigproxy/*.go
|
$(SIGPROXY_EXE): prog/sigproxy/*.go
|
||||||
$(KUBEPEERS_EXE): prog/kube-peers/*.go
|
$(KUBEPEERS_EXE): prog/kube-peers/*.go
|
||||||
$(WEAVENPC_EXE): prog/weave-npc/*.go npc/*.go npc/*/*.go
|
$(WEAVENPC_EXE): prog/weave-npc/*.go npc/*.go npc/*/*.go
|
||||||
$(PLUGIN_EXE): prog/plugin/*.go plugin/*/*.go api/*.go common/*.go common/docker/*.go net/*.go
|
$(PLUGIN_EXE): prog/plugin/*.go plugin/*/*.go api/*.go common/*.go common/docker/*.go net/*.go
|
||||||
$(TEST_TLS_EXE): test/tls/*.go
|
$(TEST_TLS_EXE): test/tls/*.go
|
||||||
|
$(RUNNER_EXE): tools/runner/*.go
|
||||||
|
$(MANIFEST_TOOL_EXE): $(MANIFEST_TOOL_DIR)/*.go
|
||||||
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
|
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
|
||||||
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
|
$(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
|
||||||
$(WEAVEWAIT_NOMCAST_EXE): prog/weavewait/*.go net/*.go
|
$(WEAVEWAIT_NOMCAST_EXE): prog/weavewait/*.go net/*.go
|
||||||
@@ -85,14 +169,16 @@ lint: tools/.git
|
|||||||
|
|
||||||
ifeq ($(BUILD_IN_CONTAINER),true)
|
ifeq ($(BUILD_IN_CONTAINER),true)
|
||||||
|
|
||||||
|
# This make target compiles all binaries inside of the weaveworks/build container
|
||||||
|
# It bind-mounts the source into the container and passes all important variables
|
||||||
exes $(EXES) tests lint: $(BUILD_UPTODATE)
|
exes $(EXES) tests lint: $(BUILD_UPTODATE)
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
@mkdir -p $(shell pwd)/.pkg
|
@mkdir -p $(shell pwd)/.pkg
|
||||||
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
|
$(SUDO) docker run $(RM) $(RUN_FLAGS) \
|
||||||
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
|
-v $(shell pwd):/go/src/github.com/weaveworks/weave \
|
||||||
-v $(shell pwd)/.pkg:/go/pkg \
|
-v $(shell pwd)/.pkg:/go/pkg \
|
||||||
-e GOARCH -e GOOS -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX -e COVERDIR -e SLOW \
|
-e GOARCH=$(ARCH) -e CGO_ENABLED=1 -e GOOS=linux -e CIRCLECI -e CIRCLE_BUILD_NUM -e CIRCLE_NODE_TOTAL -e CIRCLE_NODE_INDEX -e COVERDIR -e SLOW -e DEBUG \
|
||||||
$(BUILD_IMAGE) COVERAGE=$(COVERAGE) WEAVE_VERSION=$(WEAVE_VERSION) $@
|
$(BUILD_IMAGE) COVERAGE=$(COVERAGE) WEAVE_VERSION=$(WEAVE_VERSION) CC=$(CC) QEMUARCH=$(QEMUARCH) CGO_LDFLAGS=$(CGO_LDFLAGS) $@
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@@ -121,29 +207,48 @@ $(WEAVEWAIT_NOMCAST_EXE):
|
|||||||
|
|
||||||
# These programs need a separate rule as they fail the netgo check in
|
# These programs need a separate rule as they fail the netgo check in
|
||||||
# the main build stanza due to not importing net package
|
# the main build stanza due to not importing net package
|
||||||
$(SIGPROXY_EXE) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE):
|
$(SIGPROXY_EXE) $(TEST_TLS_EXE) $(WEAVEWAIT_NOOP_EXE) $(RUNNER_EXE) $(MANIFEST_TOOL_EXE):
|
||||||
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
go build $(BUILD_FLAGS) -o $@ ./$(@D)
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
./tools/test -no-go-get
|
./tools/test -no-go-get -netgo -timeout 8m
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
./tools/lint -nocomment -notestpackage .
|
./tools/lint -nocomment -notestpackage .
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# This rule makes sure the build image is up-to-date.
|
||||||
|
# It also makes sure the multiarch hooks are reqistered in the kernel so the QEMU emulation works
|
||||||
$(BUILD_UPTODATE): build/*
|
$(BUILD_UPTODATE): build/*
|
||||||
$(SUDO) docker build -t $(BUILD_IMAGE) build/
|
$(SUDO) docker build -t $(BUILD_IMAGE) build/
|
||||||
|
$(SUDO) docker run --rm --privileged multiarch/qemu-user-static:register --reset
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
# Creates the Dockerfile.your-user-here file from the template
|
||||||
|
# Also replaces all placeholders with real values
|
||||||
|
# If the architecture is amd64, it deletes all CROSS_BUILD lines
|
||||||
|
# but otherwise, it only removes the "CROSS_BUILD_" placeholder and downloads QEMU
|
||||||
%/Dockerfile.$(DOCKERHUB_USER): %/Dockerfile.template
|
%/Dockerfile.$(DOCKERHUB_USER): %/Dockerfile.template
|
||||||
sed -e "s/DOCKERHUB_USER/$(DOCKERHUB_USER)/" $^ > $@
|
echo "DOCKERHUB_USER|$(DOCKERHUB_USER)|g;s|ARCH_EXT|$(ARCH_EXT)|g;s|ALPINE_BASEIMAGE|$(ALPINE_BASEIMAGE)|g;s|QEMUARCH|$(QEMUARCH)"
|
||||||
|
sed -e "s|DOCKERHUB_USER|$(DOCKERHUB_USER)|g;s|ARCH_EXT|$(ARCH_EXT)|g;s|ALPINE_BASEIMAGE|$(ALPINE_BASEIMAGE)|g;s|QEMUARCH|$(QEMUARCH)|g" $^ > $@
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
# When building "normally" for amd64, remove the whole line, it has no part in the amd64 image
|
||||||
|
sed -i "/CROSS_BUILD_/d" $@
|
||||||
|
else
|
||||||
|
# When cross-building, only the placeholder "CROSS_BUILD_" should be removed
|
||||||
|
# Register /usr/bin/qemu-ARCH-static as the handler for ARM binaries in the kernel
|
||||||
|
curl -sSL https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/x86_64_qemu-$(QEMUARCH)-static.tar.gz | tar -xz -C $(shell dirname $@)
|
||||||
|
cd $(shell dirname $@) && sha256sum -c $(shell pwd)/build/shasums/qemu-$(QEMUARCH)-static.sha256sum
|
||||||
|
sed -i "s/CROSS_BUILD_//g" $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
# The targets below builds the weave images
|
||||||
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) $(WEAVEEXEC_UPTODATE)
|
$(WEAVER_UPTODATE): prog/weaver/Dockerfile.$(DOCKERHUB_USER) $(WEAVER_EXE) $(WEAVEEXEC_UPTODATE)
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaver/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVER_IMAGE) prog/weaver
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaver/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVER_IMAGE) prog/weaver
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile prog/weaveexec/symlink $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE)
|
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) prog/weaveexec/symlink $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(WEAVEWAIT_NOMCAST_EXE) $(WEAVEUTIL_EXE)
|
||||||
cp weave prog/weaveexec/weave
|
cp weave prog/weaveexec/weave
|
||||||
cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy
|
cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy
|
||||||
cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy
|
cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy
|
||||||
@@ -151,8 +256,9 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile prog/weaveexec/symlink $(DOCKER
|
|||||||
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
|
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
|
||||||
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
|
cp $(WEAVEWAIT_NOMCAST_EXE) prog/weaveexec/weavewait_nomcast
|
||||||
cp $(WEAVEUTIL_EXE) prog/weaveexec/weaveutil
|
cp $(WEAVEUTIL_EXE) prog/weaveexec/weaveutil
|
||||||
cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz
|
tar -xf $(DOCKER_DISTRIB) usr/local/bin/docker -O > prog/weaveexec/docker
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec
|
chmod +x prog/weaveexec/docker
|
||||||
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -f prog/weaveexec/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEEXEC_IMAGE) prog/weaveexec
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(PLUGIN_UPTODATE): prog/plugin/Dockerfile.$(DOCKERHUB_USER) $(PLUGIN_EXE) $(WEAVER_UPTODATE)
|
$(PLUGIN_UPTODATE): prog/plugin/Dockerfile.$(DOCKERHUB_USER) $(PLUGIN_EXE) $(WEAVER_UPTODATE)
|
||||||
@@ -164,45 +270,87 @@ $(WEAVEKUBE_UPTODATE): prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) prog/weave-k
|
|||||||
$(SUDO) docker build -f prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEKUBE_IMAGE) prog/weave-kube
|
$(SUDO) docker build -f prog/weave-kube/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVEKUBE_IMAGE) prog/weave-kube
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVENPC_UPTODATE): prog/weave-npc/Dockerfile $(WEAVENPC_EXE) prog/weave-npc/ulogd.conf
|
$(WEAVENPC_UPTODATE): prog/weave-npc/Dockerfile.$(DOCKERHUB_USER) $(WEAVENPC_EXE) prog/weave-npc/ulogd.conf
|
||||||
$(SUDO) docker build -f prog/weave-npc/Dockerfile -t $(WEAVENPC_IMAGE) prog/weave-npc
|
$(SUDO) docker build -f prog/weave-npc/Dockerfile.$(DOCKERHUB_USER) -t $(WEAVENPC_IMAGE) prog/weave-npc
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVEDB_UPTODATE): prog/weavedb/Dockerfile
|
$(WEAVEDB_UPTODATE): prog/weavedb/Dockerfile
|
||||||
$(SUDO) docker build -t $(WEAVEDB_IMAGE) prog/weavedb
|
$(SUDO) docker build -t $(WEAVEDB_IMAGE) prog/weavedb
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(WEAVE_EXPORT): $(IMAGES_UPTODATE)
|
$(WEAVE_EXPORT): $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE)
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker save $(addsuffix :latest,$(IMAGES)) | gzip > $@
|
||||||
|
|
||||||
$(DOCKER_DISTRIB):
|
$(DOCKER_DISTRIB):
|
||||||
curl -o $(DOCKER_DISTRIB) $(DOCKER_DISTRIB_URL)
|
curl -o $(DOCKER_DISTRIB) $(DOCKER_DISTRIB_URL)
|
||||||
|
cd $(shell dirname $@) && sha256sum -c $(shell pwd)/build/shasums/docker-tgz-$(WEAVEEXEC_DOCKER_ARCH).sha256sum
|
||||||
|
|
||||||
tools/.git:
|
tools/.git $(MANIFEST_TOOL_DIR)/.git:
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
||||||
$(RUNNER_EXE): tools/.git
|
# CODE FOR PUBLISHING THE IMAGES
|
||||||
GO15VENDOREXPERIMENT=1 make -C tools/runner
|
|
||||||
|
|
||||||
|
# This target first runs "make publish" for each architecture
|
||||||
|
# Then it pushes the manifest lists
|
||||||
|
publish: $(addprefix sub-publish-,$(ALL_ARCHITECTURES)) $(WEAVEDB_UPTODATE)
|
||||||
|
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) $(PUSH_ML)
|
||||||
|
ifeq ($(PUBLISH_WEAVEDB),true)
|
||||||
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/weavedb:latest
|
||||||
|
endif
|
||||||
|
|
||||||
|
sub-publish-%:
|
||||||
|
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) clean-bin
|
||||||
|
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) $(IMAGES_UPTODATE)
|
||||||
|
$(MAKE) ARCH=$* DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) publish-one-arch
|
||||||
|
|
||||||
|
publish-one-arch: $(PUBLISH)
|
||||||
|
|
||||||
|
# This rule handles the pushing of the built images
|
||||||
$(PUBLISH): publish_%: $(IMAGES_UPTODATE)
|
$(PUBLISH): publish_%: $(IMAGES_UPTODATE)
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$* $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
# Tag :latest with the real version
|
||||||
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*$(ARCH_EXT) $(DOCKERHUB_USER)/$*$(ARCH_EXT):$(WEAVE_VERSION)
|
||||||
|
# Push the image with the arch suffix for arm and arm64, and without suffix for amd64
|
||||||
|
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) push_$*$(ARCH_EXT)
|
||||||
|
|
||||||
|
ifeq ($(ARCH),amd64)
|
||||||
|
# If the architecture is amd64, add the -amd64 suffix.
|
||||||
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION) $(DOCKERHUB_USER)/$*-amd64:$(WEAVE_VERSION)
|
||||||
|
# If the version is latest, tag the -amd64 with latest as well
|
||||||
|
ifneq ($(UPDATE_LATEST),false)
|
||||||
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker tag $(DOCKERHUB_USER)/$*-amd64:$(WEAVE_VERSION) $(DOCKERHUB_USER)/$*-amd64:latest
|
||||||
|
endif
|
||||||
|
# Push the image with the -amd64-suffix so BINARY-ARCH-named images exist for all arches, so manifest lists may be made and ARCH is replaceable in scripts
|
||||||
|
$(MAKE) DOCKER_HOST=$(DOCKER_HOST) DOCKERHUB_USER=$(DOCKERHUB_USER) WEAVE_VERSION=$(WEAVE_VERSION) UPDATE_LATEST=$(UPDATE_LATEST) push_$*-amd64
|
||||||
|
endif
|
||||||
|
|
||||||
|
# This target pushes an image, and if UPDATE_LATEST is anything but false, also updates the latest tag
|
||||||
|
# It takes one parameter, the image name
|
||||||
|
push_%:
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
||||||
ifneq ($(UPDATE_LATEST),false)
|
ifneq ($(UPDATE_LATEST),false)
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:latest
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/$*:latest
|
||||||
endif
|
endif
|
||||||
|
|
||||||
publish: $(PUBLISH)
|
# This target pushes a manifest list; it takes one parameter, the image name.
|
||||||
ifeq ($(PUBLISH_WEAVEDB),true)
|
# The variable UPDATE_LATEST controls whether it updates the versioned tag and/or the latest tag
|
||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker push $(DOCKERHUB_USER)/weavedb:latest
|
$(PUSH_ML): push_ml_%: $(MANIFEST_TOOL_EXE)
|
||||||
|
ifneq ($(UPDATE_LATEST),latest-only)
|
||||||
|
$(MANIFEST_TOOL_EXE) push from-args --platforms $(ML_PLATFORMS) --template $(DOCKERHUB_USER)/$*-ARCH:$(WEAVE_VERSION) --target $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION)
|
||||||
|
endif
|
||||||
|
ifneq ($(UPDATE_LATEST),false)
|
||||||
|
# Push the manifest list to :latest as well
|
||||||
|
$(MANIFEST_TOOL_EXE) push from-args --platforms $(ML_PLATFORMS) --template $(DOCKERHUB_USER)/$*-ARCH:latest --target $(DOCKERHUB_USER)/$*:latest
|
||||||
endif
|
endif
|
||||||
|
|
||||||
clean-bin:
|
clean-bin:
|
||||||
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(IMAGES)
|
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(IMAGES)
|
||||||
rm -rf $(EXES) $(IMAGES_UPTODATE) $(WEAVE_EXPORT) .pkg
|
find prog -type f -name "Dockerfile.*" -not -name "Dockerfile.template" -print | xargs rm -f
|
||||||
|
find prog -type f -name "*qemu-*" -print | xargs rm -f
|
||||||
|
rm -rf $(EXES) $(IMAGES_UPTODATE) $(WEAVEDB_UPTODATE) weave*.tar.gz $(DOCKER_DISTRIB) prog/weaveexec/docker .pkg
|
||||||
|
|
||||||
clean: clean-bin
|
clean: clean-bin
|
||||||
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(BUILD_IMAGE)
|
-$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker rmi $(BUILD_IMAGE)
|
||||||
rm -rf test/tls/*.pem test/coverage.* test/coverage $(BUILD_UPTODATE)
|
rm -rf test/tls/*.pem test/coverage.* test/coverage $(BUILD_UPTODATE) $(MANIFEST_TOOL_EXE)
|
||||||
|
|
||||||
build:
|
build:
|
||||||
$(SUDO) go clean -i net
|
$(SUDO) go clean -i net
|
||||||
|
|||||||
@@ -11,9 +11,11 @@
|
|||||||
[Weaveworks](https://www.weave.works) is the company that delivers the most productive way for developers to connect, observe and control
|
[Weaveworks](https://www.weave.works) is the company that delivers the most productive way for developers to connect, observe and control
|
||||||
Docker containers.
|
Docker containers.
|
||||||
|
|
||||||
This repository contains [Weave Net](https://www.weave.works/products/weave-net/), the first product developed by Weaveworks, and with nearly 5 million downloads to date, it enables you to get started with Docker clusters and portable apps in a fraction of the time compared with other solutions.
|
This repository contains [Weave Net](https://www.weave.works/products/weave-net/), the first product developed by Weaveworks, and with over 8 million downloads to date, it enables you to get started with Docker clusters and portable apps in a fraction of the time compared with other solutions.
|
||||||
|
|
||||||
Other products from Weaveworks include [Weave Scope](https://www.weave.works/products/weave-scope/), a powerful container monitoring tool that automatically maps Docker containers and their interactions, and [Weave Flux](https://www.weave.works/products/weave-flux/), a microservice router that automates the access of containers as services.
|
Weaveworks' product [Weave Cloud](https://www.weave.works/solution/cloud/) takes the heavy lifting out of building, integrating and operating open source components, so you don’t have to manage databases, storage and availability.
|
||||||
|
|
||||||
|
Weave Cloud is built using these Open Source projects: [Weave Scope](https://www.weave.works/products/weave-scope/), a powerful container monitoring tool that automatically maps Docker containers and their interactions, [Weave Cortex](https://github.com/weaveworks/cortex), a horizontally-scalable version of Prometheus, and [Weave Flux](https://www.weave.works/products/weave-flux/), a continuous deployment tool that works with Kubernetes.
|
||||||
|
|
||||||
# Weave Net
|
# Weave Net
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -14,6 +14,7 @@ pkgs = %w(
|
|||||||
git
|
git
|
||||||
mercurial
|
mercurial
|
||||||
bc
|
bc
|
||||||
|
jq
|
||||||
)
|
)
|
||||||
|
|
||||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
|
|||||||
@@ -5,6 +5,15 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Special token used in place of a container identifier when:
|
||||||
|
// - the caller does not know the container ID, or
|
||||||
|
// - the caller is unsure whether IPAM was previously told the container ID.
|
||||||
|
//
|
||||||
|
// While addresses are typically stored under their container IDs, when this
|
||||||
|
// token is used, the address will be stored under its own string, something
|
||||||
|
// which should be kept in mind if the entry needs to be removed at any point.
|
||||||
|
const NoContainerID string = "_"
|
||||||
|
|
||||||
func (client *Client) ipamOp(ID string, op string) (*net.IPNet, error) {
|
func (client *Client) ipamOp(ID string, op string) (*net.IPNet, error) {
|
||||||
ip, err := client.httpVerb(op, fmt.Sprintf("/ip/%s", ID), nil)
|
ip, err := client.httpVerb(op, fmt.Sprintf("/ip/%s", ID), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ set -e
|
|||||||
|
|
||||||
echo "TEST_AND_PUBLISH=1" > "$STATE"
|
echo "TEST_AND_PUBLISH=1" > "$STATE"
|
||||||
|
|
||||||
|
# Avoid doing a full build if we can. Note if the PR doesn't exist
|
||||||
|
# when the build is kicked off, we can't run this check so we do a
|
||||||
|
# full build. Subsequent pushes to the same branch will have the desired behaviour
|
||||||
if [ -n "$CI_PULL_REQUEST" -a "$CI_PULL_REQUEST" = "$CI_PULL_REQUESTS" ] ; then
|
if [ -n "$CI_PULL_REQUEST" -a "$CI_PULL_REQUEST" = "$CI_PULL_REQUESTS" ] ; then
|
||||||
if PR=$(echo "$CI_PULL_REQUEST" | grep -oP '(?<=^https://github.com/weaveworks/weave/pull/)[0-9]+$') ; then
|
if PR=$(echo "$CI_PULL_REQUEST" | grep -oP '(?<=^https://github.com/weaveworks/weave/pull/)[0-9]+$') ; then
|
||||||
echo "GH_PR=$PR" >> "$STATE"
|
echo "GH_PR=$PR" >> "$STATE"
|
||||||
@@ -28,13 +31,16 @@ source "$STATE"
|
|||||||
mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR
|
mkdir -p $(dirname $SRCDIR) && cp -r $(pwd)/ $SRCDIR
|
||||||
|
|
||||||
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
||||||
bin/setup-circleci-secrets "$SECRET_PASSWORD"
|
[ -z "$SECRET_PASSWORD" ] || bin/setup-circleci-secrets "$SECRET_PASSWORD"
|
||||||
cd $SRCDIR; git submodule update --init
|
cd $SRCDIR; git submodule update --init
|
||||||
if [ "$CIRCLE_NODE_INDEX" = "0" ] ; then
|
if [ "$CIRCLE_NODE_INDEX" = "0" -a -n "$SECRET_PASSWORD" ] ; then
|
||||||
cd $SRCDIR/test; ./gce.sh make_template
|
cd $SRCDIR/test; ./gce.sh make_template
|
||||||
fi
|
fi
|
||||||
cd $SRCDIR/build
|
cd $SRCDIR/build
|
||||||
../tools/rebuild-image weaveworks/weavebuild . Dockerfile build.sh
|
../tools/rebuild-image weaveworks/weavebuild . Dockerfile build.sh
|
||||||
touch $SRCDIR/.build.uptodate
|
touch $SRCDIR/.build.uptodate
|
||||||
sudo chown -R ubuntu /usr/local/go
|
sudo chown -R ubuntu /usr/local/go
|
||||||
|
cd $SRCDIR
|
||||||
|
make testrunner
|
||||||
|
make COVERAGE=true RM= exes all
|
||||||
fi
|
fi
|
||||||
@@ -8,7 +8,8 @@ if [ -n "$TEST_AND_PUBLISH" ] ; then
|
|||||||
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
cd $SRCDIR
|
cd $SRCDIR
|
||||||
make clean-bin
|
make clean-bin
|
||||||
make publish
|
# CircleCI doesn't let us install the qemu module to do ARM docker builds
|
||||||
|
make publish ALL_ARCHITECTURES=amd64 UPDATE_LATEST=latest-only
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $SRCDIR
|
cd $SRCDIR
|
||||||
|
|||||||
+1
-5
@@ -5,10 +5,6 @@ set -e
|
|||||||
source "$STATE"
|
source "$STATE"
|
||||||
|
|
||||||
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
||||||
cd $SRCDIR
|
|
||||||
make testrunner
|
|
||||||
make COVERAGE=true RM= all
|
|
||||||
|
|
||||||
cd $SRCDIR/test
|
cd $SRCDIR/test
|
||||||
./gce.sh setup && eval $(./gce.sh hosts) && ./setup.sh
|
[ -z "$SECRET_PASSWORD" ] || (./gce.sh setup && eval $(./gce.sh hosts) && ./setup.sh)
|
||||||
fi
|
fi
|
||||||
@@ -5,8 +5,10 @@ set -e
|
|||||||
source "$STATE"
|
source "$STATE"
|
||||||
|
|
||||||
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
||||||
|
[ -n "$SECRET_PASSWORD" ] || { echo "Cannot run smoke tests: no secret key"; exit 1; }
|
||||||
cd $SRCDIR/test
|
cd $SRCDIR/test
|
||||||
eval $(./gce.sh hosts)
|
eval $(./gce.sh hosts)
|
||||||
export COVERAGE=true
|
export COVERAGE=true
|
||||||
|
export WEAVE_NET_SANITY_CHECKS_FILES="$CIRCLE_ARTIFACTS/weave_net_sanity_check_*.log"
|
||||||
./run_all.sh
|
./run_all.sh
|
||||||
fi
|
fi
|
||||||
@@ -6,6 +6,6 @@ source "$STATE"
|
|||||||
|
|
||||||
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
||||||
cd $SRCDIR/test
|
cd $SRCDIR/test
|
||||||
./gce.sh destroy
|
[ -z "$SECRET_PASSWORD" ] || ./gce.sh destroy
|
||||||
test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; ./gen_coverage_reports.sh)
|
test "$CIRCLE_NODE_INDEX" != "0" || (cd $SRCDIR/test; ./gen_coverage_reports.sh)
|
||||||
fi
|
fi
|
||||||
@@ -6,6 +6,6 @@ source "$STATE"
|
|||||||
|
|
||||||
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
if [ -n "$TEST_AND_PUBLISH" ] ; then
|
||||||
cd $SRCDIR
|
cd $SRCDIR
|
||||||
make lint
|
make DEBUG=1 lint
|
||||||
COVERDIR=test/coverage make RM= tests
|
COVERDIR=test/coverage make RM= tests
|
||||||
fi
|
fi
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
## This is the shape of unencrypted `do-setup-ci-secrets`
|
|
||||||
##
|
|
||||||
## cat > /tmp/boto_gsutil_cert.pem << EOF
|
|
||||||
## -----BEGIN PRIVATE KEY-----
|
|
||||||
## <...>
|
|
||||||
## -----END PRIVATE KEY-----
|
|
||||||
## EOF
|
|
||||||
##
|
|
||||||
## cat > ~/.boto << EOF
|
|
||||||
## [Credentials]
|
|
||||||
## gs_service_client_id = <...>
|
|
||||||
## gs_service_key_file = /tmp/boto_gsutil_cert.pem
|
|
||||||
##
|
|
||||||
## [Boto]
|
|
||||||
## https_validate_certificates = True
|
|
||||||
##
|
|
||||||
## [GSUtil]
|
|
||||||
## content_language = en
|
|
||||||
## default_api_version = 2
|
|
||||||
## default_project_id = <...>
|
|
||||||
## EOF
|
|
||||||
|
|
||||||
openssl base64 -d << EOF \
|
|
||||||
| openssl aes-256-cbc -d -K $1 -iv $2 \
|
|
||||||
-out bin/do-setup-ci-secrets
|
|
||||||
mOYNzNsAdwva0LbB2YFMY9VgL0SITFu1bPrbOujyLtOrBNjmOYbzR5d/sG+ARMFr
|
|
||||||
7NZ5OKcvMbItllz0n7TtNkzkCOMztMC870Wcx3nGJzbBephdcYwos4tBlp5bihTU
|
|
||||||
AXgxLUiDT1broYAFKnbE1aZC/XyNxuLTN+nXJWIWeijaXTgvhkEEm3tab+z7ioCb
|
|
||||||
tlg71W1BrUuocctAJAuVwH/uTZAaXaJGJj1s2S7F2DrFnG6sFlrp8rnCucPLWKnC
|
|
||||||
4IwJFC5saR5gxK6wECffwmwbpeXVOoQ58OgzxoZTEyAr9nhVbaBt5UZz3tfHlx8W
|
|
||||||
Rn5jHehACw5kg5eMtGPqMEksJ63LX4h3mfSTLJXJHEmOrzCRpFrigVrsbA408U2u
|
|
||||||
8jJTHJmKrGfwBh5ZFzBg6NuV4VplOp+ZquJLgegv2WH/iu/ciopXqB2YDCdx5ZBi
|
|
||||||
nHV2Puth7kjS4EMCKUGfeqpesjL9Djb8cygzv/J3ZBmLjNH9dqlSXWy2DcFZA1Iy
|
|
||||||
pFTTHkVU3w5sNz3nYOuT2UPQvULBW0FUndDKX6olyVa0mlxPwGBP9N3yGg918/rw
|
|
||||||
7rNV/r54lA334F5QMhDrVxar6sl9wfLA+Z+8qemBbNFlLog1uQGhuwWK2nFu1tRM
|
|
||||||
9uyvQIq0oq5NHKpogWc7NEuk7CPe1JyfRIcbMVj8+ilmKjUPB2HPC43IDmKt9/56
|
|
||||||
rY3IXAcxZ/ClGfGpeNHXqop9T/WhfaowponOZFcdGSUddG0OswqkTE4KIv71mgTF
|
|
||||||
jXooMkTQBOG+gBnCe+8bCRdRCG3anxHX74za4dGD58cOJtl6DYWnjWuR91NWnxdT
|
|
||||||
1Zr3iUe41txg9hCNY9LHo2QHGLPxe6pmNnSClQ1mcFhuY6NF8RmCX3HAGKJQkxJb
|
|
||||||
vpLGbXTXjAIFgIYgLNgKP2RLvCif/LmSWgkvE3ZU9GXtCUbm6xgJodwOqXiI9uuO
|
|
||||||
4H4+/vpGHnSFENiclkgMFrLG4yiMu8ArgmnCBzg9E2AoOX5zCrh/2ZRTU8Dk4mt7
|
|
||||||
jUd5SKQLsjB9QtB+y3tRO7zY9RDvR6iBOPRsjx6t8EJMCfPb06KchfMJw+VGxvMM
|
|
||||||
48jtmepREFnhd/8XDRGnw5bznjRuwohGik8BToltjIviMkkpifKWaLwlaOiDXaHh
|
|
||||||
VBFNXnUKvOBwRMU+PZqv4+DP2qff1gSXnGKqA5GIURYrK9P7TqHHNTnmjBdfJLzc
|
|
||||||
0x+W1DTiYhLT2vrLrkEpZ99o6qrg+lwvjat6IsJF8xoQEo4pLD/ZRPJ0WzoDyctT
|
|
||||||
oWZ5rMsN1TzTvJrBrTAWIJyhIzZcuNwChMrU6qogMr0fd6TSxWhWn0sOJ5y8AaTR
|
|
||||||
ej4JHx0qroS/9JPmgFYU61pX3c0ypdef/sSHWG23mcFzLTgwe2d4ty9VakypZy3T
|
|
||||||
sXCl6EHVVXlUFWhY4zQCjdZpYJv/rtoKL1BL4fPE2NV5WTjCL2GNvaO5SfHR7pA0
|
|
||||||
yQJR/iU+cS2n8UXsWNjyV+/qEn6+QXuyVHGLbxyH8EeqlliAbyHsc2rzVI8Xctzo
|
|
||||||
W5DuIqxwHAkNNurhmx27ktIIQ6HhaCp028SWwvLttkbBBgF4v1mmd4u/2bKbKjUd
|
|
||||||
dOaetaIUx1hU9OAeaePvVkeTDcc3mlFtPARCS9Fqj16hgJQ43onZyC0H1K2WAxmU
|
|
||||||
GsmzjCHlTNquzFTuuQihYGZKfsWIh9z6HEOkvNJ3VEQ=
|
|
||||||
EOF
|
|
||||||
|
|
||||||
exec sh bin/do-setup-ci-secrets
|
|
||||||
+77
-6
@@ -1,8 +1,79 @@
|
|||||||
FROM golang:1.5.2
|
FROM golang:1.7.4
|
||||||
ENV GO15VENDOREXPERIMENT 1
|
|
||||||
RUN apt-get update && apt-get install -y libpcap-dev python-requests time file
|
# Support Raspberry Pi 2 and newer
|
||||||
RUN go get github.com/fzipp/gocyclo github.com/client9/misspell/cmd/misspell
|
ENV GOARM 7
|
||||||
RUN go clean -i net && go install -tags netgo std
|
|
||||||
RUN go install -race -tags netgo std
|
# The names of the architectures that we're fetching cross-compilers for from the Ubuntu packages
|
||||||
|
ENV DEB_CROSSPLATFORMS \
|
||||||
|
armhf \
|
||||||
|
arm64
|
||||||
|
|
||||||
|
# The go platforms we are supporting to cross-compile
|
||||||
|
ENV GO_CROSSPLATFORMS \
|
||||||
|
linux/arm \
|
||||||
|
linux/arm64
|
||||||
|
|
||||||
|
# The names of the gcc cross-compilers we have installed
|
||||||
|
ENV GCC_CROSSCOMPILERS \
|
||||||
|
arm-linux-gnueabihf \
|
||||||
|
aarch64-linux-gnu
|
||||||
|
|
||||||
|
# Temporarily add the Ubuntu repositories, because we're going to install gcc cross-compilers from there
|
||||||
|
# Install the build-essential and crossbuild-essential-ARCH packages
|
||||||
|
RUN echo "deb http://archive.ubuntu.com/ubuntu xenial main universe" > /etc/apt/sources.list.d/cgocrosscompiling.list \
|
||||||
|
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 3B4FE6ACC0B21F32 \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y build-essential \
|
||||||
|
&& for platform in ${DEB_CROSSPLATFORMS}; do apt-get install -y crossbuild-essential-${platform}; done \
|
||||||
|
&& rm /etc/apt/sources.list.d/cgocrosscompiling.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install some required packages
|
||||||
|
# libpcap is required because we're linking against its C libraries from the prog/weaver binary
|
||||||
|
# flex and bison are required packages for compiling libpcap manually later
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y \
|
||||||
|
libpcap-dev \
|
||||||
|
python-requests \
|
||||||
|
time \
|
||||||
|
file \
|
||||||
|
flex \
|
||||||
|
bison
|
||||||
|
|
||||||
|
# Install common Go tools
|
||||||
|
RUN go get \
|
||||||
|
github.com/golang/lint/golint \
|
||||||
|
github.com/fzipp/gocyclo \
|
||||||
|
github.com/client9/misspell/cmd/misspell
|
||||||
|
|
||||||
|
# First clean, because we're gonna rebuild the std both with -race enabled and disabled
|
||||||
|
# Running go install std twice is intentional and required, as content is written in two different directories
|
||||||
|
# (/usr/local/go/pkg/linux_amd64 vs /usr/local/go/pkg/linux_amd64_race)
|
||||||
|
# The other architectures do not have support for -race
|
||||||
|
RUN go clean -i net \
|
||||||
|
&& go install -tags netgo std \
|
||||||
|
&& go install -race -tags netgo std
|
||||||
|
|
||||||
|
# Prebuild std for the other architectures
|
||||||
|
RUN for platform in ${GO_CROSSPLATFORMS}; do \
|
||||||
|
GOOS=${platform%/*} GOARCH=${platform##*/} \
|
||||||
|
go install -tags netgo std; done
|
||||||
|
|
||||||
|
# The libpcap version from Debian packages is 1.6.2, matching that version here although newer versions of libpcap have been released
|
||||||
|
# We have to cross-compile the libpcap library for the new architectures, that's what we're doing here
|
||||||
|
ENV LIBPCAP_CROSS_VERSION=1.6.2
|
||||||
|
RUN curl -sSL http://www.tcpdump.org/release/libpcap-${LIBPCAP_CROSS_VERSION}.tar.gz | tar -xz \
|
||||||
|
&& cd libpcap-${LIBPCAP_CROSS_VERSION} \
|
||||||
|
&& for crosscompiler in ${GCC_CROSSCOMPILERS}; do \
|
||||||
|
CC=${crosscompiler}-gcc ac_cv_linux_vers=2 ./configure --host=${crosscompiler} --with-pcap=linux \
|
||||||
|
&& make \
|
||||||
|
&& export LIB_DIR="/usr/local/lib/${crosscompiler}-gcc" VER="$(cat ./VERSION)" MAJOR_VER="$(sed 's/\([0-9][0-9]*\)\..*/\1/' ./VERSION)" \
|
||||||
|
&& mkdir -p ${LIB_DIR} \
|
||||||
|
&& cp -f libpcap.a libpcap.so.${VER} ${LIB_DIR} \
|
||||||
|
&& ln -sf libpcap.so.${VER} /usr/local/lib/libpcap.so.${MAJOR_VER} \
|
||||||
|
&& ln -sf libpcap.so.${MAJOR_VER} /usr/local/lib/libpcap.so \
|
||||||
|
&& make clean; done
|
||||||
|
|
||||||
COPY build.sh /
|
COPY build.sh /
|
||||||
ENTRYPOINT ["sh", "/build.sh"]
|
ENTRYPOINT ["sh", "/build.sh"]
|
||||||
@@ -25,4 +25,7 @@ echo "weave:x:$uid:$gid::$WEAVE_SRC:/bin/sh" >>/etc/passwd
|
|||||||
echo "weave:*:::::::" >>/etc/shadow
|
echo "weave:*:::::::" >>/etc/shadow
|
||||||
echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
echo "weave ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers
|
||||||
|
|
||||||
|
# Allow full write access to the Go folders for the user Weave
|
||||||
|
chown -R $uid:$gid /usr/local/go
|
||||||
|
|
||||||
su weave -c "PATH=$PATH make -C $WEAVE_SRC BUILD_IN_CONTAINER=false $*"
|
su weave -c "PATH=$PATH make -C $WEAVE_SRC BUILD_IN_CONTAINER=false $*"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
8f313a9df867c207ae9ceac6e0935d1d2a0360aafce780dd5d1e0687ee98e0c3 docker-1.10.3.tgz
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
7541b5490cee1183d911f909c0e91d3d9d57b2b775e40f14a1a7a6de216ca4a8 docker-1.10.3.tgz
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
c02d861383d035ba020b361ef93bf14beb3964a42a6ae645b505b6148493e7ec qemu-aarch64-static
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0ff63682b8868620d771aa812d3053dc3c579dc8633ce62d3d7ae7eee83beb06 qemu-arm-static
|
||||||
+2
-1
@@ -2,9 +2,10 @@ general:
|
|||||||
branches:
|
branches:
|
||||||
ignore:
|
ignore:
|
||||||
- gh\-pages
|
- gh\-pages
|
||||||
- /pull\/.*/
|
|
||||||
|
|
||||||
machine:
|
machine:
|
||||||
|
pre:
|
||||||
|
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package mflagext
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/weaveworks/docker/pkg/mflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
type listOpts struct {
|
|
||||||
value *[]string
|
|
||||||
hasBeenSet bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListVar(p *[]string, names []string, value []string, usage string) {
|
|
||||||
*p = value
|
|
||||||
mflag.Var(&listOpts{p, false}, names, usage)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts *listOpts) Set(value string) error {
|
|
||||||
if opts.hasBeenSet {
|
|
||||||
(*opts.value) = append((*opts.value), value)
|
|
||||||
} else {
|
|
||||||
(*opts.value) = []string{value}
|
|
||||||
opts.hasBeenSet = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts *listOpts) String() string {
|
|
||||||
return fmt.Sprintf("%v", []string(*opts.value))
|
|
||||||
}
|
|
||||||
+7
-2
@@ -21,8 +21,13 @@ func CreateDatapath(dpname string) (supported bool, err error) {
|
|||||||
defer dpif.Close()
|
defer dpif.Close()
|
||||||
|
|
||||||
dp, err := dpif.CreateDatapath(dpname)
|
dp, err := dpif.CreateDatapath(dpname)
|
||||||
if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) {
|
if err != nil {
|
||||||
return true, err
|
if !odp.IsDatapathNameAlreadyExistsError(err) {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if dp, err = dpif.LookupDatapath(dpname); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick an ephemeral port number to use in probing for vxlan
|
// Pick an ephemeral port number to use in probing for vxlan
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"runtime"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A subsystem/server/... that can be stopped or queried about the status with a signal
|
|
||||||
type SignalReceiver interface {
|
|
||||||
Stop() error
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignalHandlerLoop(ss ...SignalReceiver) {
|
|
||||||
sigs := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
|
|
||||||
buf := make([]byte, 1<<20)
|
|
||||||
for {
|
|
||||||
switch <-sigs {
|
|
||||||
case syscall.SIGINT, syscall.SIGTERM:
|
|
||||||
Log.Infof("=== received SIGINT/SIGTERM ===\n*** exiting")
|
|
||||||
for _, subsystem := range ss {
|
|
||||||
subsystem.Stop()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case syscall.SIGQUIT:
|
|
||||||
stacklen := runtime.Stack(buf, true)
|
|
||||||
Log.Infof("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end", buf[:stacklen])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+30
-5
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
)
|
)
|
||||||
@@ -23,14 +24,39 @@ var (
|
|||||||
topBucket = []byte("top")
|
topBucket = []byte("top")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NameIdent = "peername"
|
||||||
|
FileName = "data.db"
|
||||||
|
)
|
||||||
|
|
||||||
func NewBoltDB(dbPathname string) (*BoltDB, error) {
|
func NewBoltDB(dbPathname string) (*BoltDB, error) {
|
||||||
db, err := bolt.Open(dbPathname, 0660, nil)
|
db, err := bolt.Open(dbPathname, 0660, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("[boltDB] Unable to open %s: %s", dbPathname, err)
|
return nil, fmt.Errorf("[boltDB] Unable to open %s: %s", dbPathname, err)
|
||||||
}
|
}
|
||||||
// check the persistence version
|
err = db.Update(checkVersion(false))
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
return &BoltDB{db: db}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBoltDBReadOnly(dbPathname string) (*BoltDB, error) {
|
||||||
|
options := bolt.Options{Timeout: time.Millisecond * 50, ReadOnly: true}
|
||||||
|
db, err := bolt.Open(dbPathname, 0660, &options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[boltDB] Unable to open %s: %s", dbPathname, err)
|
||||||
|
}
|
||||||
|
err = db.View(checkVersion(true))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("[boltDB] Cannot use persistence file %s: %s", dbPathname, err)
|
||||||
|
}
|
||||||
|
return &BoltDB{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkVersion(readOnly bool) func(tx *bolt.Tx) error {
|
||||||
|
return func(tx *bolt.Tx) error {
|
||||||
if top := tx.Bucket(topBucket); top == nil {
|
if top := tx.Bucket(topBucket); top == nil {
|
||||||
|
if readOnly {
|
||||||
|
return fmt.Errorf("no top bucket")
|
||||||
|
}
|
||||||
top, err := tx.CreateBucket(topBucket)
|
top, err := tx.CreateBucket(topBucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -41,13 +67,12 @@ func NewBoltDB(dbPathname string) (*BoltDB, error) {
|
|||||||
} else {
|
} else {
|
||||||
if checkVersion := top.Get(versionIdent); checkVersion != nil {
|
if checkVersion := top.Get(versionIdent); checkVersion != nil {
|
||||||
if checkVersion[0] != persistenceVersion[0] {
|
if checkVersion[0] != persistenceVersion[0] {
|
||||||
return fmt.Errorf("[boltDB] Cannot use persistence file %s - version %x", dbPathname, checkVersion)
|
return fmt.Errorf("mismatched version %x", checkVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}
|
||||||
return &BoltDB{db: db}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *BoltDB) Load(ident string, data interface{}) (bool, error) {
|
func (d *BoltDB) Load(ident string, data interface{}) (bool, error) {
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
This document describes implementation details of the fast datapath encryption.
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
At the high level, we use the ESP protocol ([RFC 2406][esp]) in the Transport
|
||||||
|
mode. Each packet is encrypted with AES in GCM mode ([RFC 4106][aesgcm]), with
|
||||||
|
32byte key and 4byte salt. This combo provides the following security
|
||||||
|
properties:
|
||||||
|
|
||||||
|
* Data confidentiality.
|
||||||
|
* Data origin authentication.
|
||||||
|
* Integrity.
|
||||||
|
* Anti-replay service.
|
||||||
|
* Limited traffic flow confidentiality.
|
||||||
|
|
||||||
|
## Notation
|
||||||
|
|
||||||
|
* `SAin`: IPsec security association for inbound connections.
|
||||||
|
* `SAout`: IPsec security association for outbound connections.
|
||||||
|
* `SPout`: IPsec security policy for outbound connections. Used to match
|
||||||
|
outbound flows to SAout.
|
||||||
|
|
||||||
|
## SA Key Derivation
|
||||||
|
|
||||||
|
For each connection direction, a different AES-GCM key and salt is used.
|
||||||
|
The pairs are derived with HKDF ([RFC 5869][hkdf]):
|
||||||
|
|
||||||
|
```
|
||||||
|
SAin[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceIn, info=localPeerName)
|
||||||
|
SAout[KeyAndSalt] = HKDF(sha256, ikm=sessionKey, salt=nonceOut, info=remotePeerName)
|
||||||
|
```
|
||||||
|
|
||||||
|
Where:
|
||||||
|
|
||||||
|
* the mutual `sessionKey` is derived by the [Mesh][mesh] library during
|
||||||
|
the control plane connection establishment between the local peer and
|
||||||
|
the remote peer.
|
||||||
|
* `nonceIn` and `nonceOut` are randomly generated 32byte nonces which
|
||||||
|
are exchanged over the encrypted control plane channel.
|
||||||
|
|
||||||
|
## SPI
|
||||||
|
|
||||||
|
A directional secure connection between two peers is identified with SPI.
|
||||||
|
|
||||||
|
The kernel requires the pair of SPI and dst IP to be unique among security
|
||||||
|
associations. Thus, to avoid collisions, we generate outbound SPI on a remote
|
||||||
|
peer.
|
||||||
|
|
||||||
|
## Connection Establishment
|
||||||
|
|
||||||
|
```
|
||||||
|
Peer A Peer B
|
||||||
|
-----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
fastdp.fwd.Confirm():
|
||||||
|
install iptables blocking rules, fastdp.fwd.Confirm():
|
||||||
|
nonce_BA = rand(), install iptables blocking rules,
|
||||||
|
{key,salt}_BA = hkdf(sessionKey, nonce_BA, A), nonce_AB = rand(),
|
||||||
|
spi_BA = allocspi(), {key,salt}_AB = hkdf(sessionKey, nonce_AB, B),
|
||||||
|
create SA_BA(B<-A, spi_BA, key_BA, salt_BA), spi_AB = allocspi(),
|
||||||
|
send InitSARemote(spi_BA, nonce_BA). --> create SA_AB(A<-B, spi_AB, key_AB, salt_AB),
|
||||||
|
<-- send InitSARemote(spi_AB, nonce_AB).
|
||||||
|
|
||||||
|
|
||||||
|
--> recv InitSARemote(spi_BA, nonce_BA):
|
||||||
|
recv InitSARemote(spi_AB, nonce_AB): <-- {key,salt}_BA = hkdf(sessionKey, nonce_BA, A),
|
||||||
|
{key,salt}_AB = hkdf(sessionKey, nonce_AB, B), create SA_BA(B<-A, spi_BA, key_BA, salt_BA),
|
||||||
|
create SA_AB(A<-B, spi_AB, key_AB, salt_AB), create SP_BA(B<-A, spi_BA),
|
||||||
|
create SP_AB(A<-B, spi_AB), install marking rule.
|
||||||
|
install marking rule.
|
||||||
|
```
|
||||||
|
|
||||||
|
# Implementation Details
|
||||||
|
|
||||||
|
## XFRM
|
||||||
|
|
||||||
|
The implementation is based on the kernel IP packet transformation framework
|
||||||
|
called XFRM. Unfortunately, docs are barely existing and the complexity of
|
||||||
|
the framework is high. The best resource I found is Chapter 10 in
|
||||||
|
"Linux Kernel Networking: Implementation and Theory" by Rami Rosen.
|
||||||
|
|
||||||
|
## iptables Rules
|
||||||
|
|
||||||
|
The kernel VXLAN driver does not set a dst port of a tunnel in the ip flow
|
||||||
|
descriptor, thus XFRM policy lookup cannot match a policy (SPout) which includes
|
||||||
|
the port. This makes impossible to encrypt only tunneled traffic between
|
||||||
|
peers. To work around, we mark such outgoing packets with iptables and set
|
||||||
|
the same mark in the policy selector (funnily enough, `iptables_mangle` module
|
||||||
|
eventually sets the missing dst port in the flow descriptor). The challenge
|
||||||
|
here is to pick a mark that it would not interfere with other networking
|
||||||
|
applications before OUTPUT'ing a packet. For example, Kubernetes by default
|
||||||
|
uses 1<<14 and 1<<15 marks and we choose 1<<17 (0x20000). Additionally,
|
||||||
|
such workaround brings the requirement for at least the 4.2 kernel.
|
||||||
|
|
||||||
|
The marking rules are the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
iptables -t mangle -A OUTPUT -j WEAVE-IPSEC-OUT
|
||||||
|
iptables -t mangle -A WEAVE-IPSEC-OUT -s ${LOCAL_PEER_IP} -d ${REMOTE_PEER_IP} \
|
||||||
|
-p udp --dport ${TUNNEL_PORT} -j WEAVE-IPSEC-OUT-MARK
|
||||||
|
iptables -t mangle -A WEAVE-IPSEC-OUT-MARK --set-xmark ${MARK} -j MARK
|
||||||
|
```
|
||||||
|
|
||||||
|
As Linux does not implement [IP Security Levels][ipseclevel], we install
|
||||||
|
additional iptables rules to prevent from accidentally sending unencrypted
|
||||||
|
traffic between peers which have previously established the secure connection.
|
||||||
|
|
||||||
|
For inbound traffic, we mark each ESP packet with the mark and drop non-marked
|
||||||
|
tunnel traffic:
|
||||||
|
|
||||||
|
```
|
||||||
|
iptables -t mangle -A INPUT -j WEAVE-IPSEC-IN
|
||||||
|
iptables -t mangle -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \
|
||||||
|
-m esp --espspi ${SPIin} -j WEAVE-IPSEC-IN-MARK
|
||||||
|
iptables -t mangle -A WEAVE-IPSEC-IN-MARK --set-xmark ${MARK} -j MARK
|
||||||
|
|
||||||
|
iptables -t filter -A INPUT -j WEAVE-IPSEC-IN
|
||||||
|
iptables -t filter -A WEAVE-IPSEC-IN -s ${REMOTE_PEER_IP} -d ${LOCAL_PEER_IP} \
|
||||||
|
-p udp --dport ${TUNNEL_PORT} -m mark ! --mark ${MARK} -j DROP
|
||||||
|
```
|
||||||
|
|
||||||
|
For outbound traffic, we drop marked traffic which does not match any SPout:
|
||||||
|
|
||||||
|
```
|
||||||
|
iptables -t filter -A OUTPUT ! -p esp -m policy --dir out --pol none \
|
||||||
|
-m mark --mark ${MARK} -j DROP
|
||||||
|
```
|
||||||
|
|
||||||
|
## ESN
|
||||||
|
|
||||||
|
To prevent from cycling SeqNo which makes replay attacks possible, we use
|
||||||
|
64-bit extended sequence numbers known as [ESN](esn).
|
||||||
|
|
||||||
|
## MTU
|
||||||
|
|
||||||
|
In addition to the VXLAN overhead, the MTU calculation should take into account
|
||||||
|
the ESP overhead which is 34-37 bytes (encrypted Payload is 4 bytes aligned) and
|
||||||
|
consists of:
|
||||||
|
|
||||||
|
* 4 bytes (SPI).
|
||||||
|
* 4 bytes (Sequence Number).
|
||||||
|
* 8 bytes (ESP IV).
|
||||||
|
* 1 byte (Pad Length).
|
||||||
|
* 1 byte (NextHeader).
|
||||||
|
* 16 bytes (ICV).
|
||||||
|
* 0-3 bytes (Padding).
|
||||||
|
|
||||||
|
|
||||||
|
[esp]: https://tools.ietf.org/html/rfc2406
|
||||||
|
[aesgcm]: https://tools.ietf.org/html/rfc4106
|
||||||
|
[hkdf]: https://tools.ietf.org/html/rfc5869
|
||||||
|
[esn]: https://tools.ietf.org/html/rfc4304
|
||||||
|
[ipseclevel]: https://tools.ietf.org/html/draft-mcdonald-simple-ipsec-api-01)
|
||||||
|
[mesh]: https://github.com/weaveworks/mesh
|
||||||
@@ -107,15 +107,6 @@ the build script will complain otherwise.
|
|||||||
N.B. if you're testing the release process, push to your fork
|
N.B. if you're testing the release process, push to your fork
|
||||||
instead!
|
instead!
|
||||||
|
|
||||||
While the git.io link for weave-kube is still pointing to the
|
|
||||||
weave-kube repository, we also need to update the tag there:
|
|
||||||
|
|
||||||
cd ../weave-kube
|
|
||||||
git tag -a -m "Release $TAG" $TAG
|
|
||||||
git tag -af -m "Release $TAG" latest_release $TAG
|
|
||||||
git push -f git@github.com:weaveworks/weave latest_release
|
|
||||||
|
|
||||||
|
|
||||||
### Publish Release & Distributable Artefacts
|
### Publish Release & Distributable Artefacts
|
||||||
|
|
||||||
You can now publish the release and upload the remaining
|
You can now publish the release and upload the remaining
|
||||||
|
|||||||
+2
-1
@@ -3,6 +3,7 @@ package ipam
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/api"
|
||||||
"github.com/weaveworks/weave/net/address"
|
"github.com/weaveworks/weave/net/address"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ func (g *allocate) Try(alloc *Allocator) bool {
|
|||||||
if ok, addr := alloc.space.Allocate(g.r.HostRange()); ok {
|
if ok, addr := alloc.space.Allocate(g.r.HostRange()); ok {
|
||||||
// If caller hasn't supplied a unique ID, file it under the IP address
|
// If caller hasn't supplied a unique ID, file it under the IP address
|
||||||
// which lets the caller then release the address using DELETE /ip/address
|
// which lets the caller then release the address using DELETE /ip/address
|
||||||
if g.ident == "_" {
|
if g.ident == api.NoContainerID {
|
||||||
g.ident = addr.String()
|
g.ident = addr.String()
|
||||||
}
|
}
|
||||||
alloc.debugln("Allocated", addr, "for", g.ident, "in", g.r)
|
alloc.debugln("Allocated", addr, "for", g.ident, "in", g.r)
|
||||||
|
|||||||
+7
-8
@@ -322,7 +322,7 @@ func (alloc *Allocator) Claim(ident string, cidr address.CIDR, isContainer, noEr
|
|||||||
// ContainerDied called from the updater interface. Async.
|
// ContainerDied called from the updater interface. Async.
|
||||||
func (alloc *Allocator) ContainerDied(ident string) {
|
func (alloc *Allocator) ContainerDied(ident string) {
|
||||||
alloc.actionChan <- func() {
|
alloc.actionChan <- func() {
|
||||||
if alloc.hasOwned(ident) {
|
if alloc.hasOwnedByContainer(ident) {
|
||||||
alloc.debugln("Container", ident, "died; noting to remove later")
|
alloc.debugln("Container", ident, "died; noting to remove later")
|
||||||
alloc.dead[ident] = alloc.now()
|
alloc.dead[ident] = alloc.now()
|
||||||
}
|
}
|
||||||
@@ -335,7 +335,7 @@ func (alloc *Allocator) ContainerDied(ident string) {
|
|||||||
// ContainerDestroyed called from the updater interface. Async.
|
// ContainerDestroyed called from the updater interface. Async.
|
||||||
func (alloc *Allocator) ContainerDestroyed(ident string) {
|
func (alloc *Allocator) ContainerDestroyed(ident string) {
|
||||||
alloc.actionChan <- func() {
|
alloc.actionChan <- func() {
|
||||||
if alloc.hasOwned(ident) {
|
if alloc.hasOwnedByContainer(ident) {
|
||||||
alloc.debugln("Container", ident, "destroyed; removing addresses")
|
alloc.debugln("Container", ident, "destroyed; removing addresses")
|
||||||
alloc.delete(ident)
|
alloc.delete(ident)
|
||||||
delete(alloc.dead, ident)
|
delete(alloc.dead, ident)
|
||||||
@@ -920,13 +920,12 @@ func (alloc *Allocator) reportFreeSpace() {
|
|||||||
// Persistent data
|
// Persistent data
|
||||||
const (
|
const (
|
||||||
ringIdent = "ring"
|
ringIdent = "ring"
|
||||||
nameIdent = "peername"
|
|
||||||
ownedIdent = "ownedAddresses"
|
ownedIdent = "ownedAddresses"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (alloc *Allocator) persistRing() {
|
func (alloc *Allocator) persistRing() {
|
||||||
// It would be better if these two Save operations happened in the same transaction
|
// It would be better if these two Save operations happened in the same transaction
|
||||||
if err := alloc.db.Save(nameIdent, alloc.ourName); err != nil {
|
if err := alloc.db.Save(db.NameIdent, alloc.ourName); err != nil {
|
||||||
alloc.fatalf("Error persisting ring data: %s", err)
|
alloc.fatalf("Error persisting ring data: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -938,7 +937,7 @@ func (alloc *Allocator) persistRing() {
|
|||||||
// Returns true if persisted data is to be used, otherwise false
|
// Returns true if persisted data is to be used, otherwise false
|
||||||
func (alloc *Allocator) loadPersistedData() bool {
|
func (alloc *Allocator) loadPersistedData() bool {
|
||||||
var checkPeerName mesh.PeerName
|
var checkPeerName mesh.PeerName
|
||||||
nameFound, err := alloc.db.Load(nameIdent, &checkPeerName)
|
nameFound, err := alloc.db.Load(db.NameIdent, &checkPeerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
alloc.fatalf("Error loading persisted peer name: %s", err)
|
alloc.fatalf("Error loading persisted peer name: %s", err)
|
||||||
}
|
}
|
||||||
@@ -996,9 +995,9 @@ func (alloc *Allocator) persistOwned() {
|
|||||||
|
|
||||||
// Owned addresses
|
// Owned addresses
|
||||||
|
|
||||||
func (alloc *Allocator) hasOwned(ident string) bool {
|
func (alloc *Allocator) hasOwnedByContainer(ident string) bool {
|
||||||
_, b := alloc.owned[ident]
|
d, b := alloc.owned[ident]
|
||||||
return b
|
return b && d.IsContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB: addr must not be owned by ident already
|
// NB: addr must not be owned by ident already
|
||||||
|
|||||||
+18
-9
@@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/weaveworks/mesh"
|
"github.com/weaveworks/mesh"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/api"
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/net/address"
|
"github.com/weaveworks/weave/net/address"
|
||||||
)
|
)
|
||||||
@@ -77,26 +78,34 @@ func (c *claim) Try(alloc *Allocator) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ident == "_" { // Special "I don't have a unique ID" identifier
|
|
||||||
c.ident = c.cidr.Addr.String()
|
|
||||||
}
|
|
||||||
// We are the owner, check we haven't given it to another container
|
// We are the owner, check we haven't given it to another container
|
||||||
switch existingIdent := alloc.findOwner(c.cidr.Addr); existingIdent {
|
existingIdent := alloc.findOwner(c.cidr.Addr)
|
||||||
case "":
|
switch {
|
||||||
|
case existingIdent == "":
|
||||||
|
// Unused address, we try to claim it:
|
||||||
if err := alloc.space.Claim(c.cidr.Addr); err == nil {
|
if err := alloc.space.Claim(c.cidr.Addr); err == nil {
|
||||||
alloc.debugln("Claimed", c.cidr, "for", c.ident)
|
alloc.debugln("Claimed", c.cidr, "for", c.ident)
|
||||||
alloc.addOwned(c.ident, c.cidr, c.isContainer)
|
if c.ident == api.NoContainerID {
|
||||||
|
alloc.addOwned(c.cidr.Addr.String(), c.cidr, c.isContainer)
|
||||||
|
} else {
|
||||||
|
alloc.addOwned(c.ident, c.cidr, c.isContainer)
|
||||||
|
}
|
||||||
c.sendResult(nil)
|
c.sendResult(nil)
|
||||||
} else {
|
} else {
|
||||||
c.sendResult(err)
|
c.sendResult(err)
|
||||||
}
|
}
|
||||||
case c.ident:
|
case (existingIdent == c.ident) || (c.ident == api.NoContainerID && existingIdent == c.cidr.Addr.String()):
|
||||||
// same identifier is claiming same address; that's OK
|
// same identifier is claiming same address; that's OK
|
||||||
alloc.debugln("Re-Claimed", c.cidr, "for", c.ident)
|
alloc.debugln("Re-Claimed", c.cidr, "for", c.ident)
|
||||||
c.sendResult(nil)
|
c.sendResult(nil)
|
||||||
case c.cidr.Addr.String():
|
case existingIdent == c.cidr.Addr.String():
|
||||||
// Address already allocated via "_" name
|
// Address already allocated via api.NoContainerID name and current ID is a real container ID:
|
||||||
c.sendResult(fmt.Errorf("address %s already in use", c.cidr))
|
c.sendResult(fmt.Errorf("address %s already in use", c.cidr))
|
||||||
|
case c.ident == api.NoContainerID:
|
||||||
|
// We do not know whether this is the same container or another one,
|
||||||
|
// but we also cannot prove otherwise, so we let it reclaim the address:
|
||||||
|
alloc.debugln("Re-Claimed", c.cidr, "for ID", c.ident, "having existing ID as", existingIdent)
|
||||||
|
c.sendResult(nil)
|
||||||
default:
|
default:
|
||||||
// Addr already owned by container on this machine
|
// Addr already owned by container on this machine
|
||||||
c.sendResult(fmt.Errorf("address %s is already owned by %s", c.cidr.String(), existingIdent))
|
c.sendResult(fmt.Errorf("address %s is already owned by %s", c.cidr.String(), existingIdent))
|
||||||
|
|||||||
+2
-2
@@ -41,8 +41,8 @@ var (
|
|||||||
ErrNotSorted = errors.New("Ring not sorted")
|
ErrNotSorted = errors.New("Ring not sorted")
|
||||||
ErrTokenRepeated = errors.New("Token appears twice in ring")
|
ErrTokenRepeated = errors.New("Token appears twice in ring")
|
||||||
ErrTokenOutOfRange = errors.New("Token is out of range")
|
ErrTokenOutOfRange = errors.New("Token is out of range")
|
||||||
ErrDifferentSeeds = errors.New("Received ring was seeded differently from ours!")
|
ErrDifferentSeeds = errors.New("Received ring was seeded differently from ours")
|
||||||
ErrDifferentRange = errors.New("Received range differs from ours!")
|
ErrDifferentRange = errors.New("Received range differs from ours")
|
||||||
)
|
)
|
||||||
|
|
||||||
func errInconsistentEntry(mine, theirs *entry) error {
|
func errInconsistentEntry(mine, theirs *entry) error {
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ func TestTransfer(t *testing.T) {
|
|||||||
ring1.ClaimItAll()
|
ring1.ClaimItAll()
|
||||||
ring1.GrantRangeToHost(middle, end, peer2name)
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
||||||
ring1.Transfer(peer2name, peer1name)
|
ring1.Transfer(peer2name, peer1name)
|
||||||
require.Equal(t, []address.Range{{start, middle}, {middle, end}}, ring1.OwnedRanges())
|
require.Equal(t, []address.Range{{Start: start, End: middle}, {Start: middle, End: end}}, ring1.OwnedRanges())
|
||||||
|
|
||||||
// Second test is what happens when a token exists at the end of a range but is transferred
|
// Second test is what happens when a token exists at the end of a range but is transferred
|
||||||
// - does it get resurrected correctly?
|
// - does it get resurrected correctly?
|
||||||
@@ -503,7 +503,7 @@ func TestTransfer(t *testing.T) {
|
|||||||
ring1.GrantRangeToHost(middle, end, peer2name)
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
||||||
ring1.Transfer(peer2name, peer1name)
|
ring1.Transfer(peer2name, peer1name)
|
||||||
ring1.GrantRangeToHost(dot10, middle, peer2name)
|
ring1.GrantRangeToHost(dot10, middle, peer2name)
|
||||||
require.Equal(t, []address.Range{{start, dot10}, {middle, end}}, ring1.OwnedRanges())
|
require.Equal(t, []address.Range{{Start: start, End: dot10}, {Start: middle, End: end}}, ring1.OwnedRanges())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOwner(t *testing.T) {
|
func TestOwner(t *testing.T) {
|
||||||
|
|||||||
+1
-1
@@ -120,7 +120,7 @@ func (e1 *Entry) tombstone() bool {
|
|||||||
|
|
||||||
func check(es SortableEntries) error {
|
func check(es SortableEntries) error {
|
||||||
if !sort.IsSorted(es) {
|
if !sort.IsSorted(es) {
|
||||||
return fmt.Errorf("Not sorted!")
|
return fmt.Errorf("Not sorted")
|
||||||
}
|
}
|
||||||
for i := 1; i < es.Len(); i++ {
|
for i := 1; i < es.Len(); i++ {
|
||||||
if es.Get(i).equal(es.Get(i - 1)) {
|
if es.Get(i).equal(es.Get(i - 1)) {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -51,3 +55,56 @@ func isDatapath(link netlink.Link) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DetectHairpin(portIfName string, log *logrus.Logger) error {
|
||||||
|
link, err := netlink.LinkByName(portIfName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find link %q: %s", portIfName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan netlink.LinkUpdate)
|
||||||
|
// See EnsureInterface for why done channel is not passed
|
||||||
|
if err := netlink.LinkSubscribe(ch, nil); err != nil {
|
||||||
|
return fmt.Errorf("Unable to subscribe to netlink updates: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pi, err := netlink.LinkGetProtinfo(link)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to get link protinfo %q: %s", portIfName, err)
|
||||||
|
}
|
||||||
|
if pi.Hairpin {
|
||||||
|
return fmt.Errorf("Hairpin mode enabled on %q", portIfName)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for up := range ch {
|
||||||
|
if up.Attrs().Name == portIfName && up.Attrs().Protinfo != nil &&
|
||||||
|
up.Attrs().Protinfo.Hairpin {
|
||||||
|
log.Errorf("Hairpin mode enabled on %q", portIfName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrBridgeNoIP = fmt.Errorf("Bridge has no IP address")
|
||||||
|
|
||||||
|
func FindBridgeIP(bridgeName string, subnet *net.IPNet) (net.IP, error) {
|
||||||
|
netdev, err := GetBridgeNetDev(bridgeName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
|
||||||
|
}
|
||||||
|
if len(netdev.CIDRs) == 0 {
|
||||||
|
return nil, ErrBridgeNoIP
|
||||||
|
}
|
||||||
|
if subnet != nil {
|
||||||
|
for _, cidr := range netdev.CIDRs {
|
||||||
|
if subnet.Contains(cidr.IP) {
|
||||||
|
return cidr.IP, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No subnet, or none in the required subnet; just return the first one
|
||||||
|
return netdev.CIDRs[0].IP, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,562 @@
|
|||||||
|
// package IPsec provides primitives for establishing IPsec in the fastdp mode.
|
||||||
|
package ipsec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/coreos/go-iptables/iptables"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
"golang.org/x/crypto/hkdf"
|
||||||
|
|
||||||
|
"github.com/weaveworks/mesh"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
keySize = 36 // AES-GCM key 32 bytes + 4 bytes salt
|
||||||
|
nonceSize = 32 // HKDF nonce size
|
||||||
|
|
||||||
|
mark = uint32(0x1) << 17 // iptables marks
|
||||||
|
markStr = "0x20000/0x20000" // update if the above mark changes
|
||||||
|
|
||||||
|
tableMangle = "mangle"
|
||||||
|
tableFilter = "filter"
|
||||||
|
chainIn = "WEAVE-IPSEC-IN"
|
||||||
|
chainInMark = "WEAVE-IPSEC-IN-MARK"
|
||||||
|
chainOut = "WEAVE-IPSEC-OUT"
|
||||||
|
chainOutMark = "WEAVE-IPSEC-OUT-MARK"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SPI uint32
|
||||||
|
|
||||||
|
// Used to identify:
|
||||||
|
// - directional SPIs,
|
||||||
|
// - ipsec establishments.
|
||||||
|
type spiID [24]byte
|
||||||
|
|
||||||
|
func getSPIId(srcPeer, dstPeer mesh.PeerName, connUID uint64) (id spiID) {
|
||||||
|
binary.BigEndian.PutUint64(id[:], uint64(srcPeer))
|
||||||
|
binary.BigEndian.PutUint64(id[8:], uint64(dstPeer))
|
||||||
|
binary.BigEndian.PutUint64(id[16:], connUID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type spiInfo struct {
|
||||||
|
spi SPI
|
||||||
|
isDirOut bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPSec
|
||||||
|
|
||||||
|
type IPSec struct {
|
||||||
|
sync.RWMutex
|
||||||
|
ipt *iptables.IPTables
|
||||||
|
log *logrus.Logger
|
||||||
|
|
||||||
|
spiInfo map[spiID]spiInfo
|
||||||
|
// A reference to spiInfo; spiInfo might be of an expired SPI.
|
||||||
|
spis map[SPI]*spiInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(log *logrus.Logger) (*IPSec, error) {
|
||||||
|
ipt, err := iptables.New()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "iptables new")
|
||||||
|
}
|
||||||
|
|
||||||
|
ipsec := &IPSec{
|
||||||
|
ipt: ipt,
|
||||||
|
log: log,
|
||||||
|
spiInfo: make(map[spiID]spiInfo),
|
||||||
|
spis: make(map[SPI]*spiInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipsec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitSALocal initializes inbound ipsec from remotePeer and triggers
|
||||||
|
// the initialization on remotePeer.
|
||||||
|
func (ipsec *IPSec) InitSALocal(localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int, sessionKey *[32]byte, initRemote func([]byte) error) error {
|
||||||
|
// ID of inbound SPI
|
||||||
|
spiID := getSPIId(remotePeer, localPeer, connUID)
|
||||||
|
|
||||||
|
ipsec.Lock()
|
||||||
|
defer ipsec.Unlock()
|
||||||
|
|
||||||
|
// Derive SA key
|
||||||
|
nonce, err := genNonce()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "generate nonce")
|
||||||
|
}
|
||||||
|
key, err := deriveKey(sessionKey[:], nonce, localPeer)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "derive key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate SA
|
||||||
|
sa, err := netlink.XfrmStateAllocSpi(xfrmAllocSpiState(remoteIP, localIP))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("ip xfrm state allocspi (in, %s, %s)", remoteIP, localIP))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use SPI generated by the kernel. The kernel ensures {dstIP, spi} to
|
||||||
|
// be unique.
|
||||||
|
spi := SPI(sa.Spi)
|
||||||
|
|
||||||
|
ipsec.log.Infof("ipsec: InitSALocal: %s -> %s :%d 0x%x", remoteIP, localIP, udpPort, spi)
|
||||||
|
|
||||||
|
// Create SA
|
||||||
|
if sa, err := xfrmState(remoteIP, localIP, spi, false, key); err == nil {
|
||||||
|
if err := netlink.XfrmStateUpdate(sa); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("xfrm state update (in, %s, %s, 0x%x)", sa.Src, sa.Dst, sa.Spi))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.Wrap(err, "new xfrm state (in)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install iptables rules
|
||||||
|
if err := ipsec.installDropNonEncrypted(localIP, remoteIP, udpPort, spi); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("install protecting rules (%s, %s, %d, 0x%x)", localIP, remoteIP, udpPort, spi))
|
||||||
|
}
|
||||||
|
|
||||||
|
si := spiInfo{spi: spi, isDirOut: false}
|
||||||
|
ipsec.spiInfo[spiID] = si
|
||||||
|
ipsec.spis[spi] = &si
|
||||||
|
|
||||||
|
// Trigger the initialization on the remote peer
|
||||||
|
msg := &msgInitSARemote{nonce, spi}
|
||||||
|
if err := initRemote(msg.serialize()); err != nil {
|
||||||
|
return errors.Wrap(err, "send InitSARemote")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitSARemote initializes outbound ipsec to remotePeer.
|
||||||
|
// Triggered by remotePeer.
|
||||||
|
func (ipsec *IPSec) InitSARemote(msgInitSARemote []byte, localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int, sessionKey *[32]byte) error {
|
||||||
|
// ID of outbound SPI
|
||||||
|
spiID := getSPIId(localPeer, remotePeer, connUID)
|
||||||
|
|
||||||
|
msg, err := deserializeMsgInitSARemote(msgInitSARemote)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "deserialize InitSARemote")
|
||||||
|
}
|
||||||
|
spi := msg.spi
|
||||||
|
|
||||||
|
ipsec.Lock()
|
||||||
|
defer ipsec.Unlock()
|
||||||
|
|
||||||
|
ipsec.log.Infof("ipsec: InitSARemote: %s -> %s :%d 0x%x", localIP, remoteIP, udpPort, spi)
|
||||||
|
|
||||||
|
// Derive SA key by using the received nonce
|
||||||
|
key, err := deriveKey(sessionKey[:], msg.nonce, remotePeer)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "derive key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SA
|
||||||
|
if sa, err := xfrmState(localIP, remoteIP, spi, true, key); err == nil {
|
||||||
|
if err := netlink.XfrmStateAdd(sa); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("xfrm state update (out, %s, %s, 0x%x)", sa.Src, sa.Dst, sa.Spi))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.Wrap(err, "new xfrm state (out)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or update SP
|
||||||
|
sp := xfrmPolicy(localIP, remoteIP, spi)
|
||||||
|
if err := netlink.XfrmPolicyUpdate(sp); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("xfrm policy update (%s, %s, 0x%x)", localIP, remoteIP, spi))
|
||||||
|
}
|
||||||
|
|
||||||
|
si := spiInfo{spi: spi, isDirOut: true}
|
||||||
|
ipsec.spiInfo[spiID] = si
|
||||||
|
ipsec.spis[spi] = &si
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy destroys any (inbound / outbound) ipsec establishment between the peers.
|
||||||
|
func (ipsec *IPSec) Destroy(localPeer, remotePeer mesh.PeerName, connUID uint64, localIP, remoteIP net.IP, udpPort int) error {
|
||||||
|
outSPIID := getSPIId(localPeer, remotePeer, connUID)
|
||||||
|
inSPIID := getSPIId(remotePeer, localPeer, connUID)
|
||||||
|
|
||||||
|
ipsec.Lock()
|
||||||
|
defer ipsec.Unlock()
|
||||||
|
|
||||||
|
// Destroy inbound
|
||||||
|
|
||||||
|
if inSPIInfo, ok := ipsec.spiInfo[inSPIID]; ok {
|
||||||
|
ipsec.log.Infof("ipsec: destroy: in %s -> %s 0x%x", remoteIP, localIP, inSPIInfo.spi)
|
||||||
|
|
||||||
|
inSPI := inSPIInfo.spi
|
||||||
|
|
||||||
|
inSA := &netlink.XfrmState{
|
||||||
|
Src: remoteIP,
|
||||||
|
Dst: localIP,
|
||||||
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
|
Spi: int(inSPI),
|
||||||
|
}
|
||||||
|
if err := netlink.XfrmStateDel(inSA); err != nil {
|
||||||
|
ipsec.log.Warnf("ipsec: xfrm state del (in, %s, %s, 0x%x) failed: %s", inSA.Src, inSA.Dst, inSA.Spi, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ipsec.removeDropNonEncrypted(localIP, remoteIP, udpPort, inSPI); err != nil {
|
||||||
|
ipsec.log.Warnf("ipsec: remove protecting rules (%s, %s, %d, 0x%x) failed: %s", localIP, remoteIP, udpPort, inSPI, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(ipsec.spiInfo, inSPIID)
|
||||||
|
delete(ipsec.spis, inSPI)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy outbound
|
||||||
|
|
||||||
|
if outSPIInfo, ok := ipsec.spiInfo[outSPIID]; ok {
|
||||||
|
ipsec.log.Infof("ipsec: destroy: out %s -> %s 0x%x", localIP, remoteIP, outSPIInfo.spi)
|
||||||
|
|
||||||
|
if err := netlink.XfrmPolicyDel(xfrmPolicy(localIP, remoteIP, outSPIInfo.spi)); err != nil {
|
||||||
|
ipsec.log.Warnf("ipsec: xfrm policy del (%s, %s, 0x%x) failed: %s", localIP, remoteIP, outSPIInfo.spi, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outSA := &netlink.XfrmState{
|
||||||
|
Src: localIP,
|
||||||
|
Dst: remoteIP,
|
||||||
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
|
Spi: int(outSPIInfo.spi),
|
||||||
|
}
|
||||||
|
if err := netlink.XfrmStateDel(outSA); err != nil {
|
||||||
|
ipsec.log.Warnf("ipsec: xfrm state del (out, %s, %s, 0x%x) failed: %s", outSA.Src, outSA.Dst, outSA.Spi, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(ipsec.spiInfo, outSPIID)
|
||||||
|
delete(ipsec.spis, outSPIInfo.spi)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush removes all policies/SAs established by us. Also, it removes chains and
|
||||||
|
// rules of iptables.
|
||||||
|
//
|
||||||
|
// If destroy is true, the chains and the rules won't be re-created.
|
||||||
|
func (ipsec *IPSec) Flush(destroy bool) error {
|
||||||
|
ipsec.Lock()
|
||||||
|
defer ipsec.Unlock()
|
||||||
|
|
||||||
|
policies, err := netlink.XfrmPolicyList(syscall.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "xfrm policy list")
|
||||||
|
}
|
||||||
|
for _, p := range policies {
|
||||||
|
if p.Mark != nil && p.Mark.Value == mark && len(p.Tmpls) != 0 {
|
||||||
|
spi := SPI(p.Tmpls[0].Spi)
|
||||||
|
if err := netlink.XfrmPolicyDel(&p); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("xfrm policy del (%s, %s, 0x%x)", p.Src, p.Dst, spi))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states, err := netlink.XfrmStateList(syscall.AF_INET)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "xfrm state list")
|
||||||
|
}
|
||||||
|
for _, s := range states {
|
||||||
|
if _, ok := ipsec.spis[SPI(s.Spi)]; ok {
|
||||||
|
if err := netlink.XfrmStateDel(&s); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("xfrm state list (%s, %s, 0x%x)", s.Src, s.Dst, s.Spi))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ipsec.resetIPTables(destroy); err != nil {
|
||||||
|
return errors.Wrap(err, "reset ip tables")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// iptables
|
||||||
|
|
||||||
|
type chain struct {
|
||||||
|
table string
|
||||||
|
chain string
|
||||||
|
}
|
||||||
|
type rule struct {
|
||||||
|
table string
|
||||||
|
chain string
|
||||||
|
rulespec []string
|
||||||
|
unique bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) clearChains(chains []chain) error {
|
||||||
|
for _, c := range chains {
|
||||||
|
if err := ipsec.ipt.ClearChain(c.table, c.chain); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables clear chain (%s, %s)", c.table, c.chain))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) deleteChains(chains []chain) error {
|
||||||
|
for _, c := range chains {
|
||||||
|
if err := ipsec.ipt.DeleteChain(c.table, c.chain); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables delete chain (%s, %s)", c.table, c.chain))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) resetRules(rules []rule, destroy bool) error {
|
||||||
|
for _, r := range rules {
|
||||||
|
ok, err := ipsec.ipt.Exists(r.table, r.chain, r.rulespec...)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables exists rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case !destroy && !ok:
|
||||||
|
if err := ipsec.ipt.Append(r.table, r.chain, r.rulespec...); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables append rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
|
||||||
|
}
|
||||||
|
case destroy && ok:
|
||||||
|
if err := ipsec.ipt.Delete(r.table, r.chain, r.rulespec...); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables delete rule (%s, %s, %s)", r.table, r.chain, r.rulespec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) resetIPTables(destroy bool) error {
|
||||||
|
chains := []chain{
|
||||||
|
{tableMangle, chainIn},
|
||||||
|
{tableMangle, chainInMark},
|
||||||
|
{tableFilter, chainIn},
|
||||||
|
{tableMangle, chainOut},
|
||||||
|
{tableMangle, chainOutMark},
|
||||||
|
}
|
||||||
|
rules := []rule{
|
||||||
|
{tableMangle, "INPUT", []string{"-j", chainIn}, true},
|
||||||
|
{tableMangle, chainInMark, []string{"-j", "MARK", "--set-xmark", markStr}, true},
|
||||||
|
{tableFilter, "INPUT", []string{"-j", chainIn}, true},
|
||||||
|
{tableMangle, "OUTPUT", []string{"-j", chainOut}, true},
|
||||||
|
{tableMangle, chainOutMark, []string{"-j", "MARK", "--set-xmark", markStr}, true},
|
||||||
|
{tableFilter, "OUTPUT",
|
||||||
|
[]string{
|
||||||
|
"!", "-p", "esp",
|
||||||
|
"-m", "policy", "--dir", "out", "--pol", "none",
|
||||||
|
"-m", "mark", "--mark", markStr,
|
||||||
|
"-j", "DROP"}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ipsec.clearChains(chains); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ipsec.resetRules(rules, destroy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if destroy {
|
||||||
|
if err := ipsec.deleteChains(chains); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ruleMarkInboundESP(srcIP, dstIP net.IP, inSPI SPI) rule {
|
||||||
|
return rule{tableMangle, chainIn,
|
||||||
|
[]string{
|
||||||
|
"-s", dstIP.String(), "-d", srcIP.String(),
|
||||||
|
"-p", "esp",
|
||||||
|
"-m", "esp", "--espspi", "0x" + strconv.FormatUint(uint64(inSPI), 16),
|
||||||
|
"-j", chainInMark,
|
||||||
|
}, true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rulesDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) []rule {
|
||||||
|
udpPortStr := strconv.FormatUint(uint64(udpPort), 10)
|
||||||
|
return []rule{
|
||||||
|
ruleMarkInboundESP(srcIP, dstIP, inSPI),
|
||||||
|
{tableFilter, chainIn,
|
||||||
|
[]string{
|
||||||
|
"-s", dstIP.String(), "-d", srcIP.String(),
|
||||||
|
"-p", "udp", "--dport", udpPortStr,
|
||||||
|
"-m", "mark", "!", "--mark", markStr,
|
||||||
|
"-j", "DROP",
|
||||||
|
}, false},
|
||||||
|
{tableMangle, chainOut,
|
||||||
|
[]string{
|
||||||
|
"-s", srcIP.String(), "-d", dstIP.String(),
|
||||||
|
"-p", "udp", "--dport", udpPortStr,
|
||||||
|
"-j", chainOutMark,
|
||||||
|
}, false},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) installDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) error {
|
||||||
|
rules := rulesDropNonEncrypted(srcIP, dstIP, udpPort, inSPI)
|
||||||
|
for _, r := range rules {
|
||||||
|
appendFunc := ipsec.ipt.Append
|
||||||
|
if r.unique {
|
||||||
|
appendFunc = ipsec.ipt.AppendUnique
|
||||||
|
}
|
||||||
|
if err := appendFunc(r.table, r.chain, r.rulespec...); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables append (%s, %s, %s)", r.table, r.chain, r.rulespec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) removeDropNonEncrypted(srcIP, dstIP net.IP, udpPort int, inSPI SPI) error {
|
||||||
|
rules := rulesDropNonEncrypted(srcIP, dstIP, udpPort, inSPI)
|
||||||
|
if err := ipsec.resetRules(rules, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ipsec *IPSec) removeDropNonEncryptedInbound(srcIP, dstIP net.IP, inSPI SPI) error {
|
||||||
|
r := ruleMarkInboundESP(srcIP, dstIP, inSPI)
|
||||||
|
if err := ipsec.ipt.Delete(r.table, r.chain, r.rulespec...); err != nil {
|
||||||
|
return errors.Wrap(err, fmt.Sprintf("iptables delete unique (%s, %s, %s)", r.table, r.chain, r.rulespec))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// xfrm
|
||||||
|
|
||||||
|
func xfrmAllocSpiState(srcIP, dstIP net.IP) *netlink.XfrmState {
|
||||||
|
return &netlink.XfrmState{
|
||||||
|
Src: srcIP,
|
||||||
|
Dst: dstIP,
|
||||||
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
|
ReplayWindow: 256,
|
||||||
|
ESN: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func xfrmState(srcIP, dstIP net.IP, spi SPI, isDirOut bool, key []byte) (*netlink.XfrmState, error) {
|
||||||
|
if len(key) != keySize {
|
||||||
|
return nil, fmt.Errorf("key should be %d bytes long", keySize)
|
||||||
|
}
|
||||||
|
|
||||||
|
state := xfrmAllocSpiState(srcIP, dstIP)
|
||||||
|
|
||||||
|
state.Spi = int(spi)
|
||||||
|
state.Aead = &netlink.XfrmStateAlgo{
|
||||||
|
Name: "rfc4106(gcm(aes))",
|
||||||
|
Key: key,
|
||||||
|
ICVLen: 128,
|
||||||
|
}
|
||||||
|
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func xfrmPolicy(srcIP, dstIP net.IP, spi SPI) *netlink.XfrmPolicy {
|
||||||
|
ipMask := []byte{0xff, 0xff, 0xff, 0xff} // /32
|
||||||
|
|
||||||
|
return &netlink.XfrmPolicy{
|
||||||
|
Src: &net.IPNet{IP: srcIP, Mask: ipMask},
|
||||||
|
Dst: &net.IPNet{IP: dstIP, Mask: ipMask},
|
||||||
|
Proto: syscall.IPPROTO_UDP,
|
||||||
|
Dir: netlink.XFRM_DIR_OUT,
|
||||||
|
Mark: &netlink.XfrmMark{
|
||||||
|
Value: mark,
|
||||||
|
Mask: mark,
|
||||||
|
},
|
||||||
|
Tmpls: []netlink.XfrmPolicyTmpl{
|
||||||
|
{
|
||||||
|
Src: srcIP,
|
||||||
|
Dst: dstIP,
|
||||||
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
|
Spi: int(spi),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key derivation
|
||||||
|
|
||||||
|
func genNonce() ([]byte, error) {
|
||||||
|
buf := make([]byte, nonceSize)
|
||||||
|
n, err := rand.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("crypto rand failed: %s", err)
|
||||||
|
}
|
||||||
|
if n != nonceSize {
|
||||||
|
return nil, fmt.Errorf("not enough of random data: %d", n)
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deriveKey(sessionKey []byte, nonce []byte, peerName mesh.PeerName) ([]byte, error) {
|
||||||
|
key := make([]byte, keySize)
|
||||||
|
|
||||||
|
info := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(info, uint64(peerName))
|
||||||
|
|
||||||
|
hkdf := hkdf.New(sha256.New, sessionKey, nonce, info)
|
||||||
|
|
||||||
|
n, err := io.ReadFull(hkdf, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if n != keySize {
|
||||||
|
return nil, fmt.Errorf("derived too short key: %d", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocol Messages
|
||||||
|
|
||||||
|
type msgInitSARemote struct {
|
||||||
|
nonce []byte
|
||||||
|
spi SPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func deserializeMsgInitSARemote(b []byte) (*msgInitSARemote, error) {
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil, fmt.Errorf("empty msg")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &msgInitSARemote{}
|
||||||
|
if len(b) != msg.size() {
|
||||||
|
return nil, fmt.Errorf("invalid payload size: %d", len(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.nonce = make([]byte, nonceSize)
|
||||||
|
copy(msg.nonce, b[:nonceSize])
|
||||||
|
b = b[nonceSize:]
|
||||||
|
|
||||||
|
msg.spi = SPI(binary.BigEndian.Uint32(b))
|
||||||
|
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *msgInitSARemote) size() int {
|
||||||
|
return nonceSize + 32 // SPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *msgInitSARemote) serialize() []byte {
|
||||||
|
b := make([]byte, msg.size())
|
||||||
|
|
||||||
|
copy(b[:nonceSize], msg.nonce)
|
||||||
|
binary.BigEndian.PutUint32(b[nonceSize:], uint32(msg.spi))
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RandomMAC() (net.HardwareAddr, error) {
|
||||||
|
mac := make([]byte, 6)
|
||||||
|
if _, err := rand.Read(mac); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
setUnicastAndLocal(mac)
|
||||||
|
|
||||||
|
return net.HardwareAddr(mac), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MACfromUUID(uuid []byte) net.HardwareAddr {
|
||||||
|
hash := sha256.New()
|
||||||
|
// We salt the input just as a precaution to avoid clashes with
|
||||||
|
// other applications who might have had the bright idea of
|
||||||
|
// generating MACs in the same way.
|
||||||
|
hash.Write([]byte("9oBJ0Jmip-"))
|
||||||
|
hash.Write(uuid)
|
||||||
|
sum := hash.Sum(nil)
|
||||||
|
|
||||||
|
setUnicastAndLocal(sum)
|
||||||
|
|
||||||
|
return net.HardwareAddr(sum[:6])
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the first byte of the MAC, the 'multicast' bit should be
|
||||||
|
// clear and 'locally administered' bit should be set.
|
||||||
|
func setUnicastAndLocal(mac []byte) {
|
||||||
|
mac[0] = (mac[0] & 0xFE) | 0x02
|
||||||
|
}
|
||||||
+2
-2
@@ -13,7 +13,7 @@ import (
|
|||||||
func CheckNetworkFree(subnet *net.IPNet, ignoreIfaceNames map[string]struct{}) error {
|
func CheckNetworkFree(subnet *net.IPNet, ignoreIfaceNames map[string]struct{}) error {
|
||||||
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
||||||
if route.Dst != nil && overlaps(route.Dst, subnet) {
|
if route.Dst != nil && overlaps(route.Dst, subnet) {
|
||||||
return fmt.Errorf("Network %s overlaps with existing route %s on host.", subnet, route.Dst)
|
return fmt.Errorf("Network %s overlaps with existing route %s on host", subnet, route.Dst)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -29,7 +29,7 @@ func overlaps(n1, n2 *net.IPNet) bool {
|
|||||||
func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) error {
|
func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) error {
|
||||||
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
||||||
if route.Dst != nil && route.Dst.Contains(addr) {
|
if route.Dst != nil && route.Dst.Contains(addr) {
|
||||||
return fmt.Errorf("Address %s overlaps with existing route %s on host.", addr, route.Dst)
|
return fmt.Errorf("Address %s overlaps with existing route %s on host", addr, route.Dst)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/weaveworks/mesh"
|
||||||
|
"github.com/weaveworks/weave/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getOldStyleSystemUUID() ([]byte, error) {
|
||||||
|
uuid, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
uuid, err = ioutil.ReadFile("/sys/hypervisor/uuid")
|
||||||
|
}
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSystemUUID(hostRoot string) ([]byte, error) {
|
||||||
|
uuid, err := getOldStyleSystemUUID()
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
machineid, err := ioutil.ReadFile(hostRoot + "/etc/machine-id")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
machineid, err = ioutil.ReadFile(hostRoot + "/var/lib/dbus/machine-id")
|
||||||
|
}
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(uuid) == 0 && len(machineid) == 0 {
|
||||||
|
return nil, errors.New("All system IDs are blank")
|
||||||
|
}
|
||||||
|
return append(machineid, uuid...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPersistedPeerName(pathName string) (mesh.PeerName, error) {
|
||||||
|
d, err := db.NewBoltDBReadOnly(pathName)
|
||||||
|
if err != nil {
|
||||||
|
return mesh.UnknownPeerName, err
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
var peerName mesh.PeerName
|
||||||
|
nameFound, err := d.Load(db.NameIdent, &peerName)
|
||||||
|
if err != nil || !nameFound {
|
||||||
|
return mesh.UnknownPeerName, err
|
||||||
|
}
|
||||||
|
return peerName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemPeerName returns an ID derived from concatenated machine-id
|
||||||
|
// (either systemd or dbus), the system (aka bios) UUID and the
|
||||||
|
// hypervisor UUID. It is tweaked and formatted to be usable as a mac address
|
||||||
|
func GetSystemPeerName(dbPrefix, hostRoot string) (string, error) {
|
||||||
|
// Check if we have a persisted name that matches the old-style ID for this host
|
||||||
|
if oldUUID, err := getOldStyleSystemUUID(); err == nil {
|
||||||
|
pathName := dbPrefix + db.FileName
|
||||||
|
if _, err := os.Stat(pathName); err == nil {
|
||||||
|
persistedPeerName, err := getPersistedPeerName(pathName)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if persistedPeerName == mesh.PeerNameFromBin(MACfromUUID(oldUUID)) {
|
||||||
|
return persistedPeerName.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var mac net.HardwareAddr
|
||||||
|
if uuid, err := getSystemUUID(hostRoot); err == nil {
|
||||||
|
mac = MACfromUUID(uuid)
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
mac, err = RandomMAC()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mac.String(), nil
|
||||||
|
}
|
||||||
+37
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
@@ -271,3 +272,39 @@ func subnets(addrs []netlink.Addr) map[string]struct{} {
|
|||||||
}
|
}
|
||||||
return subnets
|
return subnets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addNatRule(ipt *iptables.IPTables, rulespec ...string) error {
|
||||||
|
// Loop until we get an exit code other than "temporarily unavailable"
|
||||||
|
for {
|
||||||
|
if err := ipt.AppendUnique("nat", "WEAVE", rulespec...); err != nil {
|
||||||
|
if ierr, ok := err.(*iptables.Error); ok {
|
||||||
|
if status, ok := ierr.ExitError.Sys().(syscall.WaitStatus); ok {
|
||||||
|
// (magic exit code 4 found in iptables source code; undocumented)
|
||||||
|
if status.ExitStatus() == 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExposeNAT(ipnet net.IPNet) error {
|
||||||
|
ipt, err := iptables.New()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cidr := ipnet.String()
|
||||||
|
if err := addNatRule(ipt, "-s", cidr, "-d", "224.0.0.0/4", "-j", "RETURN"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := addNatRule(ipt, "-d", cidr, "!", "-s", cidr, "-j", "MASQUERADE"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := addNatRule(ipt, "-s", cidr, "!", "-d", cidr, "-j", "MASQUERADE"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+10
-10
@@ -3,12 +3,12 @@ package npc
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
coreapi "k8s.io/client-go/pkg/api/v1"
|
coreapi "k8s.io/client-go/pkg/api/v1"
|
||||||
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
extnapi "k8s.io/client-go/pkg/apis/extensions/v1beta1"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/npc/ipset"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ func (npc *controller) AddPod(obj *coreapi.Pod) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT AddPod %#v", obj)
|
common.Log.Debugf("EVENT AddPod %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.addPod(obj), "add pod")
|
return errors.Wrap(ns.addPod(obj), "add pod")
|
||||||
})
|
})
|
||||||
@@ -96,7 +96,7 @@ func (npc *controller) UpdatePod(oldObj, newObj *coreapi.Pod) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT UpdatePod %#v %#v", oldObj, newObj)
|
common.Log.Debugf("EVENT UpdatePod %s %s", js(oldObj), js(newObj))
|
||||||
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.updatePod(oldObj, newObj), "update pod")
|
return errors.Wrap(ns.updatePod(oldObj, newObj), "update pod")
|
||||||
})
|
})
|
||||||
@@ -106,7 +106,7 @@ func (npc *controller) DeletePod(obj *coreapi.Pod) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT DeletePod %#v", obj)
|
common.Log.Debugf("EVENT DeletePod %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.deletePod(obj), "delete pod")
|
return errors.Wrap(ns.deletePod(obj), "delete pod")
|
||||||
})
|
})
|
||||||
@@ -116,7 +116,7 @@ func (npc *controller) AddNetworkPolicy(obj *extnapi.NetworkPolicy) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT AddNetworkPolicy %#v", obj)
|
common.Log.Infof("EVENT AddNetworkPolicy %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.addNetworkPolicy(obj), "add network policy")
|
return errors.Wrap(ns.addNetworkPolicy(obj), "add network policy")
|
||||||
})
|
})
|
||||||
@@ -126,7 +126,7 @@ func (npc *controller) UpdateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT UpdateNetworkPolicy %#v %#v", oldObj, newObj)
|
common.Log.Infof("EVENT UpdateNetworkPolicy %s %s", js(oldObj), js(newObj))
|
||||||
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(oldObj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.updateNetworkPolicy(oldObj, newObj), "update network policy")
|
return errors.Wrap(ns.updateNetworkPolicy(oldObj, newObj), "update network policy")
|
||||||
})
|
})
|
||||||
@@ -136,7 +136,7 @@ func (npc *controller) DeleteNetworkPolicy(obj *extnapi.NetworkPolicy) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT DeleteNetworkPolicy %#v", obj)
|
common.Log.Infof("EVENT DeleteNetworkPolicy %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Namespace, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.deleteNetworkPolicy(obj), "delete network policy")
|
return errors.Wrap(ns.deleteNetworkPolicy(obj), "delete network policy")
|
||||||
})
|
})
|
||||||
@@ -146,7 +146,7 @@ func (npc *controller) AddNamespace(obj *coreapi.Namespace) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT AddNamespace %#v", obj)
|
common.Log.Infof("EVENT AddNamespace %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.addNamespace(obj), "add namespace")
|
return errors.Wrap(ns.addNamespace(obj), "add namespace")
|
||||||
})
|
})
|
||||||
@@ -156,7 +156,7 @@ func (npc *controller) UpdateNamespace(oldObj, newObj *coreapi.Namespace) error
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT UpdateNamespace%#v %#v", oldObj, newObj)
|
common.Log.Infof("EVENT UpdateNamespace %s %s", js(oldObj), js(newObj))
|
||||||
return npc.withNS(oldObj.ObjectMeta.Name, func(ns *ns) error {
|
return npc.withNS(oldObj.ObjectMeta.Name, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.updateNamespace(oldObj, newObj), "update namespace")
|
return errors.Wrap(ns.updateNamespace(oldObj, newObj), "update namespace")
|
||||||
})
|
})
|
||||||
@@ -166,7 +166,7 @@ func (npc *controller) DeleteNamespace(obj *coreapi.Namespace) error {
|
|||||||
npc.Lock()
|
npc.Lock()
|
||||||
defer npc.Unlock()
|
defer npc.Unlock()
|
||||||
|
|
||||||
log.Infof("EVENT DeleteNamespace %#v", obj)
|
common.Log.Infof("EVENT DeleteNamespace %s", js(obj))
|
||||||
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
|
return npc.withNS(obj.ObjectMeta.Name, func(ns *ns) error {
|
||||||
return errors.Wrap(ns.deleteNamespace(obj), "delete namespace")
|
return errors.Wrap(ns.deleteNamespace(obj), "delete namespace")
|
||||||
})
|
})
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package npc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func js(v interface{}) string {
|
||||||
|
a, _ := json.Marshal(v)
|
||||||
|
return string(a)
|
||||||
|
}
|
||||||
+39
-6
@@ -1,7 +1,6 @@
|
|||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -11,6 +10,8 @@ import (
|
|||||||
"github.com/google/gopacket/pcapgo"
|
"github.com/google/gopacket/pcapgo"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -26,18 +27,18 @@ var (
|
|||||||
func gatherMetrics() {
|
func gatherMetrics() {
|
||||||
pipe, err := os.Open("/var/log/ulogd.pcap")
|
pipe, err := os.Open("/var/log/ulogd.pcap")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to open pcap: %v", err)
|
common.Log.Fatalf("Failed to open pcap: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err := pcapgo.NewReader(pipe)
|
reader, err := pcapgo.NewReader(pipe)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read pcap header: %v", err)
|
common.Log.Fatalf("Failed to read pcap header: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
data, _, err := reader.ReadPacketData()
|
data, _, err := reader.ReadPacketData()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to read pcap packet: %v", err)
|
common.Log.Fatalf("Failed to read pcap packet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
|
||||||
@@ -46,6 +47,7 @@ func gatherMetrics() {
|
|||||||
tcp, _ := tcpLayer.(*layers.TCP)
|
tcp, _ := tcpLayer.(*layers.TCP)
|
||||||
if tcp.SYN && !tcp.ACK { // Only plain SYN constitutes a NEW TCP connection
|
if tcp.SYN && !tcp.ACK { // Only plain SYN constitutes a NEW TCP connection
|
||||||
blockedConnections.With(prometheus.Labels{"protocol": "tcp", "dport": strconv.Itoa(int(tcp.DstPort))}).Inc()
|
blockedConnections.With(prometheus.Labels{"protocol": "tcp", "dport": strconv.Itoa(int(tcp.DstPort))}).Inc()
|
||||||
|
common.Log.Warnf("TCP connection from %v:%d to %v:%d blocked by Weave NPC.", srcIP(packet), tcp.SrcPort, dstIP(packet), tcp.DstPort)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,11 +55,42 @@ func gatherMetrics() {
|
|||||||
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
|
||||||
udp, _ := udpLayer.(*layers.UDP)
|
udp, _ := udpLayer.(*layers.UDP)
|
||||||
blockedConnections.With(prometheus.Labels{"protocol": "udp", "dport": strconv.Itoa(int(udp.DstPort))}).Inc()
|
blockedConnections.With(prometheus.Labels{"protocol": "udp", "dport": strconv.Itoa(int(udp.DstPort))}).Inc()
|
||||||
|
common.Log.Warnf("UDP connection from %v:%d to %v:%d blocked by Weave NPC.", srcIP(packet), udp.SrcPort, dstIP(packet), udp.DstPort)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unknownIP string = "<unknown IP>"
|
||||||
|
|
||||||
|
func srcIP(packet gopacket.Packet) string {
|
||||||
|
if layer := packet.Layer(layers.LayerTypeIPv4); layer != nil {
|
||||||
|
if ip, ok := layer.(*layers.IPv4); ok {
|
||||||
|
return ip.SrcIP.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if layer := packet.Layer(layers.LayerTypeIPv6); layer != nil {
|
||||||
|
if ip, ok := layer.(*layers.IPv6); ok {
|
||||||
|
return ip.SrcIP.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unknownIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func dstIP(packet gopacket.Packet) string {
|
||||||
|
if layer := packet.Layer(layers.LayerTypeIPv4); layer != nil {
|
||||||
|
if ip, ok := layer.(*layers.IPv4); ok {
|
||||||
|
return ip.DstIP.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if layer := packet.Layer(layers.LayerTypeIPv6); layer != nil {
|
||||||
|
if ip, ok := layer.(*layers.IPv6); ok {
|
||||||
|
return ip.DstIP.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unknownIP
|
||||||
|
}
|
||||||
|
|
||||||
func Start(addr string) error {
|
func Start(addr string) error {
|
||||||
if err := prometheus.Register(blockedConnections); err != nil {
|
if err := prometheus.Register(blockedConnections); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -66,9 +99,9 @@ func Start(addr string) error {
|
|||||||
http.Handle("/metrics", promhttp.Handler())
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("Serving /metrics on %s", addr)
|
common.Log.Infof("Serving /metrics on %s", addr)
|
||||||
if err := http.ListenAndServe(addr, nil); err != nil {
|
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||||
log.Fatalf("Failed to bind metrics server: %v", err)
|
common.Log.Fatalf("Failed to bind metrics server: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
+8
-7
@@ -3,7 +3,6 @@ package npc
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"k8s.io/client-go/pkg/api/unversioned"
|
"k8s.io/client-go/pkg/api/unversioned"
|
||||||
coreapi "k8s.io/client-go/pkg/api/v1"
|
coreapi "k8s.io/client-go/pkg/api/v1"
|
||||||
@@ -11,6 +10,7 @@ import (
|
|||||||
"k8s.io/client-go/pkg/types"
|
"k8s.io/client-go/pkg/types"
|
||||||
"k8s.io/client-go/pkg/util/uuid"
|
"k8s.io/client-go/pkg/util/uuid"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/npc/ipset"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ func (ns *ns) updateNetworkPolicy(oldObj, newObj *extnapi.NetworkPolicy) error {
|
|||||||
if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
|
if err := ns.nsSelectors.provision(oldObj.ObjectMeta.UID, oldNsSelectors, newNsSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newNsSelectors); err != nil {
|
if err := ns.podSelectors.provision(oldObj.ObjectMeta.UID, oldPodSelectors, newPodSelectors); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
|
if err := ns.rules.provision(oldObj.ObjectMeta.UID, oldRules, newRules); err != nil {
|
||||||
@@ -302,8 +302,9 @@ func (ns *ns) deleteNamespace(obj *coreapi.Namespace) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hasIP(pod *coreapi.Pod) bool {
|
func hasIP(pod *coreapi.Pod) bool {
|
||||||
// Ensure pod has an IP address and isn't sharing the host network namespace
|
// Ensure pod isn't dead, has an IP address and isn't sharing the host network namespace
|
||||||
return len(pod.Status.PodIP) > 0 && !pod.Spec.HostNetwork
|
return pod.Status.Phase != "Succeeded" && pod.Status.Phase != "Failed" &&
|
||||||
|
len(pod.Status.PodIP) > 0 && !pod.Spec.HostNetwork
|
||||||
}
|
}
|
||||||
|
|
||||||
func equals(a, b map[string]string) bool {
|
func equals(a, b map[string]string) bool {
|
||||||
@@ -319,14 +320,14 @@ func equals(a, b map[string]string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isDefaultDeny(namespace *coreapi.Namespace) bool {
|
func isDefaultDeny(namespace *coreapi.Namespace) bool {
|
||||||
nnpJson, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
|
nnpJSON, found := namespace.ObjectMeta.Annotations["net.beta.kubernetes.io/network-policy"]
|
||||||
if !found {
|
if !found {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var nnp NamespaceNetworkPolicy
|
var nnp NamespaceNetworkPolicy
|
||||||
if err := json.Unmarshal([]byte(nnpJson), &nnp); err != nil {
|
if err := json.Unmarshal([]byte(nnpJSON), &nnp); err != nil {
|
||||||
log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
|
common.Log.Warn("Ignoring network policy annotation: unmarshal failed:", err)
|
||||||
// If we can't understand the annotation, behave as if it isn't present
|
// If we can't understand the annotation, behave as if it isn't present
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -3,9 +3,10 @@ package npc
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"k8s.io/client-go/pkg/types"
|
"k8s.io/client-go/pkg/types"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ruleSpec struct {
|
type ruleSpec struct {
|
||||||
@@ -47,7 +48,7 @@ func (rs *ruleSet) deprovision(user types.UID, current, desired map[string]*rule
|
|||||||
if _, found := desired[key]; !found {
|
if _, found := desired[key]; !found {
|
||||||
delete(rs.users[key], user)
|
delete(rs.users[key], user)
|
||||||
if len(rs.users[key]) == 0 {
|
if len(rs.users[key]) == 0 {
|
||||||
log.Infof("deleting rule: %v", spec.args)
|
common.Log.Infof("deleting rule: %v", spec.args)
|
||||||
if err := rs.ipt.Delete(TableFilter, IngressChain, spec.args...); err != nil {
|
if err := rs.ipt.Delete(TableFilter, IngressChain, spec.args...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -63,7 +64,7 @@ func (rs *ruleSet) provision(user types.UID, current, desired map[string]*ruleSp
|
|||||||
for key, spec := range desired {
|
for key, spec := range desired {
|
||||||
if _, found := current[key]; !found {
|
if _, found := current[key]; !found {
|
||||||
if _, found := rs.users[key]; !found {
|
if _, found := rs.users[key]; !found {
|
||||||
log.Infof("adding rule: %v", spec.args)
|
common.Log.Infof("adding rule: %v", spec.args)
|
||||||
if err := rs.ipt.Append(TableFilter, IngressChain, spec.args...); err != nil {
|
if err := rs.ipt.Append(TableFilter, IngressChain, spec.args...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -1,11 +1,11 @@
|
|||||||
package npc
|
package npc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"k8s.io/client-go/pkg/api/unversioned"
|
"k8s.io/client-go/pkg/api/unversioned"
|
||||||
"k8s.io/client-go/pkg/labels"
|
"k8s.io/client-go/pkg/labels"
|
||||||
"k8s.io/client-go/pkg/types"
|
"k8s.io/client-go/pkg/types"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/npc/ipset"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ func (s *selector) matches(labelMap map[string]string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *selector) addEntry(entry string) error {
|
func (s *selector) addEntry(entry string) error {
|
||||||
log.Infof("adding entry %s to %s", entry, s.spec.ipsetName)
|
common.Log.Infof("adding entry %s to %s", entry, s.spec.ipsetName)
|
||||||
return s.ips.AddEntry(s.spec.ipsetName, entry)
|
return s.ips.AddEntry(s.spec.ipsetName, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *selector) delEntry(entry string) error {
|
func (s *selector) delEntry(entry string) error {
|
||||||
log.Infof("deleting entry %s from %s", entry, s.spec.ipsetName)
|
common.Log.Infof("deleting entry %s from %s", entry, s.spec.ipsetName)
|
||||||
return s.ips.DelEntry(s.spec.ipsetName, entry)
|
return s.ips.DelEntry(s.spec.ipsetName, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ func (ss *selectorSet) deprovision(user types.UID, current, desired map[string]*
|
|||||||
if _, found := desired[key]; !found {
|
if _, found := desired[key]; !found {
|
||||||
delete(ss.users[key], user)
|
delete(ss.users[key], user)
|
||||||
if len(ss.users[key]) == 0 {
|
if len(ss.users[key]) == 0 {
|
||||||
log.Infof("destroying ipset: %#v", spec)
|
common.Log.Infof("destroying ipset: %#v", spec)
|
||||||
if err := ss.ips.Destroy(spec.ipsetName); err != nil {
|
if err := ss.ips.Destroy(spec.ipsetName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ func (ss *selectorSet) provision(user types.UID, current, desired map[string]*se
|
|||||||
for key, spec := range desired {
|
for key, spec := range desired {
|
||||||
if _, found := current[key]; !found {
|
if _, found := current[key]; !found {
|
||||||
if _, found := ss.users[key]; !found {
|
if _, found := ss.users[key]; !found {
|
||||||
log.Infof("creating ipset: %#v", spec)
|
common.Log.Infof("creating ipset: %#v", spec)
|
||||||
if err := ss.ips.Create(spec.ipsetName, spec.ipsetType); err != nil {
|
if err := ss.ips.Create(spec.ipsetName, spec.ipsetType); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -1,21 +1,26 @@
|
|||||||
package ulogd
|
package ulogd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func waitForExit(cmd *exec.Cmd) {
|
func waitForExit(cmd *exec.Cmd) {
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
log.Fatalf("ulogd terminated: %v", err)
|
common.Log.Fatalf("ulogd terminated: %v", err)
|
||||||
}
|
}
|
||||||
log.Fatal("ulogd terminated normally")
|
common.Log.Fatal("ulogd terminated normally")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start() error {
|
func Start() error {
|
||||||
cmd := exec.Command("/usr/sbin/ulogd", "-v")
|
cmd := exec.Command("/usr/sbin/ulogd", "-v")
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Pdeathsig: syscall.SIGKILL,
|
||||||
|
}
|
||||||
stdout, err := cmd.StderrPipe()
|
stdout, err := cmd.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -72,9 +72,8 @@ func splitPoolID(poolID string) (subnet, iprange *net.IPNet, err error) {
|
|||||||
func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (ip *net.IPNet, _ map[string]string, err error) {
|
func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (ip *net.IPNet, _ map[string]string, err error) {
|
||||||
i.logReq("RequestAddress", poolID, address, options)
|
i.logReq("RequestAddress", poolID, address, options)
|
||||||
defer func() { i.logRes("RequestAddress", err, ip) }()
|
defer func() { i.logRes("RequestAddress", err, ip) }()
|
||||||
// If we pass magic string "_" to weave IPAM it stores the address under its own string
|
|
||||||
if poolID == "weavepool" { // old-style
|
if poolID == "weavepool" { // old-style
|
||||||
ip, err = i.weave.AllocateIP("_")
|
ip, err = i.weave.AllocateIP(api.NoContainerID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
subnet, iprange, err := splitPoolID(poolID)
|
subnet, iprange, err := splitPoolID(poolID)
|
||||||
@@ -83,12 +82,12 @@ func (i *Ipam) RequestAddress(poolID string, address net.IP, options map[string]
|
|||||||
}
|
}
|
||||||
if address != nil { // try to claim specific address requested
|
if address != nil { // try to claim specific address requested
|
||||||
ip = &net.IPNet{IP: address, Mask: subnet.Mask}
|
ip = &net.IPNet{IP: address, Mask: subnet.Mask}
|
||||||
if err = i.weave.ClaimIP("_", ip); err != nil {
|
if err = i.weave.ClaimIP(api.NoContainerID, ip); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We are lying slightly to IPAM here: the range is not a subnet
|
// We are lying slightly to IPAM here: the range is not a subnet
|
||||||
if ip, err = i.weave.AllocateIPInSubnet("_", iprange); err != nil {
|
if ip, err = i.weave.AllocateIPInSubnet(api.NoContainerID, iprange); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ip.Mask = subnet.Mask // fix up the subnet we lied about
|
ip.Mask = subnet.Mask // fix up the subnet we lied about
|
||||||
|
|||||||
+11
-21
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/appc/cni/pkg/ipam"
|
"github.com/appc/cni/pkg/ipam"
|
||||||
"github.com/appc/cni/pkg/skel"
|
"github.com/appc/cni/pkg/skel"
|
||||||
@@ -72,8 +73,8 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
|
|||||||
|
|
||||||
// If config says nothing about routes or gateway, default one will be via the bridge
|
// If config says nothing about routes or gateway, default one will be via the bridge
|
||||||
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
|
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
|
||||||
bridgeIP, err := findBridgeIP(conf.BrName, result.IP4.IP)
|
bridgeIP, err := weavenet.FindBridgeIP(conf.BrName, &result.IP4.IP)
|
||||||
if err == errBridgeNoIP {
|
if err == weavenet.ErrBridgeNoIP {
|
||||||
bridgeArgs := *args
|
bridgeArgs := *args
|
||||||
bridgeArgs.ContainerID = "weave:expose"
|
bridgeArgs.ContainerID = "weave:expose"
|
||||||
bridgeIPResult, err := c.getIP(conf.IPAM.Type, &bridgeArgs)
|
bridgeIPResult, err := c.getIP(conf.IPAM.Type, &bridgeArgs)
|
||||||
@@ -83,6 +84,9 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
|
|||||||
if err := assignBridgeIP(conf.BrName, bridgeIPResult.IP4.IP); err != nil {
|
if err := assignBridgeIP(conf.BrName, bridgeIPResult.IP4.IP); err != nil {
|
||||||
return fmt.Errorf("unable to assign IP address to bridge: %s", err)
|
return fmt.Errorf("unable to assign IP address to bridge: %s", err)
|
||||||
}
|
}
|
||||||
|
if err := weavenet.ExposeNAT(bridgeIPResult.IP4.IP); err != nil {
|
||||||
|
return fmt.Errorf("unable to create NAT rules: %s", err)
|
||||||
|
}
|
||||||
bridgeIP = bridgeIPResult.IP4.IP.IP
|
bridgeIP = bridgeIPResult.IP4.IP.IP
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -150,30 +154,16 @@ func assignBridgeIP(bridgeName string, ipnet net.IPNet) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: &ipnet}); err != nil {
|
if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: &ipnet}); err != nil {
|
||||||
|
// Treat as non-error if this address is already there
|
||||||
|
// - maybe another copy of this program just added it
|
||||||
|
if err == syscall.Errno(syscall.EEXIST) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return fmt.Errorf("failed to add IP address to %q: %v", bridgeName, err)
|
return fmt.Errorf("failed to add IP address to %q: %v", bridgeName, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errBridgeNoIP = fmt.Errorf("Bridge has no IP address")
|
|
||||||
|
|
||||||
func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) {
|
|
||||||
netdev, err := weavenet.GetBridgeNetDev(bridgeName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
|
|
||||||
}
|
|
||||||
if len(netdev.CIDRs) == 0 {
|
|
||||||
return nil, errBridgeNoIP
|
|
||||||
}
|
|
||||||
for _, cidr := range netdev.CIDRs {
|
|
||||||
if subnet.Contains(cidr.IP) {
|
|
||||||
return cidr.IP, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// None in the required subnet; just return the first one
|
|
||||||
return netdev.CIDRs[0].IP, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
|
func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
|
||||||
conf, err := loadNetConf(args.StdinData)
|
conf, err := loadNetConf(args.StdinData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
FROM DOCKERHUB_USER/weave
|
FROM DOCKERHUB_USER/weaveARCH_EXT
|
||||||
ADD ./plugin /home/weave/
|
ADD ./plugin /home/weave/
|
||||||
ENTRYPOINT ["/home/weave/plugin"]
|
ENTRYPOINT ["/home/weave/plugin"]
|
||||||
+1
-17
@@ -11,7 +11,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
cni "github.com/appc/cni/pkg/skel"
|
|
||||||
"github.com/docker/libnetwork/ipamapi"
|
"github.com/docker/libnetwork/ipamapi"
|
||||||
weaveapi "github.com/weaveworks/weave/api"
|
weaveapi "github.com/weaveworks/weave/api"
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
@@ -22,15 +21,13 @@ import (
|
|||||||
"github.com/weaveworks/weave/plugin/skel"
|
"github.com/weaveworks/weave/plugin/skel"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "(unreleased version)"
|
var version = "unreleased"
|
||||||
|
|
||||||
var Log = common.Log
|
var Log = common.Log
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var (
|
var (
|
||||||
justVersion bool
|
justVersion bool
|
||||||
cniNet bool
|
|
||||||
cniIpam bool
|
|
||||||
address string
|
address string
|
||||||
meshAddress string
|
meshAddress string
|
||||||
logLevel string
|
logLevel string
|
||||||
@@ -38,8 +35,6 @@ func main() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
flag.BoolVar(&justVersion, "version", false, "print version and exit")
|
flag.BoolVar(&justVersion, "version", false, "print version and exit")
|
||||||
flag.BoolVar(&cniNet, "cni-net", false, "act as a CNI network plugin")
|
|
||||||
flag.BoolVar(&cniIpam, "cni-ipam", false, "act as a CNI IPAM plugin")
|
|
||||||
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
|
flag.StringVar(&logLevel, "log-level", "info", "logging level (debug, info, warning, error)")
|
||||||
flag.StringVar(&address, "socket", "/run/docker/plugins/weave.sock", "socket on which to listen")
|
flag.StringVar(&address, "socket", "/run/docker/plugins/weave.sock", "socket on which to listen")
|
||||||
flag.StringVar(&meshAddress, "meshsocket", "/run/docker/plugins/weavemesh.sock", "socket on which to listen in mesh mode")
|
flag.StringVar(&meshAddress, "meshsocket", "/run/docker/plugins/weavemesh.sock", "socket on which to listen in mesh mode")
|
||||||
@@ -56,17 +51,6 @@ func main() {
|
|||||||
|
|
||||||
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), Log)
|
weave := weaveapi.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), Log)
|
||||||
|
|
||||||
switch {
|
|
||||||
case cniIpam || strings.HasSuffix(os.Args[0], "weave-ipam"):
|
|
||||||
i := ipamplugin.NewIpam(weave)
|
|
||||||
cni.PluginMain(i.CmdAdd, i.CmdDel)
|
|
||||||
os.Exit(0)
|
|
||||||
case cniNet || strings.HasSuffix(os.Args[0], "weave-net"):
|
|
||||||
n := netplugin.NewCNIPlugin(weave)
|
|
||||||
cni.PluginMain(n.CmdAdd, n.CmdDel)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 1.21 is the first version that supports docker network commands
|
// API 1.21 is the first version that supports docker network commands
|
||||||
dockerClient, err := docker.NewVersionedClientFromEnv("1.21")
|
dockerClient, err := docker.NewVersionedClientFromEnv("1.21")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
FROM DOCKERHUB_USER/weave
|
FROM DOCKERHUB_USER/weaveARCH_EXT
|
||||||
ADD ./launch.sh ./kube-peers /home/weave/
|
ADD ./launch.sh ./kube-peers /home/weave/
|
||||||
ENTRYPOINT ["/home/weave/launch.sh"]
|
ENTRYPOINT ["/home/weave/launch.sh"]
|
||||||
+50
-91
@@ -6,81 +6,30 @@ set -e
|
|||||||
IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
|
IPALLOC_RANGE=${IPALLOC_RANGE:-10.32.0.0/12}
|
||||||
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
|
HTTP_ADDR=${WEAVE_HTTP_ADDR:-127.0.0.1:6784}
|
||||||
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
|
STATUS_ADDR=${WEAVE_STATUS_ADDR:-0.0.0.0:6782}
|
||||||
|
HOST_ROOT=${HOST_ROOT:-/host}
|
||||||
|
|
||||||
|
# Check if the IP range overlaps anything existing on the host
|
||||||
|
/usr/bin/weaveutil netcheck $IPALLOC_RANGE weave
|
||||||
|
|
||||||
# Default for network policy
|
# Default for network policy
|
||||||
EXPECT_NPC=${EXPECT_NPC:-1}
|
EXPECT_NPC=${EXPECT_NPC:-1}
|
||||||
|
|
||||||
# kube-proxy requires that bridged traffic passes through netfilter
|
# kube-proxy requires that bridged traffic passes through netfilter
|
||||||
if [ ! -f /proc/sys/net/bridge/bridge-nf-call-iptables ] ; then
|
if ! BRIDGE_NF_ENABLED=$(cat /proc/sys/net/bridge/bridge-nf-call-iptables); then
|
||||||
echo /proc/sys/net/bridge/bridge-nf-call-iptables not found >&2
|
echo "Cannot detect bridge-nf support - network policy and iptables mode kubeproxy may not work reliably" >&2
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
|
|
||||||
|
|
||||||
# Create CNI config, if not already there
|
|
||||||
if [ ! -f /etc/cni/net.d/10-weave.conf ] ; then
|
|
||||||
mkdir -p /etc/cni/net.d
|
|
||||||
cat > /etc/cni/net.d/10-weave.conf <<EOF
|
|
||||||
{
|
|
||||||
"name": "weave",
|
|
||||||
"type": "weave-net"
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
|
|
||||||
SOURCE_BINARY=/usr/bin/weaveutil
|
|
||||||
VERSION=$(/home/weave/weaver --version | sed -E 's/weave router (.*?)/\1/')
|
|
||||||
PLUGIN="weave-plugin-$VERSION"
|
|
||||||
|
|
||||||
install_cni_plugin() {
|
|
||||||
mkdir -p $1 || return 1
|
|
||||||
if [ ! -f $1/$PLUGIN ]; then
|
|
||||||
cp "$SOURCE_BINARY" $1/$PLUGIN
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
upgrade_cni_plugin_symlink() {
|
|
||||||
# Remove potential temporary symlink from previous failed upgrade:
|
|
||||||
rm -f $1/$2.tmp
|
|
||||||
# Atomically create a symlink to the plugin:
|
|
||||||
ln -s $1/$PLUGIN $1/$2.tmp && mv -f $1/$2.tmp $1/$2
|
|
||||||
}
|
|
||||||
|
|
||||||
upgrade_cni_plugin() {
|
|
||||||
# Check if weave-net and weave-ipam are (legacy) copies of the plugin, and
|
|
||||||
# if so remove these so symlinks can be used instead from now onwards.
|
|
||||||
if [ -f $1/weave-net -a ! -L $1/weave-net ]; then rm $1/weave-net; fi
|
|
||||||
if [ -f $1/weave-ipam -a ! -L $1/weave-ipam ]; then rm $1/weave-ipam; fi
|
|
||||||
|
|
||||||
# Create two symlinks to the plugin, as it has a different
|
|
||||||
# behaviour depending on its name:
|
|
||||||
if [ "$(readlink -f $1/weave-net)" != "$1/$PLUGIN" ]; then
|
|
||||||
upgrade_cni_plugin_symlink $1 weave-net
|
|
||||||
fi
|
|
||||||
if [ "$(readlink -f $1/weave-ipam)" != "$1/$PLUGIN" ]; then
|
|
||||||
upgrade_cni_plugin_symlink $1 weave-ipam
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install CNI plugin binary to typical CNI bin location
|
|
||||||
# with fall-back to CNI directory used by kube-up on GCI OS.
|
|
||||||
if install_cni_plugin /opt/cni/bin ; then
|
|
||||||
upgrade_cni_plugin /opt/cni/bin
|
|
||||||
elif install_cni_plugin /host_home/kubernetes/bin ; then
|
|
||||||
upgrade_cni_plugin /host_home/kubernetes/bin
|
|
||||||
else
|
else
|
||||||
echo "Failed to install the Weave CNI plugin" >&2
|
if [ "$BRIDGE_NF_ENABLED" != "1" ]; then
|
||||||
exit 1
|
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Need to create bridge before running weaver so we can use the peer address
|
# Explicitly create the bridge so we can pass --expect-npc
|
||||||
# (because of https://github.com/weaveworks/weave/issues/2480)
|
|
||||||
WEAVE_NPC_OPTS="--expect-npc"
|
WEAVE_NPC_OPTS="--expect-npc"
|
||||||
if [ "${EXPECT_NPC}" = "0" ]; then
|
if [ "${EXPECT_NPC}" = "0" ]; then
|
||||||
WEAVE_NPC_OPTS=""
|
WEAVE_NPC_OPTS=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
export HOST_ROOT=/host
|
||||||
/home/weave/weave --local create-bridge --force $WEAVE_NPC_OPTS
|
/home/weave/weave --local create-bridge --force $WEAVE_NPC_OPTS
|
||||||
|
|
||||||
# Kubernetes sets HOSTNAME to the host's hostname
|
# Kubernetes sets HOSTNAME to the host's hostname
|
||||||
@@ -117,24 +66,6 @@ if [ -z "$IPALLOC_INIT" ]; then
|
|||||||
IPALLOC_INIT="consensus=$(peer_count $KUBE_PEERS)"
|
IPALLOC_INIT="consensus=$(peer_count $KUBE_PEERS)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/home/weave/weaver $EXTRA_ARGS --port=6783 $BRIDGE_OPTIONS \
|
|
||||||
--http-addr=$HTTP_ADDR --status-addr=$STATUS_ADDR --docker-api='' --no-dns \
|
|
||||||
--ipalloc-range=$IPALLOC_RANGE $NICKNAME_ARG \
|
|
||||||
--ipalloc-init $IPALLOC_INIT \
|
|
||||||
--name=$(cat /sys/class/net/weave/address) "$@" \
|
|
||||||
$KUBE_PEERS &
|
|
||||||
WEAVE_PID=$!
|
|
||||||
|
|
||||||
# Wait for weave process to become responsive
|
|
||||||
while true ; do
|
|
||||||
curl $HTTP_ADDR/status >/dev/null 2>&1 && break
|
|
||||||
if ! kill -0 $WEAVE_PID >/dev/null 2>&1 ; then
|
|
||||||
echo Weave process has died >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
|
|
||||||
reclaim_ips() {
|
reclaim_ips() {
|
||||||
ID=$1
|
ID=$1
|
||||||
shift
|
shift
|
||||||
@@ -143,16 +74,44 @@ reclaim_ips() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# Tell the newly-started weave about existing weave bridge IPs
|
post_start_actions() {
|
||||||
/usr/bin/weaveutil container-addrs weave weave:expose | while read ID IFACE MAC IPS; do
|
# Wait for weave process to become responsive
|
||||||
reclaim_ips "weave:expose" $IPS
|
while true ; do
|
||||||
done
|
curl $HTTP_ADDR/status >/dev/null 2>&1 && break
|
||||||
# Tell weave about existing weave process IPs
|
sleep 1
|
||||||
/usr/bin/weaveutil process-addrs weave | while read ID IFACE MAC IPS; do
|
done
|
||||||
reclaim_ips "_" $IPS
|
|
||||||
done
|
|
||||||
|
|
||||||
# Expose the weave network so host processes can communicate with pods
|
# Tell the newly-started weave about existing weave bridge IPs
|
||||||
/home/weave/weave --local expose $WEAVE_EXPOSE_IP
|
/usr/bin/weaveutil container-addrs weave weave:expose | while read ID IFACE MAC IPS; do
|
||||||
|
reclaim_ips "weave:expose" $IPS
|
||||||
|
done
|
||||||
|
# Tell weave about existing weave process IPs
|
||||||
|
/usr/bin/weaveutil process-addrs weave | while read ID IFACE MAC IPS; do
|
||||||
|
reclaim_ips "_" $IPS
|
||||||
|
done
|
||||||
|
|
||||||
wait $WEAVE_PID
|
# Install CNI plugin binary to typical CNI bin location
|
||||||
|
# with fall-back to CNI directory used by kube-up on GCI OS
|
||||||
|
if ! mkdir -p $HOST_ROOT/opt/cni/bin ; then
|
||||||
|
if mkdir -p $HOST_ROOT/home/kubernetes/bin ; then
|
||||||
|
export WEAVE_CNI_PLUGIN_DIR=$HOST_ROOT/home/kubernetes/bin
|
||||||
|
else
|
||||||
|
echo "Failed to install the Weave CNI plugin" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
mkdir -p $HOST_ROOT/etc/cni/net.d
|
||||||
|
/home/weave/weave --local setup-cni
|
||||||
|
|
||||||
|
# Expose the weave network so host processes can communicate with pods
|
||||||
|
/home/weave/weave --local expose $WEAVE_EXPOSE_IP
|
||||||
|
}
|
||||||
|
|
||||||
|
post_start_actions &
|
||||||
|
|
||||||
|
exec /home/weave/weaver $EXTRA_ARGS --port=6783 $BRIDGE_OPTIONS \
|
||||||
|
--http-addr=$HTTP_ADDR --status-addr=$STATUS_ADDR --docker-api='' --no-dns \
|
||||||
|
--ipalloc-range=$IPALLOC_RANGE $NICKNAME_ARG \
|
||||||
|
--ipalloc-init $IPALLOC_INIT \
|
||||||
|
"$@" \
|
||||||
|
$KUBE_PEERS
|
||||||
@@ -39,11 +39,13 @@ spec:
|
|||||||
- name: weavedb
|
- name: weavedb
|
||||||
mountPath: /weavedb
|
mountPath: /weavedb
|
||||||
- name: cni-bin
|
- name: cni-bin
|
||||||
mountPath: /opt
|
mountPath: /host/opt
|
||||||
- name: cni-bin2
|
- name: cni-bin2
|
||||||
mountPath: /host_home
|
mountPath: /host/home
|
||||||
- name: cni-conf
|
- name: cni-conf
|
||||||
mountPath: /etc
|
mountPath: /host/etc
|
||||||
|
- name: dbus
|
||||||
|
mountPath: /host/var/lib/dbus
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 10m
|
cpu: 10m
|
||||||
@@ -68,3 +70,6 @@ spec:
|
|||||||
- name: cni-conf
|
- name: cni-conf
|
||||||
hostPath:
|
hostPath:
|
||||||
path: /etc
|
path: /etc
|
||||||
|
- name: dbus
|
||||||
|
hostPath:
|
||||||
|
path: /var/lib/dbus
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
FROM alpine
|
|
||||||
RUN apk add --update \
|
|
||||||
iptables \
|
|
||||||
ipset \
|
|
||||||
ulogd \
|
|
||||||
&& rm -rf /var/cache/apk/* \
|
|
||||||
&& mknod /var/log/ulogd.pcap p
|
|
||||||
COPY ./weave-npc /usr/bin/weave-npc
|
|
||||||
COPY ./ulogd.conf /etc/ulogd.conf
|
|
||||||
ENTRYPOINT ["/usr/bin/weave-npc"]
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
FROM ALPINE_BASEIMAGE
|
||||||
|
|
||||||
|
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
|
||||||
|
# If we're building normally, for amd64, CROSS_BUILD lines are removed
|
||||||
|
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
|
||||||
|
|
||||||
|
LABEL maintainer "Weaveworks Inc <help@weave.works>"
|
||||||
|
LABEL works.weave.role=system \
|
||||||
|
org.label-schema.name="Weave Net" \
|
||||||
|
org.label-schema.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
|
||||||
|
org.label-schema.url="https://weave.works" \
|
||||||
|
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
||||||
|
org.label-schema.vendor="Weaveworks"
|
||||||
|
|
||||||
|
RUN apk add --update \
|
||||||
|
iptables \
|
||||||
|
ipset \
|
||||||
|
ulogd \
|
||||||
|
&& rm -rf /var/cache/apk/* \
|
||||||
|
&& mknod /var/log/ulogd.pcap p
|
||||||
|
COPY ./weave-npc /usr/bin/weave-npc
|
||||||
|
COPY ./ulogd.conf /etc/ulogd.conf
|
||||||
|
ENTRYPOINT ["/usr/bin/weave-npc"]
|
||||||
+23
-23
@@ -5,7 +5,6 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
@@ -17,6 +16,7 @@ import (
|
|||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/npc"
|
"github.com/weaveworks/weave/npc"
|
||||||
"github.com/weaveworks/weave/npc/ipset"
|
"github.com/weaveworks/weave/npc/ipset"
|
||||||
"github.com/weaveworks/weave/npc/metrics"
|
"github.com/weaveworks/weave/npc/metrics"
|
||||||
@@ -24,15 +24,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
version = "(unreleased)"
|
version = "unreleased"
|
||||||
metricsAddr string
|
metricsAddr string
|
||||||
|
logLevel string
|
||||||
|
allowMcast bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleError(err error) {
|
func handleError(err error) { common.CheckFatal(err) }
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeController(getter cache.Getter, resource string,
|
func makeController(getter cache.Getter, resource string,
|
||||||
objType runtime.Object, handlers cache.ResourceEventHandlerFuncs) *cache.Controller {
|
objType runtime.Object, handlers cache.ResourceEventHandlerFuncs) *cache.Controller {
|
||||||
@@ -61,6 +59,13 @@ func resetIPTables(ipt *iptables.IPTables) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if allowMcast {
|
||||||
|
if err := ipt.Append(npc.TableFilter, npc.MainChain,
|
||||||
|
"-d", "224.0.0.0/4", "-j", "ACCEPT"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := ipt.Append(npc.TableFilter, npc.MainChain,
|
if err := ipt.Append(npc.TableFilter, npc.MainChain,
|
||||||
"-m", "state", "--state", "NEW", "-j", string(npc.DefaultChain)); err != nil {
|
"-m", "state", "--state", "NEW", "-j", string(npc.DefaultChain)); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -89,30 +94,25 @@ func resetIPSets(ips ipset.Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func root(cmd *cobra.Command, args []string) {
|
func root(cmd *cobra.Command, args []string) {
|
||||||
log.Infof("Starting Weaveworks NPC %s", version)
|
common.SetLogLevel(logLevel)
|
||||||
|
common.Log.Infof("Starting Weaveworks NPC %s", version)
|
||||||
|
|
||||||
if err := metrics.Start(metricsAddr); err != nil {
|
if err := metrics.Start(metricsAddr); err != nil {
|
||||||
log.Fatalf("Failed to start metrics: %v", err)
|
common.Log.Fatalf("Failed to start metrics: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ulogd.Start(); err != nil {
|
if err := ulogd.Start(); err != nil {
|
||||||
log.Fatalf("Failed to start ulogd: %v", err)
|
common.Log.Fatalf("Failed to start ulogd: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := rest.InClusterConfig()
|
config, err := rest.InClusterConfig()
|
||||||
if err != nil {
|
handleError(err)
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := kubernetes.NewForConfig(config)
|
client, err := kubernetes.NewForConfig(config)
|
||||||
if err != nil {
|
handleError(err)
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ipt, err := iptables.New()
|
ipt, err := iptables.New()
|
||||||
if err != nil {
|
handleError(err)
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ips := ipset.New()
|
ips := ipset.New()
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ func root(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
signals := make(chan os.Signal, 1)
|
signals := make(chan os.Signal, 1)
|
||||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
|
||||||
log.Fatalf("Exiting: %v", <-signals)
|
common.Log.Fatalf("Exiting: %v", <-signals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -173,8 +173,8 @@ func main() {
|
|||||||
Run: root}
|
Run: root}
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVar(&metricsAddr, "metrics-addr", ":6781", "metrics server bind address")
|
rootCmd.PersistentFlags().StringVar(&metricsAddr, "metrics-addr", ":6781", "metrics server bind address")
|
||||||
|
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "debug", "logging level (debug, info, warning, error)")
|
||||||
|
rootCmd.PersistentFlags().BoolVar(&allowMcast, "allow-mcast", true, "allow all multicast traffic")
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
handleError(rootCmd.Execute())
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# This is a nearly-empty image that we use to create a data-only container for persistence
|
# This is a nearly-empty image that we use to create a data-only container for persistence
|
||||||
FROM scratch
|
FROM scratch
|
||||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
LABEL maintainer "Weaveworks Inc <help@weave.works>"
|
||||||
ENTRYPOINT ["data-only"]
|
ENTRYPOINT ["data-only"]
|
||||||
# Work round Docker refusing to save an empty image
|
# Work round Docker refusing to save an empty image
|
||||||
COPY Dockerfile /
|
COPY Dockerfile /
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
FROM alpine
|
|
||||||
|
|
||||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
|
||||||
LABEL works.weave.role=system
|
|
||||||
|
|
||||||
WORKDIR /home/weave
|
|
||||||
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
|
|
||||||
|
|
||||||
RUN apk add --update \
|
|
||||||
curl \
|
|
||||||
ethtool \
|
|
||||||
iptables \
|
|
||||||
iproute2 \
|
|
||||||
util-linux \
|
|
||||||
conntrack-tools \
|
|
||||||
bind-tools \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
ADD ./weave ./sigproxy ./weaveproxy ./symlink /home/weave/
|
|
||||||
ADD ./weaveutil /usr/bin/
|
|
||||||
ADD ./weavewait /w/w
|
|
||||||
ADD ./weavewait_noop /w-noop/w
|
|
||||||
ADD ./weavewait_nomcast /w-nomcast/w
|
|
||||||
ADD ./docker.tgz /
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
FROM ALPINE_BASEIMAGE
|
||||||
|
|
||||||
|
# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so e.g. CROSS_BUILD_COPY turns into COPY
|
||||||
|
# If we're building normally, for amd64, CROSS_BUILD lines are removed
|
||||||
|
CROSS_BUILD_COPY qemu-QEMUARCH-static /usr/bin/
|
||||||
|
|
||||||
|
LABEL maintainer "Weaveworks Inc <help@weave.works>"
|
||||||
|
LABEL works.weave.role=system \
|
||||||
|
org.label-schema.name="Weave Net" \
|
||||||
|
org.label-schema.description="Weave Net creates a virtual network that connects Docker containers across multiple hosts and enables their automatic discovery" \
|
||||||
|
org.label-schema.url="https://weave.works" \
|
||||||
|
org.label-schema.vcs-url="https://github.com/weaveworks/weave" \
|
||||||
|
org.label-schema.vendor="Weaveworks"
|
||||||
|
|
||||||
|
WORKDIR /home/weave
|
||||||
|
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
|
||||||
|
|
||||||
|
RUN apk add --update \
|
||||||
|
curl \
|
||||||
|
ethtool \
|
||||||
|
iptables \
|
||||||
|
iproute2 \
|
||||||
|
util-linux \
|
||||||
|
conntrack-tools \
|
||||||
|
bind-tools \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
ADD ./weave ./sigproxy ./weaveproxy ./symlink /home/weave/
|
||||||
|
ADD ./weaveutil /usr/bin/
|
||||||
|
ADD ./weavewait /w/w
|
||||||
|
ADD ./weavewait_noop /w-noop/w
|
||||||
|
ADD ./weavewait_nomcast /w-nomcast/w
|
||||||
|
ADD ./docker /usr/bin/
|
||||||
@@ -5,13 +5,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/weaveworks/docker/pkg/mflag"
|
"github.com/weaveworks/common/mflag"
|
||||||
|
"github.com/weaveworks/common/mflagext"
|
||||||
|
"github.com/weaveworks/common/signals"
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/common/mflagext"
|
|
||||||
"github.com/weaveworks/weave/proxy"
|
"github.com/weaveworks/weave/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "(unreleased version)"
|
var version = "unreleased"
|
||||||
|
|
||||||
var Log = common.Log
|
var Log = common.Log
|
||||||
|
|
||||||
@@ -79,5 +80,5 @@ func main() {
|
|||||||
p.AttachExistingContainers()
|
p.AttachExistingContainers()
|
||||||
go p.Serve(listeners)
|
go p.Serve(listeners)
|
||||||
go p.ListenAndServeStatus("/home/weave/status.sock")
|
go p.ListenAndServeStatus("/home/weave/status.sock")
|
||||||
common.SignalHandlerLoop()
|
signals.SignalHandlerLoop(common.Log)
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
FROM DOCKERHUB_USER/weaveexec
|
FROM DOCKERHUB_USER/weaveexecARCH_EXT
|
||||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
|
||||||
LABEL works.weave.role=system
|
|
||||||
WORKDIR /home/weave
|
WORKDIR /home/weave
|
||||||
ADD ./weaver /home/weave/
|
ADD ./weaver /home/weave/
|
||||||
ADD weavedata.db /weavedb/
|
ADD weavedata.db /weavedb/
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
var checker *checkpoint.Checker
|
var checker *checkpoint.Checker
|
||||||
var newVersion atomic.Value
|
var newVersion atomic.Value
|
||||||
|
var success atomic.Value
|
||||||
|
|
||||||
const (
|
const (
|
||||||
updateCheckPeriod = 6 * time.Hour
|
updateCheckPeriod = 6 * time.Hour
|
||||||
@@ -17,9 +18,11 @@ const (
|
|||||||
|
|
||||||
func checkForUpdates(dockerVersion string, network string) {
|
func checkForUpdates(dockerVersion string, network string) {
|
||||||
newVersion.Store("")
|
newVersion.Store("")
|
||||||
|
success.Store(true)
|
||||||
|
|
||||||
handleResponse := func(r *checkpoint.CheckResponse, err error) {
|
handleResponse := func(r *checkpoint.CheckResponse, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
success.Store(false)
|
||||||
Log.Printf("Error checking version: %v", err)
|
Log.Printf("Error checking version: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -211,7 +211,7 @@ var targetsTemplate = defTemplate("targetsTemplate", `\
|
|||||||
|
|
||||||
var connectionsTemplate = defTemplate("connectionsTemplate", `\
|
var connectionsTemplate = defTemplate("connectionsTemplate", `\
|
||||||
{{range .Router.Connections}}\
|
{{range .Router.Connections}}\
|
||||||
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}}
|
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}} {{range $key,$element := .Attrs}}{{if ne $key "name"}}{{$key}}={{$element}}{{end}}{{end}}
|
||||||
{{end}}\
|
{{end}}\
|
||||||
`)
|
`)
|
||||||
|
|
||||||
@@ -240,6 +240,7 @@ var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}
|
|||||||
|
|
||||||
type VersionCheck struct {
|
type VersionCheck struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
Success bool
|
||||||
NewVersion string
|
NewVersion string
|
||||||
NextCheckAt time.Time
|
NextCheckAt time.Time
|
||||||
}
|
}
|
||||||
@@ -251,6 +252,7 @@ func versionCheck() *VersionCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v.Enabled = true
|
v.Enabled = true
|
||||||
|
v.Success = success.Load().(bool)
|
||||||
v.NewVersion = newVersion.Load().(string)
|
v.NewVersion = newVersion.Load().(string)
|
||||||
v.NextCheckAt = checker.NextCheckAt()
|
v.NextCheckAt = checker.NextCheckAt()
|
||||||
|
|
||||||
@@ -261,12 +263,12 @@ func (v *VersionCheck) String() string {
|
|||||||
switch {
|
switch {
|
||||||
case !v.Enabled:
|
case !v.Enabled:
|
||||||
return "version check update disabled"
|
return "version check update disabled"
|
||||||
|
case !v.Success:
|
||||||
|
return fmt.Sprintf("failed to check latest version - see logs; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
|
||||||
case v.NewVersion != "":
|
case v.NewVersion != "":
|
||||||
return fmt.Sprintf("version %s available - please upgrade!",
|
return fmt.Sprintf("version %s available - please upgrade!", v.NewVersion)
|
||||||
v.NewVersion)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("up to date; next check at %s",
|
return fmt.Sprintf("up to date; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
|
||||||
v.NextCheckAt.Format("2006/01/02 15:04:05"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-12
@@ -13,7 +13,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pkg/profile"
|
"github.com/pkg/profile"
|
||||||
"github.com/weaveworks/docker/pkg/mflag"
|
"github.com/weaveworks/common/mflag"
|
||||||
|
"github.com/weaveworks/common/signals"
|
||||||
"github.com/weaveworks/mesh"
|
"github.com/weaveworks/mesh"
|
||||||
|
|
||||||
"github.com/weaveworks/weave/common"
|
"github.com/weaveworks/weave/common"
|
||||||
@@ -27,7 +28,7 @@ import (
|
|||||||
weave "github.com/weaveworks/weave/router"
|
weave "github.com/weaveworks/weave/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "(unreleased version)"
|
var version = "unreleased"
|
||||||
|
|
||||||
var Log = common.Log
|
var Log = common.Log
|
||||||
|
|
||||||
@@ -223,10 +224,18 @@ func main() {
|
|||||||
networkConfig.PacketLogging = nopPacketLogging{}
|
networkConfig.PacketLogging = nopPacketLogging{}
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay, bridge := createOverlay(datapathName, ifaceName, isAWSVPC, config.Host, config.Port, bufSzMB)
|
config.Password = determinePassword(password)
|
||||||
|
|
||||||
|
overlay, bridge := createOverlay(datapathName, ifaceName, isAWSVPC, config.Host, config.Port, bufSzMB, config.Password != nil)
|
||||||
networkConfig.Bridge = bridge
|
networkConfig.Bridge = bridge
|
||||||
|
|
||||||
name := peerName(routerName, bridge.Interface())
|
if bridge != nil {
|
||||||
|
if err := weavenet.DetectHairpin("vethwe-bridge", Log); err != nil {
|
||||||
|
Log.Errorf("DetectHairpin failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := peerName(routerName)
|
||||||
|
|
||||||
if nickName == "" {
|
if nickName == "" {
|
||||||
var err error
|
var err error
|
||||||
@@ -234,7 +243,6 @@ func main() {
|
|||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Password = determinePassword(password)
|
|
||||||
config.TrustedSubnets = parseTrustedSubnets(trustedSubnetStr)
|
config.TrustedSubnets = parseTrustedSubnets(trustedSubnetStr)
|
||||||
config.PeerDiscovery = !noDiscovery
|
config.PeerDiscovery = !noDiscovery
|
||||||
|
|
||||||
@@ -242,7 +250,7 @@ func main() {
|
|||||||
Log.Fatalf("--awsvpc mode is not compatible with the --password option")
|
Log.Fatalf("--awsvpc mode is not compatible with the --password option")
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := db.NewBoltDB(dbPrefix + "data.db")
|
db, err := db.NewBoltDB(dbPrefix + db.FileName)
|
||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
@@ -355,7 +363,7 @@ func main() {
|
|||||||
go listenAndServeHTTP(statusAddr, statusMux)
|
go listenAndServeHTTP(statusAddr, statusMux)
|
||||||
}
|
}
|
||||||
|
|
||||||
common.SignalHandlerLoop(router)
|
signals.SignalHandlerLoop(common.Log, router)
|
||||||
}
|
}
|
||||||
|
|
||||||
func options() map[string]string {
|
func options() map[string]string {
|
||||||
@@ -398,7 +406,7 @@ func (nopPacketLogging) LogPacket(string, weave.PacketKey) {
|
|||||||
func (nopPacketLogging) LogForwardPacket(string, weave.ForwardPacketKey) {
|
func (nopPacketLogging) LogForwardPacket(string, weave.ForwardPacketKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOverlay(datapathName string, ifaceName string, isAWSVPC bool, host string, port int, bufSzMB int) (weave.NetworkOverlay, weave.Bridge) {
|
func createOverlay(datapathName string, ifaceName string, isAWSVPC bool, host string, port int, bufSzMB int, enableEncryption bool) (weave.NetworkOverlay, weave.Bridge) {
|
||||||
overlay := weave.NewOverlaySwitch()
|
overlay := weave.NewOverlaySwitch()
|
||||||
var bridge weave.Bridge
|
var bridge weave.Bridge
|
||||||
var ignoreSleeve bool
|
var ignoreSleeve bool
|
||||||
@@ -415,7 +423,7 @@ func createOverlay(datapathName string, ifaceName string, isAWSVPC bool, host st
|
|||||||
case datapathName != "":
|
case datapathName != "":
|
||||||
iface, err := weavenet.EnsureInterface(datapathName)
|
iface, err := weavenet.EnsureInterface(datapathName)
|
||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
fastdp, err := weave.NewFastDatapath(iface, port)
|
fastdp, err := weave.NewFastDatapath(iface, port, enableEncryption)
|
||||||
checkFatal(err)
|
checkFatal(err)
|
||||||
bridge = fastdp.Bridge()
|
bridge = fastdp.Bridge()
|
||||||
overlay.Add("fastdp", fastdp.Overlay())
|
overlay.Add("fastdp", fastdp.Overlay())
|
||||||
@@ -522,10 +530,11 @@ func determinePassword(password string) []byte {
|
|||||||
return []byte(password)
|
return []byte(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
func peerName(routerName string, iface *net.Interface) mesh.PeerName {
|
func peerName(routerName string) mesh.PeerName {
|
||||||
if routerName == "" {
|
if routerName == "" {
|
||||||
if iface == nil {
|
iface, err := net.InterfaceByName(weavenet.WeaveBridgeName)
|
||||||
Log.Fatal("Either an interface must be specified with --datapath or --iface, or a name with --name")
|
if err != nil {
|
||||||
|
Log.Fatalf("Unable to find bridge %q", weavenet.WeaveBridgeName)
|
||||||
}
|
}
|
||||||
routerName = iface.HardwareAddr.String()
|
routerName = iface.HardwareAddr.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func uint64Counter(desc *prometheus.Desc, val uint64, labels ...string) promethe
|
|||||||
return prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(val), labels...)
|
return prometheus.MustNewConstMetric(desc, prometheus.CounterValue, float64(val), labels...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var metrics []metric = []metric{
|
var metrics = []metric{
|
||||||
{desc("weave_connections", "Number of peer-to-peer connections.", "state"),
|
{desc("weave_connections", "Number of peer-to-peer connections.", "state"),
|
||||||
func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
|
func(s WeaveStatus, desc *prometheus.Desc, ch chan<- prometheus.Metric) {
|
||||||
counts := make(map[string]int)
|
counts := make(map[string]int)
|
||||||
|
|||||||
@@ -77,3 +77,16 @@ func printNetDevs(cid string, netDevs []weavenet.Dev) {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bridgeIP(args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
cmdUsage("bridge-ip", "<bridgeName>")
|
||||||
|
}
|
||||||
|
bridgeName := args[0]
|
||||||
|
ip, err := weavenet.FindBridgeIP(bridgeName, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("%v", ip)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -44,7 +44,7 @@ func attach(args []string) error {
|
|||||||
if nsHost, err := netns.GetFromPid(1); err != nil {
|
if nsHost, err := netns.GetFromPid(1); err != nil {
|
||||||
return fmt.Errorf("unable to open host namespace: %s", err)
|
return fmt.Errorf("unable to open host namespace: %s", err)
|
||||||
} else if nsHost.Equal(nsContainer) {
|
} else if nsHost.Equal(nsContainer) {
|
||||||
return fmt.Errorf("Container is running in the host network namespace, and therefore cannot be\nconnected to weave. Perhaps the container was started with --net=host.")
|
return fmt.Errorf("Container is running in the host network namespace, and therefore cannot be\nconnected to weave - perhaps the container was started with --net=host")
|
||||||
}
|
}
|
||||||
mtu, err := strconv.Atoi(args[2])
|
mtu, err := strconv.Atoi(args[2])
|
||||||
if err != nil && args[3] != "" {
|
if err != nil && args[3] != "" {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
weavenet "github.com/weaveworks/weave/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func exposeNAT(args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
cmdUsage("expose-nat", "<cidr>...")
|
||||||
|
}
|
||||||
|
|
||||||
|
cidrs, err := parseCIDRs(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cidr := range cidrs {
|
||||||
|
if err := weavenet.ExposeNAT(*cidr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -34,6 +34,9 @@ func init() {
|
|||||||
"list-netdevs": listNetDevs,
|
"list-netdevs": listNetDevs,
|
||||||
"cni-net": cniNet,
|
"cni-net": cniNet,
|
||||||
"cni-ipam": cniIPAM,
|
"cni-ipam": cniIPAM,
|
||||||
|
"expose-nat": exposeNAT,
|
||||||
|
"bridge-ip": bridgeIP,
|
||||||
|
"unique-id": uniqueID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
weavenet "github.com/weaveworks/weave/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func uniqueID(args []string) error {
|
||||||
|
if len(args) != 2 {
|
||||||
|
cmdUsage("unique-id", "<db-prefix> <host-root>")
|
||||||
|
}
|
||||||
|
dbPrefix := args[0]
|
||||||
|
hostRoot := args[1]
|
||||||
|
uid, err := weavenet.GetSystemPeerName(dbPrefix, hostRoot)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf(uid)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// (C) Docker, Inc.
|
||||||
|
// Redistributed under the Apache License 2.0
|
||||||
|
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
// MalformedHostHeaderOverride is a wrapper to be able
|
||||||
|
// to overcome the 400 Bad request coming from old docker
|
||||||
|
// clients that send an invalid Host header.
|
||||||
|
type MalformedHostHeaderOverride struct {
|
||||||
|
net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
// MalformedHostHeaderOverrideConn wraps the underlying unix
|
||||||
|
// connection and keeps track of the first read from http.Server
|
||||||
|
// which just reads the headers.
|
||||||
|
type MalformedHostHeaderOverrideConn struct {
|
||||||
|
net.Conn
|
||||||
|
first bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var closeConnHeader = []byte("\r\nConnection: close\r")
|
||||||
|
|
||||||
|
// Read reads the first *read* request from http.Server to inspect
|
||||||
|
// the Host header. If the Host starts with / then we're talking to
|
||||||
|
// an old docker client which send an invalid Host header. To not
|
||||||
|
// error out in http.Server we rewrite the first bytes of the request
|
||||||
|
// to sanitize the Host header itself.
|
||||||
|
// In case we're not dealing with old docker clients the data is just passed
|
||||||
|
// to the server w/o modification.
|
||||||
|
func (l *MalformedHostHeaderOverrideConn) Read(b []byte) (n int, err error) {
|
||||||
|
// http.Server uses a 4k buffer
|
||||||
|
if l.first && len(b) == 4096 {
|
||||||
|
// This keeps track of the first read from http.Server which just reads
|
||||||
|
// the headers
|
||||||
|
l.first = false
|
||||||
|
// The first read of the connection by http.Server is done limited to
|
||||||
|
// DefaultMaxHeaderBytes (usually 1 << 20) + 4096.
|
||||||
|
// Here we do the first read which gets us all the http headers to
|
||||||
|
// be inspected and modified below.
|
||||||
|
c, err := l.Conn.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
start, end int
|
||||||
|
firstLineFeed = -1
|
||||||
|
buf []byte
|
||||||
|
)
|
||||||
|
for i := 0; i <= c-1-7; i++ {
|
||||||
|
if b[i] == '\n' && firstLineFeed == -1 {
|
||||||
|
firstLineFeed = i
|
||||||
|
}
|
||||||
|
if b[i] != '\n' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[i+1] == '\r' && b[i+2] == '\n' {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b[i+1] != 'H' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+2] != 'o' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+3] != 's' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+4] != 't' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+5] != ':' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+6] != ' ' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if b[i+7] != '/' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// ensure clients other than the docker clients do not get this hack
|
||||||
|
if i != firstLineFeed {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
start = i + 7
|
||||||
|
// now find where the value ends
|
||||||
|
for ii, bbb := range b[start:c] {
|
||||||
|
if bbb == '\n' {
|
||||||
|
end = start + ii
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf = make([]byte, 0, c+len(closeConnHeader)-(end-start))
|
||||||
|
// strip the value of the host header and
|
||||||
|
// inject `Connection: close` to ensure we don't reuse this connection
|
||||||
|
buf = append(buf, b[:start]...)
|
||||||
|
buf = append(buf, closeConnHeader...)
|
||||||
|
buf = append(buf, b[end:c]...)
|
||||||
|
copy(b, buf)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
return len(buf), nil
|
||||||
|
}
|
||||||
|
return l.Conn.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept makes the listener accepts connections and wraps the connection
|
||||||
|
// in a MalformedHostHeaderOverrideConn initilizing first to true.
|
||||||
|
func (l *MalformedHostHeaderOverride) Accept() (net.Conn, error) {
|
||||||
|
c, err := l.Listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
return &MalformedHostHeaderOverrideConn{c, true}, nil
|
||||||
|
}
|
||||||
+4
-6
@@ -148,14 +148,12 @@ func NewProxy(c Config) (*Proxy, error) {
|
|||||||
p.client = client.Client
|
p.client = client.Client
|
||||||
|
|
||||||
if !p.WithoutDNS {
|
if !p.WithoutDNS {
|
||||||
netDev, err := weavenet.GetBridgeNetDev(c.DockerBridge)
|
ip, err := weavenet.FindBridgeIP(c.DockerBridge, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(netDev.CIDRs) != 1 {
|
p.dockerBridgeIP = ip.String()
|
||||||
return nil, fmt.Errorf("Could not obtain address of %s", c.DockerBridge)
|
Log.Infof("Using docker bridge IP for DNS: %v", p.dockerBridgeIP)
|
||||||
}
|
|
||||||
p.dockerBridgeIP = netDev.CIDRs[0].IP.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch)
|
p.hostnameMatchRegexp, err = regexp.Compile(c.HostnameMatch)
|
||||||
@@ -378,7 +376,7 @@ func (proxy *Proxy) listen(protoAndAddr string) (net.Listener, string, error) {
|
|||||||
Log.Fatalf("Invalid protocol format: %q", proto)
|
Log.Fatalf("Invalid protocol format: %q", proto)
|
||||||
}
|
}
|
||||||
|
|
||||||
return listener, fmt.Sprintf("%s://%s", proto, addr), nil
|
return &MalformedHostHeaderOverride{listener}, fmt.Sprintf("%s://%s", proto, addr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// weavedocker.ContainerObserver interface
|
// weavedocker.ContainerObserver interface
|
||||||
|
|||||||
+4
-2
@@ -32,8 +32,8 @@ func (conn *AWSVPCConnection) Stop() {}
|
|||||||
func (conn *AWSVPCConnection) ControlMessage(tag byte, msg []byte) {
|
func (conn *AWSVPCConnection) ControlMessage(tag byte, msg []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *AWSVPCConnection) DisplayName() string {
|
func (conn *AWSVPCConnection) Attrs() map[string]interface{} {
|
||||||
return "awsvpc"
|
return map[string]interface{}{"name": "awsvpc"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OverlayForwarder
|
// OverlayForwarder
|
||||||
@@ -64,6 +64,8 @@ func (vpc AWSVPC) Diagnostics() interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vpc AWSVPC) Stop() {}
|
||||||
|
|
||||||
// NetworkOverlay
|
// NetworkOverlay
|
||||||
|
|
||||||
func (vpc AWSVPC) InvalidateRoutes() {}
|
func (vpc AWSVPC) InvalidateRoutes() {}
|
||||||
|
|||||||
+155
-19
@@ -9,9 +9,12 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"github.com/weaveworks/go-odp/odp"
|
"github.com/weaveworks/go-odp/odp"
|
||||||
"github.com/weaveworks/mesh"
|
"github.com/weaveworks/mesh"
|
||||||
|
|
||||||
|
"github.com/weaveworks/weave/net/ipsec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The virtual bridge accepts packets from ODP vports and the router
|
// The virtual bridge accepts packets from ODP vports and the router
|
||||||
@@ -39,6 +42,7 @@ type FastDatapath struct {
|
|||||||
localPeer *mesh.Peer
|
localPeer *mesh.Peer
|
||||||
peers *mesh.Peers
|
peers *mesh.Peers
|
||||||
overlayConsumer OverlayConsumer
|
overlayConsumer OverlayConsumer
|
||||||
|
ipsec *ipsec.IPSec
|
||||||
|
|
||||||
// Bridge state: How to send to the given bridge port
|
// Bridge state: How to send to the given bridge port
|
||||||
sendToPort map[bridgePortID]bridgeSender
|
sendToPort map[bridgePortID]bridgeSender
|
||||||
@@ -50,8 +54,10 @@ type FastDatapath struct {
|
|||||||
seenMACs map[MAC]struct{}
|
seenMACs map[MAC]struct{}
|
||||||
|
|
||||||
// vxlan vports associated with the given UDP ports
|
// vxlan vports associated with the given UDP ports
|
||||||
vxlanVportIDs map[int]odp.VportID
|
vxlanUDPPorts map[int]odp.VportID
|
||||||
|
vxlanVportIDs map[odp.VportID]struct{}
|
||||||
mainVxlanVportID odp.VportID
|
mainVxlanVportID odp.VportID
|
||||||
|
mainVxlanUDPPort int
|
||||||
|
|
||||||
// A singleton pool for the occasions when we need to decode
|
// A singleton pool for the occasions when we need to decode
|
||||||
// the packet.
|
// the packet.
|
||||||
@@ -61,7 +67,9 @@ type FastDatapath struct {
|
|||||||
forwarders map[mesh.PeerName]*fastDatapathForwarder
|
forwarders map[mesh.PeerName]*fastDatapathForwarder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFastDatapath(iface *net.Interface, port int) (*FastDatapath, error) {
|
func NewFastDatapath(iface *net.Interface, port int, encryptionEnabled bool) (*FastDatapath, error) {
|
||||||
|
var ipSec *ipsec.IPSec
|
||||||
|
|
||||||
dpif, err := odp.NewDpif()
|
dpif, err := odp.NewDpif()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -79,15 +87,27 @@ func NewFastDatapath(iface *net.Interface, port int) (*FastDatapath, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if encryptionEnabled {
|
||||||
|
var err error
|
||||||
|
if ipSec, err = ipsec.New(log); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "ipsec new")
|
||||||
|
}
|
||||||
|
if err := ipSec.Flush(false); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "ipsec flush")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fastdp := &FastDatapath{
|
fastdp := &FastDatapath{
|
||||||
iface: iface,
|
iface: iface,
|
||||||
dpif: dpif,
|
dpif: dpif,
|
||||||
dp: dp,
|
dp: dp,
|
||||||
missHandlers: make(map[odp.VportID]missHandler),
|
missHandlers: make(map[odp.VportID]missHandler),
|
||||||
|
ipsec: ipSec,
|
||||||
sendToPort: nil,
|
sendToPort: nil,
|
||||||
sendToMAC: make(map[MAC]bridgeSender),
|
sendToMAC: make(map[MAC]bridgeSender),
|
||||||
seenMACs: make(map[MAC]struct{}),
|
seenMACs: make(map[MAC]struct{}),
|
||||||
vxlanVportIDs: make(map[int]odp.VportID),
|
vxlanUDPPorts: make(map[int]odp.VportID),
|
||||||
|
vxlanVportIDs: make(map[odp.VportID]struct{}),
|
||||||
forwarders: make(map[mesh.PeerName]*fastDatapathForwarder),
|
forwarders: make(map[mesh.PeerName]*fastDatapathForwarder),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +131,8 @@ func NewFastDatapath(iface *net.Interface, port int) (*FastDatapath, error) {
|
|||||||
// numbers to be independent, but working out how to specify
|
// numbers to be independent, but working out how to specify
|
||||||
// them on the connecting side. So we can wait to find out if
|
// them on the connecting side. So we can wait to find out if
|
||||||
// anyone wants that.
|
// anyone wants that.
|
||||||
fastdp.mainVxlanVportID, err = fastdp.getVxlanVportIDHarder(port+1, 5, time.Millisecond*10)
|
fastdp.mainVxlanUDPPort = port + 1
|
||||||
|
fastdp.mainVxlanVportID, err = fastdp.getVxlanVportIDHarder(fastdp.mainVxlanUDPPort, 5, time.Millisecond*10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -313,6 +334,14 @@ func (fastdp fastDatapathOverlay) InvalidateShortIDs() {
|
|||||||
checkWarn(fastdp.deleteFlows())
|
checkWarn(fastdp.deleteFlows())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fastdp fastDatapathOverlay) Stop() {
|
||||||
|
if fastdp.ipsec != nil {
|
||||||
|
if err := fastdp.ipsec.Flush(true); err != nil {
|
||||||
|
log.Errorf("ipsec flush failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (fastDatapathOverlay) AddFeaturesTo(features map[string]string) {
|
func (fastDatapathOverlay) AddFeaturesTo(features map[string]string) {
|
||||||
// Nothing needed. Fast datapath support is indicated through
|
// Nothing needed. Fast datapath support is indicated through
|
||||||
// OverlaySwitch.
|
// OverlaySwitch.
|
||||||
@@ -433,7 +462,7 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
|||||||
fastdp.lock.Lock()
|
fastdp.lock.Lock()
|
||||||
defer fastdp.lock.Unlock()
|
defer fastdp.lock.Unlock()
|
||||||
|
|
||||||
if vxlanVportID, present := fastdp.vxlanVportIDs[udpPort]; present {
|
if vxlanVportID, present := fastdp.vxlanUDPPorts[udpPort]; present {
|
||||||
return vxlanVportID, nil
|
return vxlanVportID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +488,8 @@ func (fastdp *FastDatapath) getVxlanVportID(udpPort int) (odp.VportID, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fastdp.vxlanVportIDs[udpPort] = vxlanVportID
|
fastdp.vxlanUDPPorts[udpPort] = vxlanVportID
|
||||||
|
fastdp.vxlanVportIDs[vxlanVportID] = struct{}{}
|
||||||
fastdp.missHandlers[vxlanVportID] = func(fks odp.FlowKeys, lock *fastDatapathLock) FlowOp {
|
fastdp.missHandlers[vxlanVportID] = func(fks odp.FlowKeys, lock *fastDatapathLock) FlowOp {
|
||||||
log.Debug("ODP miss: ", fks, " on port ", vxlanVportID)
|
log.Debug("ODP miss: ", fks, " on port ", vxlanVportID)
|
||||||
tunnel := fks[odp.OVS_KEY_ATTR_TUNNEL].(odp.TunnelFlowKey)
|
tunnel := fks[odp.OVS_KEY_ATTR_TUNNEL].(odp.TunnelFlowKey)
|
||||||
@@ -539,6 +569,10 @@ type fastDatapathForwarder struct {
|
|||||||
connUID uint64
|
connUID uint64
|
||||||
vxlanVportID odp.VportID
|
vxlanVportID odp.VportID
|
||||||
|
|
||||||
|
sessionKey *[32]byte
|
||||||
|
isEncrypted bool
|
||||||
|
isOutboundIPSecEstablished bool
|
||||||
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
confirmed bool
|
confirmed bool
|
||||||
remoteAddr *net.UDPAddr
|
remoteAddr *net.UDPAddr
|
||||||
@@ -554,27 +588,25 @@ type fastDatapathForwarder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fastdp fastDatapathOverlay) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) {
|
func (fastdp fastDatapathOverlay) PrepareConnection(params mesh.OverlayConnectionParams) (mesh.OverlayConnection, error) {
|
||||||
if params.SessionKey != nil {
|
|
||||||
// No encryption support in fastdp
|
|
||||||
return nil, fmt.Errorf("encryption not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
vxlanVportID := fastdp.mainVxlanVportID
|
vxlanVportID := fastdp.mainVxlanVportID
|
||||||
var remoteAddr *net.UDPAddr
|
vxlanUDPPort := fastdp.mainVxlanUDPPort
|
||||||
|
|
||||||
|
remoteAddr := makeUDPAddr(params.RemoteAddr)
|
||||||
if params.Outbound {
|
if params.Outbound {
|
||||||
remoteAddr = makeUDPAddr(params.RemoteAddr)
|
var err error
|
||||||
// The provided address contains the main weave port
|
// The provided address contains the main weave port
|
||||||
// number to connect to. We need to derive the vxlan
|
// number to connect to. We need to derive the vxlan
|
||||||
// port number from that.
|
// port number from that.
|
||||||
vxlanRemoteAddr := *remoteAddr
|
vxlanRemoteAddr := *remoteAddr
|
||||||
vxlanRemoteAddr.Port++
|
vxlanRemoteAddr.Port++
|
||||||
remoteAddr = &vxlanRemoteAddr
|
remoteAddr = &vxlanRemoteAddr
|
||||||
var err error
|
vxlanUDPPort = remoteAddr.Port
|
||||||
vxlanVportID, err = fastdp.getVxlanVportID(remoteAddr.Port)
|
vxlanVportID, err = fastdp.getVxlanVportID(vxlanUDPPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
remoteAddr.Port = vxlanUDPPort
|
||||||
}
|
}
|
||||||
|
|
||||||
localIP, err := ipv4Bytes(params.LocalAddr.IP)
|
localIP, err := ipv4Bytes(params.LocalAddr.IP)
|
||||||
@@ -589,6 +621,7 @@ func (fastdp fastDatapathOverlay) PrepareConnection(params mesh.OverlayConnectio
|
|||||||
sendControlMsg: params.SendControlMessage,
|
sendControlMsg: params.SendControlMessage,
|
||||||
connUID: params.ConnUID,
|
connUID: params.ConnUID,
|
||||||
vxlanVportID: vxlanVportID,
|
vxlanVportID: vxlanVportID,
|
||||||
|
sessionKey: params.SessionKey,
|
||||||
|
|
||||||
remoteAddr: remoteAddr,
|
remoteAddr: remoteAddr,
|
||||||
heartbeatInterval: FastHeartbeat,
|
heartbeatInterval: FastHeartbeat,
|
||||||
@@ -598,7 +631,7 @@ func (fastdp fastDatapathOverlay) PrepareConnection(params mesh.OverlayConnectio
|
|||||||
errorChan: make(chan error, 1),
|
errorChan: make(chan error, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return fwd, err
|
return fwd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv4Bytes(ip net.IP) (res [4]byte, err error) {
|
func ipv4Bytes(ip net.IP) (res [4]byte, err error) {
|
||||||
@@ -623,11 +656,30 @@ func (fwd *fastDatapathForwarder) Confirm() {
|
|||||||
log.Fatal(fwd.logPrefix(), "already confirmed")
|
log.Fatal(fwd.logPrefix(), "already confirmed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fwd.fastdp.ipsec != nil && fwd.sessionKey != nil {
|
||||||
|
fwd.isEncrypted = true
|
||||||
|
log.Info("Setting up IPsec between ", fwd.fastdp.localPeer, " and ", fwd.remotePeer)
|
||||||
|
err := fwd.fastdp.ipsec.InitSALocal(
|
||||||
|
fwd.fastdp.localPeer.Name, fwd.remotePeer.Name, fwd.connUID,
|
||||||
|
net.IP(fwd.localIP[:]), fwd.remoteAddr.IP,
|
||||||
|
fwd.remoteAddr.Port,
|
||||||
|
fwd.sessionKey,
|
||||||
|
func(msg []byte) error {
|
||||||
|
return fwd.sendControlMsg(FastDatapathCryptoInitSARemote, msg)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(fwd.logPrefix(), "ipsec init SA local failed: ", err)
|
||||||
|
fwd.handleError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.Debug(fwd.logPrefix(), "confirmed")
|
log.Debug(fwd.logPrefix(), "confirmed")
|
||||||
fwd.fastdp.addForwarder(fwd.remotePeer.Name, fwd)
|
fwd.fastdp.addForwarder(fwd.remotePeer.Name, fwd)
|
||||||
fwd.confirmed = true
|
fwd.confirmed = true
|
||||||
|
|
||||||
if fwd.remoteAddr != nil {
|
if fwd.remoteAddr != nil && (!fwd.isEncrypted || fwd.isOutboundIPSecEstablished) {
|
||||||
// have the goroutine send a heartbeat straight away
|
// have the goroutine send a heartbeat straight away
|
||||||
fwd.heartbeatTimer = time.NewTimer(0)
|
fwd.heartbeatTimer = time.NewTimer(0)
|
||||||
} else {
|
} else {
|
||||||
@@ -716,6 +768,7 @@ func (fwd *fastDatapathForwarder) sendHeartbeat() {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
FastDatapathHeartbeatAck = iota
|
FastDatapathHeartbeatAck = iota
|
||||||
|
FastDatapathCryptoInitSARemote
|
||||||
)
|
)
|
||||||
|
|
||||||
func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte, sender *net.UDPAddr) {
|
func (fwd *fastDatapathForwarder) handleVxlanSpecialPacket(frame []byte, sender *net.UDPAddr) {
|
||||||
@@ -765,14 +818,16 @@ func (fwd *fastDatapathForwarder) ControlMessage(tag byte, msg []byte) {
|
|||||||
switch tag {
|
switch tag {
|
||||||
case FastDatapathHeartbeatAck:
|
case FastDatapathHeartbeatAck:
|
||||||
fwd.handleHeartbeatAck()
|
fwd.handleHeartbeatAck()
|
||||||
|
case FastDatapathCryptoInitSARemote:
|
||||||
|
fwd.handleCryptoInitSARemote(msg)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Info(fwd.logPrefix(), "Ignoring unknown control message: ", tag)
|
log.Info(fwd.logPrefix(), "Ignoring unknown control message: ", tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fwd *fastDatapathForwarder) DisplayName() string {
|
func (fwd *fastDatapathForwarder) Attrs() map[string]interface{} {
|
||||||
return "fastdp"
|
return map[string]interface{}{"name": "fastdp", "mtu": fwd.fastdp.iface.MTU}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fwd *fastDatapathForwarder) handleHeartbeatAck() {
|
func (fwd *fastDatapathForwarder) handleHeartbeatAck() {
|
||||||
@@ -787,6 +842,26 @@ func (fwd *fastDatapathForwarder) handleHeartbeatAck() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fwd *fastDatapathForwarder) handleCryptoInitSARemote(msg []byte) {
|
||||||
|
log.Info(fwd.logPrefix(), "IPSec init SA remote")
|
||||||
|
err := fwd.fastdp.ipsec.InitSARemote(
|
||||||
|
msg,
|
||||||
|
fwd.fastdp.localPeer.Name, fwd.remotePeer.Name, fwd.connUID,
|
||||||
|
net.IP(fwd.localIP[:]), fwd.remoteAddr.IP, fwd.remoteAddr.Port,
|
||||||
|
fwd.sessionKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Warning(fwd.logPrefix(), "IPSec init SA remote failed: ", err)
|
||||||
|
fwd.handleError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fwd.isOutboundIPSecEstablished {
|
||||||
|
fwd.isOutboundIPSecEstablished = true
|
||||||
|
fwd.heartbeatTimer.Reset(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp {
|
func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp {
|
||||||
if !key.SrcPeer.HasShortID || !key.DstPeer.HasShortID {
|
if !key.SrcPeer.HasShortID || !key.DstPeer.HasShortID {
|
||||||
return nil
|
return nil
|
||||||
@@ -836,6 +911,18 @@ func (fwd *fastDatapathForwarder) Stop() {
|
|||||||
defer fwd.lock.Unlock()
|
defer fwd.lock.Unlock()
|
||||||
fwd.sendControlMsg = func(byte, []byte) error { return nil }
|
fwd.sendControlMsg = func(byte, []byte) error { return nil }
|
||||||
|
|
||||||
|
if fwd.isEncrypted {
|
||||||
|
localIP := net.IP(fwd.localIP[:])
|
||||||
|
log.Info("Destroying IPsec between ", fwd.fastdp.localPeer, " and ", fwd.remotePeer)
|
||||||
|
err := fwd.fastdp.ipsec.Destroy(
|
||||||
|
fwd.fastdp.localPeer.Name, fwd.remotePeer.Name, fwd.connUID,
|
||||||
|
localIP, fwd.remoteAddr.IP, fwd.remoteAddr.Port,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("ipsec destroy failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// stop the heartbeat goroutine
|
// stop the heartbeat goroutine
|
||||||
if !fwd.stopped {
|
if !fwd.stopped {
|
||||||
fwd.stopped = true
|
fwd.stopped = true
|
||||||
@@ -1134,6 +1221,11 @@ func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fastdp.isHairpinFlow(&flow) {
|
||||||
|
log.Error("Vetoed installation of hairpin flow ", flow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if dec != nil {
|
if dec != nil {
|
||||||
// put the decoder back
|
// put the decoder back
|
||||||
lock.relock()
|
lock.relock()
|
||||||
@@ -1171,6 +1263,50 @@ func (fastdp *FastDatapath) takeDecoder(lock *fastDatapathLock) *EthernetDecoder
|
|||||||
return dec
|
return dec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A isHairpinFlow checks whether the flow is created due to enabled hairpin
|
||||||
|
// mode on the weave bridge port which attaches the datapath. Such flow is
|
||||||
|
// identified by either:
|
||||||
|
//
|
||||||
|
// * in_port == out_port, where in_port is non-vxlan vport;
|
||||||
|
// * a packet is sent back to a vxlan tunnel it has been received from and
|
||||||
|
// the tunnel id is either the same or dstPeer and srcPeer are reversed.
|
||||||
|
func (fastdp *FastDatapath) isHairpinFlow(flow *odp.FlowSpec) bool {
|
||||||
|
var (
|
||||||
|
vxlanKey odp.TunnelAttrs
|
||||||
|
inVport odp.VportID
|
||||||
|
inVxlan bool
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, key := range flow.FlowKeys {
|
||||||
|
switch k := key.(type) {
|
||||||
|
case odp.InPortFlowKey:
|
||||||
|
inVport = k.VportID()
|
||||||
|
case odp.TunnelFlowKey:
|
||||||
|
inVxlan = true
|
||||||
|
vxlanKey = k.Key()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, action := range flow.Actions {
|
||||||
|
switch a := action.(type) {
|
||||||
|
case odp.SetTunnelAction:
|
||||||
|
if inVxlan && a.TunnelAttrs.TunnelId == vxlanKey.TunnelId &&
|
||||||
|
a.TunnelAttrs.Ipv4Src == vxlanKey.Ipv4Dst &&
|
||||||
|
a.TunnelAttrs.Ipv4Dst == vxlanKey.Ipv4Src {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case odp.OutputAction:
|
||||||
|
if a.VportID() == inVport {
|
||||||
|
if _, ok := fastdp.vxlanVportIDs[a.VportID()]; !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type odpActionsFlowOp struct {
|
type odpActionsFlowOp struct {
|
||||||
NonDiscardingFlowOp
|
NonDiscardingFlowOp
|
||||||
fastdp *FastDatapath
|
fastdp *FastDatapath
|
||||||
|
|||||||
@@ -124,6 +124,13 @@ func (router *NetworkRouter) handleCapturedPacket(key PacketKey) FlowOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp {
|
||||||
|
srcMac := net.HardwareAddr(key.SrcMAC[:])
|
||||||
|
dstMac := net.HardwareAddr(key.DstMAC[:])
|
||||||
|
|
||||||
|
if key.SrcPeer == router.Ourself.Peer {
|
||||||
|
log.Warn("Received own packet to peer ", key.DstPeer, " from MAC (", srcMac, ") to (", dstMac, ")")
|
||||||
|
}
|
||||||
|
|
||||||
if key.DstPeer != router.Ourself.Peer {
|
if key.DstPeer != router.Ourself.Peer {
|
||||||
// it's not for us, we're just relaying it
|
// it's not for us, we're just relaying it
|
||||||
router.PacketLogging.LogForwardPacket("Relaying", key)
|
router.PacketLogging.LogForwardPacket("Relaying", key)
|
||||||
@@ -134,9 +141,6 @@ func (router *NetworkRouter) handleForwardedPacket(key ForwardPacketKey) FlowOp
|
|||||||
// (because the DstPeer on a forwarded broadcast packet is
|
// (because the DstPeer on a forwarded broadcast packet is
|
||||||
// always set to the peer being forwarded to)
|
// 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); {
|
switch newSrcMac, conflictPeer := router.Macs.AddForced(srcMac, key.SrcPeer); {
|
||||||
case newSrcMac:
|
case newSrcMac:
|
||||||
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
log.Print("Discovered remote MAC ", srcMac, " at ", key.SrcPeer)
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ func (osw *OverlaySwitch) Diagnostics() interface{} {
|
|||||||
return diagnostics
|
return diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (osw *OverlaySwitch) Stop() {
|
||||||
|
for _, overlay := range osw.overlays {
|
||||||
|
overlay.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (osw *OverlaySwitch) InvalidateRoutes() {
|
func (osw *OverlaySwitch) InvalidateRoutes() {
|
||||||
for _, overlay := range osw.overlays {
|
for _, overlay := range osw.overlays {
|
||||||
overlay.InvalidateRoutes()
|
overlay.InvalidateRoutes()
|
||||||
@@ -424,7 +430,7 @@ func (fwd *overlaySwitchForwarder) ControlMessage(tag byte, msg []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fwd *overlaySwitchForwarder) DisplayName() string {
|
func (fwd *overlaySwitchForwarder) Attrs() map[string]interface{} {
|
||||||
var best OverlayForwarder
|
var best OverlayForwarder
|
||||||
|
|
||||||
fwd.lock.Lock()
|
fwd.lock.Lock()
|
||||||
@@ -434,8 +440,8 @@ func (fwd *overlaySwitchForwarder) DisplayName() string {
|
|||||||
fwd.lock.Unlock()
|
fwd.lock.Unlock()
|
||||||
|
|
||||||
if best != nil {
|
if best != nil {
|
||||||
return best.DisplayName()
|
return best.Attrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
return "none"
|
return nil
|
||||||
}
|
}
|
||||||
+6
-2
@@ -141,6 +141,10 @@ func (*SleeveOverlay) Diagnostics() interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*SleeveOverlay) Stop() {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
func (sleeve *SleeveOverlay) lookupForwarder(peer mesh.PeerName) *sleeveForwarder {
|
func (sleeve *SleeveOverlay) lookupForwarder(peer mesh.PeerName) *sleeveForwarder {
|
||||||
sleeve.lock.Lock()
|
sleeve.lock.Lock()
|
||||||
defer sleeve.lock.Unlock()
|
defer sleeve.lock.Unlock()
|
||||||
@@ -606,8 +610,8 @@ func (fwd *sleeveForwarder) ControlMessage(tag byte, msg []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fwd *sleeveForwarder) DisplayName() string {
|
func (fwd *sleeveForwarder) Attrs() map[string]interface{} {
|
||||||
return "sleeve"
|
return map[string]interface{}{"name": "sleeve", "mtu": fwd.mtu}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fwd *sleeveForwarder) Stop() {
|
func (fwd *sleeveForwarder) Stop() {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ The most common prefix lengths are 8, 16 and 24, but there is nothing
|
|||||||
stopping you using a /9 network or a /26. For example, `6.250.3.1/9` is on the
|
stopping you using a /9 network or a /26. For example, `6.250.3.1/9` is on the
|
||||||
`6.128.0.0/9` network.
|
`6.128.0.0/9` network.
|
||||||
|
|
||||||
Several websites offer calculators to decode this kind of address, see: [IP Address Guide](http://www.ipaddressguide.com/cidr).
|
Several websites offer calculators to decode this kind of address, see, for example: [IP Address Guide](http://www.ipaddressguide.com/cidr).
|
||||||
|
|
||||||
The following is an example route table for a container that is attached to a Weave
|
The following is an example route table for a container that is attached to a Weave
|
||||||
network:
|
network:
|
||||||
|
|||||||
+1
-1
@@ -179,7 +179,7 @@ The range parameter is written in
|
|||||||
in this example "/16" means the first 16 bits of the address form the
|
in this example "/16" means the first 16 bits of the address form the
|
||||||
network address and the allocator is to allocate container addresses
|
network address and the allocator is to allocate container addresses
|
||||||
that all start 10.2. See [IP
|
that all start 10.2. See [IP
|
||||||
addresses and routes](/site/using-weave/service-management.md#routing) for more information.
|
addresses and routes](/site/how-it-works/ip-addresses.md) for more information.
|
||||||
|
|
||||||
Weave shares the IP address range across all peers, dynamically
|
Weave shares the IP address range across all peers, dynamically
|
||||||
according to their needs. If a group of peers becomes isolated from
|
according to their needs. If a group of peers becomes isolated from
|
||||||
|
|||||||
+115
-30
@@ -3,60 +3,74 @@ title: Integrating Kubernetes via the Addon
|
|||||||
menu_order: 63
|
menu_order: 63
|
||||||
---
|
---
|
||||||
|
|
||||||
## Installation
|
The following topics are discussed:
|
||||||
|
|
||||||
If you're using Kubernetes 1.4 or later, and it is configured to use
|
* [Installation](#install)
|
||||||
CNI, it is possible to install Weave Net on your cluster with a single
|
* [Network Policy Controller](#npc)
|
||||||
command:
|
* [Upgrading the Daemon Sets](#daemon-sets)
|
||||||
|
* [Network Policy Controller](#npc)
|
||||||
|
* [Troubleshooting Blocked Connections](#blocked-connections)
|
||||||
|
* [Changing Configuration Options](#configuration-options)
|
||||||
|
|
||||||
|
|
||||||
|
##<a name="install"></a> Installation
|
||||||
|
|
||||||
|
Weave Net can be installed onto your CNI-enabled Kubernetes cluster
|
||||||
|
with a single command:
|
||||||
|
|
||||||
```
|
```
|
||||||
kubectl create -f https://git.io/weave-kube
|
kubectl apply -f https://git.io/weave-kube
|
||||||
```
|
```
|
||||||
|
|
||||||
After a few seconds, you should have a Weave Net pod running on each
|
After a few seconds, a Weave Net pod should be running on each
|
||||||
node, and any further pods you create will be attached to the Weave
|
Node and any further pods you create will be automatically attached to the Weave
|
||||||
network.
|
network.
|
||||||
|
|
||||||
|
**Note:** This command requires Kubernetes 1.4 or later.
|
||||||
|
|
||||||
|
> CNI, the [_Container Network Interface_](https://github.com/containernetworking/cni),
|
||||||
|
> is a proposed standard for configuring network interfaces for Linux
|
||||||
|
> containers.
|
||||||
|
>
|
||||||
> If you do not already have a CNI-enabled cluster, you can bootstrap
|
> If you do not already have a CNI-enabled cluster, you can bootstrap
|
||||||
> one easily with
|
> one easily with
|
||||||
> [kubeadm](http://kubernetes.io/docs/getting-started-guides/kubeadm/);
|
> [kubeadm](http://kubernetes.io/docs/getting-started-guides/kubeadm/).
|
||||||
> alternatively if you are using the older cluster set-up scripts from
|
|
||||||
> the Kubernetes repo, you can use
|
|
||||||
>
|
>
|
||||||
> ```
|
> Alternatively, you can [configure CNI yourself](http://kubernetes.io/docs/admin/network-plugins/#cni)
|
||||||
> NETWORK_PROVIDER=cni cluster/kube-up.sh
|
|
||||||
> ```
|
|
||||||
|
|
||||||
NB If you were previously using the [Weave CNI
|
**Note:** If using the [Weave CNI
|
||||||
driver](/site/cni-plugin.md) from a full install of Weave Net with your
|
Plugin](/site/cni-plugin.md) from a prior full install of Weave Net with your
|
||||||
cluster, you will need to uninstall it first. Shut down Kubernetes,
|
cluster, you must first uninstall it before applying the Weave-kube addon.
|
||||||
then perform the following _on all nodes_:
|
Shut down Kubernetes, and _on all nodes_ perform the following:
|
||||||
|
|
||||||
* `weave reset`
|
* `weave reset`
|
||||||
* Remove any separate provision you have made to run weave at
|
* Remove any separate provisions you may have made to run Weave at
|
||||||
boot-time, e.g. `systemd` units
|
boot-time, e.g. `systemd` units
|
||||||
* `rm /opt/cni/bin/weave-*`
|
* `rm /opt/cni/bin/weave-*`
|
||||||
|
|
||||||
You can then relaunch Kubernetes and install the addon as described
|
Then relaunch Kubernetes and install the addon as described
|
||||||
above.
|
above.
|
||||||
|
|
||||||
The URL [https://git.io/weave-kube](https://git.io/weave-kube) points
|
The URL [https://git.io/weave-kube](https://git.io/weave-kube) points
|
||||||
to the addon YAML for the latest release of the Weave Net addon;
|
to the YAML file for the latest release of the Weave Net addon.
|
||||||
historic versions will be archived on our [GitHub release
|
Historic versions are archived on our [GitHub release
|
||||||
page](https://github.com/weaveworks/weave/releases).
|
page](https://github.com/weaveworks/weave/releases).
|
||||||
|
|
||||||
## Upgrading
|
###<a name="daemon-sets"></a> Upgrading the Daemon Sets
|
||||||
|
|
||||||
Kubernetes does not currently support rolling upgrades of daemon sets,
|
Kubernetes does not currently support rolling upgrades of daemon sets,
|
||||||
so you will need to perform the procedure manually:
|
and so you will need to perform the procedure manually:
|
||||||
|
|
||||||
* Apply the updated addon manifest `kubectl apply -f https://git.io/weave-kube`
|
* Apply the updated addon manifest `kubectl apply -f https://git.io/weave-kube`
|
||||||
* Kill each weave net pod in turn with kubectl delete; wait for the
|
* Kill each Weave Net pod with `kubectl delete` and then wait for it to reboot before moving on to the next pod.
|
||||||
replacement to begin running before moving on to the next.
|
|
||||||
|
**Note:** If you delete all Weave Net pods at the same time they will
|
||||||
|
lose track of IP address range ownership, possibly leading to
|
||||||
|
duplicate IP addresses if you then start a new copy of Weave Net.
|
||||||
|
|
||||||
##<a name="npc"></a>Network Policy Controller
|
##<a name="npc"></a>Network Policy Controller
|
||||||
|
|
||||||
The addon supports the [Kubernetes policy
|
The addon also supports the [Kubernetes policy
|
||||||
API](http://kubernetes.io/docs/user-guide/networkpolicies/) so that
|
API](http://kubernetes.io/docs/user-guide/networkpolicies/) so that
|
||||||
you can securely isolate pods from each other based on namespaces and
|
you can securely isolate pods from each other based on namespaces and
|
||||||
labels. For more information on configuring network policies in
|
labels. For more information on configuring network policies in
|
||||||
@@ -65,9 +79,80 @@ Kubernetes see the
|
|||||||
and the [NetworkPolicy API object
|
and the [NetworkPolicy API object
|
||||||
definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitions/#_v1beta1_networkpolicy).
|
definition](http://kubernetes.io/docs/api-reference/extensions/v1beta1/definitions/#_v1beta1_networkpolicy).
|
||||||
|
|
||||||
## Changing Configuration Options
|
**Note:** as of version 1.9 of Weave Net, the Network Policy
|
||||||
|
Controller allows all multicast traffic. Since a single multicast
|
||||||
|
address may be used by multiple pods, we cannot implement rules to
|
||||||
|
isolate them individually. You can turn this behaviour off (block
|
||||||
|
all multicast traffic) by adding `--allow-mcast` as an argument to
|
||||||
|
`weave-npc` in the YAML configuration.
|
||||||
|
|
||||||
You can change the default configuration by saving and editing the
|
###<a name="blocked-connections"></a> Troubleshooting Blocked Connections
|
||||||
addon YAML before you `kubectl apply`. Additional arguments can be
|
|
||||||
|
If you suspect that legitimate traffic is being blocked by the Weave Network Policy Controller, the first thing to do is check the `weave-npc` container's logs.
|
||||||
|
|
||||||
|
To do this, first you have to find the name of the Weave Net pod running on the relevant host:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ kubectl get pods -n kube-system -o wide | grep weave-net
|
||||||
|
weave-net-08y45 2/2 Running 0 1m 10.128.0.2 host1
|
||||||
|
weave-net-2zuhy 2/2 Running 0 1m 10.128.0.4 host3
|
||||||
|
weave-net-oai50 2/2 Running 0 1m 10.128.0.3 host2
|
||||||
|
```
|
||||||
|
|
||||||
|
Select the relevant container, for example, if you want to look at host2 then pick `weave-net-oai50` and run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ kubectl logs <weave-pod-name-as-above> -n kube-system weave-npc
|
||||||
|
```
|
||||||
|
|
||||||
|
When the Weave Network Policy Controller blocks a connection, it logs the following details about it:
|
||||||
|
|
||||||
|
* protocol used,
|
||||||
|
* source IP and port,
|
||||||
|
* destination IP and port,
|
||||||
|
|
||||||
|
as per the below example:
|
||||||
|
|
||||||
|
```
|
||||||
|
TCP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
|
||||||
|
UDP connection from 10.32.0.7:56648 to 10.32.0.11:80 blocked by Weave NPC.
|
||||||
|
```
|
||||||
|
|
||||||
|
###<a name="configuration-options"></a> Changing Configuration Options
|
||||||
|
|
||||||
|
The default configuration settings can be changed by saving and editing the
|
||||||
|
addon YAML before running `kubectl apply`. Additional arguments may be
|
||||||
supplied to the Weave router process by adding them to the `command:`
|
supplied to the Weave router process by adding them to the `command:`
|
||||||
array in the yaml file.
|
array in the YAML file.
|
||||||
|
|
||||||
|
Some parameters are changed by environment variables; these can be
|
||||||
|
inserted into the YAML file like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
containers:
|
||||||
|
- name: weave
|
||||||
|
env:
|
||||||
|
- name: IPALLOC_RANGE
|
||||||
|
value: 10.0.0.0/16
|
||||||
|
```
|
||||||
|
|
||||||
|
The list of variables you can set is:
|
||||||
|
|
||||||
|
* CHECKPOINT\_DISABLE - if set to 1, disable checking for new Weave Net
|
||||||
|
versions (default is blank, i.e. check is enabled)
|
||||||
|
* IPALLOC\_RANGE - the range of IP addresses used by Weave Net
|
||||||
|
and the subnet they are placed in (CIDR format; default 10.32.0.0/12)
|
||||||
|
* EXPECT\_NPC - set to 0 to disable Network Policy Controller (default is on)
|
||||||
|
* KUBE\_PEERS - list of addresses of peers in the Kubernetes cluster
|
||||||
|
(default is to fetch the list from the api-server)
|
||||||
|
* IPALLOC\_INIT - set the initialization mode of the [IP Address
|
||||||
|
Manager](/site/operational-guide/concepts.md#ip-address-manager)
|
||||||
|
(defaults to consensus amongst the KUBE\_PEERS)
|
||||||
|
* WEAVE\_EXPOSE\_IP - set the IP address used as a gateway from the
|
||||||
|
Weave network to the host network - this is useful if you are
|
||||||
|
configuring the addon as a static pod.
|
||||||
|
* WEAVE\_MTU - Weave Net defaults to 1410 bytes, but you can set a
|
||||||
|
smaller size if your underlying network has a tighter limit, or set
|
||||||
|
a larger size for better performance if your network supports jumbo
|
||||||
|
frames - see [here](/site/using-weave/fastdp.md#mtu) for more
|
||||||
|
details.
|
||||||
@@ -20,6 +20,19 @@ exposed:
|
|||||||
* `weave_dns_entries` - Number of DNS entries.
|
* `weave_dns_entries` - Number of DNS entries.
|
||||||
* `weave_flows` - Number of FastDP flows.
|
* `weave_flows` - Number of FastDP flows.
|
||||||
|
|
||||||
|
#### Publish Router Metrics Endpoint
|
||||||
|
|
||||||
|
By default, when started via `weave launch`, weave listens on its local
|
||||||
|
interface to serve metrics. To publish your metrics throughout your cluster,
|
||||||
|
e.g. if your prometheus server is installed on a different host machine,
|
||||||
|
you need to set `WEAVE_STATUS_ADDR` to your corresponding IP and port.
|
||||||
|
Default port is 6782.
|
||||||
|
|
||||||
|
`WEAVE_STATUS_ADDR=X.X.X.X:PORT`
|
||||||
|
|
||||||
|
You can set `WEAVE_STATUS_ADDR=0.0.0.0:6782` to listen on all interfaces,
|
||||||
|
but be aware, this may expose your metrics to the public internet.
|
||||||
|
|
||||||
### Kubernetes Network Policy Controller Metrics
|
### Kubernetes Network Policy Controller Metrics
|
||||||
|
|
||||||
The endpoint address is `localhost:6781`; the following metric is
|
The endpoint address is `localhost:6781`; the following metric is
|
||||||
|
|||||||
@@ -49,14 +49,18 @@ When the router is launched on a host, it derives its peer name in order of pref
|
|||||||
|
|
||||||
* From the command line, where the user is responsible for uniqueness and
|
* From the command line, where the user is responsible for uniqueness and
|
||||||
stability
|
stability
|
||||||
* From the BIOS product UUID, which is generally stable across
|
* From Weave's data volume container (`weavedb`), if you upgrade your
|
||||||
restarts and unique across different physical hardware and certain
|
Weave Net install from a pre-1.9 version and the underlying machine
|
||||||
cloned VMs
|
IDs still match.
|
||||||
* From the hypervisor UUID, which is generally stable across restarts
|
* From a unique machine ID. This is generated by combining IDs from
|
||||||
and unique across VMs which do not provide access to a BIOS product
|
[systemd](https://www.freedesktop.org/software/systemd/man/machine-id.html)
|
||||||
UUID
|
or [D-Bus](https://dbus.freedesktop.org/doc/dbus-uuidgen.1.html)
|
||||||
* From a random value, practically unique across different physical
|
with the BIOS product UUID or hypervisor UUID. Most machines have
|
||||||
hardware and cloned VMs but not stable across restarts
|
one or two of these IDs, and the combination is practically stable
|
||||||
|
across restarts unless a user re-generates it.
|
||||||
|
* If none of the machine IDs are found, a random value is generated.
|
||||||
|
This is practically unique across different physical hardware and
|
||||||
|
cloned VMs but not stable across restarts.
|
||||||
|
|
||||||
The appropriate strategy for assigning peer names depends on the type
|
The appropriate strategy for assigning peer names depends on the type
|
||||||
and method of your particular deployment and is discussed in more
|
and method of your particular deployment and is discussed in more
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ To view detailed information on the local Weave Net router's type `weave status
|
|||||||
|
|
||||||
```
|
```
|
||||||
$ weave status connections
|
$ weave status connections
|
||||||
<- 192.168.48.12:33866 established unencrypted fastdp 7e:21:4a:70:2f:45(host2)
|
<- 192.168.48.12:33866 established unencrypted fastdp 7e:21:4a:70:2f:45(host2) mtu=1410
|
||||||
<- 192.168.48.13:60773 pending encrypted fastdp 7e:ae:cd:d5:23:8d(host3)
|
<- 192.168.48.13:60773 pending encrypted fastdp 7e:ae:cd:d5:23:8d(host3)
|
||||||
-> 192.168.48.14:6783 retrying dial tcp4 192.168.48.14:6783: no route to host
|
-> 192.168.48.14:6783 retrying dial tcp4 192.168.48.14:6783: no route to host
|
||||||
-> 192.168.48.15:6783 failed dial tcp4 192.168.48.15:6783: no route to host, retry: 2015-08-06 18:55:38.246910357 +0000 UTC
|
-> 192.168.48.15:6783 failed dial tcp4 192.168.48.15:6783: no route to host, retry: 2015-08-06 18:55:38.246910357 +0000 UTC
|
||||||
@@ -153,7 +153,7 @@ The columns are as follows:
|
|||||||
* `established` - TCP connection and corresponding UDP path are up
|
* `established` - TCP connection and corresponding UDP path are up
|
||||||
* Info - the failure reason for failed and retrying connections, or
|
* Info - the failure reason for failed and retrying connections, or
|
||||||
the encryption mode, data transport method, remote peer name and
|
the encryption mode, data transport method, remote peer name and
|
||||||
nickname for pending and established connections
|
nickname for pending and established connections, mtu if known
|
||||||
|
|
||||||
### <a name="weave-status-peers"></a>List Peers
|
### <a name="weave-status-peers"></a>List Peers
|
||||||
|
|
||||||
@@ -302,7 +302,7 @@ latest snapshot release using:
|
|||||||
sudo chmod a+x /usr/local/bin/weave
|
sudo chmod a+x /usr/local/bin/weave
|
||||||
weave setup
|
weave setup
|
||||||
|
|
||||||
Snapshot releases report the script version as "(unreleased version)",
|
Snapshot releases report the script version as "unreleased",
|
||||||
and the container image versions as git hashes.
|
and the container image versions as git hashes.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Where fastdp indicates that fast datapath is being used on a connection. If fast
|
|||||||
$ weave status connections
|
$ weave status connections
|
||||||
<- 192.168.122.25:54782 established sleeve 8a:50:4c:23:11:ae(ubuntu1204)
|
<- 192.168.122.25:54782 established sleeve 8a:50:4c:23:11:ae(ubuntu1204)
|
||||||
|
|
||||||
###Packet size (MTU)
|
###<a name="mtu"></a>Packet size (MTU)
|
||||||
|
|
||||||
The Maximum Transmission Unit, or MTU, is the technical term for the
|
The Maximum Transmission Unit, or MTU, is the technical term for the
|
||||||
limit on how big a single packet can be on the network. Weave Net
|
limit on how big a single packet can be on the network. Weave Net
|
||||||
@@ -51,7 +51,8 @@ underlying network has a tighter limit, or set a larger size for
|
|||||||
better performance.
|
better performance.
|
||||||
|
|
||||||
The underlying network must be able to deliver packets of the size
|
The underlying network must be able to deliver packets of the size
|
||||||
specified plus overheads of around 50 bytes. This requirement applies
|
specified plus overheads of around 50 bytes, or else Weave Net will
|
||||||
|
fall back to Sleeve for that connection. This requirement applies
|
||||||
to _every path_ between peers.
|
to _every path_ between peers.
|
||||||
|
|
||||||
To specify a different MTU, before launching Weave Net set the
|
To specify a different MTU, before launching Weave Net set the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
start_suite "Test docker restart policy"
|
start_suite "Test docker restart policy"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.4
|
C1=10.2.1.4
|
||||||
C2=10.2.1.7
|
C2=10.2.1.7
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.41
|
C1=10.2.1.41
|
||||||
C2=10.2.1.71
|
C2=10.2.1.71
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.4
|
C1=10.2.1.4
|
||||||
C2=10.2.1.7
|
C2=10.2.1.7
|
||||||
|
|||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
C1=10.2.1.4
|
||||||
|
C2=10.2.1.7
|
||||||
|
|
||||||
|
start_suite "Ping over encrypted cross-host weave network (sleeve)"
|
||||||
|
|
||||||
|
WEAVE_NO_FASTDP=1 weave_on $HOST1 launch --password wfvAwt7sj
|
||||||
|
WEAVE_NO_FASTDP=1 weave_on $HOST2 launch --password wfvAwt7sj $HOST1
|
||||||
|
|
||||||
|
start_container $HOST1 $C1/24 --name=c1
|
||||||
|
start_container $HOST2 $C2/24 --name=c2
|
||||||
|
assert_raises "exec_on $HOST1 c1 $PING $C2"
|
||||||
|
|
||||||
|
assert_raises "weave_on $HOST1 status connections | grep -P 'encrypted *sleeve'"
|
||||||
|
assert_raises "weave_on $HOST2 status connections | grep -P 'encrypted *sleeve'"
|
||||||
|
|
||||||
|
end_suite
|
||||||
Executable
+71
@@ -0,0 +1,71 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# TODO(mp) 1. test anti-replay 2. test sleeve <-> fastdp
|
||||||
|
# TODO(mp) test with --trusted-subnets
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
HOST1_IP=$($SSH $HOST1 getent ahosts $HOST1 | grep "RAW" | cut -d' ' -f1)
|
||||||
|
HOST2_IP=$($SSH $HOST2 getent ahosts $HOST2 | grep "RAW" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
start_tcpdump() {
|
||||||
|
HOST=$1
|
||||||
|
PCAP=$2
|
||||||
|
run_on $HOST "sudo nohup tcpdump -i any -w $PCAP >/dev/null 2>&1 & echo \$! > $PCAP.pid"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_tcpdump() {
|
||||||
|
HOST=$1
|
||||||
|
PCAP=$2
|
||||||
|
$SSH $HOST "sudo kill \$(cat $PCAP.pid) && rm -f $PCAP.pid && sudo base64 $PCAP" \
|
||||||
|
| base64 -d > $PCAP
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks whether all vxlan-tunneled traffic is encrypted.
|
||||||
|
assert_pcap() {
|
||||||
|
PCAP=$1
|
||||||
|
# UDP port is not exposed in ESP
|
||||||
|
assert "tcpdump -r $PCAP 'src $HOST1_IP && dst $HOST2_IP && dst port 6784'" ""
|
||||||
|
assert "tcpdump -r $PCAP 'src $HOST2_IP && dst $HOST1_IP && dst port 6784'" ""
|
||||||
|
# ip_proto(ESP) = 50
|
||||||
|
assert_raises "[[ -n \"$(tcpdump -r $PCAP "src $HOST1_IP && dst $HOST2_IP && proto 50")\" ]]"
|
||||||
|
assert_raises "[[ -n \"$(tcpdump -r $PCAP "src $HOST2_IP && dst $HOST1_IP && proto 50")\" ]]"
|
||||||
|
|
||||||
|
rm -f $PCAP
|
||||||
|
}
|
||||||
|
|
||||||
|
C1=10.2.1.4
|
||||||
|
C2=10.2.1.7
|
||||||
|
|
||||||
|
start_suite "Ping over encrypted cross-host weave network (fastdp)"
|
||||||
|
|
||||||
|
weave_on $HOST1 launch --password wfvAwt7sj
|
||||||
|
weave_on $HOST2 launch --password wfvAwt7sj $HOST1
|
||||||
|
|
||||||
|
assert_raises "weave_on $HOST1 status connections | grep -P 'encrypted *fastdp'"
|
||||||
|
assert_raises "weave_on $HOST2 status connections | grep -P 'encrypted *fastdp'"
|
||||||
|
|
||||||
|
PCAP1=$(mktemp)
|
||||||
|
PCAP2=$(mktemp)
|
||||||
|
|
||||||
|
start_tcpdump $HOST1 $PCAP1
|
||||||
|
start_tcpdump $HOST2 $PCAP2
|
||||||
|
|
||||||
|
start_container $HOST1 $C1/24 --name=c1
|
||||||
|
start_container $HOST2 $C2/24 --name=c2
|
||||||
|
assert_raises "exec_on $HOST1 c1 $PING $C2"
|
||||||
|
|
||||||
|
stop_tcpdump $HOST1 $PCAP1
|
||||||
|
stop_tcpdump $HOST2 $PCAP2
|
||||||
|
|
||||||
|
assert_pcap $PCAP1
|
||||||
|
assert_pcap $PCAP2
|
||||||
|
|
||||||
|
weave_on $HOST2 reset
|
||||||
|
# policies/SAs and iptables rules should have been removed after terminating
|
||||||
|
# the connection.
|
||||||
|
assert "$SSH $HOST1 sudo ip xfrm state" ""
|
||||||
|
assert "$SSH $HOST1 sudo ip xfrm policy" ""
|
||||||
|
assert "$SSH $HOST1 sudo iptables -t mangle -S WEAVE-IPSEC | grep '\-A'" ""
|
||||||
|
|
||||||
|
end_suite
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
start_suite "Optional encryption via trusted subnets"
|
start_suite "Optional encryption via trusted subnets"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.41
|
C1=10.2.1.41
|
||||||
C3=10.2.1.71
|
C3=10.2.1.71
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.34
|
C1=10.2.1.34
|
||||||
C2=10.2.1.37
|
C2=10.2.1.37
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
weave_local_on() {
|
weave_local_on() {
|
||||||
host=$1
|
host=$1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.4
|
C1=10.2.1.4
|
||||||
C2=10.2.1.7
|
C2=10.2.1.7
|
||||||
@@ -11,7 +11,7 @@ direct_peers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_peers() {
|
assert_peers() {
|
||||||
assert "direct_peers $1 | sort" "$(echo "$2" | sort)"
|
assert "direct_peers $1 | sort" "$(echo -e "$2" | sort)"
|
||||||
}
|
}
|
||||||
|
|
||||||
start_suite "Connecting and forgetting routers after launch"
|
start_suite "Connecting and forgetting routers after launch"
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
|
|
||||||
assert_targets() {
|
assert_targets() {
|
||||||
HOST=$1
|
HOST=$1
|
||||||
shift
|
shift
|
||||||
EXPECTED=$(for TARGET in $@; do echo $TARGET; done | sort)
|
EXPECTED=$(for TARGET in $@; do echo $TARGET; done | sort)
|
||||||
assert "weave_on $HOST report | jq -r '.Router.Targets[] | tostring' | sort" "$EXPECTED"
|
assert "weave_on $HOST report -f '{{range .Router.Targets}}{{.}}{{\"\n\"}}{{end}}' | sort" "$EXPECTED"
|
||||||
}
|
}
|
||||||
|
|
||||||
start_suite "Check Docker restart uses persisted peer list"
|
start_suite "Check Docker restart uses persisted peer list"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.1.46
|
C1=10.2.1.46
|
||||||
C2=10.2.1.47
|
C2=10.2.1.47
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
show_multicast_route_on() {
|
show_multicast_route_on() {
|
||||||
exec_on $1 $2 ip route show 224.0.0.0/4
|
exec_on $1 $2 ip route show 224.0.0.0/4
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
. ./config.sh
|
. "$(dirname "$0")/config.sh"
|
||||||
|
|
||||||
C1=10.2.0.78
|
C1=10.2.0.78
|
||||||
C2=10.2.0.34
|
C2=10.2.0.34
|
||||||
|
|||||||
Loaded 100 of 172 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user