tailcfg, control/controlclient: add tailcfg.PeersChangedPatch [capver 33]
This adds a lighter mechanism for endpoint updates from control. Change-Id: If169c26becb76d683e9877dc48cfb35f90cc5f24 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>pull/5109/head
parent
b763a12331
commit
d8cb5aae17
|
@ -5,6 +5,7 @@
|
||||||
package controlclient
|
package controlclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
@ -238,7 +239,7 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) {
|
||||||
sortNodes(newFull)
|
sortNodes(newFull)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(mapRes.PeerSeenChange) != 0 || len(mapRes.OnlineChange) != 0 {
|
if len(mapRes.PeerSeenChange) != 0 || len(mapRes.OnlineChange) != 0 || len(mapRes.PeersChangedPatch) != 0 {
|
||||||
peerByID := make(map[tailcfg.NodeID]*tailcfg.Node, len(newFull))
|
peerByID := make(map[tailcfg.NodeID]*tailcfg.Node, len(newFull))
|
||||||
for _, n := range newFull {
|
for _, n := range newFull {
|
||||||
peerByID[n.ID] = n
|
peerByID[n.ID] = n
|
||||||
|
@ -259,6 +260,16 @@ func undeltaPeers(mapRes *tailcfg.MapResponse, prev []*tailcfg.Node) {
|
||||||
n.Online = &online
|
n.Online = &online
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, ec := range mapRes.PeersChangedPatch {
|
||||||
|
if n, ok := peerByID[ec.NodeID]; ok {
|
||||||
|
if ec.DERPRegion != 0 {
|
||||||
|
n.DERP = fmt.Sprintf("%s:%v", tailcfg.DerpMagicIP, ec.DERPRegion)
|
||||||
|
}
|
||||||
|
if ec.Endpoints != nil {
|
||||||
|
n.Endpoints = ec.Endpoints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mapRes.Peers = newFull
|
mapRes.Peers = newFull
|
||||||
|
|
|
@ -34,6 +34,16 @@ func TestUndeltaPeers(t *testing.T) {
|
||||||
n.LastSeen = &t
|
n.LastSeen = &t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
withDERP := func(d string) func(*tailcfg.Node) {
|
||||||
|
return func(n *tailcfg.Node) {
|
||||||
|
n.DERP = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withEP := func(ep string) func(*tailcfg.Node) {
|
||||||
|
return func(n *tailcfg.Node) {
|
||||||
|
n.Endpoints = []string{ep}
|
||||||
|
}
|
||||||
|
}
|
||||||
n := func(id tailcfg.NodeID, name string, mod ...func(*tailcfg.Node)) *tailcfg.Node {
|
n := func(id tailcfg.NodeID, name string, mod ...func(*tailcfg.Node)) *tailcfg.Node {
|
||||||
n := &tailcfg.Node{ID: id, Name: name}
|
n := &tailcfg.Node{ID: id, Name: name}
|
||||||
for _, f := range mod {
|
for _, f := range mod {
|
||||||
|
@ -137,7 +147,53 @@ func TestUndeltaPeers(t *testing.T) {
|
||||||
n(2, "bar", seenAt(time.Unix(123, 0))),
|
n(2, "bar", seenAt(time.Unix(123, 0))),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ep_change_derp",
|
||||||
|
prev: peers(n(1, "foo", withDERP("127.3.3.40:3"))),
|
||||||
|
mapRes: &tailcfg.MapResponse{
|
||||||
|
PeersChangedPatch: []*tailcfg.PeerChange{{
|
||||||
|
NodeID: 1,
|
||||||
|
DERPRegion: 4,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: peers(n(1, "foo", withDERP("127.3.3.40:4"))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ep_change_udp",
|
||||||
|
prev: peers(n(1, "foo", withEP("1.2.3.4:111"))),
|
||||||
|
mapRes: &tailcfg.MapResponse{
|
||||||
|
PeersChangedPatch: []*tailcfg.PeerChange{{
|
||||||
|
NodeID: 1,
|
||||||
|
Endpoints: []string{"1.2.3.4:56"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: peers(n(1, "foo", withEP("1.2.3.4:56"))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ep_change_udp",
|
||||||
|
prev: peers(n(1, "foo", withDERP("127.3.3.40:3"), withEP("1.2.3.4:111"))),
|
||||||
|
mapRes: &tailcfg.MapResponse{
|
||||||
|
PeersChangedPatch: []*tailcfg.PeerChange{{
|
||||||
|
NodeID: 1,
|
||||||
|
Endpoints: []string{"1.2.3.4:56"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: peers(n(1, "foo", withDERP("127.3.3.40:3"), withEP("1.2.3.4:56"))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ep_change_both",
|
||||||
|
prev: peers(n(1, "foo", withDERP("127.3.3.40:3"), withEP("1.2.3.4:111"))),
|
||||||
|
mapRes: &tailcfg.MapResponse{
|
||||||
|
PeersChangedPatch: []*tailcfg.PeerChange{{
|
||||||
|
NodeID: 1,
|
||||||
|
DERPRegion: 2,
|
||||||
|
Endpoints: []string{"1.2.3.4:56"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
want: peers(n(1, "foo", withDERP("127.3.3.40:2"), withEP("1.2.3.4:56"))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if !tt.curTime.IsZero() {
|
if !tt.curTime.IsZero() {
|
||||||
|
|
|
@ -67,7 +67,8 @@ type CapabilityVersion int
|
||||||
// 30: 2022-03-22: client can request id tokens.
|
// 30: 2022-03-22: client can request id tokens.
|
||||||
// 31: 2022-04-15: PingRequest & PingResponse TSMP & disco support
|
// 31: 2022-04-15: PingRequest & PingResponse TSMP & disco support
|
||||||
// 32: 2022-04-17: client knows FilterRule.CapMatch
|
// 32: 2022-04-17: client knows FilterRule.CapMatch
|
||||||
const CurrentCapabilityVersion CapabilityVersion = 32
|
// 33: 2022-07-20: added MapResponse.PeersChangedPatch (DERPRegion + Endpoints)
|
||||||
|
const CurrentCapabilityVersion CapabilityVersion = 33
|
||||||
|
|
||||||
type StableID string
|
type StableID string
|
||||||
|
|
||||||
|
@ -1237,6 +1238,15 @@ type MapResponse struct {
|
||||||
// PeersRemoved are the NodeIDs that are no longer in the peer list.
|
// PeersRemoved are the NodeIDs that are no longer in the peer list.
|
||||||
PeersRemoved []NodeID `json:",omitempty"`
|
PeersRemoved []NodeID `json:",omitempty"`
|
||||||
|
|
||||||
|
// PeersChangedPatch, if non-nil, means that node(s) have changed.
|
||||||
|
// This is a lighter version of the older PeersChanged support that
|
||||||
|
// only supports certain types of updates
|
||||||
|
//
|
||||||
|
// These are applied after Peers* above, but in practice the
|
||||||
|
// control server should only send these on their own, without
|
||||||
|
// the Peers* fields also set.
|
||||||
|
PeersChangedPatch []*PeerChange `json:",omitempty"`
|
||||||
|
|
||||||
// PeerSeenChange contains information on how to update peers' LastSeen
|
// PeerSeenChange contains information on how to update peers' LastSeen
|
||||||
// times. If the value is false, the peer is gone. If the value is true,
|
// times. If the value is false, the peer is gone. If the value is true,
|
||||||
// the LastSeen time is now. Absent means unchanged.
|
// the LastSeen time is now. Absent means unchanged.
|
||||||
|
@ -1724,3 +1734,27 @@ type TokenResponse struct {
|
||||||
// `uid` | user ID, if not tagged
|
// `uid` | user ID, if not tagged
|
||||||
IDToken string `json:"id_token"`
|
IDToken string `json:"id_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PeerChange is an update to a node.
|
||||||
|
type PeerChange struct {
|
||||||
|
// NodeID is the node ID being mutated. If the NodeID is not
|
||||||
|
// known in the current netmap, this update should be
|
||||||
|
// ignored. (But the server will try not to send such useless
|
||||||
|
// updates.)
|
||||||
|
NodeID NodeID
|
||||||
|
|
||||||
|
// DERPRegion, if non-zero, means that NodeID's home DERP
|
||||||
|
// region ID is now this number.
|
||||||
|
DERPRegion int `json:",omitempty"`
|
||||||
|
|
||||||
|
// Endpoints, if non-empty, means that NodeID's UDP Endpoints
|
||||||
|
// have changed to these.
|
||||||
|
Endpoints []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DerpMagicIP is a fake WireGuard endpoint IP address that means to
|
||||||
|
// use DERP. When used (in the Node.DERP field), the port number of
|
||||||
|
// the WireGuard endpoint is the DERP region ID number to use.
|
||||||
|
//
|
||||||
|
// Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
|
||||||
|
const DerpMagicIP = "127.3.3.40"
|
||||||
|
|
|
@ -442,14 +442,7 @@ func (c *Conn) addDerpPeerRoute(peer key.NodePublic, derpID int, dc *derphttp.Cl
|
||||||
mak.Set(&c.derpRoute, peer, derpRoute{derpID, dc})
|
mak.Set(&c.derpRoute, peer, derpRoute{derpID, dc})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DerpMagicIP is a fake WireGuard endpoint IP address that means
|
var derpMagicIPAddr = netaddr.MustParseIP(tailcfg.DerpMagicIP)
|
||||||
// to use DERP. When used, the port number of the WireGuard endpoint
|
|
||||||
// is the DERP server number to use.
|
|
||||||
//
|
|
||||||
// Mnemonic: 3.3.40 are numbers above the keys D, E, R, P.
|
|
||||||
const DerpMagicIP = "127.3.3.40"
|
|
||||||
|
|
||||||
var derpMagicIPAddr = netaddr.MustParseIP(DerpMagicIP)
|
|
||||||
|
|
||||||
// activeDerp contains fields for an active DERP connection.
|
// activeDerp contains fields for an active DERP connection.
|
||||||
type activeDerp struct {
|
type activeDerp struct {
|
||||||
|
|
Loading…
Reference in New Issue