@@ -6,7 +6,6 @@ package wgengine
6
6
7
7
import (
8
8
"bufio"
9
- "bytes"
10
9
crand "crypto/rand"
11
10
"errors"
12
11
"fmt"
@@ -19,7 +18,6 @@ import (
19
18
"sync"
20
19
"time"
21
20
22
- "go4.org/mem"
23
21
"golang.zx2c4.com/wireguard/device"
24
22
"golang.zx2c4.com/wireguard/tun"
25
23
"tailscale.com/control/controlclient"
@@ -53,6 +51,7 @@ import (
53
51
"tailscale.com/wgengine/monitor"
54
52
"tailscale.com/wgengine/router"
55
53
"tailscale.com/wgengine/wgcfg"
54
+ "tailscale.com/wgengine/wgint"
56
55
"tailscale.com/wgengine/wglog"
57
56
)
58
57
@@ -990,126 +989,42 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
990
989
derpConns := e .magicConn .DERPs ()
991
990
992
991
e .wgLock .Lock ()
993
- defer e .wgLock .Unlock ()
994
-
995
- e .mu .Lock ()
996
- closing := e .closing
997
- e .mu .Unlock ()
998
- if closing {
999
- return nil , ErrEngineClosing
1000
- }
992
+ wgdev := e .wgdev
993
+ e .wgLock .Unlock ()
1001
994
1002
- if e .wgdev == nil {
995
+ // Assume that once created, wgdev is typically not replaced in-flight.
996
+ if wgdev == nil {
1003
997
// RequestStatus was invoked before the wgengine has
1004
998
// finished initializing. This can happen when wgegine
1005
999
// provides a callback to magicsock for endpoint
1006
1000
// updates that calls RequestStatus.
1007
1001
return nil , nil
1008
1002
}
1009
1003
1010
- pr , pw := io .Pipe ()
1011
- defer pr .Close () // to unblock writes on error path returns
1012
-
1013
- errc := make (chan error , 1 )
1014
- go func () {
1015
- defer pw .Close ()
1016
- // TODO(apenwarr): get rid of silly uapi stuff for in-process comms
1017
- // FIXME: get notified of status changes instead of polling.
1018
- err := e .wgdev .IpcGetOperation (pw )
1019
- if err != nil {
1020
- err = fmt .Errorf ("IpcGetOperation: %w" , err )
1021
- }
1022
- errc <- err
1023
- }()
1024
-
1025
- pp := make (map [key.NodePublic ]ipnstate.PeerStatusLite )
1026
- var p ipnstate.PeerStatusLite
1027
-
1028
- var hst1 , hst2 , n int64
1029
-
1030
- br := e .statusBufioReader
1031
- if br != nil {
1032
- br .Reset (pr )
1033
- } else {
1034
- br = bufio .NewReaderSize (pr , 1 << 10 )
1035
- e .statusBufioReader = br
1036
- }
1037
- for {
1038
- line , err := br .ReadSlice ('\n' )
1039
- if err == io .EOF {
1040
- break
1041
- }
1042
- if err != nil {
1043
- return nil , fmt .Errorf ("reading from UAPI pipe: %w" , err )
1044
- }
1045
- line = bytes .TrimSuffix (line , singleNewline )
1046
- k := line
1047
- var v mem.RO
1048
- if i := bytes .IndexByte (line , '=' ); i != - 1 {
1049
- k = line [:i ]
1050
- v = mem .B (line [i + 1 :])
1051
- }
1052
- switch string (k ) {
1053
- case "public_key" :
1054
- pk , err := key .ParseNodePublicUntyped (v )
1055
- if err != nil {
1056
- return nil , fmt .Errorf ("IpcGetOperation: invalid key in line %q" , line )
1057
- }
1058
- if ! p .NodeKey .IsZero () {
1059
- pp [p .NodeKey ] = p
1060
- }
1061
- p = ipnstate.PeerStatusLite {NodeKey : pk }
1062
- case "rx_bytes" :
1063
- n , err = mem .ParseInt (v , 10 , 64 )
1064
- p .RxBytes = n
1065
- if err != nil {
1066
- return nil , fmt .Errorf ("IpcGetOperation: rx_bytes invalid: %#v" , line )
1067
- }
1068
- case "tx_bytes" :
1069
- n , err = mem .ParseInt (v , 10 , 64 )
1070
- p .TxBytes = n
1071
- if err != nil {
1072
- return nil , fmt .Errorf ("IpcGetOperation: tx_bytes invalid: %#v" , line )
1073
- }
1074
- case "last_handshake_time_sec" :
1075
- hst1 , err = mem .ParseInt (v , 10 , 64 )
1076
- if err != nil {
1077
- return nil , fmt .Errorf ("IpcGetOperation: hst1 invalid: %#v" , line )
1078
- }
1079
- case "last_handshake_time_nsec" :
1080
- hst2 , err = mem .ParseInt (v , 10 , 64 )
1081
- if err != nil {
1082
- return nil , fmt .Errorf ("IpcGetOperation: hst2 invalid: %#v" , line )
1083
- }
1084
- if hst1 != 0 || hst2 != 0 {
1085
- p .LastHandshake = time .Unix (hst1 , hst2 )
1086
- } // else leave at time.IsZero()
1087
- }
1088
- }
1089
- if ! p .NodeKey .IsZero () {
1090
- pp [p .NodeKey ] = p
1091
- }
1092
- if err := <- errc ; err != nil {
1093
- return nil , fmt .Errorf ("IpcGetOperation: %v" , err )
1094
- }
1095
-
1096
1004
e .mu .Lock ()
1097
- defer e .mu .Unlock ()
1005
+ closing := e .closing
1006
+ peerKeys := make ([]key.NodePublic , len (e .peerSequence ))
1007
+ copy (peerKeys , e .peerSequence )
1008
+ e .mu .Unlock ()
1098
1009
1099
- // Do two passes, one to calculate size and the other to populate.
1100
- // This code is sensitive to allocations.
1101
- npeers := 0
1102
- for _ , pk := range e .peerSequence {
1103
- if _ , ok := pp [pk ]; ok { // ignore idle ones not in wireguard-go's config
1104
- npeers ++
1105
- }
1010
+ if closing {
1011
+ return nil , ErrEngineClosing
1106
1012
}
1107
1013
1108
- peers := make ([]ipnstate.PeerStatusLite , 0 , npeers )
1109
- for _ , pk := range e .peerSequence {
1110
- if p , ok := pp [pk ]; ok { // ignore idle ones not in wireguard-go's config
1111
- peers = append (peers , p )
1014
+ peers := make ([]ipnstate.PeerStatusLite , 0 , len (peerKeys ))
1015
+ for _ , key := range peerKeys {
1016
+ // LookupPeer is internally locked in wgdev.
1017
+ peer := wgdev .LookupPeer (key .Raw32 ())
1018
+ if peer == nil {
1019
+ continue
1112
1020
}
1021
+
1022
+ var p ipnstate.PeerStatusLite
1023
+ p .NodeKey = key
1024
+ p .RxBytes = int64 (wgint .PeerRxBytes (peer ))
1025
+ p .TxBytes = int64 (wgint .PeerTxBytes (peer ))
1026
+ p .LastHandshake = time .Unix (0 , wgint .PeerLastHandshakeNano (peer ))
1027
+ peers = append (peers , p )
1113
1028
}
1114
1029
1115
1030
return & Status {
0 commit comments