Merge pull request #795 from inercia/weave-711

Make the TTL configurable
This commit is contained in:
Adam Harrison committed 2015-06-01 12:51:45 +01:00
commit 59f919bda3
13 files changed
+104 -55

No files matched your search

+2
View File
@@ -22,6 +22,8 @@ var (
)
const (
DefaultCacheNegLocalTTL = 30 // Default TTL for negative local resolutions
defPendingTimeout int = 5 // timeout for a resolution
)
+13 -13
View File
@@ -36,7 +36,7 @@ func TestCacheLength(t *testing.T) {
ip := net.ParseIP(fmt.Sprintf("10.0.1.%d", i))
records := []ZoneRecord{Record{name, ip, 0, 0, 0}}
reply := makeAddressReply(questionMsg, question, records)
reply := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
reply.Answer[0].Header().Ttl = uint32(i)
l.Put(questionMsg, reply, 0, 0)
@@ -89,7 +89,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Inserting the reply")
records := []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.1"), 0, 0, 0}}
reply1 := makeAddressReply(questionMsg, question, records)
reply1 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply1, nullTTL, 0)
t.Logf("Checking we can Get() the reply now")
@@ -110,8 +110,8 @@ func TestCacheEntries(t *testing.T) {
ttlGet2 := resp.Answer[0].Header().Ttl
wt.AssertEqualInt(t, int(ttlGet1-ttlGet2), 1, "TTL difference")
clk.Add(time.Duration(localTTL) * time.Second)
t.Logf("Checking that a third Get(), after %d second, gets no result", localTTL)
clk.Add(time.Duration(DefaultLocalTTL) * time.Second)
t.Logf("Checking that a third Get(), after %d second, gets no result", DefaultLocalTTL)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
if resp != nil {
@@ -121,7 +121,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking that an Remove() results in Get() returning nothing")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}}
replyTemp := makeAddressReply(questionMsg, question, records)
replyTemp := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, replyTemp, nullTTL, 0)
lenBefore := l.Len()
l.Remove(question)
@@ -135,11 +135,11 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Inserting a two replies for the same query")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.2"), 0, 0, 0}}
reply2 := makeAddressReply(questionMsg, question, records)
reply2 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply2, nullTTL, 0)
clk.Add(time.Duration(1) * time.Second)
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.3"), 0, 0, 0}}
reply3 := makeAddressReply(questionMsg, question, records)
reply3 := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
l.Put(questionMsg, reply3, nullTTL, 0)
t.Logf("Checking we get the last one...")
@@ -149,9 +149,9 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Received '%s'", resp.Answer[0])
wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record")
wt.AssertEqualString(t, resp.Answer[0].(*dns.A).A.String(), "10.0.1.3", "IP address")
wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), int(localTTL), "TTL")
wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), int(DefaultLocalTTL), "TTL")
clk.Add(time.Duration(localTTL-1) * time.Second)
clk.Add(time.Duration(DefaultLocalTTL-1) * time.Second)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
wt.AssertTrue(t, resp != nil, "reponse from the Get()")
@@ -162,7 +162,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking we get empty replies when they are expired...")
lenBefore = l.Len()
clk.Add(time.Duration(localTTL) * time.Second)
clk.Add(time.Duration(DefaultLocalTTL) * time.Second)
resp, err = l.Get(questionMsg, minUDPSize)
wt.AssertNoErr(t, err)
if resp != nil {
@@ -183,7 +183,7 @@ func TestCacheEntries(t *testing.T) {
t.Logf("Checking that an Remove() between Get() and Put() does not break things")
records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}}
replyTemp2 := makeAddressReply(questionMsg2, question2, records)
replyTemp2 := makeAddressReply(questionMsg2, question2, records, DefaultLocalTTL)
l.Remove(question2)
l.Put(questionMsg2, replyTemp2, nullTTL, 0)
resp, err = l.Get(questionMsg2, minUDPSize)
@@ -201,8 +201,8 @@ func TestCacheEntries(t *testing.T) {
wt.AssertNil(t, resp, "Get() response with CacheNoLocalReplies")
wt.AssertNotNil(t, err, "Get() error with CacheNoLocalReplies")
clk.Add(time.Second * time.Duration(negLocalTTL+1))
t.Logf("Checking that we get an expired response after %d seconds", negLocalTTL)
clk.Add(time.Second * time.Duration(DefaultCacheNegLocalTTL+1))
t.Logf("Checking that we get an expired response after %d seconds", DefaultCacheNegLocalTTL)
resp, err = l.Get(questionMsg3, minUDPSize)
wt.AssertNil(t, resp, "expired Get() response with CacheNoLocalReplies")
wt.AssertNil(t, err, "expired Get() error with CacheNoLocalReplies")
+13 -12
View File
@@ -8,16 +8,17 @@ import (
)
const (
localTTL uint32 = 30 // somewhat arbitrary; we don't expect anyone downstream to cache results
negLocalTTL = 30 // TTL for negative local resolutions
minUDPSize = 512
maxUDPSize = 65535
minUDPSize = 512
maxUDPSize = 65535
)
func makeHeader(r *dns.Msg, q *dns.Question) *dns.RR_Header {
func makeHeader(r *dns.Msg, q *dns.Question, ttl int) *dns.RR_Header {
return &dns.RR_Header{
Name: q.Name, Rrtype: q.Qtype,
Class: dns.ClassINET, Ttl: localTTL}
Name: q.Name,
Rrtype: q.Qtype,
Class: dns.ClassINET,
Ttl: uint32(ttl),
}
}
func makeReply(r *dns.Msg, as []dns.RR) *dns.Msg {
@@ -36,11 +37,11 @@ func makeTruncatedReply(r *dns.Msg) *dns.Msg {
return reply
}
type DNSResponseBuilder func(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg
type DNSResponseBuilder func(r *dns.Msg, q *dns.Question, addrs []ZoneRecord, ttl int) *dns.Msg
func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg {
func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord, ttl int) *dns.Msg {
answers := make([]dns.RR, len(addrs))
header := makeHeader(r, q)
header := makeHeader(r, q, ttl)
count := 0
for _, addr := range addrs {
ip := addr.IP()
@@ -62,9 +63,9 @@ func makeAddressReply(r *dns.Msg, q *dns.Question, addrs []ZoneRecord) *dns.Msg
return makeReply(r, answers[:count])
}
func makePTRReply(r *dns.Msg, q *dns.Question, names []ZoneRecord) *dns.Msg {
func makePTRReply(r *dns.Msg, q *dns.Question, names []ZoneRecord, ttl int) *dns.Msg {
answers := make([]dns.RR, len(names))
header := makeHeader(r, q)
header := makeHeader(r, q, ttl)
for i, name := range names {
answers[i] = &dns.PTR{Hdr: *header, Ptr: name.Name()}
}
+2 -2
View File
@@ -25,8 +25,8 @@ func TestPrune(t *testing.T) {
Record{"name", net.ParseIP("10.0.1.4"), 0, 0, 0},
}
reply := makeAddressReply(questionMsg, question, records)
reply.Answer[0].Header().Ttl = localTTL
reply := makeAddressReply(questionMsg, question, records, DefaultLocalTTL)
reply.Answer[0].Header().Ttl = DefaultLocalTTL
pruned := pruneAnswers(reply.Answer, 1)
wt.AssertEqualInt(t, len(pruned), 1, "wrong number of answers")
+9 -4
View File
@@ -13,13 +13,18 @@ type MDNSServer struct {
srv *dns.Server
zone Zone
allowLocal bool
ttl int
running bool
}
// Create a new mDNS server
// Nothing will be done (including port bindings) until you `Start()` the server
func NewMDNSServer(zone Zone, local bool) (*MDNSServer, error) {
return &MDNSServer{zone: zone, allowLocal: local}, nil
func NewMDNSServer(zone Zone, local bool, ttl int) (*MDNSServer, error) {
return &MDNSServer{
zone: zone,
allowLocal: local,
ttl: ttl,
}, nil
}
// Return true if testaddr is a UDP address with IP matching my local i/f
@@ -66,7 +71,7 @@ func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
handleLocal := s.makeHandler(dns.TypeA,
func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
if ips, err := zone.LookupName(q.Name); err == nil {
return makeAddressReply(r, q, ips)
return makeAddressReply(r, q, ips, s.ttl)
}
return nil
})
@@ -74,7 +79,7 @@ func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
handleReverse := s.makeHandler(dns.TypePTR,
func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
if names, err := zone.LookupInaddr(q.Name); err == nil {
return makePTRReply(r, q, names)
return makePTRReply(r, q, names, s.ttl)
}
return nil
})
+1 -1
View File
@@ -21,7 +21,7 @@ func TestServerSimpleQuery(t *testing.T) {
Info.Println("TestServerSimpleQuery starting")
mzone := newMockedZoneWithRecords([]ZoneRecord{testRecord1, testRecord2})
mdnsServer, err := NewMDNSServer(mzone, true)
mdnsServer, err := NewMDNSServer(mzone, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer.Start(nil)
wt.AssertNoErr(t, err)
+4 -4
View File
@@ -18,7 +18,7 @@ func TestClientServerSimpleQuery(t *testing.T) {
testInAddr1 := "1.2.2.10.in-addr.arpa."
mzone := newMockedZoneWithRecords([]ZoneRecord{testRecord1})
mdnsServer, err := NewMDNSServer(mzone, true)
mdnsServer, err := NewMDNSServer(mzone, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer.Start(nil)
wt.AssertNoErr(t, err)
@@ -94,21 +94,21 @@ func TestClientServerInsistentQuery(t *testing.T) {
testInAddr2 := "2.2.2.10.in-addr.arpa."
mzone1 := newMockedZoneWithRecords([]ZoneRecord{testRecord1})
mdnsServer1, err := NewMDNSServer(mzone1, true)
mdnsServer1, err := NewMDNSServer(mzone1, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer1.Start(nil)
wt.AssertNoErr(t, err)
defer mdnsServer1.Stop()
mzone2 := newMockedZoneWithRecords([]ZoneRecord{testRecord2})
mdnsServer2, err := NewMDNSServer(mzone2, true)
mdnsServer2, err := NewMDNSServer(mzone2, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer2.Start(nil)
wt.AssertNoErr(t, err)
defer mdnsServer2.Stop()
// create a third server with exactly the same info as the second server (so we can test duplicates removals)
mdnsServer3, err := NewMDNSServer(mzone2, true)
mdnsServer3, err := NewMDNSServer(mzone2, true, DefaultLocalTTL)
wt.AssertNoErr(t, err)
err = mdnsServer3.Start(nil)
wt.AssertNoErr(t, err)
+10 -2
View File
@@ -16,6 +16,7 @@ import (
const (
DefaultServerPort = 53 // The default server port
DefaultCLICfgFile = "/etc/resolv.conf" // default "resolv.conf" file to try to load
DefaultLocalTTL = 30 // default TTL for responses for local domain queries
DefaultUDPBuflen = 4096 // bigger than the default 512
DefaultCacheLen = 8192 // default cache capacity
DefaultTimeout = 5000 // default timeout for DNS resolutions (millisecs)
@@ -41,6 +42,8 @@ type DNSServerConfig struct {
UDPBufLen int
// (Optional) force a specific cache
Cache ZoneCache
// (Optional) TTL for local domain responses
LocalTTL int
// (Optional) TTL for negative results in the local domain
CacheNegLocalTTL int
// (Optional) for a specific clock provider
@@ -94,6 +97,7 @@ type DNSServer struct {
cache ZoneCache
cacheDisabled bool
maxAnswers int
localTTL int
negLocalTTL int
timeout time.Duration
readTimeout time.Duration
@@ -114,7 +118,8 @@ func NewDNSServer(config DNSServerConfig) (s *DNSServer, err error) {
readTimeout: DefaultTimeout * time.Millisecond,
cacheDisabled: false,
maxAnswers: DefaultMaxAnswers,
negLocalTTL: negLocalTTL,
localTTL: DefaultLocalTTL,
negLocalTTL: DefaultCacheNegLocalTTL,
clock: config.Clock,
}
@@ -153,6 +158,9 @@ func NewDNSServer(config DNSServerConfig) (s *DNSServer, err error) {
if config.MaxAnswers > 0 {
s.maxAnswers = config.MaxAnswers
}
if config.LocalTTL > 0 {
s.localTTL = config.LocalTTL
}
if config.CacheNegLocalTTL > 0 {
s.negLocalTTL = config.CacheNegLocalTTL
}
@@ -344,7 +352,7 @@ func (s *DNSServer) localHandler(proto dnsProtocol, kind string, qtype uint16,
maybeCache(nil, s.negLocalTTL, CacheNoLocalReplies)
fallback(w, r)
} else {
m := msgBuilder(r, &q, answers)
m := msgBuilder(r, &q, answers, s.localTTL)
m.Authoritative = true
maybeCache(m, nullTTL, 0)
m.Answer = pruneAnswers(shuffleAnswers(m.Answer), s.maxAnswers)
+1 -1
View File
@@ -17,7 +17,7 @@ func TestServerCacheRefresh(t *testing.T) {
containerID = "somecontainer"
testName1 = "first.weave.local."
testName2 = "second.weave.local."
refreshInterval = int(localTTL) / 3
refreshInterval = int(DefaultLocalTTL) / 3
)
InitDefaultLogging(testing.Verbose())
+2 -2
View File
@@ -158,7 +158,7 @@ func TestTCPDNSServer(t *testing.T) {
t.Logf("Fallback UDP server got asked: returning %d answers", numAnswers)
q := req.Question[0]
m := makeAddressReply(req, &q, addrs)
m := makeAddressReply(req, &q, addrs, DefaultLocalTTL)
mLen := m.Len()
m.SetEdns0(uint16(maxLen), false)
@@ -171,7 +171,7 @@ func TestTCPDNSServer(t *testing.T) {
fallbackTCPHandler := func(w dns.ResponseWriter, req *dns.Msg) {
t.Logf("Fallback TCP server got asked: returning %d answers", numAnswers)
q := req.Question[0]
m := makeAddressReply(req, &q, addrs)
m := makeAddressReply(req, &q, addrs, DefaultLocalTTL)
w.WriteMsg(m)
}
+13 -6
View File
@@ -17,10 +17,10 @@ const (
)
const (
DefaultLocalDomain = "weave.local." // The default name used for the local domain
DefaultRefreshInterval = int(localTTL) // Period for background updates with mDNS
DefaultRelevantTime = 60 // When to forget info about remote info if nobody asks...
DefaultNumUpdaters = 4 // Default number of background updaters
DefaultLocalDomain = "weave.local." // The default name used for the local domain
DefaultRefreshInterval = int(DefaultLocalTTL) // Period for background updates with mDNS
DefaultRelevantTime = 60 // When to forget info about remote info if nobody asks...
DefaultNumUpdaters = 4 // Default number of background updaters
defaultRefreshMailbox = 1000 // Number of on-the-fly background queries
defaultRemoteIdent = "weave:remote" // Ident used for info obtained from mDNS
@@ -126,7 +126,7 @@ func (re *recordEntry) notifyIPObservers() {
func (re *recordEntry) TTL() int {
// if we never set the TTL (eg, when using AddRecord()), return the standard value...
if re.ttl == 0 {
return int(localTTL)
return int(DefaultLocalTTL)
}
return re.ttl
}
@@ -429,6 +429,8 @@ type ZoneConfig struct {
RelevantTime int
// Max pending refresh requests
MaxRefreshRequests int
// TTL returnined in local asnwers (with mDNS)
LocalTTL int
// Force a specific mDNS client
MDNSClient ZoneMDNSClient
// Force a specific mDNS server
@@ -505,7 +507,12 @@ func NewZoneDb(config ZoneConfig) (zone *ZoneDb, err error) {
}
}
if zone.mdnsSrv == nil {
if zone.mdnsSrv, err = NewMDNSServer(zone, false); err != nil {
mdnsTTL := DefaultLocalTTL
if config.LocalTTL > 0 {
mdnsTTL = config.LocalTTL
}
if zone.mdnsSrv, err = NewMDNSServer(zone, false, mdnsTTL); err != nil {
return
}
}
+20 -1
View File
@@ -134,7 +134,7 @@ Notice how the ping reaches different addresses.
WeaveDNS removes the addresses of any container that dies. This offers
a simple way to implement redundancy. E.g. if in our example we stop
one of the `pingme` containers and re-run the ping tests, eventually
(within ~30s at most, since that is the weaveDNS cache expiry time) we
(within ~30s at most, since that is the weaveDNS [cache expiry time](#ttl)) we
will only be hitting the address of the container that is still alive.
@@ -179,6 +179,25 @@ to the container args:
$ weave launch-dns 10.2.254.1/24 --watch=false
```
## <a name="ttl"></a>Using a different TTL value
By default, weaveDNS specifies a TTL of 30 seconds in any reply sent to
another peer. Peers will honor the TTL received and cache the answer
until it is considered invalid.
However, you can force a different TTL value by launching weaveDNS with
the `--ttl` argument:
```bash
$ weave launch-dns 10.2.254.1/24 --ttl=10
```
This will shorten the lifespan of answers sent to other peers,
so you will be effectively reducing the probability of them having stale
information, but you will also be increasing their resolution times (as
their cache hit rate will be reduced) and the number of request this
weaveDNS instance will receive.
## <a name="domain-search-path"></a>Configuring the domain search paths
If you don't supply a domain search path (with `--dns-search=`),
+14 -7
View File
@@ -24,6 +24,8 @@ func main() {
dnsPort int
httpPort int
wait int
ttl int
negTTL int
timeout int
udpbuf int
fallback string
@@ -46,9 +48,11 @@ func main() {
flag.IntVar(&dnsPort, "dnsport", weavedns.DefaultServerPort, "port to listen to DNS requests")
flag.IntVar(&httpPort, "httpport", 6785, "port to listen to HTTP requests")
flag.IntVar(&cacheLen, "cache", weavedns.DefaultCacheLen, "cache length")
flag.IntVar(&ttl, "ttl", weavedns.DefaultLocalTTL, "TTL (in secs) for responses for local names")
flag.BoolVar(&watch, "watch", true, "watch the docker socket for container events")
flag.BoolVar(&debug, "debug", false, "output debugging info to stderr")
// advanced options
flag.IntVar(&negTTL, "neg-ttl", weavedns.DefaultCacheNegLocalTTL, "negative TTL (in secs) for unanswered queries for local names")
flag.IntVar(&refreshInterval, "refresh", weavedns.DefaultRefreshInterval, "refresh interval (in secs) for local names (0=disable)")
flag.IntVar(&refreshWorkers, "refresh-workers", weavedns.DefaultNumUpdaters, "default number of background updaters")
flag.IntVar(&maxAnswers, "max-answers", weavedns.DefaultMaxAnswers, "maximum number of answers returned to clients (0=unlimited)")
@@ -82,6 +86,7 @@ func main() {
zoneConfig := weavedns.ZoneConfig{
Domain: domain,
Iface: iface,
LocalTTL: ttl,
RefreshInterval: refreshInterval,
RefreshWorkers: refreshWorkers,
RelevantTime: relevantTime,
@@ -104,13 +109,15 @@ func main() {
}
srvConfig := weavedns.DNSServerConfig{
Zone: zone,
Port: dnsPort,
CacheLen: cacheLen,
MaxAnswers: maxAnswers,
Timeout: timeout,
UDPBufLen: udpbuf,
CacheDisabled: cacheDisabled,
Zone: zone,
Port: dnsPort,
CacheLen: cacheLen,
LocalTTL: ttl,
CacheNegLocalTTL: negTTL,
MaxAnswers: maxAnswers,
Timeout: timeout,
UDPBufLen: udpbuf,
CacheDisabled: cacheDisabled,
}
if len(fallback) > 0 {