control/controlclient, types/netmap: start plumbing delta netmap updates

Currently only the top four most popular changes: endpoints, DERP
home, online, and LastSeen.

Updates #1909

Change-Id: I03152da176b2b95232b56acabfb55dcdfaa16b79
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2023-09-01 19:28:00 -07:00
committed by Brad Fitzpatrick
parent c0ade132e6
commit 3af051ea27
14 changed files with 715 additions and 13 deletions

View File

@@ -29,6 +29,7 @@ import (
"tailscale.com/tstime/mono"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/views"
"tailscale.com/util/mak"
"tailscale.com/util/ringbuffer"
)
@@ -805,20 +806,38 @@ func (de *endpoint) updateFromNode(n tailcfg.NodeView, heartbeatDisabled bool) {
de.derpAddr = newDerp
}
de.setEndpointsLocked(addrPortsFromStringsView{n.Endpoints()})
}
// addrPortsFromStringsView converts a view of AddrPort strings
// to a view-like thing of netip.AddrPort.
// TODO(bradfitz): change the type of tailcfg.Node.Endpoint.
type addrPortsFromStringsView struct {
views.Slice[string]
}
func (a addrPortsFromStringsView) At(i int) netip.AddrPort {
ap, _ := netip.ParseAddrPort(a.Slice.At(i))
return ap // or the zero value on error
}
func (de *endpoint) setEndpointsLocked(eps interface {
LenIter() []struct{}
At(i int) netip.AddrPort
}) {
for _, st := range de.endpointState {
st.index = indexSentinelDeleted // assume deleted until updated in next loop
}
var newIpps []netip.AddrPort
for i := range n.Endpoints().LenIter() {
epStr := n.Endpoints().At(i)
for i := range eps.LenIter() {
if i > math.MaxInt16 {
// Seems unlikely.
continue
break
}
ipp, err := netip.ParseAddrPort(epStr)
if err != nil {
de.c.logf("magicsock: bogus netmap endpoint %q", epStr)
ipp := eps.At(i)
if !ipp.IsValid() {
de.c.logf("magicsock: bogus netmap endpoint from %v", eps)
continue
}
if st, ok := de.endpointState[ipp]; ok {
@@ -1214,3 +1233,9 @@ func (de *endpoint) resetLocked() {
func (de *endpoint) numStopAndReset() int64 {
return atomic.LoadInt64(&de.numStopAndResetAtomic)
}
func (de *endpoint) setDERPHome(regionID uint16) {
de.mu.Lock()
defer de.mu.Unlock()
de.derpAddr = netip.AddrPortFrom(tailcfg.DerpMagicIPAddr, uint16(regionID))
}

View File

@@ -2588,6 +2588,29 @@ func simpleDur(d time.Duration) time.Duration {
return d.Round(time.Minute)
}
// UpdateNetmapDelta implements controlclient.NetmapDeltaUpdater.
func (c *Conn) UpdateNetmapDelta(muts []netmap.NodeMutation) (handled bool) {
c.mu.Lock()
defer c.mu.Unlock()
for _, m := range muts {
nodeID := m.NodeIDBeingMutated()
ep, ok := c.peerMap.endpointForNodeID(nodeID)
if !ok {
continue
}
switch m := m.(type) {
case netmap.NodeMutationDERPHome:
ep.setDERPHome(uint16(m.DERPRegion))
case netmap.NodeMutationEndpoints:
ep.mu.Lock()
ep.setEndpointsLocked(views.SliceOf(m.Endpoints))
ep.mu.Unlock()
}
}
return true
}
// UpdateStatus implements the interface nede by ipnstate.StatusBuilder.
//
// This method adds in the magicsock-specific information only. Most