Browse Source

derp: add some guardrails for derpReason metrics getting out of sync

The derp metrics got out of sync in 74eb99aed17539 (2023-03).

They were fixed in 0380cbc90d6 (2024-05).

This adds some further guardrails (atop the previous fix) to make sure
they don't get out of sync again.

Updates #12288

Change-Id: I809061a81f8ff92f45054d0253bc13871fc71634
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 1 year ago
parent
commit
f227083539
2 changed files with 27 additions and 11 deletions
  1. 24 9
      derp/derp_server.go
  2. 3 2
      derp/dropreason_string.go

+ 24 - 9
derp/derp_server.go

@@ -330,21 +330,35 @@ func NewServer(privateKey key.NodePrivate, logf logger.Logf) *Server {
 	s.packetsRecvDisco = s.packetsRecvByKind.Get("disco")
 	s.packetsRecvOther = s.packetsRecvByKind.Get("other")
 
-	s.packetsDroppedReasonCounters = []*expvar.Int{
-		dropReasonUnknownDest:      s.packetsDroppedReason.Get("unknown_dest"),
-		dropReasonUnknownDestOnFwd: s.packetsDroppedReason.Get("unknown_dest_on_fwd"),
-		dropReasonGoneDisconnected: s.packetsDroppedReason.Get("gone_disconnected"),
-		dropReasonQueueHead:        s.packetsDroppedReason.Get("queue_head"),
-		dropReasonQueueTail:        s.packetsDroppedReason.Get("queue_tail"),
-		dropReasonWriteError:       s.packetsDroppedReason.Get("write_error"),
-		dropReasonDupClient:        s.packetsDroppedReason.Get("dup_client"),
-	}
+	s.packetsDroppedReasonCounters = s.genPacketsDroppedReasonCounters()
 
 	s.packetsDroppedTypeDisco = s.packetsDroppedType.Get("disco")
 	s.packetsDroppedTypeOther = s.packetsDroppedType.Get("other")
 	return s
 }
 
+func (s *Server) genPacketsDroppedReasonCounters() []*expvar.Int {
+	getMetric := s.packetsDroppedReason.Get
+	ret := []*expvar.Int{
+		dropReasonUnknownDest:      getMetric("unknown_dest"),
+		dropReasonUnknownDestOnFwd: getMetric("unknown_dest_on_fwd"),
+		dropReasonGoneDisconnected: getMetric("gone_disconnected"),
+		dropReasonQueueHead:        getMetric("queue_head"),
+		dropReasonQueueTail:        getMetric("queue_tail"),
+		dropReasonWriteError:       getMetric("write_error"),
+		dropReasonDupClient:        getMetric("dup_client"),
+	}
+	if len(ret) != int(numDropReasons) {
+		panic("dropReason metrics out of sync")
+	}
+	for i := range numDropReasons {
+		if ret[i] == nil {
+			panic("dropReason metrics out of sync")
+		}
+	}
+	return ret
+}
+
 // SetMesh sets the pre-shared key that regional DERP servers used to mesh
 // amongst themselves.
 //
@@ -1049,6 +1063,7 @@ const (
 	dropReasonQueueTail                          // destination queue is full, dropped packet at queue tail
 	dropReasonWriteError                         // OS write() failed
 	dropReasonDupClient                          // the public key is connected 2+ times (active/active, fighting)
+	numDropReasons                               // unused; keep last
 )
 
 func (s *Server) recordDrop(packetBytes []byte, srcKey, dstKey key.NodePublic, reason dropReason) {

+ 3 - 2
derp/dropreason_string.go

@@ -18,11 +18,12 @@ func _() {
 	_ = x[dropReasonQueueTail-4]
 	_ = x[dropReasonWriteError-5]
 	_ = x[dropReasonDupClient-6]
+	_ = x[numDropReasons-7]
 }
 
-const _dropReason_name = "UnknownDestUnknownDestOnFwdGoneDisconnectedQueueHeadQueueTailWriteErrorDupClient"
+const _dropReason_name = "UnknownDestUnknownDestOnFwdGoneDisconnectedQueueHeadQueueTailWriteErrorDupClientnumDropReasons"
 
-var _dropReason_index = [...]uint8{0, 11, 27, 43, 52, 61, 71, 80}
+var _dropReason_index = [...]uint8{0, 11, 27, 43, 52, 61, 71, 80, 94}
 
 func (i dropReason) String() string {
 	if i < 0 || i >= dropReason(len(_dropReason_index)-1) {