mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 13:18:53 +00:00
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:

committed by
Brad Fitzpatrick

parent
b040094b90
commit
58a4fd43d8
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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",
|
||||
},
|
||||
|
Reference in New Issue
Block a user