Что обозначает вывод «ss -s»

от автора

На смену утилите netstat пришла утилита ss и очень часто вывод агрегированной (суммарной) информации «ss -s» (или «ss —summary») используется для нужд мониторинга. Однако, что же означает каждое из выводимых полей?

# ss -s Total: 15046 (kernel 16739) TCP:   39306 (estab 11458, closed 25092, orphaned 110, synrecv 0, timewait 24929/0), ports 0  Transport Total     IP        IPv6 *	  16739     -         -         RAW	  0         0         0         UDP	  15        5         10        TCP	  14214     1214      13000     INET	  14229     1219      13010     FRAG	  0         0         0         

Как выяснилось, тут есть тонкости.

Источником истины является исходный код. Исходный код утилиты «ss» можно найти в iproute2/misc/ss.c. Вывод «ss -s» производится в функции print_summary.

До версии 4.17.0 вывод «ss -s» отображен выше. После коммита 90ee99d он стал выглядеть следующим образом:

# ss -s Total: 15046 TCP:   39306 (estab 11458, closed 25092, orphaned 110, timewait 24929)  Transport Total     IP        IPv6 RAW	  0         0         0         UDP	  15        5         10        TCP	  14214     1214      13000     INET	  14229     1219      13010     FRAG	  0         0         0         

Как можно заметить, из строки «Total» удалено поле «kernel». В строке «TCP» удалено поле «synrecv», осталось одно (первое) число «timewait», удалено поле «ports». В таблице «Transport» удалена строка «*». Общий смысл коммита можно перевести как: "Мы удалили из вывода то, что давно было сломано".

Что же было сломано?

В print_summary версии 4.16.0 используется структура slabstat, заполняемая вызовом get_slabstat. Если попробовать перевести вызов «get_slabstat» в команды shell, получим следующее:

# egrep '^(sock|tcp_bind_bucket|tcp_tw_bucket|tcp_open_request|skbuff_head_cache)' /proc/slabinfo | awk '{ print $1, $2; }'

Где ключи из «/proc/slabinfo» соответствуют полям структуры «slabstat»:

struct slabstat { 	int socks;       // sock, net/core/sock.c:sk_init, удалено в 2.6.12 	int tcp_ports;   // tcp_bind_bucket, net/ipv4/tcp.c:tcp_init 	int tcp_tws;     // tcp_tw_bucket, net/ipv4/tcp.c:tcp_init, удалено в 2.6.14 	int tcp_syns;    // tcp_open_request, net/ipv4/tcp.c:tcp_init, удалено в 2.6.13 	int skbs;        // skbuff_head_cache, net/core/skbuff:skb_init, не используется }; 

Другими словами, из всех значений получаемых из «/proc/slabinfo» на сегодняшний день можно получить только значение «tcp_bind_bucket», которое отображается в поле «ports». Приведу его описание из книги «TCP/IP Architecture, Design, and Implementation in Linux. By S. Seth and M. A. Venkatesulu 2008 the IEEE Computer Society»:

This structure keeps information about the port number usage by sockets and the way the port number is being used. The information is useful enough to tell the new binding socket whether it can bind itself to a particular port number that is already in use. The data structure also keeps track of all the socket’s that are associated with this port number.

Теперь еще раз то же самое, но в виде картинки (художник из меня так себе):

Ничего странного не замечаете? Slab «sock» (удаленный в 2.6.12) имеет ненулевое значение. Объяснение очень простое — из за особенности сравнения строк в значение поля попадет любое число у которого ключ начинается на «sock». В моем случае это «sock_inode_cache» из «net/socket.c:init_inodecache» относящийся к «sockfs» — список «inode», содержащих «socket struct» (возможно это не совсем то, что задумал автор утилиты):

# egrep '^sock' /proc/slabinfo | awk '{ print $1, $2; }' sock_inode_cache 16739 

Ну а «tcp_bind_bucket» отсутствует как раз из за опций сборки ядра (и, соответственно, поле «ports» всегда имеет значение «0»).

Описание вывода «ss -s»

Перед погружением в хитросплетения вычисления полей имеет смысл освежить в памяти состояния сокетов (ESTABLISHED, CLOSE-WAIT, TIME-WAIT и т.д.). Для тех подзабыл, вики в помощь: RU, EN.

Вывод утилиты строится на базе значений, получаемых из файлов:

# cat /proc/net/sockstat sockets: used 15046 TCP: inuse 1205 orphan 111 tw 24952 alloc 14368 mem 5890 UDP: inuse 5 mem 86 UDPLITE: inuse 0 RAW: inuse 0 FRAG: inuse 0 memory 0  # cat /proc/net/sockstat6 TCP6: inuse 13000 UDP6: inuse 10 UDPLITE6: inuse 0 RAW6: inuse 0 FRAG6: inuse 0 memory 0  # egrep '^Tcp:' /proc/net/snmp Tcp: RtoAlgorithm RtoMin RtoMax ... AttemptFails EstabResets CurrEstab ... Tcp: 1 200 120000 ... 1348218 4095008 11458 ... 

Значения, рассчитываемые по содержимому «net/sockstat» (для упрощения восприятия в картинках):

  • Total — общее число сокетов в системе (включая unix-сокеты) в любом состоянии кроме TIME_WAIT;
  • TCP: — общее число TCP сокетов (включая IPv6) в любом состоянии, tw сокеты отделены от alloc сокетов из за т.н. «death row» — их нельзя использовать до перевода в состояние CLOSED.
    • orphaned — общее число «осиротевших» TCP сокетов (сокетов, не связанных с дескрипторами в пользовательских процессах);
    • timewait — общее число TCP сокетов в состоянии TIME_WAIT;
    • inuse TCP, UDP, RAW — общее число v4 сокетов соответствующего типа в любом состоянии за исключением CLOSED и TIME_WAIT;
    • inuse FRAG (bool) — флаг фрагментации памяти, memory — объем памяти для дефрагментации в байтах (в отличии от mem, которая указываются в страницах).

Значения, рассчитываемые по содержимому «net/sockstat6»:

Тут вроде все просто — «Transport / Total» есть поколоночная сумма значений «IP» и «IPv6».

Значения, рассчитываемые по содержимому «net/snmp». Согласно RFC-4022, «tcpCurrEstab» есть «The number of TCP connections for which the current state is either ESTABLISHED or CLOSE-WAIT».

И последнее поле «closed» — есть сумма аллоцированных сокетов и сокетов в состоянии TIME_WAIT за вычетом суммы TCPv4 и TCPv6 сокетов в любом из незакрытых состояний:

P.S. И не забудьте подписать оси на графиках.

ссылка на оригинал статьи https://habr.com/ru/post/503648/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *