mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-18 20:51:45 +00:00
appc: optimize dns response observation for large route tables
Advertise DNS discovered addresses as a single preference update rather than one at a time. Sort the list of observed addresses and use binary search to consult the list. Updates tailscale/corp#16636 Signed-off-by: James Tucker <james@tailscale.com>
This commit is contained in:
parent
db3776d5bf
commit
0f5e031133
@ -52,8 +52,8 @@ type AppConnector struct {
|
|||||||
// mu guards the fields that follow
|
// mu guards the fields that follow
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
// domains is a map of lower case domain names with no trailing dot, to a
|
// domains is a map of lower case domain names with no trailing dot, to an
|
||||||
// list of resolved IP addresses.
|
// ordered list of resolved IP addresses.
|
||||||
domains map[string][]netip.Addr
|
domains map[string][]netip.Addr
|
||||||
|
|
||||||
// controlRoutes is the list of routes that were last supplied by control.
|
// controlRoutes is the list of routes that were last supplied by control.
|
||||||
@ -297,14 +297,15 @@ func (e *AppConnector) ObserveDNSResponse(res []byte) {
|
|||||||
|
|
||||||
// advertise each address we have learned for the routed domain, that
|
// advertise each address we have learned for the routed domain, that
|
||||||
// was not already known.
|
// was not already known.
|
||||||
|
var toAdvertise []netip.Prefix
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
e.logf("[v2] observed routed DNS response for %s: %s", domain, addr)
|
if !e.isAddrKnownLocked(domain, addr) {
|
||||||
if e.isAddrKnownLocked(domain, addr) {
|
toAdvertise = append(toAdvertise, netip.PrefixFrom(addr, addr.BitLen()))
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
e.scheduleAdvertisement(domain, addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.logf("[v2] observed new routes for %s: %s", domain, toAdvertise)
|
||||||
|
e.scheduleAdvertisement(domain, toAdvertise...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,35 +345,58 @@ func (e *AppConnector) findRoutedDomainLocked(domain string, cnameChain map[stri
|
|||||||
// up future matches.
|
// up future matches.
|
||||||
// e.mu must be held.
|
// e.mu must be held.
|
||||||
func (e *AppConnector) isAddrKnownLocked(domain string, addr netip.Addr) bool {
|
func (e *AppConnector) isAddrKnownLocked(domain string, addr netip.Addr) bool {
|
||||||
if slices.Contains(e.domains[domain], addr) {
|
if e.hasDomainAddrLocked(domain, addr) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for _, route := range e.controlRoutes {
|
for _, route := range e.controlRoutes {
|
||||||
if route.Contains(addr) {
|
if route.Contains(addr) {
|
||||||
// record the new address associated with the domain for faster matching in subsequent
|
// record the new address associated with the domain for faster matching in subsequent
|
||||||
// requests and for diagnostic records.
|
// requests and for diagnostic records.
|
||||||
e.domains[domain] = append(e.domains[domain], addr)
|
e.addDomainAddrLocked(domain, addr)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// scheduleAdvertisement schedules an advertisement of the given address
|
// scheduleAdvertisement schedules an advertisement of the given address
|
||||||
// associated with the given domain.
|
// associated with the given domain.
|
||||||
func (e *AppConnector) scheduleAdvertisement(domain string, addr netip.Addr) {
|
func (e *AppConnector) scheduleAdvertisement(domain string, routes ...netip.Prefix) {
|
||||||
e.queue.Add(func() {
|
e.queue.Add(func() {
|
||||||
if err := e.routeAdvertiser.AdvertiseRoute(netip.PrefixFrom(addr, addr.BitLen())); err != nil {
|
if err := e.routeAdvertiser.AdvertiseRoute(routes...); err != nil {
|
||||||
e.logf("failed to advertise route for %s: %v: %v", domain, addr, err)
|
e.logf("failed to advertise routes for %s: %v: %v", domain, routes, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
defer e.mu.Unlock()
|
defer e.mu.Unlock()
|
||||||
|
|
||||||
if !slices.Contains(e.domains[domain], addr) {
|
for _, route := range routes {
|
||||||
e.logf("[v2] advertised route for %v: %v", domain, addr)
|
if !route.IsSingleIP() {
|
||||||
e.domains[domain] = append(e.domains[domain], addr)
|
continue
|
||||||
|
}
|
||||||
|
addr := route.Addr()
|
||||||
|
if !e.hasDomainAddrLocked(domain, addr) {
|
||||||
|
e.addDomainAddrLocked(domain, addr)
|
||||||
|
e.logf("[v2] advertised route for %v: %v", domain, addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasDomainAddrLocked returns true if the address has been observed in a
|
||||||
|
// resolution of domain.
|
||||||
|
func (e *AppConnector) hasDomainAddrLocked(domain string, addr netip.Addr) bool {
|
||||||
|
_, ok := slices.BinarySearchFunc(e.domains[domain], addr, compareAddr)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// addDomainAddrLocked adds the address to the list of addresses resolved for
|
||||||
|
// domain and ensures the list remains sorted. Does not attempt to deduplicate.
|
||||||
|
func (e *AppConnector) addDomainAddrLocked(domain string, addr netip.Addr) {
|
||||||
|
e.domains[domain] = append(e.domains[domain], addr)
|
||||||
|
slices.SortFunc(e.domains[domain], compareAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareAddr(l, r netip.Addr) int {
|
||||||
|
return l.Compare(r)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user