mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-20 11:58:39 +00:00
types/netmap: move some mutations earlier, remove, document some fields
And optimize the Persist setting a bit, allocating later and only mutating fields when there's been a Node change. Updates #1909 Change-Id: Iaddfd9e88ef76e1d18e8d0a41926eb44d0955312 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
21170fb175
commit
165f0116f1
@ -54,6 +54,7 @@ import (
|
|||||||
"tailscale.com/types/ptr"
|
"tailscale.com/types/ptr"
|
||||||
"tailscale.com/types/tkatype"
|
"tailscale.com/types/tkatype"
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
|
"tailscale.com/util/cmpx"
|
||||||
"tailscale.com/util/multierr"
|
"tailscale.com/util/multierr"
|
||||||
"tailscale.com/util/singleflight"
|
"tailscale.com/util/singleflight"
|
||||||
"tailscale.com/util/systemd"
|
"tailscale.com/util/systemd"
|
||||||
@ -1098,6 +1099,9 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||||||
setControlKnobsFromNodeAttrs(resp.Node.Capabilities)
|
setControlKnobsFromNodeAttrs(resp.Node.Capabilities)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call Node.InitDisplayNames on any changed nodes.
|
||||||
|
initDisplayNames(cmpx.Or(resp.Node, sess.lastNode).View(), &resp)
|
||||||
|
|
||||||
nm := sess.netmapForResponse(&resp)
|
nm := sess.netmapForResponse(&resp)
|
||||||
if nm.SelfNode == nil {
|
if nm.SelfNode == nil {
|
||||||
c.logf("MapResponse lacked node")
|
c.logf("MapResponse lacked node")
|
||||||
@ -1122,14 +1126,16 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||||||
c.lastPrintMap = now
|
c.lastPrintMap = now
|
||||||
c.logf("[v1] new network map[%d]:\n%s", i, nm.VeryConcise())
|
c.logf("[v1] new network map[%d]:\n%s", i, nm.VeryConcise())
|
||||||
}
|
}
|
||||||
newPersist := persist.AsStruct()
|
|
||||||
newPersist.NodeID = nm.SelfNode.StableID
|
|
||||||
newPersist.UserProfile = nm.UserProfiles[nm.User]
|
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
// If we are the ones who last updated persist, then we can update it
|
// If we are the ones who last updated persist, then we can update it
|
||||||
// again. Otherwise, we should not touch it.
|
// again. Otherwise, we should not touch it. Also, it's only worth
|
||||||
if persist == c.persist {
|
// change it if the Node info changed.
|
||||||
|
if persist == c.persist && resp.Node != nil {
|
||||||
|
newPersist := persist.AsStruct()
|
||||||
|
newPersist.NodeID = nm.SelfNode.StableID
|
||||||
|
newPersist.UserProfile = nm.UserProfiles[nm.User()]
|
||||||
|
|
||||||
c.persist = newPersist.View()
|
c.persist = newPersist.View()
|
||||||
persist = c.persist
|
persist = c.persist
|
||||||
}
|
}
|
||||||
@ -1144,6 +1150,28 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initDisplayNames mutates any tailcfg.Nodes in resp to populate their display names,
|
||||||
|
// calling InitDisplayNames on each.
|
||||||
|
//
|
||||||
|
// The magicDNSSuffix used is based on selfNode.
|
||||||
|
func initDisplayNames(selfNode tailcfg.NodeView, resp *tailcfg.MapResponse) {
|
||||||
|
if resp.Node == nil && len(resp.Peers) == 0 && len(resp.PeersChanged) == 0 {
|
||||||
|
// Fast path for a common case (delta updates). No need to compute
|
||||||
|
// magicDNSSuffix.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
magicDNSSuffix := netmap.MagicDNSSuffixOfNodeName(selfNode.Name())
|
||||||
|
if resp.Node != nil {
|
||||||
|
resp.Node.InitDisplayNames(magicDNSSuffix)
|
||||||
|
}
|
||||||
|
for _, n := range resp.Peers {
|
||||||
|
n.InitDisplayNames(magicDNSSuffix)
|
||||||
|
}
|
||||||
|
for _, n := range resp.PeersChanged {
|
||||||
|
n.InitDisplayNames(magicDNSSuffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// decode JSON decodes the res.Body into v. If serverNoiseKey is not specified,
|
// decode JSON decodes the res.Body into v. If serverNoiseKey is not specified,
|
||||||
// it uses the serverKey and mkey to decode the message from the NaCl-crypto-box.
|
// it uses the serverKey and mkey to decode the message from the NaCl-crypto-box.
|
||||||
func decode(res *http.Response, v any, serverKey, serverNoiseKey key.MachinePublic, mkey key.MachinePrivate) error {
|
func decode(res *http.Response, v any, serverKey, serverNoiseKey key.MachinePublic, mkey key.MachinePrivate) error {
|
||||||
|
@ -67,6 +67,9 @@ func newMapSession(privateNodeKey key.NodePrivate) *mapSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ms *mapSession) addUserProfile(userID tailcfg.UserID) {
|
func (ms *mapSession) addUserProfile(userID tailcfg.UserID) {
|
||||||
|
if userID == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
nm := ms.netMapBuilding
|
nm := ms.netMapBuilding
|
||||||
if _, dup := nm.UserProfiles[userID]; dup {
|
if _, dup := nm.UserProfiles[userID]; dup {
|
||||||
// Already populated it from a previous peer.
|
// Already populated it from a previous peer.
|
||||||
@ -184,7 +187,6 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
|
|||||||
nm.Expiry = node.KeyExpiry
|
nm.Expiry = node.KeyExpiry
|
||||||
nm.Name = node.Name
|
nm.Name = node.Name
|
||||||
nm.Addresses = filterSelfAddresses(node.Addresses)
|
nm.Addresses = filterSelfAddresses(node.Addresses)
|
||||||
nm.User = node.User
|
|
||||||
if node.Hostinfo.Valid() {
|
if node.Hostinfo.Valid() {
|
||||||
nm.Hostinfo = *node.Hostinfo.AsStruct()
|
nm.Hostinfo = *node.Hostinfo.AsStruct()
|
||||||
}
|
}
|
||||||
@ -195,16 +197,9 @@ func (ms *mapSession) netmapForResponse(resp *tailcfg.MapResponse) *netmap.Netwo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.addUserProfile(nm.User)
|
ms.addUserProfile(nm.User())
|
||||||
magicDNSSuffix := nm.MagicDNSSuffix()
|
|
||||||
if nm.SelfNode != nil {
|
|
||||||
nm.SelfNode.InitDisplayNames(magicDNSSuffix)
|
|
||||||
}
|
|
||||||
for _, peer := range resp.Peers {
|
for _, peer := range resp.Peers {
|
||||||
peer.InitDisplayNames(magicDNSSuffix)
|
ms.addUserProfile(peer.Sharer)
|
||||||
if !peer.Sharer.IsZero() {
|
|
||||||
ms.addUserProfile(peer.Sharer)
|
|
||||||
}
|
|
||||||
ms.addUserProfile(peer.User)
|
ms.addUserProfile(peer.User)
|
||||||
}
|
}
|
||||||
if DevKnob.ForceProxyDNS() {
|
if DevKnob.ForceProxyDNS() {
|
||||||
|
@ -446,10 +446,11 @@ func TestNetmapForResponse(t *testing.T) {
|
|||||||
ComputedNameWithHost: "foo",
|
ComputedNameWithHost: "foo",
|
||||||
}
|
}
|
||||||
ms := newTestMapSession(t)
|
ms := newTestMapSession(t)
|
||||||
|
mapRes := &tailcfg.MapResponse{
|
||||||
nm1 := ms.netmapForResponse(&tailcfg.MapResponse{
|
|
||||||
Node: someNode,
|
Node: someNode,
|
||||||
})
|
}
|
||||||
|
initDisplayNames(mapRes.Node.View(), mapRes)
|
||||||
|
nm1 := ms.netmapForResponse(mapRes)
|
||||||
if nm1.SelfNode == nil {
|
if nm1.SelfNode == nil {
|
||||||
t.Fatal("nil Node in 1st netmap")
|
t.Fatal("nil Node in 1st netmap")
|
||||||
}
|
}
|
||||||
|
@ -703,7 +703,7 @@ func (b *LocalBackend) updateStatus(sb *ipnstate.StatusBuilder, extraLocked func
|
|||||||
ss.InNetworkMap = true
|
ss.InNetworkMap = true
|
||||||
ss.HostName = b.netMap.Hostinfo.Hostname
|
ss.HostName = b.netMap.Hostinfo.Hostname
|
||||||
ss.DNSName = b.netMap.Name
|
ss.DNSName = b.netMap.Name
|
||||||
ss.UserID = b.netMap.User
|
ss.UserID = b.netMap.User()
|
||||||
if sn := b.netMap.SelfNode; sn != nil {
|
if sn := b.netMap.SelfNode; sn != nil {
|
||||||
peerStatusFromNode(ss, sn.View())
|
peerStatusFromNode(ss, sn.View())
|
||||||
if c := sn.Capabilities; len(c) > 0 {
|
if c := sn.Capabilities; len(c) > 0 {
|
||||||
@ -2781,7 +2781,7 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) ipn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if netMap != nil {
|
if netMap != nil {
|
||||||
newProfile := netMap.UserProfiles[netMap.User]
|
newProfile := netMap.UserProfiles[netMap.User()]
|
||||||
if newLoginName := newProfile.LoginName; newLoginName != "" {
|
if newLoginName := newProfile.LoginName; newLoginName != "" {
|
||||||
if !oldp.Persist().Valid() {
|
if !oldp.Persist().Valid() {
|
||||||
b.logf("active login: %s", newLoginName)
|
b.logf("active login: %s", newLoginName)
|
||||||
@ -3972,7 +3972,7 @@ func (b *LocalBackend) setNetMapLocked(nm *netmap.NetworkMap) {
|
|||||||
b.dialer.SetNetMap(nm)
|
b.dialer.SetNetMap(nm)
|
||||||
var login string
|
var login string
|
||||||
if nm != nil {
|
if nm != nil {
|
||||||
login = cmpx.Or(nm.UserProfiles[nm.User].LoginName, "<missing-profile>")
|
login = cmpx.Or(nm.UserProfiles[nm.User()].LoginName, "<missing-profile>")
|
||||||
}
|
}
|
||||||
b.netMap = nm
|
b.netMap = nm
|
||||||
if login != b.activeLogin {
|
if login != b.activeLogin {
|
||||||
@ -4323,7 +4323,7 @@ func (b *LocalBackend) peerIsTaildropTargetLocked(p tailcfg.NodeView) bool {
|
|||||||
if b.netMap == nil || !p.Valid() {
|
if b.netMap == nil || !p.Valid() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if b.netMap.User == p.User() {
|
if b.netMap.User() == p.User() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if p.Addresses().Len() > 0 &&
|
if p.Addresses().Len() > 0 &&
|
||||||
|
@ -30,12 +30,22 @@ type NetworkMap struct {
|
|||||||
PrivateKey key.NodePrivate
|
PrivateKey key.NodePrivate
|
||||||
Expiry time.Time
|
Expiry time.Time
|
||||||
// Name is the DNS name assigned to this node.
|
// Name is the DNS name assigned to this node.
|
||||||
Name string
|
// It is the MapResponse.Node.Name value and ends with a period.
|
||||||
Addresses []netip.Prefix // same as tailcfg.Node.Addresses (IP addresses of this Node directly)
|
Name string
|
||||||
|
|
||||||
|
// Addresses is SelfNode.Addresses. (IP addresses of this Node directly)
|
||||||
|
//
|
||||||
|
// TODO(bradfitz): remove this field and make this a method.
|
||||||
|
Addresses []netip.Prefix
|
||||||
|
|
||||||
|
// MachineStatus is either tailcfg.MachineAuthorized or tailcfg.MachineUnauthorized,
|
||||||
|
// depending on SelfNode.MachineAuthorized.
|
||||||
|
// TODO(bradfitz): remove this field and make it a method.
|
||||||
MachineStatus tailcfg.MachineStatus
|
MachineStatus tailcfg.MachineStatus
|
||||||
MachineKey key.MachinePublic
|
|
||||||
Peers []tailcfg.NodeView // sorted by Node.ID
|
MachineKey key.MachinePublic
|
||||||
DNS tailcfg.DNSConfig
|
Peers []tailcfg.NodeView // sorted by Node.ID
|
||||||
|
DNS tailcfg.DNSConfig
|
||||||
// TODO(maisem) : replace with View.
|
// TODO(maisem) : replace with View.
|
||||||
Hostinfo tailcfg.Hostinfo
|
Hostinfo tailcfg.Hostinfo
|
||||||
PacketFilter []filter.Match
|
PacketFilter []filter.Match
|
||||||
@ -66,10 +76,6 @@ type NetworkMap struct {
|
|||||||
// hash of the latest update message to tick through TKA).
|
// hash of the latest update message to tick through TKA).
|
||||||
TKAHead tka.AUMHash
|
TKAHead tka.AUMHash
|
||||||
|
|
||||||
// ACLs
|
|
||||||
|
|
||||||
User tailcfg.UserID
|
|
||||||
|
|
||||||
// Domain is the current Tailnet name.
|
// Domain is the current Tailnet name.
|
||||||
Domain string
|
Domain string
|
||||||
|
|
||||||
@ -81,6 +87,15 @@ type NetworkMap struct {
|
|||||||
UserProfiles map[tailcfg.UserID]tailcfg.UserProfile
|
UserProfiles map[tailcfg.UserID]tailcfg.UserProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User returns nm.SelfNode.User if nm.SelfNode is non-nil, otherwise it returns
|
||||||
|
// 0.
|
||||||
|
func (nm *NetworkMap) User() tailcfg.UserID {
|
||||||
|
if nm.SelfNode != nil {
|
||||||
|
return nm.SelfNode.User
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
|
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
|
||||||
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
|
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
|
||||||
for _, p := range nm.Peers {
|
for _, p := range nm.Peers {
|
||||||
@ -111,16 +126,24 @@ func (nm *NetworkMap) PeerByTailscaleIP(ip netip.Addr) (peer tailcfg.NodeView, o
|
|||||||
return tailcfg.NodeView{}, false
|
return tailcfg.NodeView{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if MagicDNS isn't
|
||||||
|
// necessarily in use) of the provided Node.Name value.
|
||||||
|
//
|
||||||
|
// It will neither start nor end with a period.
|
||||||
|
func MagicDNSSuffixOfNodeName(nodeName string) string {
|
||||||
|
name := strings.Trim(nodeName, ".")
|
||||||
|
if _, rest, ok := strings.Cut(name, "."); ok {
|
||||||
|
return rest
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if
|
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if
|
||||||
// MagicDNS isn't necessarily in use).
|
// MagicDNS isn't necessarily in use).
|
||||||
//
|
//
|
||||||
// It will neither start nor end with a period.
|
// It will neither start nor end with a period.
|
||||||
func (nm *NetworkMap) MagicDNSSuffix() string {
|
func (nm *NetworkMap) MagicDNSSuffix() string {
|
||||||
name := strings.Trim(nm.Name, ".")
|
return MagicDNSSuffixOfNodeName(nm.Name)
|
||||||
if _, rest, ok := strings.Cut(name, "."); ok {
|
|
||||||
return rest
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelfCapabilities returns SelfNode.Capabilities if nm and nm.SelfNode are
|
// SelfCapabilities returns SelfNode.Capabilities if nm and nm.SelfNode are
|
||||||
@ -171,12 +194,12 @@ func (nm *NetworkMap) PeerWithStableID(pid tailcfg.StableNodeID) (_ tailcfg.Node
|
|||||||
func (nm *NetworkMap) printConciseHeader(buf *strings.Builder) {
|
func (nm *NetworkMap) printConciseHeader(buf *strings.Builder) {
|
||||||
fmt.Fprintf(buf, "netmap: self: %v auth=%v",
|
fmt.Fprintf(buf, "netmap: self: %v auth=%v",
|
||||||
nm.NodeKey.ShortString(), nm.MachineStatus)
|
nm.NodeKey.ShortString(), nm.MachineStatus)
|
||||||
login := nm.UserProfiles[nm.User].LoginName
|
login := nm.UserProfiles[nm.User()].LoginName
|
||||||
if login == "" {
|
if login == "" {
|
||||||
if nm.User.IsZero() {
|
if nm.User().IsZero() {
|
||||||
login = "?"
|
login = "?"
|
||||||
} else {
|
} else {
|
||||||
login = fmt.Sprint(nm.User)
|
login = fmt.Sprint(nm.User())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(buf, " u=%s", login)
|
fmt.Fprintf(buf, " u=%s", login)
|
||||||
@ -189,7 +212,7 @@ func (nm *NetworkMap) printConciseHeader(buf *strings.Builder) {
|
|||||||
func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool {
|
func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool {
|
||||||
if a.NodeKey != b.NodeKey ||
|
if a.NodeKey != b.NodeKey ||
|
||||||
a.MachineStatus != b.MachineStatus ||
|
a.MachineStatus != b.MachineStatus ||
|
||||||
a.User != b.User ||
|
a.User() != b.User() ||
|
||||||
len(a.Addresses) != len(b.Addresses) {
|
len(a.Addresses) != len(b.Addresses) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user