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>
pull/11060/head
James Tucker 10 months ago committed by James Tucker
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…
Cancel
Save