ss工具和netstat工具的功能相似,当是更加高效,ss属于iproute2 package,这个包的工具还有 ss、ip、和 nstat 等等,此软件包中的工具最有可能支持最新的 Linux 内核功能,因此推荐用ss取代netstat。
即用 iproute2 package取代net-tools package。
关于netstat请参考:Linux 网络之netstat
由于ss和netstat使用相似,列出其选项:
ss is used to dump socket statistics
-b, --bpf
Show socket BPF filters
-4, --ipv4
Display only IP version 4 sockets (alias for -f inet).
-6, --ipv6
Display only IP version 6 sockets (alias for -f inet6).
-0, --packet
Display PACKET sockets (alias for -f link).
-t, --tcp
Display TCP sockets.
-u, --udp
Display UDP sockets.
-d, --dccp
Display DCCP sockets.
-w, --raw
Display RAW sockets.
-x, --unix
Display Unix domain sockets (alias for -f unix).
-l, --listening
Display only listening sockets (these are omitted by default).
-o, --options
Show timer information.
-e, --extended
Show detailed socket information
-m, --memory
Show socket memory usage.
-p, --processes
Show process using socket.
-i, --info
Show internal TCP information.
在使用选项时,ss 相比 netstat 可以显示更多信息。 例如,仅显示 TCP 套接字 (-t)、TCP 内部信息 (-i)、扩展套接字信息 (-e)、进程信息 (-p) 和内存使用 (-m):
[root@localhost ~]# ss -tiepm
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 112 xx.xx.xx.xxx:ssh xx.xx.xx.xx:xxxxx
users:(("sshd",pid=1608,fd=3)) timer:(on,242ms,0) ino:134147 sk:ffff9f1d0ae7ae80 <->
......rto:242 rtt:41.707/6.808 mss:1460 cwnd:10 bytes_acked:5069 bytes_received:3836 pacing_rate 5.6Mbps
其中一些字段说明:
"sshd",pid=1608 : Process name "sshd", PID 1608.
fd=3: File descriptor 3 (for PID 1608).
ino:134147: socket inode : 134147
rto:242: TCP retransmission timeout: 242 milliseconds.
rtt:41.707/6.808: Average round-trip time is 41.707 milliseconds, with 6.808 milliseconds
mean deviation.
mss:1460: Maximum segment size: 1460 bytes.
cwnd:10: Congestion window size: 10 × MSS.
bytes_acked:5069: 5069 bytes successfully transmitted.
bytes_received:3836: 3836 bytes received.
pacing_rate 5.6Mbps: Pacing rate of 5.6 Mbps.
其中sk:ffff9f1d0ae7ae80,代表该tcp 连接 struct sock结构体的起始地址,我们可以用crash查看:
crash> sock ffff9f1d0ae7ae80
struct sock {
......
skc_family = 2,
skc_state = 1 '\001',
......
sk_protocol = 6,
sk_type = 1,
......
}
struct sock :套接字的网络层表示结构体。
// linux-3.10/include/net/sock.h
/* struct sock - network layer representation of sockets */
struct sock {
/*
* Now struct inet_timewait_sock also uses sock_common, so please just
* don't add nothing before this first member (__sk_common) --acme
*/
struct sock_common __sk_common;
#define sk_family __sk_common.skc_family
#define sk_state __sk_common.skc_state
......
unsigned int sk_shutdown : 2,
......
sk_protocol : 8,
sk_type : 16;
......
}
对于TCP struct sock sk :
sk. skc_family = 2
// linux-3.10/include/linux/socket.h
/* Supported address families. */
#define AF_UNIX 1 /* Unix domain sockets */
#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
#define AF_INET 2 /* Internet IP Protocol */
sk.sk_state = 1
sk_state表示该TCP连接当前的连接状态
// linux-3.10/include/net/tcp_states.h
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Definitions for the TCP protocol sk_state field.
*
*/
#ifndef _LINUX_TCP_STATES_H
#define _LINUX_TCP_STATES_H
enum {
TCP_ESTABLISHED = 1,
TCP_SYN_SENT,
TCP_SYN_RECV,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING, /* Now a valid state */
TCP_MAX_STATES /* Leave at the end! */
};
sk.sk_type = 1
type就是socket的类型,对于AF_INET协议族而言有流套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)
// linux-3.10/include/linux/net.h
/**
* enum sock_type - Socket types
* @SOCK_STREAM: stream (connection) socket
* @SOCK_DGRAM: datagram (conn.less) socket
* @SOCK_RAW: raw socket
* @SOCK_RDM: reliably-delivered message
* @SOCK_SEQPACKET: sequential packet socket
* @SOCK_DCCP: Datagram Congestion Control Protocol socket
* @SOCK_PACKET: linux specific way of getting packets at the dev level.
* For writing rarp and other similar things on the user level.
*
* When adding some new socket type please
* grep ARCH_HAS_SOCKET_TYPE include/asm-* /socket.h, at least MIPS
* overrides this enum for binary compat reasons.
*/
enum sock_type {
SOCK_STREAM = 1,
SOCK_DGRAM = 2,
SOCK_RAW = 3,
SOCK_RDM = 4,
SOCK_SEQPACKET = 5,
SOCK_DCCP = 6,
SOCK_PACKET = 10,
};
sk.sk_protocol = 6
// linux-3.10/include/uapi/linux/in.h
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* Definitions of the Internet Protocol.
*/
/* Standard well-defined IP protocols. */
enum {
IPPROTO_IP = 0, /* Dummy protocol for TCP */
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
IPPROTO_TCP = 6, /* Transmission Control Protocol */
IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
IPPROTO_PUP = 12, /* PUP protocol */
IPPROTO_UDP = 17, /* User Datagram Protocol */
IPPROTO_IDP = 22, /* XNS IDP protocol */
IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
IPPROTO_RSVP = 46, /* RSVP protocol */
IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
IPPROTO_AH = 51, /* Authentication Header protocol */
IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
IPPROTO_COMP = 108, /* Compression Header protocol */
IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
IPPROTO_RAW = 255, /* Raw IP packets */
IPPROTO_MAX
};
上述输出中缺少的一个细节是连接的时间,这是计算平均吞吐量所必需的。 可以在 /proc 中的文件描述符文件上使用 the change timestamp:对于此连接,将在 /proc/1608/fd/3 上运行 stat:
[root@localhost ~]# stat /proc/1608/fd/3
File: ‘/proc/1608/fd/3’ -> ‘socket:[134147]’
Size: 64 Blocks: 0 IO Block: 1024 symbolic link
Device: 3h/3d Inode: 133169 Links: 1
Access: (xxx/lxxxxxxxxx) Uid: ( x/ xxx) Gid: ( x/ xxx)
Context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Access: 2022-10-28 10:19:58.728134501 +0800
Modify: 2022-10-28 09:50:45.580537840 +0800
Change: 2022-10-28 09:50:45.580537840 +0800
Birth: -
ss 从 netlink 接口读取这些扩展细节,该接口通过 AF_NETLINK 系列的套接字操作以从内核获取信息。
netlink 是一个特殊的套接字地址族(AF_NETLINK),用于获取内核信息。使用netlink需要打开一个带有AF_NETLINK地址族的网络套接字,然后使用一系列 send 和 recv 调用以二进制结构传递请求和接收信息。 虽然这是一个比 /proc 更复杂的接口,但它更高效,并且还支持通知机制。
// linux-3.10/include/linux/socket.h
#define AF_NETLINK 16
使用strace跟踪ss -t命令执行过程中调用socket系统调用(-e socket 字面意思是 -e trace= socket ,这意味着只跟踪 socket 系统调用):
[root@localhost ~]# strace -e socket ss -t
State Recv-Q Send-Q Local Address:Port Peer Address:Port
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_SOCK_DIAG) = 3
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
socket(AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 5
这是为 the group NETLINK_SOCK_DIAG 打开一个AF_NETLINK套接字,它返回关于套接字的信息。
netlink groups include:
NETLINK_ROUTE: Route information (there is also /proc/net/route)
NETLINK_SOCK_DIAG: Socket information
NETLINK_SELINUX: SELinux event notifications
NETLINK_AUDIT: Auditing (security)
NETLINK_SCSITRANSPORT: SCSI transports
NETLINK_CRYPTO: Kernel crypto information
跟踪ss -t执行过程中的sendmsg和recvmsg系统调用:
strace -e sendmsg,recvmsg ss -t 2>ss_log
cat ss_log | grep AF_NETLINK
sendmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
sendmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
recvmsg(3, {msg_name(12)={sa_family=AF_NETLINK, ......})
源码分析请参考:ss源代码调试&原理分析
Linux 3.10
Systems.Performance.Enterprise.and.the.Cloud.2nd.Edition