types/netmap, all: use read-only tailcfg.NodeView in NetworkMap

Updates #8948

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2023-08-18 07:57:44 -07:00
committed by Brad Fitzpatrick
parent b040094b90
commit 58a4fd43d8
32 changed files with 501 additions and 422 deletions

View File

@@ -34,7 +34,7 @@ type NetworkMap struct {
Addresses []netip.Prefix // same as tailcfg.Node.Addresses (IP addresses of this Node directly)
MachineStatus tailcfg.MachineStatus
MachineKey key.MachinePublic
Peers []*tailcfg.Node // sorted by Node.ID
Peers []tailcfg.NodeView // sorted by Node.ID
DNS tailcfg.DNSConfig
// TODO(maisem) : replace with View.
Hostinfo tailcfg.Hostinfo
@@ -84,7 +84,7 @@ type NetworkMap struct {
// AnyPeersAdvertiseRoutes reports whether any peer is advertising non-exit node routes.
func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
for _, p := range nm.Peers {
if len(p.PrimaryRoutes) > 0 {
if p.PrimaryRoutes().Len() > 0 {
return true
}
}
@@ -94,19 +94,21 @@ func (nm *NetworkMap) AnyPeersAdvertiseRoutes() bool {
// PeerByTailscaleIP returns a peer's Node based on its Tailscale IP.
//
// If nm is nil or no peer is found, ok is false.
func (nm *NetworkMap) PeerByTailscaleIP(ip netip.Addr) (peer *tailcfg.Node, ok bool) {
func (nm *NetworkMap) PeerByTailscaleIP(ip netip.Addr) (peer tailcfg.NodeView, ok bool) {
// TODO(bradfitz):
if nm == nil {
return nil, false
return tailcfg.NodeView{}, false
}
for _, n := range nm.Peers {
for _, a := range n.Addresses {
ad := n.Addresses()
for i := 0; i < ad.Len(); i++ {
a := ad.At(i)
if a.Addr() == ip {
return n, true
}
}
}
return nil, false
return tailcfg.NodeView{}, false
}
// MagicDNSSuffix returns the domain's MagicDNS suffix (even if
@@ -153,13 +155,13 @@ func (nm *NetworkMap) VeryConcise() string {
}
// PeerWithStableID finds and returns the peer associated to the inputted StableNodeID.
func (nm *NetworkMap) PeerWithStableID(pid tailcfg.StableNodeID) (_ *tailcfg.Node, ok bool) {
func (nm *NetworkMap) PeerWithStableID(pid tailcfg.StableNodeID) (_ tailcfg.NodeView, ok bool) {
for _, p := range nm.Peers {
if p.StableID == pid {
if p.StableID() == pid {
return p, true
}
}
return nil, false
return tailcfg.NodeView{}, false
}
// printConciseHeader prints a concise header line representing nm to buf.
@@ -203,15 +205,17 @@ func (a *NetworkMap) equalConciseHeader(b *NetworkMap) bool {
//
// If this function is changed to access different fields of p, keep
// in nodeConciseEqual in sync.
func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
aip := make([]string, len(p.AllowedIPs))
for i, a := range p.AllowedIPs {
func printPeerConcise(buf *strings.Builder, p tailcfg.NodeView) {
aip := make([]string, p.AllowedIPs().Len())
for i := range aip {
a := p.AllowedIPs().At(i)
s := strings.TrimSuffix(fmt.Sprint(a), "/32")
aip[i] = s
}
ep := make([]string, len(p.Endpoints))
for i, e := range p.Endpoints {
ep := make([]string, p.Endpoints().Len())
for i := range ep {
e := p.Endpoints().At(i)
// Align vertically on the ':' between IP and port
colon := strings.IndexByte(e, ':')
spaces := 0
@@ -222,21 +226,21 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
ep[i] = fmt.Sprintf("%21v", e+strings.Repeat(" ", spaces))
}
derp := p.DERP
derp := p.DERP()
const derpPrefix = "127.3.3.40:"
if strings.HasPrefix(derp, derpPrefix) {
derp = "D" + derp[len(derpPrefix):]
}
var discoShort string
if !p.DiscoKey.IsZero() {
discoShort = p.DiscoKey.ShortString() + " "
if !p.DiscoKey().IsZero() {
discoShort = p.DiscoKey().ShortString() + " "
}
// Most of the time, aip is just one element, so format the
// table to look good in that case. This will also make multi-
// subnet nodes stand out visually.
fmt.Fprintf(buf, " %v %s%-2v %-15v : %v\n",
p.Key.ShortString(),
p.Key().ShortString(),
discoShort,
derp,
strings.Join(aip, " "),
@@ -244,12 +248,12 @@ func printPeerConcise(buf *strings.Builder, p *tailcfg.Node) {
}
// nodeConciseEqual reports whether a and b are equal for the fields accessed by printPeerConcise.
func nodeConciseEqual(a, b *tailcfg.Node) bool {
return a.Key == b.Key &&
a.DERP == b.DERP &&
a.DiscoKey == b.DiscoKey &&
eqCIDRsIgnoreNil(a.AllowedIPs, b.AllowedIPs) &&
eqStringsIgnoreNil(a.Endpoints, b.Endpoints)
func nodeConciseEqual(a, b tailcfg.NodeView) bool {
return a.Key() == b.Key() &&
a.DERP() == b.DERP() &&
a.DiscoKey() == b.DiscoKey() &&
eqViewsIgnoreNil(a.AllowedIPs(), b.AllowedIPs()) &&
eqViewsIgnoreNil(a.Endpoints(), b.Endpoints())
}
func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
@@ -268,7 +272,7 @@ func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
for len(aps) > 0 && len(bps) > 0 {
pa, pb := aps[0], bps[0]
switch {
case pa.ID == pb.ID:
case pa.ID() == pb.ID():
if !nodeConciseEqual(pa, pb) {
diff.WriteByte('-')
printPeerConcise(&diff, pa)
@@ -276,12 +280,12 @@ func (b *NetworkMap) ConciseDiffFrom(a *NetworkMap) string {
printPeerConcise(&diff, pb)
}
aps, bps = aps[1:], bps[1:]
case pa.ID > pb.ID:
case pa.ID() > pb.ID():
// New peer in b.
diff.WriteByte('+')
printPeerConcise(&diff, pb)
bps = bps[1:]
case pb.ID > pa.ID:
case pb.ID() > pa.ID():
// Deleted peer in b.
diff.WriteByte('-')
printPeerConcise(&diff, pa)
@@ -316,28 +320,18 @@ const (
AllowSubnetRoutes
)
// eqStringsIgnoreNil reports whether a and b have the same length and
// contents, but ignore whether a or b are nil.
func eqStringsIgnoreNil(a, b []string) bool {
if len(a) != len(b) {
// eqViewsIgnoreNil reports whether a and b have the same length and comparably
// equal values at each index. It's used for comparing views of slices and not
// caring about whether the slices are nil or not.
func eqViewsIgnoreNil[T comparable](a, b interface {
Len() int
At(int) T
}) bool {
if a.Len() != b.Len() {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
// eqCIDRsIgnoreNil reports whether a and b have the same length and
// contents, but ignore whether a or b are nil.
func eqCIDRsIgnoreNil(a, b []netip.Prefix) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
for i, n := 0, a.Len(); i < n; i++ {
if a.At(i) != b.At(i) {
return false
}
}

View File

@@ -34,6 +34,14 @@ func testDiscoKey(hexPrefix string) (ret key.DiscoPublic) {
return key.DiscoPublicFromRaw32(mem.B(bs[:]))
}
func nodeViews(v []*tailcfg.Node) []tailcfg.NodeView {
nv := make([]tailcfg.NodeView, len(v))
for i, n := range v {
nv[i] = n.View()
}
return nv
}
func TestNetworkMapConcise(t *testing.T) {
for _, tt := range []struct {
name string
@@ -44,7 +52,7 @@ func TestNetworkMapConcise(t *testing.T) {
name: "basic",
nm: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
@@ -55,7 +63,7 @@ func TestNetworkMapConcise(t *testing.T) {
DERP: "127.3.3.40:4",
Endpoints: []string{"10.2.0.100:12", "10.1.0.100:12345"},
},
},
}),
},
want: "netmap: self: [AQEBA] auth=machine-unknown u=? []\n [AgICA] D2 : 192.168.0.100:12 192.168.0.100:12354\n [AwMDA] D4 : 10.2.0.100:12 10.1.0.100:12345\n",
},
@@ -83,23 +91,23 @@ func TestConciseDiffFrom(t *testing.T) {
name: "no_change",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
want: "",
},
@@ -107,23 +115,23 @@ func TestConciseDiffFrom(t *testing.T) {
name: "header_change",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(2),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
want: "-netmap: self: [AQEBA] auth=machine-unknown u=? []\n+netmap: self: [AgICA] auth=machine-unknown u=? []\n",
},
@@ -131,18 +139,18 @@ func TestConciseDiffFrom(t *testing.T) {
name: "peer_add",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 1,
Key: testNodeKey(1),
@@ -161,7 +169,7 @@ func TestConciseDiffFrom(t *testing.T) {
DERP: "127.3.3.40:3",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
want: "+ [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n+ [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
},
@@ -169,7 +177,7 @@ func TestConciseDiffFrom(t *testing.T) {
name: "peer_remove",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 1,
Key: testNodeKey(1),
@@ -188,18 +196,18 @@ func TestConciseDiffFrom(t *testing.T) {
DERP: "127.3.3.40:3",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "192.168.0.100:12354"},
},
},
}),
},
want: "- [AQEBA] D1 : 192.168.0.100:12 192.168.0.100:12354\n- [AwMDA] D3 : 192.168.0.100:12 192.168.0.100:12354\n",
},
@@ -207,25 +215,25 @@ func TestConciseDiffFrom(t *testing.T) {
name: "peer_port_change",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:1"},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
DERP: "127.3.3.40:2",
Endpoints: []string{"192.168.0.100:12", "1.1.1.1:2"},
},
},
}),
},
want: "- [AgICA] D2 : 192.168.0.100:12 1.1.1.1:1 \n+ [AgICA] D2 : 192.168.0.100:12 1.1.1.1:2 \n",
},
@@ -233,7 +241,7 @@ func TestConciseDiffFrom(t *testing.T) {
name: "disco_key_only_change",
a: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
@@ -242,11 +250,11 @@ func TestConciseDiffFrom(t *testing.T) {
DiscoKey: testDiscoKey("f00f00f00f"),
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
},
},
}),
},
b: &NetworkMap{
NodeKey: testNodeKey(1),
Peers: []*tailcfg.Node{
Peers: nodeViews([]*tailcfg.Node{
{
ID: 2,
Key: testNodeKey(2),
@@ -255,7 +263,7 @@ func TestConciseDiffFrom(t *testing.T) {
DiscoKey: testDiscoKey("ba4ba4ba4b"),
AllowedIPs: []netip.Prefix{netip.PrefixFrom(netaddr.IPv4(100, 102, 103, 104), 32)},
},
},
}),
},
want: "- [AgICA] d:f00f00f00f000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n+ [AgICA] d:ba4ba4ba4b000000 D2 100.102.103.104 : 192.168.0.100:41641 1.1.1.1:41641\n",
},