@@ -10,6 +10,7 @@ import (
10
10
"sort"
11
11
"strings"
12
12
"sync"
13
+ "sync/atomic"
13
14
"time"
14
15
15
16
"github.com/dsnet/golib/unitconv"
@@ -20,7 +21,7 @@ type packetLogger struct {
20
21
last time.Time // Last time we printed statistics
21
22
c chan packetLog
22
23
m map [packetLog ]packetCount
23
- rx , tx struct { okay , drop packetCount }
24
+ rx , tx struct { okay , drop packetCount } // Atomically updated
24
25
}
25
26
26
27
type packetLog struct {
@@ -74,19 +75,53 @@ func (pl *packetLogger) Log(b []byte, d direction, dropped bool) {
74
75
pl .c <- p
75
76
}
76
77
78
+ // Stats returns statistics on the total number and sizes of packets
79
+ // transmitted or received.
80
+ func (pl * packetLogger ) Stats () (s struct {
81
+ Rx , Tx struct { Okay , Drop struct { Count , Sizes uint64 } }
82
+ }) {
83
+ s .Tx .Okay .Count = atomic .LoadUint64 (& pl .tx .okay .count )
84
+ s .Tx .Okay .Sizes = atomic .LoadUint64 (& pl .tx .okay .sizes )
85
+ s .Rx .Okay .Count = atomic .LoadUint64 (& pl .rx .okay .count )
86
+ s .Rx .Okay .Sizes = atomic .LoadUint64 (& pl .rx .okay .sizes )
87
+ s .Tx .Drop .Count = atomic .LoadUint64 (& pl .tx .drop .count )
88
+ s .Tx .Drop .Sizes = atomic .LoadUint64 (& pl .tx .drop .sizes )
89
+ s .Rx .Drop .Count = atomic .LoadUint64 (& pl .rx .drop .count )
90
+ s .Rx .Drop .Sizes = atomic .LoadUint64 (& pl .rx .drop .sizes )
91
+ return
92
+ }
93
+
77
94
func (pl * packetLogger ) monitor (ctx context.Context ) {
78
95
t := time .NewTicker (30 * time .Second )
79
96
defer t .Stop ()
80
97
81
98
for {
82
99
select {
83
100
case p := <- pl .c :
84
- size := p .length
101
+ size := uint64 (p .length )
102
+
103
+ // Update fine-granularity statistics.
85
104
p .length = 0
86
105
pc := pl .m [p ]
87
106
pc .count ++
88
- pc .sizes += uint64 ( size )
107
+ pc .sizes += size
89
108
pl .m [p ] = pc
109
+
110
+ // Update total packet statistics.
111
+ switch {
112
+ case ! p .dropped && p .direction == outbound :
113
+ atomic .AddUint64 (& pl .tx .okay .count , 1 )
114
+ atomic .AddUint64 (& pl .tx .okay .sizes , size )
115
+ case ! p .dropped && p .direction == inbound :
116
+ atomic .AddUint64 (& pl .rx .okay .count , 1 )
117
+ atomic .AddUint64 (& pl .rx .okay .sizes , size )
118
+ case p .dropped && p .direction == outbound :
119
+ atomic .AddUint64 (& pl .tx .drop .count , 1 )
120
+ atomic .AddUint64 (& pl .tx .drop .sizes , size )
121
+ case p .dropped && p .direction == inbound :
122
+ atomic .AddUint64 (& pl .rx .drop .count , 1 )
123
+ atomic .AddUint64 (& pl .rx .drop .sizes , size )
124
+ }
90
125
case <- t .C :
91
126
var count , sizes uint64
92
127
for _ , v := range pl .m {
@@ -113,19 +148,6 @@ func (pl *packetLogger) print() {
113
148
stats := make ([]string , 2 ) // First 2 lines for total stats
114
149
protoNames := map [int ]string {icmp : "ICMP" , udp : "UDP" , tcp : "TCP" }
115
150
for k , v := range pl .m {
116
- var pc * packetCount
117
- switch {
118
- case ! k .dropped && k .direction == outbound :
119
- pc = & pl .tx .okay
120
- case ! k .dropped && k .direction == inbound :
121
- pc = & pl .rx .okay
122
- case k .dropped && k .direction == outbound :
123
- pc = & pl .tx .drop
124
- case k .dropped && k .direction == inbound :
125
- pc = & pl .rx .drop
126
- }
127
- pc .count += v .count
128
- pc .sizes += v .sizes
129
151
130
152
proto := protoNames [k .ipProtocol ]
131
153
if proto == "" {
@@ -142,10 +164,12 @@ func (pl *packetLogger) print() {
142
164
stats = append (stats , fmt .Sprintf ("\t IPv%d/%s %s - %cx %d %spackets (%sB)" ,
143
165
k .ipVersion , proto , link , k .direction , v .count , drop , formatIEC (v .sizes )))
144
166
}
167
+
168
+ s := pl .Stats ()
145
169
stats [0 ] = fmt .Sprintf ("\t Rx %d total packets (%sB), dropped %d total packets (%sB)" ,
146
- pl . rx . okay . count , formatIEC (pl . rx . okay . sizes ), pl . rx . drop . count , formatIEC (pl . rx . drop . sizes ))
170
+ s . Rx . Okay . Count , formatIEC (s . Rx . Okay . Sizes ), s . Rx . Drop . Count , formatIEC (s . Rx . Drop . Sizes ))
147
171
stats [1 ] = fmt .Sprintf ("\t Tx %d total packets (%sB), dropped %d total packets (%sB)" ,
148
- pl . tx . okay . count , formatIEC (pl . tx . okay . sizes ), pl . tx . drop . count , formatIEC (pl . tx . drop . sizes ))
172
+ s . Tx . Okay . Count , formatIEC (s . Tx . Okay . Sizes ), s . Tx . Drop . Count , formatIEC (s . Tx . Drop . Sizes ))
149
173
sort .Strings (stats [2 :])
150
174
period := time .Now ().Round (time .Second ).Sub (pl .last )
151
175
pl .logger .Printf ("Packet statistics (%v):\n %s" , period , strings .Join (stats , "\n " ))
0 commit comments