Netstat, где мои дейтаграммы?

Вероятно, что трудно найти другую, настолько же полезную и плохо документированную программу, как Netstat, имеется в виду, опция показа статистики сетевого потока данных. Когда мы проводим инспекцию состояния сети на отдельно взятом Linux узле, всегда можно быть уверенным, что это утилита имеется в наличии. И вот мы хотим понять — справляется ли сетевой стэк с нагрузкой, или проблема на верхних этажах OSI, собственно там, где сосредоточенно крутятся колесики бизнес-логики нашего приложения.


e464f2d7ff72473b8fd0c40807c0851f.jpg


(5:562)$ netstat -s |wc -l
124


Ура, у нас куча полезной информации, сейчас мы быстренько сообразим, что к чему. Вот только бы понять, что же это за зверь такой timeout in transit, явно что-то нехорошее.


Icmp:
11475275 ICMP messages received
327527 input ICMP message failed.
ICMP input histogram:
detination unreachable: 2233840
timeout in transit: 5612259

Сейчас гляну в мануал.


# man netstat |grep timeout
#

Пустое множество подсказывает, что пора узнавать у Яндекса, Гугла и даже у DuckDuckGo. Результат поиска был примерно такой-же, но только Гугл выдал 111 тыс. вариантов пустого множества, а Яндекс лаконично ограничился 326 вариантами.


Но мы ведь не напрасно выбрали открытое ПО, всегда можно свериться с первоисточником. В нашем случае исходный код находится в файле nertstat.c пакета Net-tools.


Вот та часть функции int main, в которой определяется действие для показа статистики.


    case '?':
        usage(E_OPTERR);
    case 'h':
        usage(E_USAGE);
    case 's':
        flag_sta++;
...
    if (flag_sta) {
        if (!afname[0])
            safe_strncpy(afname, DFLT_AF, sizeof(afname));

        if (!strcmp(afname, "inet")) {
#if HAVE_AFINET
            parsesnmp(flag_raw, flag_tcp, flag_udp, flag_sctp);

Функция parsesnmp определена в файле statistics.c и парсит файлы:


/proc/net/netstat
/proc/net/snmp
/proc/net/sctp/snmp

Ясно понятно, значит можно просто заглянуть в /proc/net/snmp и увидеть, что стоит за timeout in transit.


# cat /proc/net/snmp |grep -iw icmp
Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 127 2 0 90 0 0 0 0 25 0 8 0 4 0 1763 0 1730 0 0 0 0 0 25 0 8 0 0

Сравнивая эти значения с выводом команды netstat, можем заключить, что timeout in transit соответствует переменной InTimeExcds, а цепочка далее ведет к файлу /usr/include/linux/snmp.h, где определены все эти поля.


/* icmp mib definitions */
/*
 * RFC 1213:  MIB-II ICMP Group
 * RFC 2011 (updates 1213):  SNMPv2 MIB for IP: ICMP group
 */
enum
{
    ICMP_MIB_NUM = 0,
    ICMP_MIB_INMSGS,            /* InMsgs */
    ICMP_MIB_INERRORS,          /* InErrors */
    ICMP_MIB_INDESTUNREACHS,        /* InDestUnreachs */
    ICMP_MIB_INTIMEEXCDS,           /* InTimeExcds */
    ICMP_MIB_INPARMPROBS,           /* InParmProbs */
    ICMP_MIB_INSRCQUENCHS,          /* InSrcQuenchs */
    ICMP_MIB_INREDIRECTS,           /* InRedirects */
    ICMP_MIB_INECHOS,           /* InEchos */
    ICMP_MIB_INECHOREPS,            /* InEchoReps */
    ICMP_MIB_INTIMESTAMPS,          /* InTimestamps */
    ICMP_MIB_INTIMESTAMPREPS,       /* InTimestampReps */
    ICMP_MIB_INADDRMASKS,           /* InAddrMasks */
    ICMP_MIB_INADDRMASKREPS,        /* InAddrMaskReps */
    ICMP_MIB_OUTMSGS,           /* OutMsgs */
    ICMP_MIB_OUTERRORS,         /* OutErrors */
    ICMP_MIB_OUTDESTUNREACHS,       /* OutDestUnreachs */
    ICMP_MIB_OUTTIMEEXCDS,          /* OutTimeExcds */
    ICMP_MIB_OUTPARMPROBS,          /* OutParmProbs */
    ICMP_MIB_OUTSRCQUENCHS,         /* OutSrcQuenchs */
    ICMP_MIB_OUTREDIRECTS,          /* OutRedirects */
    ICMP_MIB_OUTECHOS,          /* OutEchos */
    ICMP_MIB_OUTECHOREPS,           /* OutEchoReps */
    ICMP_MIB_OUTTIMESTAMPS,         /* OutTimestamps */
    ICMP_MIB_OUTTIMESTAMPREPS,      /* OutTimestampReps */
    ICMP_MIB_OUTADDRMASKS,          /* OutAddrMasks */
    ICMP_MIB_OUTADDRMASKREPS,       /* OutAddrMaskReps */
    ICMP_MIB_CSUMERRORS,            /* InCsumErrors */
    __ICMP_MIB_MAX
};

Кому как, а для меня RFC 1213 как для химика таблица Менделеева — необходимо знать на зубок, так как, это один из краеугольных камней мониторинга сетевых устройств. Вот определение элемента из RFC 1213 пишу по памяти.


icmpInTimeExcds OBJECT-TYPE
              SYNTAX  Counter
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                      "The number of ICMP Time Exceeded messages received."
              ::= { icmp 4 }

Пока что создается впечатление, что все эти определение как масло масляное, не раскрывают сути, но по счастью ICMP Time Exceeded — часть определения протокола ICMP.


Если обрабатывающий дейтаграмму шлюз видит, что поле TTL содержит нулевое значение, дейтаграмма должна быть отброшена. Шлюз может уведомить отправителя дейтаграммы с помощью сообщения time exceeded.

Итак, мы нашли то что искали. Вывод команды netstat, в котором было это загадочное поле, означает число отброшенных ICMP пакетов с нулевым TTL. IRL[1] это означает, что в сети есть кольцо, где пакеты профукали весь TTL[2] .


timeout in transit: 5612259

Linux MIB


В процессе этого погружения в дебри Linux ядра, я с удивлением обнаружил SNMP подсистему. Нет, не SNMP агента, упаси нас Alan Cox, а именно небольшой SNMP стэк. Об этом написано в комментария к файлу /usr/src/linux/include/net/snmp.h.


/*
 *              SNMP MIB entries for the IP subsystem.
 *              Alan Cox 
 *
 *              We don't chose to implement SNMP in the kernel (this would
 *              be silly as SNMP is a pain in the backside in places). We do
 *              however need to collect the MIB statistics and export them
 *              out of /proc (eventually)
 */

SNMP означает Simple Network Management Protocol, но как гласит бородатая шутка, никогда еще в аббревиатуре буква S так не лгала. Я планирую написать об этой мозгодробилке отдельно, так как именно на нем крутится весь софт мониторинга вычислительных сетей и сетевых узлов. Пока же — необходимый минимум, чтобы было понятно, откуда берутся переменные статистики netstat.


0caabf7359444c3d91cf459f09076f43.jpg



В самом простом случае мы имеем архитектуру клиент — сервер, где в роли клиента может выступать MRTG или Munin, а серверная часть — это SNMP агент на сетевом узле. Почти все современные сетевые устройства имеют на борту SNMP агента, даже домашние WiFi роутеры. Windows имеет свой SNMP Service, а Linux и открытые Unix системы используют Net-SNMP.


SNMP клиент и сервер обмениваются сообщениями: клиент посылает запрос, а сервер возвращает ответ. Обычно, этот обмен выгладит следующим образом.


К. — Чебурашка, приборы!
С. — Сорок
К. — Что сорок?
С. — А что приборы?

Клиент просит выдать значение некой переменной из Великого Словаря. Сервер смотрит в ВС, находит переменную, смотрит в свой реестр и возвращает значение. Великий Словарь — это MIB Database из рисунка.


Вот как выглядит опрос системных переменных, uptime и других на man странице.


snmpwalk -Os -c public -v 1 zeus system 

sysDescr.0 = STRING: "SunOS zeus.net.cmu.edu 4.1.3_U1 1 sun4m"
sysObjectID.0 = OID: enterprises.hp.nm.hpsystem.10.1.1
sysUpTime.0 = Timeticks: (155274552) 17 days, 23:19:05
sysContact.0 = STRING: ""
sysName.0 = STRING: "zeus.net.cmu.edu"
sysLocation.0 = STRING: ""
sysServices.0 = INTEGER: 72

Надо понимать, что за эвфемизмами Великого Словаря, реестра и самого протокола SNMP скрываются десятки RFC и бездна их возможных реализаций. Возвращаясь к нашему файлу snmp.h, видна лишь надводная часть айсберга:


# grep RFC /usr/include/linux/snmp.h

* RFC 1213:  MIB-II
* RFC 2011 (updates 1213):  SNMPv2-MIB-IP
* RFC 2863:  Interfaces Group MIB
* RFC 2465:  IPv6 MIB: General Group
* RFC 1213:  MIB-II ICMP Group
* RFC 2011 (updates 1213):  SNMPv2 MIB for IP: ICMP group
* RFC 2466:  ICMPv6-MIB
* RFC 1213:  MIB-II TCP group
* RFC 2012 (updates 1213):  SNMPv2-MIB-TCP
* RFC 1213:  MIB-II UDP group
* RFC 2013 (updates 1213):  SNMPv2-MIB-UDP
 LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */

И если бы это было всё, расшифровка статистки netstat могла быть такой:


переменная из netstat --> соответствующая ей строка из /proc:
* /proc/net/snmp
* /proc/net/netstat
* /proc/net/sctp/snmp
--> соответствующее RFC --> определение.

Однако, даже такой многоступенчатой расшифровки недостаточно, так как значительную часть snmp.h занимает загадочный Linux MIB, переменные которого ни в каком RFC не определены, и в Великом Словаре — MIB Database, их тоже нет.


/* linux mib definitions */
enum
{
    LINUX_MIB_NUM = 0,
    LINUX_MIB_SYNCOOKIESSENT,       /* SyncookiesSent */
    LINUX_MIB_SYNCOOKIESRECV,       /* SyncookiesRecv */
    LINUX_MIB_SYNCOOKIESFAILED,     /* SyncookiesFailed */
    LINUX_MIB_EMBRYONICRSTS,        /* EmbryonicRsts */
    LINUX_MIB_PRUNECALLED,          /* PruneCalled */
    LINUX_MIB_RCVPRUNED,            /* RcvPruned */
    LINUX_MIB_OFOPRUNED,            /* OfoPruned */
...
    LINUX_MIB_TCPMTUPSUCCESS,       /* TCPMTUPSuccess */
    __LINUX_MIB_MAX
};

Мы готовы к следующему этапу погружения, в следующей статье попытаемся выяснить, что скрывается за ошибками памяти буфера, и как в tcp коллапсируют нарушителей очереди .



  1. ↑ В реальной жизни, от английского in real life.
  2. ↑ Время жизни пакета, от английского time to live

Комментарии (0)

© Habrahabr.ru