mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-27 20:19:31 +00:00
tailcfg: add Hostinfo.ExitNodeID to report the selected exit node (#16625)
When a client selects a particular exit node, Control may use that as a signal for deciding other routes. This patch causes the client to report whenever the current exit node changes, through tailcfg.Hostinfo.ExitNodeID. It relies on a properly set ipn.Prefs.ExitNodeID, which should already be resolved by `tailscale set`. Updates tailscale/corp#30536 Signed-off-by: Simon Law <sfllaw@tailscale.com>
This commit is contained in:
@@ -166,7 +166,8 @@ type CapabilityVersion int
|
||||
// - 119: 2025-07-10: Client uses Hostinfo.Location.Priority to prioritize one route over another.
|
||||
// - 120: 2025-07-15: Client understands peer relay disco messages, and implements peer client and relay server functions
|
||||
// - 121: 2025-07-19: Client understands peer relay endpoint alloc with [disco.AllocateUDPRelayEndpointRequest] & [disco.AllocateUDPRelayEndpointResponse]
|
||||
const CurrentCapabilityVersion CapabilityVersion = 121
|
||||
// - 122: 2025-07-21: Client sends Hostinfo.ExitNodeID to report which exit node it has selected, if any.
|
||||
const CurrentCapabilityVersion CapabilityVersion = 122
|
||||
|
||||
// ID is an integer ID for a user, node, or login allocated by the
|
||||
// control plane.
|
||||
@@ -875,6 +876,7 @@ type Hostinfo struct {
|
||||
UserspaceRouter opt.Bool `json:",omitempty"` // if the client's subnet router is running in userspace (netstack) mode
|
||||
AppConnector opt.Bool `json:",omitempty"` // if the client is running the app-connector service
|
||||
ServicesHash string `json:",omitempty"` // opaque hash of the most recent list of tailnet services, change in hash indicates config should be fetched via c2n
|
||||
ExitNodeID StableNodeID `json:",omitzero"` // the client’s selected exit node, empty when unselected.
|
||||
|
||||
// Location represents geographical location data about a
|
||||
// Tailscale host. Location is optional and only set if
|
||||
|
||||
@@ -186,6 +186,7 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct {
|
||||
UserspaceRouter opt.Bool
|
||||
AppConnector opt.Bool
|
||||
ServicesHash string
|
||||
ExitNodeID StableNodeID
|
||||
Location *Location
|
||||
TPM *TPMInfo
|
||||
StateEncrypted opt.Bool
|
||||
|
||||
@@ -67,6 +67,7 @@ func TestHostinfoEqual(t *testing.T) {
|
||||
"UserspaceRouter",
|
||||
"AppConnector",
|
||||
"ServicesHash",
|
||||
"ExitNodeID",
|
||||
"Location",
|
||||
"TPM",
|
||||
"StateEncrypted",
|
||||
@@ -273,6 +274,21 @@ func TestHostinfoEqual(t *testing.T) {
|
||||
&Hostinfo{IngressEnabled: true},
|
||||
false,
|
||||
},
|
||||
{
|
||||
&Hostinfo{ExitNodeID: "stable-exit"},
|
||||
&Hostinfo{ExitNodeID: "stable-exit"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&Hostinfo{ExitNodeID: ""},
|
||||
&Hostinfo{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&Hostinfo{ExitNodeID: ""},
|
||||
&Hostinfo{ExitNodeID: "stable-exit"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
got := tt.a.Equal(tt.b)
|
||||
|
||||
@@ -300,6 +300,7 @@ func (v HostinfoView) Userspace() opt.Bool { return v.ж.User
|
||||
func (v HostinfoView) UserspaceRouter() opt.Bool { return v.ж.UserspaceRouter }
|
||||
func (v HostinfoView) AppConnector() opt.Bool { return v.ж.AppConnector }
|
||||
func (v HostinfoView) ServicesHash() string { return v.ж.ServicesHash }
|
||||
func (v HostinfoView) ExitNodeID() StableNodeID { return v.ж.ExitNodeID }
|
||||
func (v HostinfoView) Location() LocationView { return v.ж.Location.View() }
|
||||
func (v HostinfoView) TPM() views.ValuePointer[TPMInfo] { return views.ValuePointerOf(v.ж.TPM) }
|
||||
|
||||
@@ -345,6 +346,7 @@ var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
|
||||
UserspaceRouter opt.Bool
|
||||
AppConnector opt.Bool
|
||||
ServicesHash string
|
||||
ExitNodeID StableNodeID
|
||||
Location *Location
|
||||
TPM *TPMInfo
|
||||
StateEncrypted opt.Bool
|
||||
|
||||
Reference in New Issue
Block a user