Netstack exposes useful debugging information as inspectable data that can be retrieved from snapshots (inspect.json
within snapshots created by fx snapshot
) or by using the iquery
tool (fx iquery
).
In this document we list useful example queries into the inspect data that netstack exposes.
We'll use the jq
tool throughout, all queries can be used from an inspect.json
or fx iquery --format json
by piping either into jq
, e.g.:
cat snapshot/inspect.json | fx jq '...'
fx iquery --format json show core/network/netstack | fx jq '...'
There are different sources of inspect data in Netstack, referenced by their payload keys.
Socket Info
contains information of all currently open sockets, keyed by socket identifier, e.g.:
{ "12345": { "NetworkProtocol": "IPv6", "TransportProtocol": "UDP", "State": "BOUND", "LocalAddress": "[fe80::8d88:9942:4f32:7259]:546", "RemoteAddress": ":0", "BindAddress": "", "BindNICID": "5", "RegisterNICID": "5", "Stats": { ... }, "Socket Option Stats": { "AddIpMembership": 0, ... }, } }
The Socket Option Stats
section is keyed on each socket option operation (either set or get, but note that some socket options only have one but not the other), with the value indicating how many times the operation has been performed. Note that there are socket options that only apply to certain kinds of sockets, so the list of socket option operations differs between the different socket types. The maximum across all sockets is also exposed, see the Networking Stat Counters section.
To retrieve all sockets from inspect data use:
fx jq '.[] | select(.moniker == "core/network/netstack") | .payload."Socket Info" | .[]?'
NICs
contains information about each of the network interfaces presently installed in the netstack, keyed by their interface identifier, e.g:
{ "2": { "Name": "wlanx62", "NICID": "3", "AdminUp": "true", "LinkOnline": "true", "Up": "true", "Running": "true", "Loopback": "false", "Promiscuous": "false", "LinkAddress": "44:07:0b:e2:cf:62", "ProtocolAddress0": "[arp] 617270/0", "ProtocolAddress1": "[ipv4] 192.168.0.23/24", "ProtocolAddress2": "[ipv6] fe80::916b:7615:6b2e:f8b3/64", "ProtocolAddress3": "[ipv6] fe80::4607:bff:fee2:cf62/128", "DHCP enabled": "true", "MTU": 1500, "Ethernet Info": { ... }, "DHCP Info": { ... }, "Stats": { ... } } }
To retrieve all NICs from inspect data use:
fx jq '.[] | select(.moniker == "core/network/netstack") | .payload."NICs" | .[]?'
To look at a single NIC with id
or name
simply append | select(.NICID == "id")
or | select(.Name == "name")
, respectively.
Networking Stat Counters
contain stack-global counters for traffic and errors, e.g.:
{ "DroppedPackets": 0, "SocketCount": 12, "SocketsCreated": 1016568, "SocketsDestroyed": 1016559, "ARP": { ... }, "DHCPv6": { ... }, "ICMP": { ... }, "IGMP": { ... }, "IP": { ... }, "IPv6AddressConfig": { ... }, "MaxSocketOptionStats": { ... }, "NICs": { ... }, "TCP": { "ActiveConnectionOpenings": 4443, "PassiveConnectionOpenings": 53, ... }, "UDP": { "PacketsReceived": 51551, "UnknownPortErrors": 30509, ... }, }
MaxSocketOptionStats
is a map from each socket option operation to the maximum number of times the operation has been called on a single socket in the current boot. The max could come from a socket that's been closed, or is currently open at the time inspect was queried.
To get counters use:
fx jq '.[] | select(.moniker == "core/network/netstack") | .payload."Networking Stat Counters" | select(. != null)'
You can append | .TCP
, or | .UDP
to look at only the subset of interest if needed.
Routes
contains information about all the routes in the routing table, e.g.:
{ "0": { "Destination": "127.0.0.0/8", "Dynamic": "false", "Enabled": "true", "Gateway": "", "Metric": "100", "MetricTracksInterface": "true", "NIC": "1" }, }
To retrieve all routes from inspect data use:
fx jq '.[] | select(.moniker == "core/network/netstack") | .payload."Routes" | .[]?'
Netstack exposes pprof
data that can be used to gather more information from the Go runtime.
A typical snapshot will contain periodic pprof
data which is gathered at set intervals. You can query the available pprof
information with:
fx jq -c '.[] | select(.moniker == "core/network/netstack") | select(.payload.root.pprof != null) | {file: .metadata.filename, keys: (.payload.root.pprof | keys)}'
Which will generate output like
{"file":"pprof/2020-10-22T16:21:49Z.inspect","keys":["allocs","block","goroutine","heap","mutex","threadcreate"]} {"file":"pprof/now.inspect","keys":["allocs","block","goroutine","heap","mutex","threadcreate"]} {"file":"pprof/2020-10-22T16:19:49Z.inspect","keys":["allocs","block","goroutine","heap","mutex","threadcreate"]} {"file":"pprof/2020-10-22T16:20:49Z.inspect","keys":["allocs","block","goroutine","heap","mutex","threadcreate"]}
Each of the pprof
profiles is encoded in base64. The following line gets all the pprof
files and decodes them at once (remember to either pipe in your inspect
data or add path to your inspect file after the jq
command):
fx jq -rc '.[] | select(.moniker == "core/network/netstack") | select(.payload.root.pprof != null) | . as $parent | (.payload.root.pprof | to_entries | .[] | ($parent | .metadata.filename) + "_" + .key + " " + .value)' | \ while read f c; do echo $c | sed s/b64://g | base64 -d > $(echo $f | sed 's/pprof\///g'); done
You can modify the selector .payload.root.pprof != null
and append and .metadata.filename == "pprof/now.inspect"
to only get the latest profile.