From 4d941338fd1fb738690975a4a6554845b077a19a Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 15 Apr 2015 17:58:35 +0100 Subject: [PATCH 01/24] Add optional hostname argument to weave expose --- site/features.md | 5 +++++ weave | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/site/features.md b/site/features.md index de64420f..226005ce 100644 --- a/site/features.md +++ b/site/features.md @@ -190,6 +190,11 @@ invocation: host2# weave expose 10.2.1.102/24 10.2.2.102/24 host2# weave hide 10.2.1.102/24 10.2.2.102/24 +Finally, exposed addresses can be added to weaveDNS by supplying a +hostname: + + host2# weave expose 10.2.1.102/24 -h exposed.weave.local + ### Service export Services running in containers on a weave network can be made diff --git a/weave b/weave index a46f9659..019f24cf 100755 --- a/weave +++ b/weave @@ -23,7 +23,7 @@ usage() { echo "weave start [ ...] " echo "weave attach [ ...] " echo "weave detach [ ...] " - echo "weave expose " + echo "weave expose [-h ]" echo "weave hide " echo "weave ps [ ...]" echo "weave status" @@ -760,7 +760,15 @@ case "$COMMAND" in ;; expose) [ $# -gt 0 ] || usage - for CIDR; do + collect_cidr_args "$@" + shift $CIDR_COUNT + if [ $# -eq 0 ]; then + FQDN="" + else + [ $# -eq 2 -a "$1" = "-h" ] || usage + FQDN="$2" + fi + for CIDR in $CIDR_ARGS; do validate_cidr $CIDR create_bridge --without-ethtool if ! ip addr show dev $BRIDGE | grep -qF $CIDR @@ -769,6 +777,9 @@ case "$COMMAND" in arp_update $BRIDGE $CIDR add_iptables_rule nat WEAVE -o $BRIDGE ! -s $CIDR -j MASQUERADE add_iptables_rule nat WEAVE -s $CIDR ! -o $BRIDGE -j MASQUERADE + if [ "$FQDN" ]; then + http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT PUT /name/weave:expose/${CIDR%/*} --data-urlencode "fqdn=$FQDN" 2>/dev/null || true + fi fi done ;; @@ -782,6 +793,7 @@ case "$COMMAND" in ip addr del dev $BRIDGE $CIDR delete_iptables_rule nat WEAVE -o $BRIDGE ! -s $CIDR -j MASQUERADE delete_iptables_rule nat WEAVE -s $CIDR ! -o $BRIDGE -j MASQUERADE + http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT DELETE /name/weave:expose/${CIDR%/*} 2>/dev/null || true fi done ;; From 779b69c0f6d528685c59c1d0f9de17b496446eec Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 16 Apr 2015 17:49:17 +0100 Subject: [PATCH 02/24] correct usage for expose+hide Hangover from #498. --- weave | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/weave b/weave index 7bdab5ef..e10abcd6 100755 --- a/weave +++ b/weave @@ -23,8 +23,8 @@ usage() { echo "weave start [ ...] " echo "weave attach [ ...] " echo "weave detach [ ...] " - echo "weave expose [-h ]" - echo "weave hide " + echo "weave expose [ ...] [-h ]" + echo "weave hide [ ...]" echo "weave ps [ ...]" echo "weave status" echo "weave version" From 19da213dab58213ebef2507d23c270569ce95d48 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 16 Apr 2015 18:00:18 +0100 Subject: [PATCH 03/24] refactor: more shell magic, for consistency --- weave | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weave b/weave index e10abcd6..f864b611 100755 --- a/weave +++ b/weave @@ -107,7 +107,7 @@ dns_args() { docker_bridge_ip DNS_ARG="--dns $DOCKER_BRIDGE_IP" DNS_SEARCH_ARG="--dns-search=." - for arg in "$@"; do + for arg; do case $arg in --dns-search=*) DNS_SEARCH_ARG="" From 705dda9d3ec27c55a4ac6cc69b3738e394b7f21d Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 16 Apr 2015 18:19:00 +0100 Subject: [PATCH 04/24] cosmetic: remove outdated comment --- weave | 1 - 1 file changed, 1 deletion(-) diff --git a/weave b/weave index f864b611..89efc39b 100755 --- a/weave +++ b/weave @@ -456,7 +456,6 @@ tell_dns() { fi # get the long form of the container ID CONTAINER=$(docker inspect --format='{{.Id}}' $CONTAINER_ID 2>/dev/null) - # extract IP address and routing prefix from CIDR MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true for ADDR; do http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT $METHOD /name/$CONTAINER/${ADDR%/*} $MORE_ARGS || true From 1cd31fd0904cd0a60dac304b195f40d4890c631b Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Thu, 16 Apr 2015 18:19:15 +0100 Subject: [PATCH 05/24] only invoke create_bridge once in expose/hide --- weave | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/weave b/weave index 89efc39b..5c88c985 100755 --- a/weave +++ b/weave @@ -785,9 +785,9 @@ case "$COMMAND" in [ $# -eq 2 -a "$1" = "-h" ] || usage FQDN="$2" fi + create_bridge --without-ethtool for CIDR in $CIDR_ARGS; do validate_cidr $CIDR - create_bridge --without-ethtool if ! ip addr show dev $BRIDGE | grep -qF $CIDR then ip addr add dev $BRIDGE $CIDR @@ -802,9 +802,9 @@ case "$COMMAND" in ;; hide) [ $# -gt 0 ] || usage + create_bridge --without-ethtool for CIDR; do validate_cidr $CIDR - create_bridge --without-ethtool if ip addr show dev $BRIDGE | grep -qF $CIDR then ip addr del dev $BRIDGE $CIDR From 803821ab2c97738d6879fc1a01d089edab3a5edd Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Fri, 17 Apr 2015 10:22:08 +0100 Subject: [PATCH 06/24] we need arping in the vagrant vm, for `weave --local` to work --- Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index 87c23060..d3f9565e 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,7 +1,7 @@ VAGRANTFILE_API_VERSION = "2" vm_ip = "172.16.0.3" # arbitrary private IP -pkgs = "lxc-docker aufs-tools build-essential ethtool libpcap-dev git mercurial bc" +pkgs = "lxc-docker aufs-tools build-essential ethtool iputils-arping libpcap-dev git mercurial bc" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| From 2332bc9a94f865eb77afa0938b7700405c1d233d Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Fri, 17 Apr 2015 11:07:53 +0100 Subject: [PATCH 07/24] Require minimum Vagrant version (1.7.0) in smoke tests --- test/Vagrantfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Vagrantfile b/test/Vagrantfile index eb986682..0016e9ce 100644 --- a/test/Vagrantfile +++ b/test/Vagrantfile @@ -1,5 +1,9 @@ VAGRANTFILE_API_VERSION = "2" +# Necessary because the switch disabling unwanted insecure key +# replacement in Vagrant 1.7+ is not accepted by earlier versions +Vagrant.require_version ">= 1.7.0" + # these ought to match what is in config.sh n_machines = 2 ip_prefix = "192.168.48" From 7c68525e9344078f34c86a923252376e56b46c43 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 17 Apr 2015 11:04:29 +0100 Subject: [PATCH 08/24] Simplify address parsing for populate_dns() --- weave | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/weave b/weave index 01a9d7de..15d4c363 100755 --- a/weave +++ b/weave @@ -478,8 +478,7 @@ populate_dns() { fi for CONTAINER in $(docker ps -q --no-trunc); do MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true - if CONTAINER_ADDRS=$(with_container_netns $CONTAINER container_weave_addrs 2>&1) ; then - CONTAINER_IPS=$(echo "$CONTAINER_ADDRS" | grep -o 'inet .*' | sed -e 's/inet \([^/]*\)\/\(.*\)/\1/') + if CONTAINER_IPS=$(with_container_netns $CONTAINER container_weave_addrs 2>&1 | sed -n -e 's/inet \([^/]*\)\/\(.*\)/\1/p') ; then for IP in $CONTAINER_IPS; do http_call_ip $TARGET_IP $DNS_HTTP_PORT PUT /name/$CONTAINER/$IP $MORE_ARGS done From f17cd6ac3b9f77cd66f855952407c2956591e370 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Fri, 17 Apr 2015 11:37:28 +0100 Subject: [PATCH 09/24] Convert hide to use collect_cidr_args --- weave | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/weave b/weave index 5c88c985..66a03727 100755 --- a/weave +++ b/weave @@ -802,8 +802,10 @@ case "$COMMAND" in ;; hide) [ $# -gt 0 ] || usage + collect_cidr_args "$@" + shift $CIDR_COUNT create_bridge --without-ethtool - for CIDR; do + for CIDR in $CIDR_ARGS; do validate_cidr $CIDR if ip addr show dev $BRIDGE | grep -qF $CIDR then From be05cec1b0a264471f600becfbb98577bfd2abce Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Fri, 17 Apr 2015 11:38:46 +0100 Subject: [PATCH 10/24] Ensure at least one CIDR is supplied to multi-CIDR commands --- weave | 3 +++ 1 file changed, 3 insertions(+) diff --git a/weave b/weave index 66a03727..dc2dea4f 100755 --- a/weave +++ b/weave @@ -147,6 +147,9 @@ collect_cidr_args() { CIDR_COUNT=$(($CIDR_COUNT + 1)) shift 1 done + if [ $CIDR_COUNT -eq 0 ]; then + [ $# -gt 0 ] && validate_cidr "$1" || usage + fi } run_iptables() { From eef5559a43711e001e2c0cfebdd3462029971617 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Fri, 17 Apr 2015 11:11:52 +0000 Subject: [PATCH 11/24] Lint the codebase in travis. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 56eb4711..1cc66109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,13 @@ addons: packages: - libpcap-dev -install: +install: - go clean -i net - go install -tags netgo std - make travis script: + - bin/lint . - make tests after_success: From c187c9b290512d4e4daa825563b1df9b020f8b3d Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Fri, 17 Apr 2015 11:37:36 +0000 Subject: [PATCH 12/24] Make lint script work; $result has special meaning! --- bin/lint | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/lint b/bin/lint index 9f5d3c89..78b9f6a5 100755 --- a/bin/lint +++ b/bin/lint @@ -63,11 +63,11 @@ function lint { } function lint_files { - result=0 + lint_result=0 while read filename; do - lint "${filename}" || result=1 + lint "${filename}" || lint_result=1 done - exit $result + exit $lint_result } function list_files { From f735082d9501bbb78d8a60e716813ccba76f9e8a Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Fri, 17 Apr 2015 11:39:39 +0000 Subject: [PATCH 13/24] Fix gofmt errors in nameserver. --- nameserver/cache.go | 2 +- nameserver/server.go | 4 ++-- weavedns/main.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nameserver/cache.go b/nameserver/cache.go index 107dbe22..137f048a 100644 --- a/nameserver/cache.go +++ b/nameserver/cache.go @@ -22,7 +22,7 @@ const ( defPendingTimeout int = 5 // timeout for a resolution ) -const nullTTL = 0 // a null TTL +const nullTTL = 0 // a null TTL type entryStatus uint8 diff --git a/nameserver/server.go b/nameserver/server.go index 3b7e4d8c..9c80670c 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -278,7 +278,7 @@ func (s *DNSServer) rdnsHandler(proto dnsProtocol) dns.HandlerFunc { lookups := []Lookup{s.Zone, s.mdnsCli} maxLen := getMaxReplyLen(r, proto) - Debug.Printf("Reverse query: %+v", q) + Debug.Printf("Reverse query: %+v", q) reply, err := s.cache.Get(r, maxLen, time.Now()) if err != nil { if err == errNoLocalReplies { @@ -300,7 +300,7 @@ func (s *DNSServer) rdnsHandler(proto dnsProtocol) dns.HandlerFunc { // catch unsupported queries if q.Qtype != dns.TypePTR { Warning.Printf("[dns msgid %d] Unexpected reverse query type %s: %+v", - r.MsgHdr.Id, dns.TypeToString[q.Qtype], q) + r.MsgHdr.Id, dns.TypeToString[q.Qtype], q) m := makeDNSNotImplResponse(r) s.cache.Put(r, m, negLocalTTL, 0, now) w.WriteMsg(m) diff --git a/weavedns/main.go b/weavedns/main.go index 8891d40c..476282b8 100644 --- a/weavedns/main.go +++ b/weavedns/main.go @@ -53,7 +53,7 @@ func main() { } InitDefaultLogging(debug) - Info.Printf("WeaveDNS version %s\n", version) // first thing in log: the version + Info.Printf("WeaveDNS version %s\n", version) // first thing in log: the version var zone = new(weavedns.ZoneDb) From 3943b0231ba2f981e8aec31201c40e19f5ee8a8b Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Fri, 17 Apr 2015 11:58:40 +0100 Subject: [PATCH 14/24] Improved validation of trailing arguments --- weave | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/weave b/weave index dc2dea4f..c73b14a5 100755 --- a/weave +++ b/weave @@ -751,9 +751,9 @@ case "$COMMAND" in echo -n $DNS_ARGS ;; start) - [ $# -gt 1 ] || usage collect_cidr_args "$@" shift $CIDR_COUNT + [ $# -eq 1 ] || usage CONTAINER_ID="$1" create_bridge CONTAINER=$(docker start $CONTAINER_ID) @@ -762,24 +762,23 @@ case "$COMMAND" in echo $CONTAINER ;; attach) - [ $# -gt 1 ] || usage collect_cidr_args "$@" shift $CIDR_COUNT + [ $# -eq 1 ] || usage CONTAINER_ID="$1" create_bridge with_container_netns $CONTAINER_ID attach $CIDR_ARGS >/dev/null tell_dns PUT $CONTAINER_ID $CIDR_ARGS ;; detach) - [ $# -gt 1 ] || usage collect_cidr_args "$@" shift $CIDR_COUNT + [ $# -eq 1 ] || usage CONTAINER_ID="$1" with_container_netns $CONTAINER_ID detach $CIDR_ARGS >/dev/null tell_dns DELETE $CONTAINER_ID $CIDR_ARGS ;; expose) - [ $# -gt 0 ] || usage collect_cidr_args "$@" shift $CIDR_COUNT if [ $# -eq 0 ]; then @@ -804,12 +803,11 @@ case "$COMMAND" in done ;; hide) - [ $# -gt 0 ] || usage collect_cidr_args "$@" shift $CIDR_COUNT + [ $# -eq 0 ] || usage create_bridge --without-ethtool for CIDR in $CIDR_ARGS; do - validate_cidr $CIDR if ip addr show dev $BRIDGE | grep -qF $CIDR then ip addr del dev $BRIDGE $CIDR From dceef04ffac4a1fb4010272fc86509b3cd86718e Mon Sep 17 00:00:00 2001 From: David Wragg Date: Sat, 18 Apr 2015 10:38:05 +0100 Subject: [PATCH 15/24] Separate Forwarder and ForwarderDF Much of the state and code associated with Forwarder only applied in the DF case. --- router/connection.go | 2 +- router/forwarder.go | 236 +++++++++++++++++++++++++------------------ 2 files changed, 137 insertions(+), 101 deletions(-) diff --git a/router/connection.go b/router/connection.go index 32678453..151d892e 100644 --- a/router/connection.go +++ b/router/connection.go @@ -53,7 +53,7 @@ type LocalConnection struct { heartbeat *time.Ticker fragTest *time.Ticker forwarder *Forwarder - forwarderDF *Forwarder + forwarderDF *ForwarderDF Decryptor Decryptor Router *Router uid uint64 diff --git a/router/forwarder.go b/router/forwarder.go index 750217cf..337f41a1 100644 --- a/router/forwarder.go +++ b/router/forwarder.go @@ -38,12 +38,10 @@ func (conn *LocalConnection) ensureForwarders() error { } forwarder := NewForwarder(conn, encryptor, udpSender, DefaultPMTU) - forwarderDF := NewForwarder(conn, encryptorDF, udpSenderDF, DefaultPMTU) + forwarderDF := NewForwarderDF(conn, encryptorDF, udpSenderDF, DefaultPMTU) effectivePMTU := forwarderDF.unverifiedPMTU - //NB: only forwarderDF can ever encounter EMSGSIZE errors, and - //thus perform PMTU verification - forwarder.Start(nil) - forwarderDF.Start(make(chan int, ChannelSize)) + forwarder.Start() + forwarderDF.Start() // Various fields in the conn struct are read by other processes, // so we have to use locks. @@ -186,38 +184,30 @@ func fragment(eth layers.Ethernet, ip layers.IPv4, pmtu int, frame *ForwardedFra // Forwarder type Forwarder struct { - conn *LocalConnection - ch chan<- *ForwardedFrame - finished <-chan struct{} - verifyPMTUTick <-chan time.Time - verifyPMTU chan<- int - pmtuVerifyCount uint - enc Encryptor - udpSender UDPSender - maxPayload int - pmtuVerified bool - highestGoodPMTU int - unverifiedPMTU int - lowestBadPMTU int + conn *LocalConnection + ch chan<- *ForwardedFrame + finished <-chan struct{} + enc Encryptor + udpSender UDPSender + maxPayload int + processSendError func(error) error } func NewForwarder(conn *LocalConnection, enc Encryptor, udpSender UDPSender, pmtu int) *Forwarder { - fwd := &Forwarder{ - conn: conn, - enc: enc, - udpSender: udpSender} - fwd.unverifiedPMTU = pmtu - fwd.effectiveOverhead() - fwd.maxPayload = pmtu - UDPOverhead - return fwd + return &Forwarder{ + conn: conn, + enc: enc, + udpSender: udpSender, + maxPayload: pmtu - UDPOverhead, + processSendError: func(err error) error { return err }} } -func (fwd *Forwarder) Start(verifyPMTU chan int) { +func (fwd *Forwarder) Start() { ch := make(chan *ForwardedFrame, ChannelSize) fwd.ch = ch finished := make(chan struct{}) fwd.finished = finished - fwd.verifyPMTU = verifyPMTU - go fwd.run(ch, finished, verifyPMTU) + go fwd.run(ch, finished) } func (fwd *Forwarder) Shutdown() { @@ -231,52 +221,12 @@ func (fwd *Forwarder) Forward(frame *ForwardedFrame) { } } -func (fwd *Forwarder) PMTUVerified(pmtu int) { - select { - case fwd.verifyPMTU <- pmtu: - case <-fwd.finished: - } -} - -func (fwd *Forwarder) run(ch <-chan *ForwardedFrame, finished chan<- struct{}, verifyPMTU <-chan int) { +func (fwd *Forwarder) run(ch <-chan *ForwardedFrame, finished chan<- struct{}) { defer fwd.udpSender.Shutdown() for { - select { - case <-fwd.verifyPMTUTick: - // We only do this case here when we know the buffers are - // all empty so that we don't risk appending verify-frames - // to other data. - fwd.verifyPMTUTick = nil - if fwd.pmtuVerified { - continue - } - if fwd.pmtuVerifyCount > 0 { - fwd.pmtuVerifyCount-- - fwd.attemptVerifyEffectivePMTU() - } else { - // we've exceeded the verification attempts of the - // unverifiedPMTU - fwd.lowestBadPMTU = fwd.unverifiedPMTU - fwd.verifyEffectivePMTU((fwd.highestGoodPMTU + fwd.lowestBadPMTU) / 2) - } - case epmtu := <-verifyPMTU: - if fwd.pmtuVerified || epmtu != fwd.unverifiedPMTU { - continue - } - if epmtu+1 < fwd.lowestBadPMTU { - fwd.highestGoodPMTU = fwd.unverifiedPMTU // = epmtu - fwd.verifyEffectivePMTU((fwd.highestGoodPMTU + fwd.lowestBadPMTU) / 2) - } else { - fwd.pmtuVerified = true - fwd.maxPayload = epmtu + fwd.effectiveOverhead() - UDPOverhead - fwd.conn.setEffectivePMTU(epmtu) - fwd.conn.Log("Effective PMTU verified at", epmtu) - } - case frame := <-ch: - if !fwd.accumulateAndSendFrames(ch, frame) { - close(finished) - return - } + if !fwd.accumulateAndSendFrames(ch, <-ch) { + close(finished) + return } } } @@ -285,21 +235,6 @@ func (fwd *Forwarder) effectiveOverhead() int { return UDPOverhead + fwd.enc.PacketOverhead() + fwd.enc.FrameOverhead() + EthernetOverhead } -func (fwd *Forwarder) verifyEffectivePMTU(newUnverifiedPMTU int) { - fwd.unverifiedPMTU = newUnverifiedPMTU - fwd.pmtuVerifyCount = PMTUVerifyAttempts - fwd.attemptVerifyEffectivePMTU() -} - -func (fwd *Forwarder) attemptVerifyEffectivePMTU() { - fwd.enc.AppendFrame(fwd.conn.local.NameByte, fwd.conn.remote.NameByte, - make([]byte, fwd.unverifiedPMTU+EthernetOverhead)) - fwd.flush() - if fwd.verifyPMTUTick == nil { - fwd.verifyPMTUTick = time.After(PMTUVerifyTimeout << (PMTUVerifyAttempts - fwd.pmtuVerifyCount)) - } -} - // Drain the inbound channel of frames, aggregating them into larger // packets for efficient transmission. // @@ -338,6 +273,10 @@ func (fwd *Forwarder) accumulateAndSendFrames(ch <-chan *ForwardedFrame, frame * } } +func (fwd *Forwarder) logDrop(frame *ForwardedFrame) { + fwd.conn.Log("Dropping too big frame during forwarding: frame len:", len(frame.frame), "; effective PMTU:", fwd.maxPayload+UDPOverhead-fwd.effectiveOverhead()) +} + func (fwd *Forwarder) appendFrame(frame *ForwardedFrame) bool { frameLen := len(frame.frame) if fwd.enc.TotalLen()+fwd.enc.FrameOverhead()+frameLen > fwd.maxPayload { @@ -348,27 +287,124 @@ func (fwd *Forwarder) appendFrame(frame *ForwardedFrame) bool { } func (fwd *Forwarder) flush() { - err := fwd.udpSender.Send(fwd.enc.Bytes()) - if err != nil { - if mtbe, ok := err.(MsgTooBigError); ok { - newUnverifiedPMTU := mtbe.PMTU - fwd.effectiveOverhead() - if newUnverifiedPMTU >= fwd.unverifiedPMTU { + err := fwd.processSendError(fwd.udpSender.Send(fwd.enc.Bytes())) + if err != nil && PosixError(err) != syscall.ENOBUFS { + fwd.conn.Shutdown(err) + } +} + +type ForwarderDF struct { + Forwarder + verifyPMTUTick <-chan time.Time + verifyPMTU chan<- int + pmtuVerifyCount uint + pmtuVerified bool + highestGoodPMTU int + unverifiedPMTU int + lowestBadPMTU int +} + +func NewForwarderDF(conn *LocalConnection, enc Encryptor, udpSender UDPSender, pmtu int) *ForwarderDF { + fwd := &ForwarderDF{ + Forwarder: Forwarder{ + conn: conn, + enc: enc, + udpSender: udpSender, + maxPayload: pmtu - UDPOverhead}} + fwd.Forwarder.processSendError = fwd.processSendError + fwd.unverifiedPMTU = pmtu - fwd.effectiveOverhead() + return fwd +} + +func (fwd *ForwarderDF) Start() { + ch := make(chan *ForwardedFrame, ChannelSize) + fwd.ch = ch + finished := make(chan struct{}) + fwd.finished = finished + verifyPMTU := make(chan int, ChannelSize) + fwd.verifyPMTU = verifyPMTU + go fwd.run(ch, finished, verifyPMTU) +} + +func (fwd *ForwarderDF) PMTUVerified(pmtu int) { + select { + case fwd.verifyPMTU <- pmtu: + case <-fwd.finished: + } +} + +func (fwd *ForwarderDF) run(ch <-chan *ForwardedFrame, finished chan<- struct{}, verifyPMTU <-chan int) { + defer fwd.udpSender.Shutdown() + for { + select { + case <-fwd.verifyPMTUTick: + // We only do this case here when we know the + // buffers are all empty so that we don't risk + // appending verify-frames to other data. + fwd.verifyPMTUTick = nil + if fwd.pmtuVerified { + continue + } + if fwd.pmtuVerifyCount > 0 { + fwd.pmtuVerifyCount-- + fwd.attemptVerifyEffectivePMTU() + } else { + // we've exceeded the verification + // attempts of the unverifiedPMTU + fwd.lowestBadPMTU = fwd.unverifiedPMTU + fwd.verifyEffectivePMTU((fwd.highestGoodPMTU + fwd.lowestBadPMTU) / 2) + } + case epmtu := <-verifyPMTU: + if fwd.pmtuVerified || epmtu != fwd.unverifiedPMTU { + continue + } + if epmtu+1 < fwd.lowestBadPMTU { + fwd.highestGoodPMTU = fwd.unverifiedPMTU // = epmtu + fwd.verifyEffectivePMTU((fwd.highestGoodPMTU + fwd.lowestBadPMTU) / 2) + } else { + fwd.pmtuVerified = true + fwd.maxPayload = epmtu + fwd.effectiveOverhead() - UDPOverhead + fwd.conn.setEffectivePMTU(epmtu) + fwd.conn.Log("Effective PMTU verified at", epmtu) + } + case frame := <-ch: + if !fwd.accumulateAndSendFrames(ch, frame) { + close(finished) return } + } + } +} + +func (fwd *ForwarderDF) verifyEffectivePMTU(newUnverifiedPMTU int) { + fwd.unverifiedPMTU = newUnverifiedPMTU + fwd.pmtuVerifyCount = PMTUVerifyAttempts + fwd.attemptVerifyEffectivePMTU() +} + +func (fwd *ForwarderDF) attemptVerifyEffectivePMTU() { + fwd.enc.AppendFrame(fwd.conn.local.NameByte, fwd.conn.remote.NameByte, + make([]byte, fwd.unverifiedPMTU+EthernetOverhead)) + fwd.flush() + if fwd.verifyPMTUTick == nil { + fwd.verifyPMTUTick = time.After(PMTUVerifyTimeout << (PMTUVerifyAttempts - fwd.pmtuVerifyCount)) + } +} + +func (fwd *ForwarderDF) processSendError(err error) error { + if mtbe, ok := err.(MsgTooBigError); ok { + newUnverifiedPMTU := mtbe.PMTU - fwd.effectiveOverhead() + if newUnverifiedPMTU < fwd.unverifiedPMTU { fwd.pmtuVerified = false fwd.maxPayload = mtbe.PMTU - UDPOverhead fwd.highestGoodPMTU = 8 fwd.lowestBadPMTU = newUnverifiedPMTU + 1 fwd.conn.setEffectivePMTU(newUnverifiedPMTU) fwd.verifyEffectivePMTU(newUnverifiedPMTU) - } else if PosixError(err) == syscall.ENOBUFS { - // TODO handle this better - } else { - fwd.conn.Shutdown(err) } - } -} -func (fwd *Forwarder) logDrop(frame *ForwardedFrame) { - fwd.conn.Log("Dropping too big frame during forwarding: frame len:", len(frame.frame), "; effective PMTU:", fwd.maxPayload+UDPOverhead-fwd.effectiveOverhead()) + return nil + } + + return err } From 5addf4e7b17b1bbd6b0c5ac68e78d98d198da8aa Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 09:14:28 +0100 Subject: [PATCH 16/24] cosmetic: logical grouping of functions in weave script --- weave | 252 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 137 insertions(+), 115 deletions(-) diff --git a/weave b/weave index f29dd3ed..7cd0e1ad 100755 --- a/weave +++ b/weave @@ -95,30 +95,9 @@ COMMAND=$1 shift 1 -dns_args() { - if [ "$1" = "--with-dns" ] ; then - shift 1 - if [ \( "$DOCKER_VERSION_MAJOR" -lt 1 \) -o \ - \( "$DOCKER_VERSION_MAJOR" -eq 1 -a \ - "$DOCKER_VERSION_MINOR" -lt 2 \) ] ; then - echo "ERROR: The '--with-dns' option requires Docker 1.2.0 or later; you are running $DOCKER_VERSION" >&2 - exit 1 - fi - docker_bridge_ip - DNS_ARG="--dns $DOCKER_BRIDGE_IP" - DNS_SEARCH_ARG="--dns-search=." - for arg; do - case $arg in - --dns-search=*) - DNS_SEARCH_ARG="" - ;; - *) - ;; - esac; - done - fi - DNS_ARGS="$DNS_ARG $DNS_SEARCH_ARG" -} +###################################################################### +# general helpers; independent of docker and weave +###################################################################### # utility function to check whether a command can be executed by the shell # see http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script @@ -216,6 +195,10 @@ random_mac() { od -txC -An -N6 /dev/urandom | sed 's|^ ||;s| |:|;s|[0-3]:|2:|;s|[4-7]:|6:|;s|[89ab]:|a:|;s|[c-f]:|e:|;s| |:|g' } +###################################################################### +# weave and docker specific helpers +###################################################################### + create_bridge() { [ ! -d /sys/class/net/$BRIDGE ] && { ip link add name $BRIDGE type bridge @@ -339,6 +322,19 @@ connect_container_to_bridge() { fi } +ask_version() { + if ! DOCKERIMAGE=$(docker inspect --format='{{.Image}}' $1 2>/dev/null) ; then + if ! DOCKERIMAGE=$(docker inspect --format='{{.Id}}' $2 2>/dev/null) ; then + echo "Unable to find $2 image." >&2 + fi + fi + [ -n "$DOCKERIMAGE" ] && docker run --rm $DOCKERIMAGE --version +} + +###################################################################### +# functions invoked through with_container_netns +###################################################################### + launch() { if ! ip netns exec $NETNS ip link show eth0 >/dev/null ; then echo "Perhaps you are running the docker daemon with container networking disabled (-b=none)." >&2 @@ -414,91 +410,13 @@ detach() { ip netns exec $NETNS ip link del $CONTAINER_IFNAME type veth } -# Call url $4 with http verb $3 on container $1 at port $2 -http_call() { - if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null); then - echo "$1 container is not present; have you launched it?" >&2 - return 1 - fi - case "$status" in - "true ") - echo "$1 container has no IP address; is Docker networking enabled?" >&2 - return 1 - ;; - true*) - ip="${status#true }" - ;; - *) - echo "$1 container is not running." >&2 - return 1 - ;; - esac - shift 1 - http_call_ip $ip "$@" +container_weave_addrs() { + ip netns exec $NETNS ip addr show dev $CONTAINER_IFNAME } -http_call_ip() { - ip="$1" - port="$2" - http_verb="$3" - url="$4" - shift 4 - curl --connect-timeout 3 -s -X $http_verb "$@" http://$ip:$port$url -} - -# Perform operation $1 on container ID $2 to local DNS database at address $3 -# This function is only called where we know $2 is a valid container name -tell_dns() { - METHOD="$1" - CONTAINER_ID="$2" - shift 2 - - if ! status=$(docker inspect --format='{{.State.Running}}' $DNS_CONTAINER_NAME 2>/dev/null) || [ "$status" != "true" ] ; then - # weavedns not running - silently return - return - fi - # get the long form of the container ID - CONTAINER=$(docker inspect --format='{{.Id}}' $CONTAINER_ID 2>/dev/null) - MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true - for ADDR; do - http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT $METHOD /name/$CONTAINER/${ADDR%/*} $MORE_ARGS || true - done -} - -# Wait until container $1 on port $2 is alive enough to respond to its status call -wait_for_status() { - TARGET_IP=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' $1) - WAIT_TIME=1 - while ! http_call_ip $TARGET_IP $2 GET /status >/dev/null && [ $WAIT_TIME -lt 4 ]; do - if ! status=$(docker inspect --format='{{.State.Running}}' $1 2>/dev/null) || [ "$status" != "true" ] ; then - echo "Container $1 died" >&2 - return 1 - fi - sleep $WAIT_TIME - WAIT_TIME=$((WAIT_TIME+1)) - done - if [ $WAIT_TIME = 4 ]; then - echo "Timed out waiting for $1 container to start." >&2 - return 1 - fi - return 0 -} - -# Tell the newly-started weaveDNS about existing weave IPs -populate_dns() { - if ! wait_for_status $DNS_CONTAINER_NAME $DNS_HTTP_PORT ; then - echo "If running, it will not be pre-populated." >&2 - return 0 - fi - for CONTAINER in $(docker ps -q --no-trunc); do - MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true - if CONTAINER_IPS=$(with_container_netns $CONTAINER container_weave_addrs 2>&1 | sed -n -e 's/inet \([^/]*\)\/\(.*\)/\1/p') ; then - for IP in $CONTAINER_IPS; do - http_call_ip $TARGET_IP $DNS_HTTP_PORT PUT /name/$CONTAINER/$IP $MORE_ARGS - done - fi - done -} +###################################################################### +# functions for interacting with containers +###################################################################### # Check that a container named $1 with image $2 is not running check_not_running() { @@ -528,19 +446,123 @@ check_not_running() { esac } -container_weave_addrs() { - ip netns exec $NETNS ip addr show dev $CONTAINER_IFNAME +http_call_ip() { + ip="$1" + port="$2" + http_verb="$3" + url="$4" + shift 4 + curl --connect-timeout 3 -s -X $http_verb "$@" http://$ip:$port$url } -ask_version() { - if ! DOCKERIMAGE=$(docker inspect --format='{{.Image}}' $1 2>/dev/null) ; then - if ! DOCKERIMAGE=$(docker inspect --format='{{.Id}}' $2 2>/dev/null) ; then - echo "Unable to find $2 image." >&2 - fi +# Call url $4 with http verb $3 on container $1 at port $2 +http_call() { + if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null); then + echo "$1 container is not present; have you launched it?" >&2 + return 1 fi - [ -n "$DOCKERIMAGE" ] && docker run --rm $DOCKERIMAGE --version + case "$status" in + "true ") + echo "$1 container has no IP address; is Docker networking enabled?" >&2 + return 1 + ;; + true*) + ip="${status#true }" + ;; + *) + echo "$1 container is not running." >&2 + return 1 + ;; + esac + shift 1 + http_call_ip $ip "$@" } +# Wait until container $1 on port $2 is alive enough to respond to its status call +wait_for_status() { + TARGET_IP=$(docker inspect --format='{{.NetworkSettings.IPAddress}}' $1) + WAIT_TIME=1 + while ! http_call_ip $TARGET_IP $2 GET /status >/dev/null && [ $WAIT_TIME -lt 4 ]; do + if ! status=$(docker inspect --format='{{.State.Running}}' $1 2>/dev/null) || [ "$status" != "true" ] ; then + echo "Container $1 died" >&2 + return 1 + fi + sleep $WAIT_TIME + WAIT_TIME=$((WAIT_TIME+1)) + done + if [ $WAIT_TIME = 4 ]; then + echo "Timed out waiting for $1 container to start." >&2 + return 1 + fi + return 0 +} + +###################################################################### +# weaveDNS helpers +###################################################################### + +dns_args() { + if [ "$1" = "--with-dns" ] ; then + shift 1 + if [ \( "$DOCKER_VERSION_MAJOR" -lt 1 \) -o \ + \( "$DOCKER_VERSION_MAJOR" -eq 1 -a \ + "$DOCKER_VERSION_MINOR" -lt 2 \) ] ; then + echo "ERROR: The '--with-dns' option requires Docker 1.2.0 or later; you are running $DOCKER_VERSION" >&2 + exit 1 + fi + docker_bridge_ip + DNS_ARG="--dns $DOCKER_BRIDGE_IP" + DNS_SEARCH_ARG="--dns-search=." + for arg; do + case $arg in + --dns-search=*) + DNS_SEARCH_ARG="" + ;; + *) + ;; + esac; + done + fi + DNS_ARGS="$DNS_ARG $DNS_SEARCH_ARG" +} + +# Perform operation $1 on container ID $2 to local DNS database at address $3 +# This function is only called where we know $2 is a valid container name +tell_dns() { + METHOD="$1" + CONTAINER_ID="$2" + shift 2 + + if ! status=$(docker inspect --format='{{.State.Running}}' $DNS_CONTAINER_NAME 2>/dev/null) || [ "$status" != "true" ] ; then + # weavedns not running - silently return + return + fi + # get the long form of the container ID + CONTAINER=$(docker inspect --format='{{.Id}}' $CONTAINER_ID 2>/dev/null) + MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true + for ADDR; do + http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT $METHOD /name/$CONTAINER/${ADDR%/*} $MORE_ARGS || true + done +} + +# Tell the newly-started weaveDNS about existing weave IPs +populate_dns() { + if ! wait_for_status $DNS_CONTAINER_NAME $DNS_HTTP_PORT ; then + echo "If running, it will not be pre-populated." >&2 + return 0 + fi + for CONTAINER in $(docker ps -q --no-trunc); do + MORE_ARGS=$(docker inspect --format='--data-urlencode fqdn={{.Config.Hostname}}.{{.Config.Domainname}}.' $CONTAINER 2>/dev/null) && true + if CONTAINER_IPS=$(with_container_netns $CONTAINER container_weave_addrs 2>&1 | sed -n -e 's/inet \([^/]*\)\/\(.*\)/\1/p') ; then + for IP in $CONTAINER_IPS; do + http_call_ip $TARGET_IP $DNS_HTTP_PORT PUT /name/$CONTAINER/$IP $MORE_ARGS + done + fi + done +} + +########################################################################################## + if [ -n "$LOCAL" ]; then uname -s -r | sed -n -e 's|^\([^ ]*\) \([0-9][0-9]*\)\.\([0-9][0-9]*\).*|\1 \2 \3|p' | { if ! read sys maj min ; then From 40cd8757636ee1f97fddbbd1bd449c8a3eaee1e3 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 11:17:42 +0100 Subject: [PATCH 17/24] don't validate CIDRs twice in `weave expose` --- weave | 1 - 1 file changed, 1 deletion(-) diff --git a/weave b/weave index 7cd0e1ad..85158fd3 100755 --- a/weave +++ b/weave @@ -810,7 +810,6 @@ case "$COMMAND" in fi create_bridge --without-ethtool for CIDR in $CIDR_ARGS; do - validate_cidr $CIDR if ! ip addr show dev $BRIDGE | grep -qF $CIDR then ip addr add dev $BRIDGE $CIDR From 74f77a71ce825772edb8a841ba123bdc80b4bd70 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 11:53:33 +0100 Subject: [PATCH 18/24] cosmetic: move usage() --- weave | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/weave b/weave index 85158fd3..9d6bb1f4 100755 --- a/weave +++ b/weave @@ -12,6 +12,18 @@ fi IMAGE_VERSION=${VERSION:-$IMAGE_VERSION} +# These are potentially used for remote execs, and have defaults, so +# we introduce them here +DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} +PROCFS=${PROCFS:-/proc} + +BASE_IMAGE=$DOCKERHUB_USER/weave +BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns +BASE_EXEC_IMAGE=$DOCKERHUB_USER/weaveexec +IMAGE=$BASE_IMAGE:$IMAGE_VERSION +DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION +EXEC_IMAGE=$BASE_EXEC_IMAGE:$IMAGE_VERSION + usage() { echo "Usage:" echo "weave setup" @@ -37,20 +49,6 @@ usage() { exit 1 } -[ $# -gt 0 ] || usage - -# These are potentially used for remote execs, and have defaults, so -# we introduce them here -DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} -PROCFS=${PROCFS:-/proc} - -BASE_IMAGE=$DOCKERHUB_USER/weave -BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns -BASE_EXEC_IMAGE=$DOCKERHUB_USER/weaveexec -IMAGE=$BASE_IMAGE:$IMAGE_VERSION -DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION -EXEC_IMAGE=$BASE_EXEC_IMAGE:$IMAGE_VERSION - exec_remote() { docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ @@ -66,6 +64,8 @@ exec_remote() { $EXEC_IMAGE --local "$@" } +[ $# -gt 0 ] || usage + # "run" is a special case because we want to use docker directly, # rather than the docker in $EXEC_IMAGE remotely. That's because we # are passing arbitrary arguments on to docker run, and we can't rely From 7752d6b102d906965659ccb347b7d91a756eb8ae Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 13:18:22 +0100 Subject: [PATCH 19/24] refactor: move "need to run as root" check to a more obvious place --- weave | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/weave b/weave index 9d6bb1f4..92388f2a 100755 --- a/weave +++ b/weave @@ -73,10 +73,6 @@ exec_remote() { if [ "$1" = "--local" ]; then LOCAL="$1" shift 1 - [ $(id -u) = 0 ] || { - echo "weave must be run as 'root' when run locally" >&2 - exit 1 - } elif [ "$1" != "run" ]; then exec_remote "$@" exit $? @@ -564,6 +560,11 @@ populate_dns() { ########################################################################################## if [ -n "$LOCAL" ]; then + [ $(id -u) = 0 ] || { + echo "weave must be run as 'root' when run locally" >&2 + exit 1 + } + uname -s -r | sed -n -e 's|^\([^ ]*\) \([0-9][0-9]*\)\.\([0-9][0-9]*\).*|\1 \2 \3|p' | { if ! read sys maj min ; then echo "ERROR: Unable to parse operating system version $(uname -s -r)" >&2 From fbf76127263970f9dab8f7dd6c848fe3cb07a1cc Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 10:32:13 +0100 Subject: [PATCH 20/24] only check for command / print usage at remote This is desirable since we want to do as little as possible locally, and not duplicate any checks. --- weave | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/weave b/weave index 92388f2a..1926d86a 100755 --- a/weave +++ b/weave @@ -64,8 +64,6 @@ exec_remote() { $EXEC_IMAGE --local "$@" } -[ $# -gt 0 ] || usage - # "run" is a special case because we want to use docker directly, # rather than the docker in $EXEC_IMAGE remotely. That's because we # are passing arbitrary arguments on to docker run, and we can't rely @@ -87,10 +85,6 @@ PORT=${WEAVE_PORT:-6783} HTTP_PORT=6784 DNS_HTTP_PORT=6785 -COMMAND=$1 - -shift 1 - ###################################################################### # general helpers; independent of docker and weave ###################################################################### @@ -608,6 +602,10 @@ DOCKER_VERSION_MAJOR=$(echo "$DOCKER_VERSION" | cut -d. -f 1) DOCKER_VERSION_MINOR=$(echo "$DOCKER_VERSION" | cut -d. -f 2) DOCKER_VERSION_PATCH=$(echo "$DOCKER_VERSION" | cut -d. -f 3) +[ $# -gt 0 ] || usage +COMMAND=$1 +shift 1 + case "$COMMAND" in setup) for img in $IMAGE $DNS_IMAGE $EXEC_IMAGE ; do From cefd89b7d8eeac3ed8580563d6c308f7a559cfc1 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 10:41:35 +0100 Subject: [PATCH 21/24] only set vars that we need for remote execution --- weave | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/weave b/weave index 1926d86a..d4fad485 100755 --- a/weave +++ b/weave @@ -14,15 +14,9 @@ IMAGE_VERSION=${VERSION:-$IMAGE_VERSION} # These are potentially used for remote execs, and have defaults, so # we introduce them here -DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} -PROCFS=${PROCFS:-/proc} - -BASE_IMAGE=$DOCKERHUB_USER/weave -BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns BASE_EXEC_IMAGE=$DOCKERHUB_USER/weaveexec -IMAGE=$BASE_IMAGE:$IMAGE_VERSION -DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION EXEC_IMAGE=$BASE_EXEC_IMAGE:$IMAGE_VERSION +PROCFS=${PROCFS:-/proc} usage() { echo "Usage:" @@ -76,6 +70,12 @@ elif [ "$1" != "run" ]; then exit $? fi +BASE_IMAGE=$DOCKERHUB_USER/weave +BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns +IMAGE=$BASE_IMAGE:$IMAGE_VERSION +DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION + +DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} CONTAINER_NAME=${WEAVE_CONTAINER_NAME:-weave} DNS_CONTAINER_NAME=weavedns BRIDGE=weave From 0a2f341c6bd50d5cab569be9cf698daa6f8f9e6b Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 10:42:43 +0100 Subject: [PATCH 22/24] cosmetic: move DOCKERHUB_USER setting for more logical grouping --- weave | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/weave b/weave index d4fad485..e102f09d 100755 --- a/weave +++ b/weave @@ -2,18 +2,16 @@ set -e SCRIPT_VERSION="(unreleased version)" -DOCKERHUB_USER=zettio - if [ "$SCRIPT_VERSION" = "(unreleased version)" ] ; then IMAGE_VERSION=latest else IMAGE_VERSION=$SCRIPT_VERSION fi - IMAGE_VERSION=${VERSION:-$IMAGE_VERSION} # These are potentially used for remote execs, and have defaults, so # we introduce them here +DOCKERHUB_USER=zettio BASE_EXEC_IMAGE=$DOCKERHUB_USER/weaveexec EXEC_IMAGE=$BASE_EXEC_IMAGE:$IMAGE_VERSION PROCFS=${PROCFS:-/proc} From 53e145bea76aeaf1b6ed96c9c7025517402a6552 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 12:52:13 +0100 Subject: [PATCH 23/24] simplify local portion of `weave run` pull all the local `weave run` execution into one place, thus dispensing with the need to have lots of tests for whether we are executing in the context of "--local". Also, we only remote exec dns-args if "--with-dns" is supplied, which is more efficient in the common case (and also more obvious). NB: we need to retain the docker version check for `run` since the specific breakage it guards against does affect the code we execute locally for `run`. --- weave | 158 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/weave b/weave index e102f09d..b20f8f9b 100755 --- a/weave +++ b/weave @@ -56,41 +56,17 @@ exec_remote() { $EXEC_IMAGE --local "$@" } -# "run" is a special case because we want to use docker directly, -# rather than the docker in $EXEC_IMAGE remotely. That's because we -# are passing arbitrary arguments on to docker run, and we can't rely -# on our baked-in docker to support those arguments. -if [ "$1" = "--local" ]; then - LOCAL="$1" - shift 1 -elif [ "$1" != "run" ]; then - exec_remote "$@" - exit $? -fi +check_docker_version() { + if ! DOCKER_VERSION=$(docker -v | sed -n -e 's|^Docker version \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p') || [ -z "$DOCKER_VERSION" ] ; then + echo "ERROR: Unable to parse docker version" >&2 + exit 1 + fi -BASE_IMAGE=$DOCKERHUB_USER/weave -BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns -IMAGE=$BASE_IMAGE:$IMAGE_VERSION -DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION - -DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} -CONTAINER_NAME=${WEAVE_CONTAINER_NAME:-weave} -DNS_CONTAINER_NAME=weavedns -BRIDGE=weave -CONTAINER_IFNAME=ethwe -MTU=65535 -PORT=${WEAVE_PORT:-6783} -HTTP_PORT=6784 -DNS_HTTP_PORT=6785 - -###################################################################### -# general helpers; independent of docker and weave -###################################################################### - -# utility function to check whether a command can be executed by the shell -# see http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script -command_exists () { - command -v $1 >/dev/null 2>&1 + # guard against https://github.com/docker/docker/issues/8632 + if [ "$DOCKER_VERSION" = "1.3.0" ] ; then + echo "You are running Docker version $DOCKER_VERSION, which contains a bug that prevents weave from working properly. Please upgrade." >&2 + exit 1 + fi } is_cidr() { @@ -119,6 +95,55 @@ collect_cidr_args() { fi } +# "run" is a special case because we want to use docker directly, +# rather than the docker in $EXEC_IMAGE remotely. That's because we +# are passing arbitrary arguments on to docker run, and we can't rely +# on our baked-in docker to support those arguments. +if [ "$1" = "run" ]; then + shift 1 + check_docker_version + if [ "$1" = "--with-dns" ]; then + DNS_ARGS=$(exec_remote dns-args "$@") + shift 1 + fi + collect_cidr_args "$@" + shift $CIDR_COUNT + CONTAINER=$(docker run $DNS_ARGS -d "$@") + exec_remote attach $CIDR_ARGS $CONTAINER + echo $CONTAINER + exit 0 +elif [ "$1" != "--local" ]; then + exec_remote "$@" + exit $? +fi + +shift 1 + +BASE_IMAGE=$DOCKERHUB_USER/weave +BASE_DNS_IMAGE=$DOCKERHUB_USER/weavedns +IMAGE=$BASE_IMAGE:$IMAGE_VERSION +DNS_IMAGE=$BASE_DNS_IMAGE:$IMAGE_VERSION + +DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0} +CONTAINER_NAME=${WEAVE_CONTAINER_NAME:-weave} +DNS_CONTAINER_NAME=weavedns +BRIDGE=weave +CONTAINER_IFNAME=ethwe +MTU=65535 +PORT=${WEAVE_PORT:-6783} +HTTP_PORT=6784 +DNS_HTTP_PORT=6785 + +###################################################################### +# general helpers; independent of docker and weave +###################################################################### + +# utility function to check whether a command can be executed by the shell +# see http://stackoverflow.com/questions/592620/how-to-check-if-a-program-exists-from-a-bash-script +command_exists () { + command -v $1 >/dev/null 2>&1 +} + run_iptables() { # -w is recent addition to iptables if [ -z "$CHECKED_IPTABLES_W" ] ; then @@ -551,51 +576,39 @@ populate_dns() { ########################################################################################## -if [ -n "$LOCAL" ]; then - [ $(id -u) = 0 ] || { - echo "weave must be run as 'root' when run locally" >&2 - exit 1 - } +[ $(id -u) = 0 ] || { + echo "weave must be run as 'root' when run locally" >&2 + exit 1 +} - uname -s -r | sed -n -e 's|^\([^ ]*\) \([0-9][0-9]*\)\.\([0-9][0-9]*\).*|\1 \2 \3|p' | { - if ! read sys maj min ; then +uname -s -r | sed -n -e 's|^\([^ ]*\) \([0-9][0-9]*\)\.\([0-9][0-9]*\).*|\1 \2 \3|p' | { + if ! read sys maj min ; then echo "ERROR: Unable to parse operating system version $(uname -s -r)" >&2 exit 1 - fi + fi - if [ "$sys" != 'Linux' ] ; then - echo "ERROR: Operating systems other than Linux are not supported (you have $(uname -s -r))" >&2 - exit 1 - fi - - if ! [ \( "$maj" -eq 3 -a "$min" -ge 5 \) -o "$maj" -gt 3 ] ; then - echo "WARNING: Linux kernel version 3.5 or newer is required (you have ${maj}.${min})" >&2 - fi - } - - if ! command_exists ip ; then - echo "ERROR: ip utility is missing. Please install it." >&2 + if [ "$sys" != 'Linux' ] ; then + echo "ERROR: Operating systems other than Linux are not supported (you have $(uname -s -r))" >&2 exit 1 fi - if ! ip netns list >/dev/null 2>&1 ; then - echo "ERROR: $(ip -V) does not support network namespaces." >&2 - echo " Please install iproute2-ss111010 or later." >&2 - exit 1 + if ! [ \( "$maj" -eq 3 -a "$min" -ge 5 \) -o "$maj" -gt 3 ] ; then + echo "WARNING: Linux kernel version 3.5 or newer is required (you have ${maj}.${min})" >&2 fi -fi +} -if ! DOCKER_VERSION=$(docker -v | sed -n -e 's|^Docker version \([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*|\1|p') || [ -z "$DOCKER_VERSION" ] ; then - echo "ERROR: Unable to parse docker version" >&2 +if ! command_exists ip ; then + echo "ERROR: ip utility is missing. Please install it." >&2 exit 1 fi -# guard against https://github.com/docker/docker/issues/8632 -if [ "$DOCKER_VERSION" = "1.3.0" ] ; then - echo "You are running Docker version $DOCKER_VERSION, which contains a bug that prevents weave from working properly. Please upgrade." >&2 +if ! ip netns list >/dev/null 2>&1 ; then + echo "ERROR: $(ip -V) does not support network namespaces." >&2 + echo " Please install iproute2-ss111010 or later." >&2 exit 1 fi +check_docker_version DOCKER_VERSION_MAJOR=$(echo "$DOCKER_VERSION" | cut -d. -f 1) DOCKER_VERSION_MINOR=$(echo "$DOCKER_VERSION" | cut -d. -f 2) DOCKER_VERSION_PATCH=$(echo "$DOCKER_VERSION" | cut -d. -f 3) @@ -746,22 +759,13 @@ case "$COMMAND" in ;; run) [ $# -gt 0 ] || usage - if [ -n "$LOCAL" ]; then - dns_args "$@" - else - DNS_ARGS=$(exec_remote dns-args "$@") - [ "$1" = "--with-dns" ] && shift 1 - fi + dns_args "$@" collect_cidr_args "$@" shift $CIDR_COUNT CONTAINER=$(docker run $DNS_ARGS -d "$@") - if [ -n "$LOCAL" ]; then - create_bridge - with_container_netns $CONTAINER attach $CIDR_ARGS >/dev/null - tell_dns PUT $CONTAINER $CIDR_ARGS - else - exec_remote attach $CIDR_ARGS $CONTAINER - fi + create_bridge + with_container_netns $CONTAINER attach $CIDR_ARGS >/dev/null + tell_dns PUT $CONTAINER $CIDR_ARGS echo $CONTAINER ;; dns-args) From b4c00050e01544fee06b16f2394cbced511fd13b Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Sun, 19 Apr 2015 13:14:59 +0100 Subject: [PATCH 24/24] simplify dns-args it makes more sense to strip off the `--with-dns` at the call site. `weave dns-args` now does something useful, instead of having to be invoked as `weave dns-args --with-dns`. --- weave | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/weave b/weave index b20f8f9b..cb86bb84 100755 --- a/weave +++ b/weave @@ -103,8 +103,8 @@ if [ "$1" = "run" ]; then shift 1 check_docker_version if [ "$1" = "--with-dns" ]; then - DNS_ARGS=$(exec_remote dns-args "$@") shift 1 + DNS_ARGS=$(exec_remote dns-args) fi collect_cidr_args "$@" shift $CIDR_COUNT @@ -515,27 +515,24 @@ wait_for_status() { ###################################################################### dns_args() { - if [ "$1" = "--with-dns" ] ; then - shift 1 - if [ \( "$DOCKER_VERSION_MAJOR" -lt 1 \) -o \ - \( "$DOCKER_VERSION_MAJOR" -eq 1 -a \ - "$DOCKER_VERSION_MINOR" -lt 2 \) ] ; then - echo "ERROR: The '--with-dns' option requires Docker 1.2.0 or later; you are running $DOCKER_VERSION" >&2 - exit 1 - fi - docker_bridge_ip - DNS_ARG="--dns $DOCKER_BRIDGE_IP" - DNS_SEARCH_ARG="--dns-search=." - for arg; do - case $arg in - --dns-search=*) - DNS_SEARCH_ARG="" - ;; - *) - ;; - esac; - done + if [ \( "$DOCKER_VERSION_MAJOR" -lt 1 \) -o \ + \( "$DOCKER_VERSION_MAJOR" -eq 1 -a \ + "$DOCKER_VERSION_MINOR" -lt 2 \) ] ; then + echo "ERROR: The '--with-dns' option requires Docker 1.2.0 or later; you are running $DOCKER_VERSION" >&2 + exit 1 fi + docker_bridge_ip + DNS_ARG="--dns $DOCKER_BRIDGE_IP" + DNS_SEARCH_ARG="--dns-search=." + for arg; do + case $arg in + --dns-search=*) + DNS_SEARCH_ARG="" + ;; + *) + ;; + esac; + done DNS_ARGS="$DNS_ARG $DNS_SEARCH_ARG" } @@ -759,7 +756,10 @@ case "$COMMAND" in ;; run) [ $# -gt 0 ] || usage - dns_args "$@" + if [ "$1" = "--with-dns" ] ; then + shift 1 + dns_args + fi collect_cidr_args "$@" shift $CIDR_COUNT CONTAINER=$(docker run $DNS_ARGS -d "$@") @@ -769,7 +769,7 @@ case "$COMMAND" in echo $CONTAINER ;; dns-args) - dns_args "$@" + dns_args echo -n $DNS_ARGS ;; start)