SNMP counter¶
This document explains the meaning of SNMP counters.
General IPv4 counters¶
All layer 4 packets and ICMP packets will change these counters, butthese counters won’t be changed by layer 2 packets (such as STP) orARP packets.
- IpInReceives
Defined inRFC1213 ipInReceives
The number of packets received by the IP layer. It gets increasing at thebeginning of ip_rcv function, always be updated together withIpExtInOctets. It will be increased even if the packet is droppedlater (e.g. due to the IP header is invalid or the checksum is wrongand so on). It indicates the number of aggregated segments afterGRO/LRO.
- IpInDelivers
Defined inRFC1213 ipInDelivers
The number of packets delivers to the upper layer protocols. E.g. TCP, UDP,ICMP and so on. If no one listens on a raw socket, only kernelsupported protocols will be delivered, if someone listens on the rawsocket, all valid IP packets will be delivered.
- IpOutRequests
Defined inRFC1213 ipOutRequests
The number of packets sent via IP layer, for both single cast andmulticast packets, and would always be updated together withIpExtOutOctets.
- IpExtInOctets and IpExtOutOctets
They are Linux kernel extensions, no RFC definitions. Please note,RFC1213 indeed defines ifInOctets and ifOutOctets, but theyare different things. The ifInOctets and ifOutOctets include the MAClayer header size but IpExtInOctets and IpExtOutOctets don’t, theyonly include the IP layer header and the IP layer data.
- IpExtInNoECTPkts, IpExtInECT1Pkts, IpExtInECT0Pkts, IpExtInCEPkts
They indicate the number of four kinds of ECN IP packets, please referExplicit Congestion Notification for more details.
These 4 counters calculate how many packets received per ECNstatus. They count the real frame number regardless the LRO/GRO. Sofor the same packet, you might find that IpInReceives count 1, butIpExtInNoECTPkts counts 2 or more.
- IpInHdrErrors
Defined inRFC1213 ipInHdrErrors. It indicates the packet isdropped due to the IP header error. It might happen in both IP inputand IP forward paths.
- IpInAddrErrors
Defined inRFC1213 ipInAddrErrors. It will be increased in twoscenarios: (1) The IP address is invalid. (2) The destination IPaddress is not a local address and IP forwarding is not enabled
- IpExtInNoRoutes
This counter means the packet is dropped when the IP stack receives apacket and can’t find a route for it from the route table. It mighthappen when IP forwarding is enabled and the destination IP address isnot a local address and there is no route for the destination IPaddress.
- IpInUnknownProtos
Defined inRFC1213 ipInUnknownProtos. It will be increased if thelayer 4 protocol is unsupported by kernel. If an application is usingraw socket, kernel will always deliver the packet to the raw socketand this counter won’t be increased.
- IpExtInTruncatedPkts
For IPv4 packet, it means the actual data size is smaller than the“Total Length” field in the IPv4 header.
- IpInDiscards
Defined inRFC1213 ipInDiscards. It indicates the packet is droppedin the IP receiving path and due to kernel internal reasons (e.g. noenough memory).
- IpOutDiscards
Defined inRFC1213 ipOutDiscards. It indicates the packet isdropped in the IP sending path and due to kernel internal reasons.
- IpOutNoRoutes
Defined inRFC1213 ipOutNoRoutes. It indicates the packet isdropped in the IP sending path and no route is found for it.
ICMP counters¶
- IcmpInMsgs and IcmpOutMsgs
Defined byRFC1213 icmpInMsgs andRFC1213 icmpOutMsgs
As mentioned in the RFC1213, these two counters include errors, theywould be increased even if the ICMP packet has an invalid type. TheICMP output path will check the header of a raw socket, so theIcmpOutMsgs would still be updated if the IP header is constructed bya userspace program.
- ICMP named types
Every ICMP type has two counters: ‘In’ and ‘Out’. E.g., for the ICMPEcho packet, they are IcmpInEchos and IcmpOutEchos. Their meanings arestraightforward. The ‘In’ counter means kernel receives such a packetand the ‘Out’ counter means kernel sends such a packet.
- ICMP numeric types
They are IcmpMsgInType[N] and IcmpMsgOutType[N], the [N] indicates theICMP type number. These counters track all kinds of ICMP packets. TheICMP type number definition could be found in theICMP parametersdocument.
For example, if the Linux kernel sends an ICMP Echo packet, theIcmpMsgOutType8 would increase 1. And if kernel gets an ICMP Echo Replypacket, IcmpMsgInType0 would increase 1.
- IcmpInCsumErrors
This counter indicates the checksum of the ICMP packet iswrong. Kernel verifies the checksum after updating the IcmpInMsgs andbefore updating IcmpMsgInType[N]. If a packet has bad checksum, theIcmpInMsgs would be updated but none of IcmpMsgInType[N] would be updated.
- IcmpInErrors and IcmpOutErrors
Defined byRFC1213 icmpInErrors andRFC1213 icmpOutErrors
When an error occurs in the ICMP packet handler path, these twocounters would be updated. The receiving packet path use IcmpInErrorsand the sending packet path use IcmpOutErrors. When IcmpInCsumErrorsis increased, IcmpInErrors would always be increased too.
relationship of the ICMP counters¶
The sum of IcmpMsgOutType[N] is always equal to IcmpOutMsgs, as theyare updated at the same time. The sum of IcmpMsgInType[N] plusIcmpInErrors should be equal or larger than IcmpInMsgs. When kernelreceives an ICMP packet, kernel follows below logic:
- increase IcmpInMsgs
- if has any error, update IcmpInErrors and finish the process
- update IcmpMsgOutType[N]
- handle the packet depending on the type, if has any error, updateIcmpInErrors and finish the process
So if all errors occur in step (2), IcmpInMsgs should be equal to thesum of IcmpMsgOutType[N] plus IcmpInErrors. If all errors occur instep (4), IcmpInMsgs should be equal to the sum ofIcmpMsgOutType[N]. If the errors occur in both step (2) and step (4),IcmpInMsgs should be less than the sum of IcmpMsgOutType[N] plusIcmpInErrors.
General TCP counters¶
- TcpInSegs
Defined inRFC1213 tcpInSegs
The number of packets received by the TCP layer. As mentioned inRFC1213, it includes the packets received in error, such as checksumerror, invalid TCP header and so on. Only one error won’t be included:if the layer 2 destination address is not the NIC’s layer 2address. It might happen if the packet is a multicast or broadcastpacket, or the NIC is in promiscuous mode. In these situations, thepackets would be delivered to the TCP layer, but the TCP layer will discardthese packets before increasing TcpInSegs. The TcpInSegs counterisn’t aware of GRO. So if two packets are merged by GRO, the TcpInSegscounter would only increase 1.
- TcpOutSegs
Defined inRFC1213 tcpOutSegs
The number of packets sent by the TCP layer. As mentioned in RFC1213,it excludes the retransmitted packets. But it includes the SYN, ACKand RST packets. Doesn’t like TcpInSegs, the TcpOutSegs is aware ofGSO, so if a packet would be split to 2 by GSO, TcpOutSegs willincrease 2.
- TcpActiveOpens
Defined inRFC1213 tcpActiveOpens
It means the TCP layer sends a SYN, and come into the SYN-SENTstate. Every time TcpActiveOpens increases 1, TcpOutSegs should alwaysincrease 1.
- TcpPassiveOpens
Defined inRFC1213 tcpPassiveOpens
It means the TCP layer receives a SYN, replies a SYN+ACK, come intothe SYN-RCVD state.
- TcpExtTCPRcvCoalesce
When packets are received by the TCP layer and are not be read by theapplication, the TCP layer will try to merge them. This counterindicate how many packets are merged in such situation. If GRO isenabled, lots of packets would be merged by GRO, these packetswouldn’t be counted to TcpExtTCPRcvCoalesce.
- TcpExtTCPAutoCorking
When sending packets, the TCP layer will try to merge small packets toa bigger one. This counter increase 1 for every packet merged in suchsituation. Please refer to the LWN article for more details:https://lwn.net/Articles/576263/
- TcpExtTCPOrigDataSent
This counter is explained bykernel commit f19c29e3e391, I pasted theexplaination below:
TCPOrigDataSent: number of outgoing packets with original data (excludingretransmission but including data-in-SYN). This counter is different fromTcpOutSegs because TcpOutSegs also tracks pure ACKs. TCPOrigDataSent ismore useful to track the TCP retransmission rate.
- TCPSynRetrans
This counter is explained bykernel commit f19c29e3e391, I pasted theexplaination below:
TCPSynRetrans: number of SYN and SYN/ACK retransmits to break downretransmissions into SYN, fast-retransmits, timeout retransmits, etc.
- TCPFastOpenActiveFail
This counter is explained bykernel commit f19c29e3e391, I pasted theexplaination below:
TCPFastOpenActiveFail: Fast Open attempts (SYN/data) failed becausethe remote does not accept it or the attempts timed out.
- TcpExtListenOverflows and TcpExtListenDrops
When kernel receives a SYN from a client, and if the TCP accept queueis full, kernel will drop the SYN and add 1 to TcpExtListenOverflows.At the same time kernel will also add 1 to TcpExtListenDrops. When aTCP socket is in LISTEN state, and kernel need to drop a packet,kernel would always add 1 to TcpExtListenDrops. So increaseTcpExtListenOverflows would let TcpExtListenDrops increasing at thesame time, but TcpExtListenDrops would also increase withoutTcpExtListenOverflows increasing, e.g. a memory allocation fail wouldalso let TcpExtListenDrops increase.
Note: The above explanation is based on kernel 4.10 or above version, onan old kernel, the TCP stack has different behavior when TCP acceptqueue is full. On the old kernel, TCP stack won’t drop the SYN, itwould complete the 3-way handshake. As the accept queue is full, TCPstack will keep the socket in the TCP half-open queue. As it is in thehalf open queue, TCP stack will send SYN+ACK on an exponential backofftimer, after client replies ACK, TCP stack checks whether the acceptqueue is still full, if it is not full, moves the socket to the acceptqueue, if it is full, keeps the socket in the half-open queue, at nexttime client replies ACK, this socket will get another chance to moveto the accept queue.
TCP Fast Open¶
- TcpEstabResets
Defined inRFC1213 tcpEstabResets.
- TcpAttemptFails
Defined inRFC1213 tcpAttemptFails.
- TcpOutRsts
Defined inRFC1213 tcpOutRsts. The RFC says this counter indicatesthe ‘segments sent containing the RST flag’, but in linux kernel, thiscouner indicates the segments kerenl tried to send. The sendingprocess might be failed due to some errors (e.g. memory alloc failed).
- TcpExtTCPSpuriousRtxHostQueues
When the TCP stack wants to retransmit a packet, and finds that packetis not lost in the network, but the packet is not sent yet, the TCPstack would give up the retransmission and update this counter. Itmight happen if a packet stays too long time in a qdisc or driverqueue.
- TcpEstabResets
The socket receives a RST packet in Establish or CloseWait state.
- TcpExtTCPKeepAlive
This counter indicates many keepalive packets were sent. The keepalivewon’t be enabled by default. A userspace program could enable it bysetting the SO_KEEPALIVE socket option.
- TcpExtTCPSpuriousRTOs
The spurious retransmission timeout detected by theF-RTOalgorithm.
TCP Fast Path¶
When kernel receives a TCP packet, it has two paths to handler thepacket, one is fast path, another is slow path. The comment in kernelcode provides a good explanation of them, I pasted them below:
It is split into a fast path and a slow path. The fast path isdisabled when:- A zero window was announced from us- zero window probing is only handled properly on the slow path.- Out of order segments arrived.- Urgent data is expected.- There is no buffer space left- Unexpected TCP flags/window values/header lengths are received (detected by checking the TCP header against pred_flags)- Data is sent in both directions. The fast path only supports pure senders or pure receivers (this means either the sequence number or the ack value must stay constant)- Unexpected TCP option.
Kernel will try to use fast path unless any of the above conditionsare satisfied. If the packets are out of order, kernel will handlethem in slow path, which means the performance might be not verygood. Kernel would also come into slow path if the “Delayed ack” isused, because when using “Delayed ack”, the data is sent in bothdirections. When the TCP window scale option is not used, kernel willtry to enable fast path immediately when the connection comes into theestablished state, but if the TCP window scale option is used, kernelwill disable the fast path at first, and try to enable it after kernelreceives packets.
- TcpExtTCPPureAcks and TcpExtTCPHPAcks
If a packet set ACK flag and has no data, it is a pure ACK packet, ifkernel handles it in the fast path, TcpExtTCPHPAcks will increase 1,if kernel handles it in the slow path, TcpExtTCPPureAcks willincrease 1.
- TcpExtTCPHPHits
If a TCP packet has data (which means it is not a pure ACK packet),and this packet is handled in the fast path, TcpExtTCPHPHits willincrease 1.
TCP abort¶
- TcpExtTCPAbortOnData
It means TCP layer has data in flight, but need to close theconnection. So TCP layer sends a RST to the other side, indicate theconnection is not closed very graceful. An easy way to increase thiscounter is using the SO_LINGER option. Please refer to the SO_LINGERsection of thesocket man page:
By default, when an application closes a connection, the close functionwill return immediately and kernel will try to send the in-flight dataasync. If you use the SO_LINGER option, set l_onoff to 1, and l_lingerto a positive number, the close function won’t return immediately, butwait for the in-flight data are acked by the other side, the max waittime is l_linger seconds. If set l_onoff to 1 and set l_linger to 0,when the application closes a connection, kernel will send a RSTimmediately and increase the TcpExtTCPAbortOnData counter.
- TcpExtTCPAbortOnClose
This counter means the application has unread data in the TCP layer whenthe application wants to close the TCP connection. In such a situation,kernel will send a RST to the other side of the TCP connection.
- TcpExtTCPAbortOnMemory
When an application closes a TCP connection, kernel still need to trackthe connection, let it complete the TCP disconnect process. E.g. anapp calls the close method of a socket, kernel sends fin to the otherside of the connection, then the app has no relationship with thesocket any more, but kernel need to keep the socket, this socketbecomes an orphan socket, kernel waits for the reply of the other side,and would come to the TIME_WAIT state finally. When kernel has noenough memory to keep the orphan socket, kernel would send an RST tothe other side, and delete the socket, in such situation, kernel willincrease 1 to the TcpExtTCPAbortOnMemory. Two conditions would triggerTcpExtTCPAbortOnMemory:
1. the memory used by the TCP protocol is higher than the third value ofthe tcp_mem. Please refer the tcp_mem section in theTCP man page:
- the orphan socket count is higher than net.ipv4.tcp_max_orphans
- TcpExtTCPAbortOnTimeout
This counter will increase when any of the TCP timers expire. In suchsituation, kernel won’t send RST, just give up the connection.
- TcpExtTCPAbortOnLinger
When a TCP connection comes into FIN_WAIT_2 state, instead of waitingfor the fin packet from the other side, kernel could send a RST anddelete the socket immediately. This is not the default behavior ofLinux kernel TCP stack. By configuring the TCP_LINGER2 socket option,you could let kernel follow this behavior.
- TcpExtTCPAbortFailed
The kernel TCP layer will send RST if theRFC2525 2.17 section issatisfied. If an internal error occurs during this process,TcpExtTCPAbortFailed will be increased.
TCP Hybrid Slow Start¶
The Hybrid Slow Start algorithm is an enhancement of the traditionalTCP congestion window Slow Start algorithm. It uses two pieces ofinformation to detect whether the max bandwidth of the TCP path isapproached. The two pieces of information are ACK train length andincrease in packet delay. For detail information, please refer theHybrid Slow Start paper. Either ACK train length or packet delayhits a specific threshold, the congestion control algorithm will comeinto the Congestion Avoidance state. Until v4.20, two congestioncontrol algorithms are using Hybrid Slow Start, they are cubic (thedefault congestion control algorithm) and cdg. Four snmp countersrelate with the Hybrid Slow Start algorithm.
- TcpExtTCPHystartTrainDetect
How many times the ACK train length threshold is detected
- TcpExtTCPHystartTrainCwnd
The sum of CWND detected by ACK train length. Dividing this value byTcpExtTCPHystartTrainDetect is the average CWND which detected by theACK train length.
- TcpExtTCPHystartDelayDetect
How many times the packet delay threshold is detected.
- TcpExtTCPHystartDelayCwnd
The sum of CWND detected by packet delay. Dividing this value byTcpExtTCPHystartDelayDetect is the average CWND which detected by thepacket delay.
TCP retransmission and congestion control¶
The TCP protocol has two retransmission mechanisms: SACK and fastrecovery. They are exclusive with each other. When SACK is enabled,the kernel TCP stack would use SACK, or kernel would use fastrecovery. The SACK is a TCP option, which is defined inRFC2018,the fast recovery is defined inRFC6582, which is also called‘Reno’.
The TCP congestion control is a big and complex topic. To understandthe related snmp counter, we need to know the states of the congestioncontrol state machine. There are 5 states: Open, Disorder, CWR,Recovery and Loss. For details about these states, please refer page 5and page 6 of this document:https://pdfs.semanticscholar.org/0e9c/968d09ab2e53e24c4dca5b2d67c7f7140f8e.pdf
- TcpExtTCPRenoRecovery and TcpExtTCPSackRecovery
When the congestion control comes into Recovery state, if sack isused, TcpExtTCPSackRecovery increases 1, if sack is not used,TcpExtTCPRenoRecovery increases 1. These two counters mean the TCPstack begins to retransmit the lost packets.
- TcpExtTCPSACKReneging
A packet was acknowledged by SACK, but the receiver has dropped thispacket, so the sender needs to retransmit this packet. In thissituation, the sender adds 1 to TcpExtTCPSACKReneging. A receivercould drop a packet which has been acknowledged by SACK, although it isunusual, it is allowed by the TCP protocol. The sender doesn’t reallyknow what happened on the receiver side. The sender just waits untilthe RTO expires for this packet, then the sender assumes this packethas been dropped by the receiver.
- TcpExtTCPRenoReorder
The reorder packet is detected by fast recovery. It would only be usedif SACK is disabled. The fast recovery algorithm detects recorder bythe duplicate ACK number. E.g., if retransmission is triggered, andthe original retransmitted packet is not lost, it is just out oforder, the receiver would acknowledge multiple times, one for theretransmitted packet, another for the arriving of the original out oforder packet. Thus the sender would find more ACks than itsexpectation, and the sender knows out of order occurs.
- TcpExtTCPTSReorder
The reorder packet is detected when a hole is filled. E.g., assume thesender sends packet 1,2,3,4,5, and the receiving order is1,2,4,5,3. When the sender receives the ACK of packet 3 (which willfill the hole), two conditions will let TcpExtTCPTSReorder increase1: (1) if the packet 3 is not re-retransmitted yet. (2) if the packet3 is retransmitted but the timestamp of the packet 3’s ACK is earlierthan the retransmission timestamp.
- TcpExtTCPSACKReorder
The reorder packet detected by SACK. The SACK has two methods todetect reorder: (1) DSACK is received by the sender. It means thesender sends the same packet more than one times. And the only reasonis the sender believes an out of order packet is lost so it sends thepacket again. (2) Assume packet 1,2,3,4,5 are sent by the sender, andthe sender has received SACKs for packet 2 and 5, now the senderreceives SACK for packet 4 and the sender doesn’t retransmit thepacket yet, the sender would know packet 4 is out of order. The TCPstack of kernel will increase TcpExtTCPSACKReorder for both of theabove scenarios.
- TcpExtTCPSlowStartRetrans
The TCP stack wants to retransmit a packet and the congestion controlstate is ‘Loss’.
- TcpExtTCPFastRetrans
The TCP stack wants to retransmit a packet and the congestion controlstate is not ‘Loss’.
- TcpExtTCPLostRetransmit
A SACK points out that a retransmission packet is lost again.
- TcpExtTCPRetransFail
The TCP stack tries to deliver a retransmission packet to lower layersbut the lower layers return an error.
- TcpExtTCPSynRetrans
The TCP stack retransmits a SYN packet.
DSACK¶
The DSACK is defined inRFC2883. The receiver uses DSACK to reportduplicate packets to the sender. There are two kinds ofduplications: (1) a packet which has been acknowledged isduplicate. (2) an out of order packet is duplicate. The TCP stackcounts these two kinds of duplications on both receiver side andsender side.
- TcpExtTCPDSACKOldSent
The TCP stack receives a duplicate packet which has been acked, so itsends a DSACK to the sender.
- TcpExtTCPDSACKOfoSent
The TCP stack receives an out of order duplicate packet, so it sends aDSACK to the sender.
- TcpExtTCPDSACKRecv
The TCP stack receives a DSACK, which indicates an acknowledgedduplicate packet is received.
- TcpExtTCPDSACKOfoRecv
The TCP stack receives a DSACK, which indicate an out of orderduplicate packet is received.
invalid SACK and DSACK¶
When a SACK (or DSACK) block is invalid, a corresponding counter wouldbe updated. The validation method is base on the start/end sequencenumber of the SACK block. For more details, please refer the commentof the function tcp_is_sackblock_valid in the kernel source code. ASACK option could have up to 4 blocks, they are checkedindividually. E.g., if 3 blocks of a SACk is invalid, thecorresponding counter would be updated 3 times. The comment of theAdd counters for discarded SACK blocks patch has additionalexplaination:
- TcpExtTCPSACKDiscard
This counter indicates how many SACK blocks are invalid. If the invalidSACK block is caused by ACK recording, the TCP stack will only ignoreit and won’t update this counter.
- TcpExtTCPDSACKIgnoredOld and TcpExtTCPDSACKIgnoredNoUndo
When a DSACK block is invalid, one of these two counters would beupdated. Which counter will be updated depends on the undo_marker flagof the TCP socket. If the undo_marker is not set, the TCP stack isn’tlikely to re-transmit any packets, and we still receive an invalidDSACK block, the reason might be that the packet is duplicated in themiddle of the network. In such scenario, TcpExtTCPDSACKIgnoredNoUndowill be updated. If the undo_marker is set, TcpExtTCPDSACKIgnoredOldwill be updated. As implied in its name, it might be an old packet.
SACK shift¶
The linux networking stack stores data in sk_buff struct (skb forshort). If a SACK block acrosses multiple skb, the TCP stack will tryto re-arrange data in these skb. E.g. if a SACK block acknowledges seq10 to 15, skb1 has seq 10 to 13, skb2 has seq 14 to 20. The seq 14 and15 in skb2 would be moved to skb1. This operation is ‘shift’. If aSACK block acknowledges seq 10 to 20, skb1 has seq 10 to 13, skb2 hasseq 14 to 20. All data in skb2 will be moved to skb1, and skb2 will bediscard, this operation is ‘merge’.
- TcpExtTCPSackShifted
A skb is shifted
- TcpExtTCPSackMerged
A skb is merged
- TcpExtTCPSackShiftFallback
A skb should be shifted or merged, but the TCP stack doesn’t do it forsome reasons.
TCP out of order¶
- TcpExtTCPOFOQueue
The TCP layer receives an out of order packet and has enough memoryto queue it.
- TcpExtTCPOFODrop
The TCP layer receives an out of order packet but doesn’t have enoughmemory, so drops it. Such packets won’t be counted intoTcpExtTCPOFOQueue.
- TcpExtTCPOFOMerge
The received out of order packet has an overlay with the previouspacket. the overlay part will be dropped. All of TcpExtTCPOFOMergepackets will also be counted into TcpExtTCPOFOQueue.
TCP PAWS¶
PAWS (Protection Against Wrapped Sequence numbers) is an algorithmwhich is used to drop old packets. It depends on the TCPtimestamps. For detail information, please refer thetimestamp wikiand theRFC of PAWS.
- TcpExtPAWSActive
Packets are dropped by PAWS in Syn-Sent status.
- TcpExtPAWSEstab
Packets are dropped by PAWS in any status other than Syn-Sent.
TCP ACK skip¶
In some scenarios, kernel would avoid sending duplicate ACKs toofrequently. Please find more details in the tcp_invalid_ratelimitsection of thesysctl document. When kernel decides to skip an ACKdue to tcp_invalid_ratelimit, kernel would update one of belowcounters to indicate the ACK is skipped in which scenario. The ACKwould only be skipped if the received packet is either a SYN packet orit has no data.
- TcpExtTCPACKSkippedSynRecv
The ACK is skipped in Syn-Recv status. The Syn-Recv status means theTCP stack receives a SYN and replies SYN+ACK. Now the TCP stack iswaiting for an ACK. Generally, the TCP stack doesn’t need to send ACKin the Syn-Recv status. But in several scenarios, the TCP stack needto send an ACK. E.g., the TCP stack receives the same SYN packetrepeately, the received packet does not pass the PAWS check, or thereceived packet sequence number is out of window. In these scenarios,the TCP stack needs to send ACK. If the ACk sending frequency is higher thantcp_invalid_ratelimit allows, the TCP stack will skip sending ACK andincrease TcpExtTCPACKSkippedSynRecv.
- TcpExtTCPACKSkippedPAWS
The ACK is skipped due to PAWS (Protect Against Wrapped Sequencenumbers) check fails. If the PAWS check fails in Syn-Recv, Fin-Wait-2or Time-Wait statuses, the skipped ACK would be counted toTcpExtTCPACKSkippedSynRecv, TcpExtTCPACKSkippedFinWait2 orTcpExtTCPACKSkippedTimeWait. In all other statuses, the skipped ACKwould be counted to TcpExtTCPACKSkippedPAWS.
- TcpExtTCPACKSkippedSeq
The sequence number is out of window and the timestamp passes the PAWScheck and the TCP status is not Syn-Recv, Fin-Wait-2, and Time-Wait.
- TcpExtTCPACKSkippedFinWait2
The ACK is skipped in Fin-Wait-2 status, the reason would be eitherPAWS check fails or the received sequence number is out of window.
- TcpExtTCPACKSkippedTimeWait
Tha ACK is skipped in Time-Wait status, the reason would be eitherPAWS check failed or the received sequence number is out of window.
- TcpExtTCPACKSkippedChallenge
The ACK is skipped if the ACK is a challenge ACK. The RFC 5961 defines3 kind of challenge ACK, please referRFC 5961 section 3.2,RFC 5961 section 4.2 andRFC 5961 section 5.2. Besides thesethree scenarios, In some TCP status, the linux TCP stack would alsosend challenge ACKs if the ACK number is before the firstunacknowledged number (more strict thanRFC 5961 section 5.2).
TCP receive window¶
- TcpExtTCPWantZeroWindowAdv
Depending on current memory usage, the TCP stack tries to set receivewindow to zero. But the receive window might still be a no-zerovalue. For example, if the previous window size is 10, and the TCPstack receives 3 bytes, the current window size would be 7 even if thewindow size calculated by the memory usage is zero.
- TcpExtTCPToZeroWindowAdv
The TCP receive window is set to zero from a no-zero value.
- TcpExtTCPFromZeroWindowAdv
The TCP receive window is set to no-zero value from zero.
Delayed ACK¶
The TCP Delayed ACK is a technique which is used for reducing thepacket count in the network. For more details, please refer theDelayed ACK wiki
- TcpExtDelayedACKs
A delayed ACK timer expires. The TCP stack will send a pure ACK packetand exit the delayed ACK mode.
- TcpExtDelayedACKLocked
A delayed ACK timer expires, but the TCP stack can’t send an ACKimmediately due to the socket is locked by a userspace program. TheTCP stack will send a pure ACK later (after the userspace programunlock the socket). When the TCP stack sends the pure ACK later, theTCP stack will also update TcpExtDelayedACKs and exit the delayed ACKmode.
- TcpExtDelayedACKLost
It will be updated when the TCP stack receives a packet which has beenACKed. A Delayed ACK loss might cause this issue, but it would also betriggered by other reasons, such as a packet is duplicated in thenetwork.
Tail Loss Probe (TLP)¶
TLP is an algorithm which is used to detect TCP packet loss. For moredetails, please refer theTLP paper.
- TcpExtTCPLossProbes
A TLP probe packet is sent.
- TcpExtTCPLossProbeRecovery
A packet loss is detected and recovered by TLP.
TCP Fast Open description¶
TCP Fast Open is a technology which allows data transfer before the3-way handshake complete. Please refer theTCP Fast Open wiki for ageneral description.
- TcpExtTCPFastOpenActive
When the TCP stack receives an ACK packet in the SYN-SENT status, andthe ACK packet acknowledges the data in the SYN packet, the TCP stackunderstand the TFO cookie is accepted by the other side, then itupdates this counter.
- TcpExtTCPFastOpenActiveFail
This counter indicates that the TCP stack initiated a TCP Fast Open,but it failed. This counter would be updated in three scenarios: (1)the other side doesn’t acknowledge the data in the SYN packet. (2) TheSYN packet which has the TFO cookie is timeout at least once. (3)after the 3-way handshake, the retransmission timeout happensnet.ipv4.tcp_retries1 times, because some middle-boxes may black-holefast open after the handshake.
- TcpExtTCPFastOpenPassive
This counter indicates how many times the TCP stack accepts the fastopen request.
- TcpExtTCPFastOpenPassiveFail
This counter indicates how many times the TCP stack rejects the fastopen request. It is caused by either the TFO cookie is invalid or theTCP stack finds an error during the socket creating process.
- TcpExtTCPFastOpenListenOverflow
When the pending fast open request number is larger thanfastopenq->max_qlen, the TCP stack will reject the fast open requestand update this counter. When this counter is updated, the TCP stackwon’t update TcpExtTCPFastOpenPassive orTcpExtTCPFastOpenPassiveFail. The fastopenq->max_qlen is set by theTCP_FASTOPEN socket operation and it could not be larger thannet.core.somaxconn. For example:
setsockopt(sfd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
- TcpExtTCPFastOpenCookieReqd
This counter indicates how many times a client wants to request a TFOcookie.
SYN cookies¶
SYN cookies are used to mitigate SYN flood, for details, please refertheSYN cookies wiki.
- TcpExtSyncookiesSent
It indicates how many SYN cookies are sent.
- TcpExtSyncookiesRecv
How many reply packets of the SYN cookies the TCP stack receives.
- TcpExtSyncookiesFailed
The MSS decoded from the SYN cookie is invalid. When this counter isupdated, the received packet won’t be treated as a SYN cookie and theTcpExtSyncookiesRecv counter wont be updated.
Challenge ACK¶
For details of challenge ACK, please refer the explaination ofTcpExtTCPACKSkippedChallenge.
- TcpExtTCPChallengeACK
The number of challenge acks sent.
- TcpExtTCPSYNChallenge
The number of challenge acks sent in response to SYN packets. Afterupdates this counter, the TCP stack might send a challenge ACK andupdate the TcpExtTCPChallengeACK counter, or it might also skip tosend the challenge and update the TcpExtTCPACKSkippedChallenge.
prune¶
When a socket is under memory pressure, the TCP stack will try toreclaim memory from the receiving queue and out of order queue. One ofthe reclaiming method is ‘collapse’, which means allocate a big sbk,copy the contiguous skbs to the single big skb, and free thesecontiguous skbs.
- TcpExtPruneCalled
The TCP stack tries to reclaim memory for a socket. After updates thiscounter, the TCP stack will try to collapse the out of order queue andthe receiving queue. If the memory is still not enough, the TCP stackwill try to discard packets from the out of order queue (and update theTcpExtOfoPruned counter)
- TcpExtOfoPruned
The TCP stack tries to discard packet on the out of order queue.
- TcpExtRcvPruned
After ‘collapse’ and discard packets from the out of order queue, ifthe actually used memory is still larger than the max allowed memory,this counter will be updated. It means the ‘prune’ fails.
- TcpExtTCPRcvCollapsed
This counter indicates how many skbs are freed during ‘collapse’.
examples¶
ping test¶
Run the ping command against the public dns server 8.8.8.8:
nstatuser@nstat-a:~$ ping 8.8.8.8 -c 1PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.64 bytes from 8.8.8.8: icmp_seq=1 ttl=119 time=17.8 ms--- 8.8.8.8 ping statistics ---1 packets transmitted, 1 received, 0% packet loss, time 0msrtt min/avg/max/mdev = 17.875/17.875/17.875/0.000 ms
The nstayt result:
nstatuser@nstat-a:~$ nstat#kernelIpInReceives 1 0.0IpInDelivers 1 0.0IpOutRequests 1 0.0IcmpInMsgs 1 0.0IcmpInEchoReps 1 0.0IcmpOutMsgs 1 0.0IcmpOutEchos 1 0.0IcmpMsgInType0 1 0.0IcmpMsgOutType8 1 0.0IpExtInOctets 84 0.0IpExtOutOctets 84 0.0IpExtInNoECTPkts 1 0.0
The Linux server sent an ICMP Echo packet, so IpOutRequests,IcmpOutMsgs, IcmpOutEchos and IcmpMsgOutType8 were increased 1. Theserver got ICMP Echo Reply from 8.8.8.8, so IpInReceives, IcmpInMsgs,IcmpInEchoReps and IcmpMsgInType0 were increased 1. The ICMP Echo Replywas passed to the ICMP layer via IP layer, so IpInDelivers wasincreased 1. The default ping data size is 48, so an ICMP Echo packetand its corresponding Echo Reply packet are constructed by:
- 14 bytes MAC header
- 20 bytes IP header
- 16 bytes ICMP header
- 48 bytes data (default value of the ping command)
So the IpExtInOctets and IpExtOutOctets are 20+16+48=84.
tcp 3-way handshake¶
On server side, we run:
nstatuser@nstat-b:~$ nc -lknv 0.0.0.0 9000Listening on [0.0.0.0] (family 0, port 9000)
On client side, we run:
nstatuser@nstat-a:~$ nc -nv 192.168.122.251 9000Connection to 192.168.122.251 9000 port [tcp/*] succeeded!
The server listened on tcp 9000 port, the client connected to it, theycompleted the 3-way handshake.
On server side, we can find below nstat output:
nstatuser@nstat-b:~$ nstat | grep -i tcpTcpPassiveOpens 1 0.0TcpInSegs 2 0.0TcpOutSegs 1 0.0TcpExtTCPPureAcks 1 0.0
On client side, we can find below nstat output:
nstatuser@nstat-a:~$ nstat | grep -i tcpTcpActiveOpens 1 0.0TcpInSegs 1 0.0TcpOutSegs 2 0.0
When the server received the first SYN, it replied a SYN+ACK, and came intoSYN-RCVD state, so TcpPassiveOpens increased 1. The server receivedSYN, sent SYN+ACK, received ACK, so server sent 1 packet, received 2packets, TcpInSegs increased 2, TcpOutSegs increased 1. The last ACKof the 3-way handshake is a pure ACK without data, soTcpExtTCPPureAcks increased 1.
When the client sent SYN, the client came into the SYN-SENT state, soTcpActiveOpens increased 1, the client sent SYN, received SYN+ACK, sentACK, so client sent 2 packets, received 1 packet, TcpInSegs increased1, TcpOutSegs increased 2.
TCP normal traffic¶
Run nc on server:
nstatuser@nstat-b:~$ nc -lkv 0.0.0.0 9000Listening on [0.0.0.0] (family 0, port 9000)
Run nc on client:
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!
Input a string in the nc client (‘hello’ in our example):
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!hello
The client side nstat output:
nstatuser@nstat-a:~$ nstat#kernelIpInReceives 1 0.0IpInDelivers 1 0.0IpOutRequests 1 0.0TcpInSegs 1 0.0TcpOutSegs 1 0.0TcpExtTCPPureAcks 1 0.0TcpExtTCPOrigDataSent 1 0.0IpExtInOctets 52 0.0IpExtOutOctets 58 0.0IpExtInNoECTPkts 1 0.0
The server side nstat output:
nstatuser@nstat-b:~$ nstat#kernelIpInReceives 1 0.0IpInDelivers 1 0.0IpOutRequests 1 0.0TcpInSegs 1 0.0TcpOutSegs 1 0.0IpExtInOctets 58 0.0IpExtOutOctets 52 0.0IpExtInNoECTPkts 1 0.0
Input a string in nc client side again (‘world’ in our exmaple):
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!helloworld
Client side nstat output:
nstatuser@nstat-a:~$ nstat#kernelIpInReceives 1 0.0IpInDelivers 1 0.0IpOutRequests 1 0.0TcpInSegs 1 0.0TcpOutSegs 1 0.0TcpExtTCPHPAcks 1 0.0TcpExtTCPOrigDataSent 1 0.0IpExtInOctets 52 0.0IpExtOutOctets 58 0.0IpExtInNoECTPkts 1 0.0
Server side nstat output:
nstatuser@nstat-b:~$ nstat#kernelIpInReceives 1 0.0IpInDelivers 1 0.0IpOutRequests 1 0.0TcpInSegs 1 0.0TcpOutSegs 1 0.0TcpExtTCPHPHits 1 0.0IpExtInOctets 58 0.0IpExtOutOctets 52 0.0IpExtInNoECTPkts 1 0.0
Compare the first client-side nstat and the second client-side nstat,we could find one difference: the first one had a ‘TcpExtTCPPureAcks’,but the second one had a ‘TcpExtTCPHPAcks’. The first server-sidenstat and the second server-side nstat had a difference too: thesecond server-side nstat had a TcpExtTCPHPHits, but the firstserver-side nstat didn’t have it. The network traffic patterns wereexactly the same: the client sent a packet to the server, the serverreplied an ACK. But kernel handled them in different ways. When theTCP window scale option is not used, kernel will try to enable fastpath immediately when the connection comes into the established state,but if the TCP window scale option is used, kernel will disable thefast path at first, and try to enable it after kerenl receivespackets. We could use the ‘ss’ command to verify whether the windowscale option is used. e.g. run below command on either server orclient:
nstatuser@nstat-a:~$ ss -o state established -i '( dport = :9000 or sport = :9000 )Netid Recv-Q Send-Q Local Address:Port Peer Address:Porttcp 0 0 192.168.122.250:40654 192.168.122.251:9000 ts sack cubic wscale:7,7 rto:204 rtt:0.98/0.49 mss:1448 pmtu:1500 rcvmss:536 advmss:1448 cwnd:10 bytes_acked:1 segs_out:2 segs_in:1 send 118.2Mbps lastsnd:46572 lastrcv:46572 lastack:46572 pacing_rate 236.4Mbps rcv_space:29200 rcv_ssthresh:29200 minrtt:0.98
The ‘wscale:7,7’ means both server and client set the window scaleoption to 7. Now we could explain the nstat output in our test:
In the first nstat output of client side, the client sent a packet, serverreply an ACK, when kernel handled this ACK, the fast path was notenabled, so the ACK was counted into ‘TcpExtTCPPureAcks’.
In the second nstat output of client side, the client sent a packet again,and received another ACK from the server, in this time, the fast path isenabled, and the ACK was qualified for fast path, so it was handled bythe fast path, so this ACK was counted into TcpExtTCPHPAcks.
In the first nstat output of server side, fast path was not enabled,so there was no ‘TcpExtTCPHPHits’.
In the second nstat output of server side, the fast path was enabled,and the packet received from client qualified for fast path, so itwas counted into ‘TcpExtTCPHPHits’.
TcpExtTCPAbortOnClose¶
On the server side, we run below python script:
import socketimport timeport = 9000s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('0.0.0.0', port))s.listen(1)sock, addr = s.accept()while True: time.sleep(9999999)This python script listen on 9000 port, but doesn’t read anything fromthe connection.
On the client side, we send the string “hello” by nc:
nstatuser@nstat-a:~$ echo "hello" | nc nstat-b 9000
Then, we come back to the server side, the server has received the “hello”packet, and the TCP layer has acked this packet, but the application didn’tread it yet. We type Ctrl-C to terminate the server script. Then wecould find TcpExtTCPAbortOnClose increased 1 on the server side:
nstatuser@nstat-b:~$ nstat | grep -i abortTcpExtTCPAbortOnClose 1 0.0
If we run tcpdump on the server side, we could find the server sent aRST after we type Ctrl-C.
TcpExtTCPAbortOnMemory and TcpExtTCPAbortOnTimeout¶
Below is an example which let the orphan socket count be higher thannet.ipv4.tcp_max_orphans.Change tcp_max_orphans to a smaller value on client:
sudo bash -c "echo 10 > /proc/sys/net/ipv4/tcp_max_orphans"
Client code (create 64 connection to server):
nstatuser@nstat-a:~$ cat client_orphan.pyimport socketimport timeserver = 'nstat-b' # server addressport = 9000count = 64connection_list = []for i in range(64): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server, port)) connection_list.append(s) print("connection_count: %d" % len(connection_list))while True: time.sleep(99999)Server code (accept 64 connection from client):
nstatuser@nstat-b:~$ cat server_orphan.pyimport socketimport timeport = 9000count = 64s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('0.0.0.0', port))s.listen(count)connection_list = []while True: sock, addr = s.accept() connection_list.append((sock, addr)) print("connection_count: %d" % len(connection_list))Run the python scripts on server and client.
On server:
python3 server_orphan.py
On client:
python3 client_orphan.py
Run iptables on server:
sudo iptables -A INPUT -i ens3 -p tcp --destination-port 9000 -j DROP
Type Ctrl-C on client, stop client_orphan.py.
Check TcpExtTCPAbortOnMemory on client:
nstatuser@nstat-a:~$ nstat | grep -i abortTcpExtTCPAbortOnMemory 54 0.0
Check orphane socket count on client:
nstatuser@nstat-a:~$ ss -sTotal: 131 (kernel 0)TCP: 14 (estab 1, closed 0, orphaned 10, synrecv 0, timewait 0/0), ports 0Transport Total IP IPv6* 0 - -RAW 1 0 1UDP 1 1 0TCP 14 13 1INET 16 14 2FRAG 0 0 0
The explanation of the test: after run server_orphan.py andclient_orphan.py, we set up 64 connections between server andclient. Run the iptables command, the server will drop all packets fromthe client, type Ctrl-C on client_orphan.py, the system of the clientwould try to close these connections, and before they are closedgracefully, these connections became orphan sockets. As the iptablesof the server blocked packets from the client, the server won’t receive finfrom the client, so all connection on clients would be stuck on FIN_WAIT_1stage, so they will keep as orphan sockets until timeout. We have echo10 to /proc/sys/net/ipv4/tcp_max_orphans, so the client system wouldonly keep 10 orphan sockets, for all other orphan sockets, the clientsystem sent RST for them and delete them. We have 64 connections, sothe ‘ss -s’ command shows the system has 10 orphan sockets, and thevalue of TcpExtTCPAbortOnMemory was 54.
An additional explanation about orphan socket count: You could find theexactly orphan socket count by the ‘ss -s’ command, but when kerneldecide whither increases TcpExtTCPAbortOnMemory and sends RST, kerneldoesn’t always check the exactly orphan socket count. For increasingperformance, kernel checks an approximate count firstly, if theapproximate count is more than tcp_max_orphans, kernel checks theexact count again. So if the approximate count is less thantcp_max_orphans, but exactly count is more than tcp_max_orphans, youwould find TcpExtTCPAbortOnMemory is not increased at all. Iftcp_max_orphans is large enough, it won’t occur, but if you decreasetcp_max_orphans to a small value like our test, you might find thisissue. So in our test, the client set up 64 connections although thetcp_max_orphans is 10. If the client only set up 11 connections, wecan’t find the change of TcpExtTCPAbortOnMemory.
Continue the previous test, we wait for several minutes. Because of theiptables on the server blocked the traffic, the server wouldn’t receivefin, and all the client’s orphan sockets would timeout on theFIN_WAIT_1 state finally. So we wait for a few minutes, we could find10 timeout on the client:
nstatuser@nstat-a:~$ nstat | grep -i abortTcpExtTCPAbortOnTimeout 10 0.0
TcpExtTCPAbortOnLinger¶
The server side code:
nstatuser@nstat-b:~$ cat server_linger.pyimport socketimport timeport = 9000s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('0.0.0.0', port))s.listen(1)sock, addr = s.accept()while True: time.sleep(9999999)The client side code:
nstatuser@nstat-a:~$ cat client_linger.pyimport socketimport structserver = 'nstat-b' # server addressport = 9000s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 10))s.setsockopt(socket.SOL_TCP, socket.TCP_LINGER2, struct.pack('i', -1))s.connect((server, port))s.close()Run server_linger.py on server:
nstatuser@nstat-b:~$ python3 server_linger.py
Run client_linger.py on client:
nstatuser@nstat-a:~$ python3 client_linger.py
After run client_linger.py, check the output of nstat:
nstatuser@nstat-a:~$ nstat | grep -i abortTcpExtTCPAbortOnLinger 1 0.0
TcpExtTCPRcvCoalesce¶
On the server, we run a program which listen on TCP port 9000, butdoesn’t read any data:
import socketimport timeport = 9000s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('0.0.0.0', port))s.listen(1)sock, addr = s.accept()while True: time.sleep(9999999)Save the above code as server_coalesce.py, and run:
python3 server_coalesce.py
On the client, save below code as client_coalesce.py:
import socketserver = 'nstat-b'port = 9000s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect((server, port))
Run:
nstatuser@nstat-a:~$ python3 -i client_coalesce.py
We use ‘-i’ to come into the interactive mode, then a packet:
>>> s.send(b'foo')3
Send a packet again:
>>> s.send(b'bar')3
On the server, run nstat:
ubuntu@nstat-b:~$ nstat#kernelIpInReceives 2 0.0IpInDelivers 2 0.0IpOutRequests 2 0.0TcpInSegs 2 0.0TcpOutSegs 2 0.0TcpExtTCPRcvCoalesce 1 0.0IpExtInOctets 110 0.0IpExtOutOctets 104 0.0IpExtInNoECTPkts 2 0.0
The client sent two packets, server didn’t read any data. Whenthe second packet arrived at server, the first packet was still inthe receiving queue. So the TCP layer merged the two packets, and wecould find the TcpExtTCPRcvCoalesce increased 1.
TcpExtListenOverflows and TcpExtListenDrops¶
On server, run the nc command, listen on port 9000:
nstatuser@nstat-b:~$ nc -lkv 0.0.0.0 9000Listening on [0.0.0.0] (family 0, port 9000)
On client, run 3 nc commands in different terminals:
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!
The nc command only accepts 1 connection, and the accept queue lengthis 1. On current linux implementation, set queue length to n means theactual queue length is n+1. Now we create 3 connections, 1 is acceptedby nc, 2 in accepted queue, so the accept queue is full.
Before running the 4th nc, we clean the nstat history on the server:
nstatuser@nstat-b:~$ nstat -n
Run the 4th nc on the client:
nstatuser@nstat-a:~$ nc -v nstat-b 9000
If the nc server is running on kernel 4.10 or higher version, youwon’t see the “Connection to … succeeded!” string, because kernelwill drop the SYN if the accept queue is full. If the nc client is runningon an old kernel, you would see that the connection is succeeded,because kernel would complete the 3 way handshake and keep the socketon half open queue. I did the test on kernel 4.15. Below is the nstaton the server:
nstatuser@nstat-b:~$ nstat#kernelIpInReceives 4 0.0IpInDelivers 4 0.0TcpInSegs 4 0.0TcpExtListenOverflows 4 0.0TcpExtListenDrops 4 0.0IpExtInOctets 240 0.0IpExtInNoECTPkts 4 0.0
Both TcpExtListenOverflows and TcpExtListenDrops were 4. If the timebetween the 4th nc and the nstat was longer, the value ofTcpExtListenOverflows and TcpExtListenDrops would be larger, becausethe SYN of the 4th nc was dropped, the client was retrying.
IpInAddrErrors, IpExtInNoRoutes and IpOutNoRoutes¶
server A IP address: 192.168.122.250server B IP address: 192.168.122.251Prepare on server A, add a route to server B:
$ sudo ip route add 8.8.8.8/32 via 192.168.122.251
Prepare on server B, disable send_redirects for all interfaces:
$ sudo sysctl -w net.ipv4.conf.all.send_redirects=0$ sudo sysctl -w net.ipv4.conf.ens3.send_redirects=0$ sudo sysctl -w net.ipv4.conf.lo.send_redirects=0$ sudo sysctl -w net.ipv4.conf.default.send_redirects=0
We want to let sever A send a packet to 8.8.8.8, and route the packetto server B. When server B receives such packet, it might send a ICMPRedirect message to server A, set send_redirects to 0 will disablethis behavior.
First, generate InAddrErrors. On server B, we disable IP forwarding:
$ sudo sysctl -w net.ipv4.conf.all.forwarding=0
On server A, we send packets to 8.8.8.8:
$ nc -v 8.8.8.8 53
On server B, we check the output of nstat:
$ nstat#kernelIpInReceives 3 0.0IpInAddrErrors 3 0.0IpExtInOctets 180 0.0IpExtInNoECTPkts 3 0.0
As we have let server A route 8.8.8.8 to server B, and we disabled IPforwarding on server B, Server A sent packets to server B, then server Bdropped packets and increased IpInAddrErrors. As the nc command wouldre-send the SYN packet if it didn’t receive a SYN+ACK, we could findmultiple IpInAddrErrors.
Second, generate IpExtInNoRoutes. On server B, we enable IPforwarding:
$ sudo sysctl -w net.ipv4.conf.all.forwarding=1
Check the route table of server B and remove the default route:
$ ip route showdefault via 192.168.122.1 dev ens3 proto static192.168.122.0/24 dev ens3 proto kernel scope link src 192.168.122.251$ sudo ip route delete default via 192.168.122.1 dev ens3 proto static
On server A, we contact 8.8.8.8 again:
$ nc -v 8.8.8.8 53nc: connect to 8.8.8.8 port 53 (tcp) failed: Network is unreachable
On server B, run nstat:
$ nstat#kernelIpInReceives 1 0.0IpOutRequests 1 0.0IcmpOutMsgs 1 0.0IcmpOutDestUnreachs 1 0.0IcmpMsgOutType3 1 0.0IpExtInNoRoutes 1 0.0IpExtInOctets 60 0.0IpExtOutOctets 88 0.0IpExtInNoECTPkts 1 0.0
We enabled IP forwarding on server B, when server B received a packetwhich destination IP address is 8.8.8.8, server B will try to forwardthis packet. We have deleted the default route, there was no route for8.8.8.8, so server B increase IpExtInNoRoutes and sent the “ICMPDestination Unreachable” message to server A.
Third, generate IpOutNoRoutes. Run ping command on server B:
$ ping -c 1 8.8.8.8connect: Network is unreachable
Run nstat on server B:
$ nstat#kernelIpOutNoRoutes 1 0.0
We have deleted the default route on server B. Server B couldn’t finda route for the 8.8.8.8 IP address, so server B increasedIpOutNoRoutes.
TcpExtTCPACKSkippedSynRecv¶
In this test, we send 3 same SYN packets from client to server. Thefirst SYN will let server create a socket, set it to Syn-Recv status,and reply a SYN/ACK. The second SYN will let server reply the SYN/ACKagain, and record the reply time (the duplicate ACK reply time). Thethird SYN will let server check the previous duplicate ACK reply time,and decide to skip the duplicate ACK, then increase theTcpExtTCPACKSkippedSynRecv counter.
Run tcpdump to capture a SYN packet:
nstatuser@nstat-a:~$ sudo tcpdump -c 1 -w /tmp/syn.pcap port 9000tcpdump: listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes
Open another terminal, run nc command:
nstatuser@nstat-a:~$ nc nstat-b 9000
As the nstat-b didn’t listen on port 9000, it should reply a RST, andthe nc command exited immediately. It was enough for the tcpdumpcommand to capture a SYN packet. A linux server might use hardwareoffload for the TCP checksum, so the checksum in the /tmp/syn.pcapmight be not correct. We call tcprewrite to fix it:
nstatuser@nstat-a:~$ tcprewrite --infile=/tmp/syn.pcap --outfile=/tmp/syn_fixcsum.pcap --fixcsum
On nstat-b, we run nc to listen on port 9000:
nstatuser@nstat-b:~$ nc -lkv 9000Listening on [0.0.0.0] (family 0, port 9000)
On nstat-a, we blocked the packet from port 9000, or nstat-a would sendRST to nstat-b:
nstatuser@nstat-a:~$ sudo iptables -A INPUT -p tcp --sport 9000 -j DROP
Send 3 SYN repeatly to nstat-b:
nstatuser@nstat-a:~$ for i in {1..3}; do sudo tcpreplay -i ens3 /tmp/syn_fixcsum.pcap; doneCheck snmp cunter on nstat-b:
nstatuser@nstat-b:~$ nstat | grep -i skipTcpExtTCPACKSkippedSynRecv 1 0.0
As we expected, TcpExtTCPACKSkippedSynRecv is 1.
TcpExtTCPACKSkippedPAWS¶
To trigger PAWS, we could send an old SYN.
On nstat-b, let nc listen on port 9000:
nstatuser@nstat-b:~$ nc -lkv 9000Listening on [0.0.0.0] (family 0, port 9000)
On nstat-a, run tcpdump to capture a SYN:
nstatuser@nstat-a:~$ sudo tcpdump -w /tmp/paws_pre.pcap -c 1 port 9000tcpdump: listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes
On nstat-a, run nc as a client to connect nstat-b:
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!
Now the tcpdump has captured the SYN and exit. We should fix thechecksum:
nstatuser@nstat-a:~$ tcprewrite --infile /tmp/paws_pre.pcap --outfile /tmp/paws.pcap --fixcsum
Send the SYN packet twice:
nstatuser@nstat-a:~$ for i in {1..2}; do sudo tcpreplay -i ens3 /tmp/paws.pcap; doneOn nstat-b, check the snmp counter:
nstatuser@nstat-b:~$ nstat | grep -i skipTcpExtTCPACKSkippedPAWS 1 0.0
We sent two SYN via tcpreplay, both of them would let PAWS checkfailed, the nstat-b replied an ACK for the first SYN, skipped the ACKfor the second SYN, and updated TcpExtTCPACKSkippedPAWS.
TcpExtTCPACKSkippedSeq¶
To trigger TcpExtTCPACKSkippedSeq, we send packets which have validtimestamp (to pass PAWS check) but the sequence number is out ofwindow. The linux TCP stack would avoid to skip if the packet hasdata, so we need a pure ACK packet. To generate such a packet, wecould create two sockets: one on port 9000, another on port 9001. Thenwe capture an ACK on port 9001, change the source/destination portnumbers to match the port 9000 socket. Then we could triggerTcpExtTCPACKSkippedSeq via this packet.
On nstat-b, open two terminals, run two nc commands to listen on bothport 9000 and port 9001:
nstatuser@nstat-b:~$ nc -lkv 9000Listening on [0.0.0.0] (family 0, port 9000)nstatuser@nstat-b:~$ nc -lkv 9001Listening on [0.0.0.0] (family 0, port 9001)
On nstat-a, run two nc clients:
nstatuser@nstat-a:~$ nc -v nstat-b 9000Connection to nstat-b 9000 port [tcp/*] succeeded!nstatuser@nstat-a:~$ nc -v nstat-b 9001Connection to nstat-b 9001 port [tcp/*] succeeded!
On nstat-a, run tcpdump to capture an ACK:
nstatuser@nstat-a:~$ sudo tcpdump -w /tmp/seq_pre.pcap -c 1 dst port 9001tcpdump: listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes
On nstat-b, send a packet via the port 9001 socket. E.g. we sent astring ‘foo’ in our example:
nstatuser@nstat-b:~$ nc -lkv 9001Listening on [0.0.0.0] (family 0, port 9001)Connection from nstat-a 42132 received!foo
On nstat-a, the tcpdump should have caputred the ACK. We should checkthe source port numbers of the two nc clients:
nstatuser@nstat-a:~$ ss -ta '( dport = :9000 || dport = :9001 )' | teeState Recv-Q Send-Q Local Address:Port Peer Address:PortESTAB 0 0 192.168.122.250:50208 192.168.122.251:9000ESTAB 0 0 192.168.122.250:42132 192.168.122.251:9001
Run tcprewrite, change port 9001 to port 9000, chagne port 42132 toport 50208:
nstatuser@nstat-a:~$ tcprewrite --infile /tmp/seq_pre.pcap --outfile /tmp/seq.pcap -r 9001:9000 -r 42132:50208 --fixcsum
Now the /tmp/seq.pcap is the packet we need. Send it to nstat-b:
nstatuser@nstat-a:~$ for i in {1..2}; do sudo tcpreplay -i ens3 /tmp/seq.pcap; doneCheck TcpExtTCPACKSkippedSeq on nstat-b:
nstatuser@nstat-b:~$ nstat | grep -i skipTcpExtTCPACKSkippedSeq 1 0.0