Udp send error

Ниже — перевод статьи о проблеме работы с udp в сетевых приложениях. Переводчик позволил себе сменить примеры: в исходном тексте другие сетевые адреса и код на...

Время прочтения
6 мин

Просмотры 43K

image
Ниже — перевод статьи о проблеме работы с udp в сетевых приложениях. Переводчик позволил себе сменить примеры: в исходном тексте другие сетевые адреса и код на ruby. В переводе использован простенький скрипт на перле. Суть проблемы и решение от этого не меняются.
Кроме того, местами добавлены мои комментарии (в скобках, выделены курсивом).
Картинка для привлечения внимания взята из текста замечательной книги «learnyousomeerlang.com»

Тяжкая работа лёгких протоколов

Иногда начинает казаться, что протоколы без установки соединения не оправдывают всей той кутерьмы, которую вызывают.

Для примера разберём ситуацию с получением ответа, когда UDP датаграмма с начальным запросом посылается на дополнительный IP адрес на интерфейсе (alias или secondary IP).
Есть интерфейс eth1:

$ ip a add 192.168.1.235/24 dev eth1 && ip a ls dev eth1       
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:30:84:9e:95:60 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.47/24 brd 192.168.1.255 scope global eth1
    inet 192.168.1.235/24 scope global secondary eth1
    inet6 fe80::230:84ff:fe9e:9560/64 scope link 
       valid_lft forever preferred_lft forever

Как обычно выглядит код для получения пакета по udp? Ну, echo сервер может выглядеть как-то очень похоже на то, что под катом:

echo_server.pl

#!/usr/bin/perl
use IO::Socket::INET;

# flush after every write
$| = 1;

my ($socket,$received_data);
my ($peeraddress,$peerport);

$socket = new IO::Socket::INET ( 
    MultiHomed => '1',
    LocalAddr => $ARGV[0],
    LocalPort => defined ($ARGV[1])?$ARGV[1]:'5000',
    Proto => 'udp'
) or die "ERROR in Socket Creation : $! n";
print "Waiting for data...";
while(1)
{
$socket->recv($recieved_data,1024);
$peer_address = $socket->peerhost();
$peer_port = $socket->peerport();
chomp($recieved_data);
print "n($peer_address , $peer_port) said : $recieved_data";

#send the data to the client at which the read/write operations done recently.
$data = "echo: $recieved_datan";
$socket->send("$data");

}

$socket->close();

Это достаточно простой скрипт на перле, который покажет от кого пришёл udp пакет, содержимое пакета и отправит этот пакет обратно отправителю. Проще некуда. Теперь запустим наш сервер:

$ ./echo_server.pl
Waiting for data...

Посмотрим, что он слушает:

$ netstat -unpl | grep perl
udp        0      0 0.0.0.0:5000            0.0.0.0:*                           9509/perl

И после этого подключимся с удалённой машины к нашему серверу по основному IP:

-bash-3.2$ nc -u 192.168.1.47 5000
test1
echo: test1
test2
echo: test2

Как это выглядит в tcpdump’е на нашей машине (ну, или должно выглядеть):

-bash-3.2$ tcpdump -i eth1 -nn  port 5000
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
17:41:00.517186 IP 192.168.3.11.44199 > 192.168.1.47.5000: UDP, length 6
17:41:00.517351 IP 192.168.1.47.5000 > 192.168.3.11.44199: UDP, length 12
17:41:02.307634 IP 192.168.3.11.44199 > 192.168.1.47.5000: UDP, length 6
17:41:02.307773 IP 192.168.1.47.5000 > 192.168.3.11.44199: UDP, length 12

Просто фантастика — я отправляю пакет и получаю пакет обратно. В netcat’е мы получаем обратно что бы мы не напечатали (смешной эффект, если печатать «стрелочки»).

А теперь тоже самое на вторичный адрес на том же интерфейсе:

-bash-3.2$ nc -u 192.168.1.235 5000
test1
test2

Как это сумасшествие выглядит в tcpdump’е на этот раз:

-bash-3.2$ tcpdump -i eth1 -nn  port 5000
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
17:48:32.467167 IP 192.168.3.11.34509 > 192.168.1.235.5000: UDP, length 6
17:48:32.467292 IP 192.168.1.47.5000 > 192.168.3.11.34509: UDP, length 12
17:48:33.667182 IP 192.168.3.11.34509 > 192.168.1.235.5000: UDP, length 6
17:48:33.667332 IP 192.168.1.47.5000 > 192.168.3.11.34509: UDP, length 12

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

То что происходит, на первый взгляд кажется полным бредом. Но на самом деле, это обычный дефект для протокола без установки сессии, такого как UDP. Видите ли, наш сокет слушает любой адрес, (пустой параметр LocalAddr при создании сокета передаётся системе как адрес вида «0.0.0.0», любой доступный, что заставляет сокет слушать на всех доступных адресах. И нет, я тоже не знаю, почему это так. Это не особенно интуитивное действие). Когда мы получаем пакет в нашем приложении с помощью socket->recv(), мы не получаем информации о том, на какой конкретно адрес был послан пакет. Мы лишь знаем, что операционная система решила, что пакет был для нас (вот вам и инкапсуляция). Всё что мы знаем, это откуда пакет пришёл к нам. И из-за того, что ядро не хранит никакой информации о соединениях для сокета (ядро штука логичная, просили без соединений — будет без соединений), когда приходит время отправлять пакет обратно, всё что мы можем сообщить это «куда» отправить пакет. (В перле это делается в неявном виде. С объектом $socket связаны адрес и порт отправителя датаграммы, так что в вызове send его указывать не надо).
Но настоящая мозголомка начинается, когда мы пытаемся проставить адрес отправителя в ответной датаграмме. Ещё раз: ядро не хранит никакой информации об отправителе или получателе, так как мы работаем без соединений. И посколько мы слушаем «любой» интерфейс, операционная система думает, что у неё есть карт-бланш на отправку пакета с того адреса, который ей «по душе». В линуксе, похоже, выбирается основной адрес того интерфейса, с которого пакет будет отправлен. (А на самом деле, адрес определяется в соответсвии с RFC1122, 3.3.4.2 «Multihoming Requirements», по таблице маршрутизации — примечание переводчика). Так что для распространнёного случая «один адрес — один интерфейс» — всё работает. Но как только дело доходит до менее распространённых ситуаций, начинают проявляться нюансы.
Решение в том, чтобы создавать сокеты слушающие конкретные адреса. И отправлять пакет с этих сокетов: ядро будет знать, с какого адреса вы хотите отправлять пакеты и всё будет отлично. Выглядит достаточно просто, ага? Ну и естественно, любое вменяемое сетевое приложение уже так делает, ага? Так что очевидно, что реализация UDP в Ruby просто дерьмо(в оригинале исходники на руби, — примечание переводчика;). Именно так я подумал в начале, и не виню вас, если вы подумали так же. Но пока РУБИкон войны с авторами Ruby’ового UDPSocket’а не перейдён, давайте проведём небольшой эксперимент с другими часто используемыми приложениями. Например, SNMPd. Демон из пакета net-snmpd в убунте подвержен той же проблеме, что и наше тестовое приложение выше. Не похоже, что это какие-то новые грабли, на которые только наступили и рассыпались кучей патчей для испрвалений.
Так что в целом, все страдают одной и той же «болезнью». Под «всеми» подразумевается «некоторые UDP сервера». Есть некоторое количество ПО, которое не подвержено подобной проблеме с алиасами на интерфейсах. На ум сразу приходит Bind и NTPd работает нормально, если запущен после того, как вы сконфигурировали все интерфейсы. В чём же разница? Разница в том, что эти сервисы несколько «умнее» и биндятся на все адреса в системе по отдельности. На примере bind’а:

$ netstat -lun |grep :53
 udp        0      0 192.168.1.47:53          0.0.0.0:*                          
 udp        0      0 192.168.1.47:53          0.0.0.0:*                          
 udp        0      0 127.0.0.1:53             0.0.0.0:*  

Это очень круто и решает проблему. Исключение составляет ситуация, когда вы добавляете лишний алиас уже после того, как демон стартовал. Bind не подцепит новый адрес и вам придётся рестартовать сервер. Кроме того, это несколько усложняет код, так как вам приходится как ладить с кучей сокетов внутри программы (например, использовать select() вместо простого блокирования на попытке приёма.) В общем-то, никто не любит лишних сложностей, но с этой можно справится. Однако, настоящая проблема это правило «не добавляйте адресов после старта демона». Необходимость проверять, не добавилось ли в системе ip-адресов, и рестартовать службу после добавляения адреса станет настоящей проблемой.
Однако, есть некоторый workaround и для этой проблемы. Здесь мы вспомним про ntpd. Порты, которые слушает он, выглядят следующим образом:

$ netstat -nlup | grep 123
udp        0      0 192.168.1.235:123       0.0.0.0:*                                    
udp        0      0 192.168.1.47:123        0.0.0.0:*                                          
udp        0      0 127.0.0.3:123           0.0.0.0:*                                         
udp        0      0 127.0.0.1:123           0.0.0.0:*                                          
udp        0      0 0.0.0.0:123             0.0.0.0:* 
udp6       0      0 fe80::230:84ff:fe9e:123 :::*                                              
udp6       0      0 ::1:123  

NTPd слушает каждый адрес в отдельности и дополнительно слушает на любом адресе, доступном системе. Я не знаю точно, зачем это нужно. Если просто слушать на каждом адресе в отдельности, то всё будет хорошо, как в случае с байндом. Но если вы добавляете ещё один адрес на интерфейс после старта ntpd, то начинает проявляться та же самая проблема, что и в случае с udp-echo-сервером. Так что я не думаю, что слушание на «любом» интерфейсе даёт какой либо плюс. Однако, это заставляет ntpd вести себя несколько отлично от Bind’а: когда вы посылаете пакет на интерфейс, добавляенный после старта Bind’а, то он просто игнорирует вас (у него нет сокета, который бы слушал ваши запросы). Ntpd же пытается отправить ответ и страдает от проблемы неправильного адреса в ответах. (Зато можно менять primary адреса на интерфейсах и создавать новые интерфейсы, примечание переводчика).

На текущий момент, лучшим решением кажется следовать пути Bind’а и ntpd и слушать на всех адреса в отдельности с «фокусом» от ntpd: слушать дополнительно и на 0.0.0.0. При этом, если я получил пакет на 0.0.0.0, то надо запускать сканирования доступных в системе адресов и биндится дополнительно и на них. Это должно решить проблему.
Осталось только заставить это работать (и решить кучу проблем, которые наверняка вылезут на пути). Пожелайте мне удачи. Крики боли и мучений которые вы слышите (не имеет значение, где вы находитесь) наверняка мои.

UPD: в комментариях появилось интересное пояснение от Quasar_ru. Всё таки реализация UDP в скриптовых языках неоднозначна: на чистом С можно написать такое клиентское приложение, которое сможет принять ответ от сервера с другого адреса. Польза от такой реализации — спорная, но всё же реализация возможна.

sd43065

OpenVpn Newbie
Posts: 2
Joined: Sun Jul 13, 2014 2:55 pm

Connection keeps dropping with «UDP send error»

I’m new to OpenVPN.

I already set up 2 OpenVPN servers on 2 Windows boxes and another 2 on Debian systems (one is a standalone box, the other runs in VirtualBox hosted in a Windows box).

I’m using OpenVPN Connect for Android to test server connections. It connects to those 2 in Windows boxes fine.

But it could not hold the connection with both Debian servers. Connection keeps dropping every 5 to 15 seconds.

I checked server log and could not see anything outstanding at all (no error or warning or anything). But on Android device, I could see the following sequence:

Code: Select all

......
... EVENT: CONNECTED info=...
... UDP send error: send: invalid argument
... EVENT: PAUSE trans=TO_DISCONNECTED
... EVENT: RESUME
... EVENT: RECONNECTING
......

I already googled for this error and failed to anything meaningful. So I readlly have no idea where to start to resolve this issue.

Any help would be greatly appreciated.


ufergus

OpenVpn Newbie
Posts: 3
Joined: Fri Jul 25, 2014 12:57 pm

Re: Connection keeps dropping with «UDP send error»

Post

by ufergus » Fri Jul 25, 2014 1:00 pm

I can’t confirm the Windows part of the post, but I am experiencing the same behavior connecting to a debian server from my nexus 5. I can connect just fine, but after transferring a small amount of data my connection will drop out. I tried upgrading the server verison to 2.3.2 via wheezy-backports but there was no change in behavior. Any ideas?


sd43065

OpenVpn Newbie
Posts: 2
Joined: Sun Jul 13, 2014 2:55 pm

Re: Connection keeps dropping with «UDP send error»

Post

by sd43065 » Fri Jul 25, 2014 1:32 pm

Hi, ufergus,

I’m still waiting for a solution or at least a way to test/diagnose the problem.

My OpenVPN servers are all on my home network. And I only have a Samsung S4 phone with OpenVPN Connect to test their connection through 4G.

With my Debian servers, I never get a chance to do any file transfer since connection gets dropped so often. However, I could browse some web pages while connected. So I believe my server configuration should be mostly correct.

When connected to servers running on Windows, it’s quite stable with no frequent drops.

I originally thought, setting up and running OpenVPN on Linux should be easier than on Windows. Or at least it should provide more meaningful clue about connection issue.

The problem might very well be on the server side (need to tweak the configuration or something?). But since I only have OpenVPN Connect for testing connection and only it shows «UDP send error», I posted it here. Maybe I should have this posted on OpenVPN server forum instead.


ufergus

OpenVpn Newbie
Posts: 3
Joined: Fri Jul 25, 2014 12:57 pm

Re: Connection keeps dropping with «UDP send error»

Post

by ufergus » Tue Jul 29, 2014 12:05 am

I did some testing with an mssfix value of 1300. It did improve my throughput but I still experienced the disconnect. The other thing I noticed was my 3G icon, which indicates a data connection, also disappears when I experience the disconnect. I am thinking the phone is dropping the data connection for some reason and OpenVPN then gets the UDP send error. What I don’t understand is why the phone is dropping an active data connection. I know the nexus 5 uses a signal transmission path and periodically disconnects to scan for LTE but I wouldn’t expect this to happen while a transfer is active. Maybe it only monitors tcp connections? What provider do you use?


ufergus

OpenVpn Newbie
Posts: 3
Joined: Fri Jul 25, 2014 12:57 pm

Re: Connection keeps dropping with «UDP send error»

Post

by ufergus » Wed Jul 30, 2014 9:34 pm

I was able to do a little more testing. I first put my phone in 3G mode, which ‘should’ prevent it from dropping a connection and searching for LTE. This did not change the disconnect behavior. I next did some testing in an area with an LTE signal. When connected to LTE, I did not experience the disconnect. I was able to load many webpages and even streamed a bit of netflix without an issue.


ОБЗОР

#include <sys/socket.h>

#include <netinet/in.h>

#include <netinet/udp.h>

udp_socket = socket(AF_INET, SOCK_DGRAM, 0);

ОПИСАНИЕ

Это реализация протокола пользовательских датаграмм (User Datagram Protocol,
UDP), который описан в RFC 768. Он обеспечивает ненадежную передачу
датаграмм без установления соединения. При пересылке пакеты могут
дублироваться, а их порядок может быть нарушен. UDP генерирует и проверяет
контрольные суммы, чтобы отловить ошибки передачи.

При создании UDP-сокета его локальный и удалённый адрес не
указываются. Датаграммы могут быть посланы немедленно с помощью sendto(2)
или sendmsg(2) с правильным адресом назначения в качестве
аргумента. Когда для сокета вызывается connect(2), то устанавливается
адрес назначения по умолчанию и с этого момента датаграммы могут отсылаться
с помощью send(2) или write(2) без указания адреса назначения. При
этом всё ещё сохраняется возможность послать пакет другому адресату,
передавая его адрес через вызовы sendto(2) или sendmsg(2). Для
получения пакетов сокет сначала можно привязать к локальному адресу с
помощью bind(2). В противном случае сокетный уровень автоматически
присвоит свободный локальный порт из диапазона, заданного в
/proc/sys/net/ipv4/ip_local_port_range, и привяжет сокет к INADDR_ANY.

Все операции приёма возвращают только один пакет. Если пакет меньше, чем
размер буфера приема, то он возвращается целиком; если пакет больше, то он
обрезается и устанавливается флаг MSG_TRUNC. Флаг MSG_WAITALL не
поддерживается.

Параметры IP могут быть посланы или получены при помощи параметров сокета,
описанных в ip(7). Они обрабатываются ядром, только если включён
соответствующий параметр в /proc (но даже если он отключен, параметры всё
равно передаются пользователю). Смотрите ip(7).

Если при отсылке установлен флаг MSG_DONTROUTE, то адрес назначения
должен указывать на адрес локального интерфейса, и пакеты посылаются только
на этот интерфейс.

По умолчанию, Linux UDP выполняет обнаружение MTU (Maximum Transmission
Unit) пути. Это означает, что ядро будет следить за MTU до IP-адреса
назначения и возвращать EMSGSIZE, если запись пакета UDP превысит это
значение. Когда это происходит, приложение должно уменьшить размер
пакета. Также обнаружение MTU пути можно выключить с помощью параметра
сокета IP_MTU_DISCOVER или в файле /proc/sys/net/ipv4/ip_no_pmtu_disc;
подробней смотрите в ip(7). При отключении обнаружения UDP фрагментирует
исходящий пакет, если его общий размер превышает MTU интерфейса. Однако по
соображениям производительности и надёжности отключение не рекомендуется.

Формат адреса

В UDP используется формат адреса IPv4 sockaddr_in, который описан в
ip(7).

Обработка ошибок

Все критические ошибки передаются пользователю в виде кода ошибки, который
возвращается, даже если сокет не был соединен. Это относится также и к
асинхронным ошибкам, при работе с сетью. Вы можете получить ошибку,
относящуюся к предыдущим пакетам, посланным на том же сокете. Такое
поведение отличается от поведения многих других реализаций BSD-сокетов,
которые никогда не передают коды ошибок, если на сокете не установлено
соединение. Поведение Linux в этом случае соответствует RFC 1122.

Для совместимости со старым кодом в Linux 2.0 и 2.2 можно установить
параметр SOL_SOCKET равным SO_BSDCOMPAT, чтобы получать ошибки при
работе с сетью, только если сокет был соединён (кроме ошибок EPROTO и
EMSGSIZE). Ошибки, возникшие локально, передаются всегда. Поддержка
данного параметра сокета была удалена в более новых ядрах; подробней
смотрите в socket(7).

Если включён параметр IP_RECVERR, то все ошибки хранятся в очереди ошибок
сокета и могут быть получены с помощью вызова recvmsg(2) с установленным
флагом MSG_ERRQUEUE.

Интерфейс /proc

Системные настройки параметров UDP доступны через файлы в каталоге
/proc/sys/net/ipv4/.

udp_mem (начиная с Linux 2.6.25)
Вектор из трёх значений, управляющий количеством страниц, выделенных для
очереди под все сокеты UDP.

min
При значении ниже этого количества страниц UDP не беспокоится о том, как
потребляется память. Когда количество памяти, выделенной для UDP, превышает
это значение, UDP начинает регулировать расход памяти.
pressure
Формат этого значения совпадает с tcp_mem (смотрите tcp(7)).
max
Количество страниц, выделенных для очереди под все сокеты UDP.
Значения по умолчанию этих трёх параметров вычисляются при запуске ОС исходя
из количества имеющейся памяти.
udp_rmem_min (integer; значение по умолчанию: PAGE_SIZE; начиная с Linux 2.6.25)
Минимальный размер (в байтах) буферов приёма, используемых сокетами UDP в
режиме регулирования. Каждый сокет UDP может использовать этот объём
принимаемых данных, даже если общее количество страниц сокетов UDP превышает
ограничение udp_mem.
udp_wmem_min (integer; значение по умолчанию: PAGE_SIZE; начиная с Linux 2.6.25)
Минимальный размер (в байтах) буферов отправки, используемых сокетами UDP в
режиме регулирования. Каждый сокет UDP может использовать этот объём
отправляемых данных, даже если общее количество страниц сокетов UDP
превышает ограничение udp_mem.

Параметры сокета

Для получения и задания параметров сокетов UDP используйте вызовы
getsockopt(2) и setsockopt(2), соответственно. Значение аргумента
уровня параметров должно быть равно IPPROTO_UDP. Если не указано
обратного, значение optval является указателем на int.

UDP_CORK (начиная с Linux 2.5.44)
Если этот параметр установлен, то все выходные данные сокета накапливаются в
одной датаграмме, которая отправляется после того, как параметр
сбрасывается. Данный параметр не должен использоваться в переносимом коде.

Вызовы ioctl

Данные ioctl доступны через вызов ioctl(2). Синтаксис:

int value;
error = ioctl(udp_socket, ioctl_type, &value);
FIONREAD (SIOCINQ)
В качестве параметра ожидается указатель на integer. Возвращает размер (в
байтах) следующей ожидающей датаграммы, помещая его по указанному адресу,
или 0, если нет ожидающей датаграммы. Предупреждение: при использовании
FIONREAD невозможно понять, есть ли ожидающие датаграммы или просто
следующая датаграмма не содержит данных. В этих случаях безопасней
использовать select(2), poll(2), или epoll(7).
TIOCOUTQ (SIOCOUTQ)
Возвращает количество байт данных в локальной очереди
отправки. Поддерживается только в Linux 2.4 и выше.

Дополнительно поддерживаются все ioctl, описанные в ip(7) и socket(7).

ВЕРСИИ

Параметр IP_RECVERR появился в Linux 2.2.

https://cizixs.com/2018/01/13/linux-udp-packet-drop-debug/

Эта ссылка на статью

Недавно я встретил серверную заявку UDP потери пакетов. Я провел много информации во время процесса расследования. Я в основном использую TCPDUMP для захвата во всех аспектах проблемы. Проанализировать в этой ссылке. Вопрос, предназначенный для устранения неполадок проблем, нажимает Болезнь, и, наконец, проблема может быть решена. Однако эта ситуация заключается в том, что проблема самой службы, если это экологическая проблема, операционная система и даже проблемы с аппаратными средствами, она может не быть в состоянии решить проблемы с самого обслуживания, но эта статья будет иметь другой подход, от Внешний экологический анализ причины, после прочтения, это очень полезно, некоторые главы были изменены к исходному тексту и поделитесь его для большего количества людей.


Прежде чем начать, давайте будем использовать диаграмму, чтобы объяснить процесс получения сетевых пакетов в системе Linux.

  1. Во-первых, веб-пакет отправляется в NIC через физический сетевой кабель.

  2. Драйвер сети считывает пакеты в сети для кольца буфера, этот процесс использует DMA (прямой доступ к памяти), не участие ЦП

  3. Ядро читает сообщение из кольцевого буфера для выполнения логики слоев IP и TCP / UDP и, наконец, поместите сообщение в буфер приложения.

  4. Приложение обрабатывается из буфера сокета

Во время приема пакетов UDP любая из процессов может быть отброшена или пассивно, поэтому потеря пакета может происходить в NIC и DRIVE, или может происходить в системах и приложениях.

Причина, по которой нет анализа для отправки процесса данных, один состоит в том, что процесс передачи аналогичен, но направление обращается к обращению; вероятность того, что потеря пакета передачи является небольшим, только когда скорость нанесения, отправленная приложением, является больше Чем частота обработки ядра и сетевой карты произойдет.

Эта статья предполагает, что только одно имяeth0Интерфейс, если есть несколько имен интерфейса или интерфейса, а не ETH0, следуйте фактической ситуации.

Примечание:RX(Прием) означает получение пакета,TX(Передача) означает отправку сообщения.

Убедитесь, что есть потеря пакета UDP

Чтобы увидеть, имеет ли NIC пакет, вы можете использоватьethtool -S eth0Вид, ищите на выходеbadИли жеdropЕсть ли соответствующее поле данных, в обычном случае числа, соответствующие этим полям, должны быть 0. Если вы видите соответствующий номер, вы объясните, что у NIC есть пакет.

Другая команда для просмотра данных потери пакета сетиifconfigЭто будет иметь его в своем выходеRX(Получить приемный пакет) иTX(Передача отправка пакета) Статистика:

[[email protected] ng]# ifconfig enp1
enp2s0f1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 04:b0:e7:fa:75:9d  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device memory 0x92200000-922fffff

Кроме того, система Linux также обеспечивает информацию о потерях пакетов для каждого сетевого протокола, который можно использовать.netstat -sКоманда представления, плюс--udpВы можете посмотреть только на сообщения сообщения, связанные с UDP:

[[email protected] ng]# netstat -s -u
IcmpMsg:
    InType0: 17
    InType3: 75
    InType8: 77
    OutType0: 77
    OutType3: 692
    OutType8: 249
Udp:
    5728807 packets received
    12 packets to unknown port received.
    0 packet receive errors
    982710 packets sent
    0 receive buffer errors
    0 send buffer errors
UdpLite:
IpExt:
    InNoRoutes: 3
    InBcastPkts: 497633
    InOctets: 1044710406807
    OutOctets: 17460621991142
    InBcastOctets: 114600482
    InNoECTPkts: 2886955071


Для вышеуказанного выхода обратите внимание на следующую информацию, чтобы просмотреть случай, когда пакет UDP:

  • packet receive errorsНе пусто, и в течение длительного времени система имеет удр пакетов UDP

  • packets to unknown port receivedЦелевой порт, указывающий, что сообщение UDP, полученное системой, не используется в прослушивании. Обычно это вызвано услугой без запуска и не вызывает серьезных проблем.

  • receive buffer errorsУказывает, что количество потери пакетов вызвано, потому что приема UDP слишком мала.

NOTEНе количество потери пакета не равно нулю, для UDP, если существует небольшое количество потери пакета, вероятно, ожидаемое поведение, такое как скорость потерь пакетов (количество пакетов для пакетов / приема), составляет один миллион еще меньше.

Ник или привод потеря пакета

Я сказал раньше, еслиethtool -S eth0Посерединеrx_***_errorsТогда это, вероятно, проблема с сетевой картой, вызывая терять пакет, вам необходимо связаться с сервером или поставщиком сетевого карта для обработки.

[[email protected] ng]# ethtool -S enp1 | grep rx_ | grep errors
     rx_crc_errors: 0
     rx_missed_errors: 0
     rx_long_length_errors: 0
     rx_short_length_errors: 0
     rx_align_errors: 0
     rx_errors: 0
     rx_length_errors: 0
     rx_over_errors: 0
     rx_frame_errors: 0
     rx_fifo_errors: 0


netstat -iОн также доступен для приемных пакетов каждого NIC и корпус потери пакетов, а ошибка или падение должны быть 0 на выходе.

Если аппаратное обеспечение или драйвер не проблема, общая сетевая карта теряется, потому что набор буфер слишком мал, вы можете использоватьethtoolКоманда для просмотра и настройки кольцевого буфера для сети.

ethtool -gВы можете просматривать кольцевой буфер сетевой карты, такой как пример ниже.

[[email protected] ng]# ethtool -g enp1
Ring parameters for enp2s0f1:
Pre-set maximums:
RX:    4096
RX Mini:  0
RX Jumbo:  0
TX:    4096
Current hardware settings:
RX:    256
RX Mini:  0
RX Jumbo:  0
TX:    256


Предварительный набор представляет наибольшее значение буфера кольца NIC, вы можете использоватьethtool -G eth0 rx 8192Установите его значение.

Linux System потери пакета

Существует много причин для потери пакета Linux System, общие: пакеты UDP, брандмауэр, размер буфера UDP, системные нагрузки высоки, и эти причины потери пакета анализируются.

Ошибка пакета UDP

Если пакет UDP модифицирован во время передачи, ошибка контрольной суммы или ошибка длины, Linux проверяет это, когда сообщение UDP получено, и сообщение будет отброшено после того, как изобретение будет отказаться от сообщения.

Если вы хотите контрольную сумму UDP пакета, вы должны отправить его в свое приложение вовремя, вы можете проверить проверку контрольной суммы UDP в параметре сокетов.

Брандмауэр

Если система брандмауэра потери пакета, поведение производительности, как правило, все, как правило, все пакеты UDP, и, безусловно, не исключают возможности только брандмауэра только падать.

Если вы столкнулись с множеством соотношения убытков пакетов, сначала проверьте правила брандмауэра и убедитесь, что брандмауэр не активно падает пакеты UDP.

Размер буфера UDP

После того, как система Linux принимает сообщение, система Linux сохранит пакет в область кэша. Поскольку размер кэша ограничен, если пакет UDP слишком велик (превышает размер кэша или размер MTU), скорость получения сообщения слишком быстро, что может привести к тому, что Linux пакет находится непосредственно с помощью кэша.

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

  • / proc / sys / net / core / rmem_max: разрешено принять максимум буфера

  • / proc / sys / net / core / rmem_default: Получить значение буфера, используемое по умолчанию

  • / proc / sys / net / core / wmem_max: максимальное значение разрешено быть установленным

  • / proc / sys / net / core / wmem_dafault: максимальное значение, используемое по умолчанию

Однако эти начальные значения не должны устранять пакеты UDP большого потока. Если приложение получает и отправляет UDP-сообщения, необходимо сказать это значение. можешь использовать sysctlКоманда позвольте вступить в силу немедленно:

[root @ k8s-master ~] # sysctl -w net.core.rmem_max = 26214400 # установлен на 25 м
net.core.rmem_max = 26214400

Также может быть изменено/etc/sysctl.confСоответствующие параметры позволяют параметрам вступать в силу на следующем запуске.

Если пакет слишком велик, отправитель может разделить данные, чтобы гарантировать, что размер каждого сообщения находится в MTU.

Другой параметр, который можно настроить, этоnetdev_max_backlogОн указывает на то, что ядро ​​Linux читает номер пакета после прочтения сообщения от драйвера сети, по умолчанию составляет 1000, что может быть защищено, например, установлено на 2000:

[[email protected] ~]# sudo sysctl -w net.core.netdev_max_backlog=2000
net.core.netdev_max_backlog = 2000
[[email protected] ~]#

Системная нагрузка слишком высока

System CPU, память, нагрузка на io наполнено, чтобы вызвать потеря сетевой пакеты, такой как CPU, если нагрузка слишком высока, система не успевает сделать сообщение, копировать память и т. Д. Потеря пакета; Память нагрузка слишком высока, приложение слишком медленно, и сообщение не может быть обрабатывается во времени; если нагрузка на io слишком высока, процессор используется для ответа на IO ждать, нет времени для обработки UDP пакеты в кеше.

Сама система Linux является взаимосвязанной системой, и любой компонент может повлиять на нормальную работу других компонентов. Для системы нагрузки слишком высоки, или если есть проблема с приложением, или система недостаточна. Для прежних потребностей, отладки и ремонта; для последнего, также можно найти и расширяться во времени.

Применяемый

Размер буфера UDP системы упоминается выше, параметр регулировки SYSCTL — это просто максимальная допустимая система, каждое приложение должно устанавливать значение размера буфера сокета при создании сокета.

Система Linux поставит принятые пакеты в буфер сокета, а приложение постоянно читает пакеты из буфера. Таким образом, есть два и приложения, связанные с приложениями, которые влияют на размер размера буфера разъема и приложение прочитал пакет.

В течение первого вопроса вы можете установить размер буфера приема розетки, когда приложение инициализирует сокет, например, следующий код устанавливает буфер сокета до 20 МБ:

uint64_t receive_buf_size = 20*1024*1024;  //20 MB
setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &receive_buf_size, sizeof(receive_buf_size));

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

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

Другим фактором является применение скорости пакетов в буфере. Для приложений пакеты обработки должны принимать асинхронный путь.

Где пакет?

Если вы хотите узнать больше о том, какая функция брошена, вы можете использовать ее.dropwatchИнструменты, оно слушает информацию о потерях системной пакеты и распечатает адрес функции пакета из пакета:

# dropwatch -l kas
Initalizing kallsyms db
dropwatch> start
Enabling monitoring...
Kernel monitoring activated.
Issue Ctrl-C to stop monitoring


1 drops at tcp_v4_do_rcv+cd (0xffffffff81799bad)
10 drops at tcp_v4_rcv+80 (0xffffffff8179a620)
1 drops at sk_stream_kill_queues+57 (0xffffffff81729ca7)
4 drops at unix_release_sock+20e (0xffffffff817dc94e)
1 drops at igmp_rcv+e1 (0xffffffff817b4c41)
1 drops at igmp_rcv+e1 (0xffffffff817b4c41)

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

TCPDUMP -I Имя сетевого интерфейса UDP Port 2020 -S0 -xx -nn

Кроме того, вы также можете использовать инструмент Linux Perf для прослушиванияkfree_skb(Когда сетевое сообщение отбрасывается, функция будет называться) инцидент:

sudo perf record -g -a -e skb:kfree_skb
sudo perf script


Об использовании и интерпретации Perf Commands, есть много статей в Интернете.


подводить итоги

  • Сам UDP является неисправным протоколом, который применим к сценарию пакетов и не влияет на состояние программы, например видео, аудио, игру, мониторинг и т. Д. Приложения, которые являются относительно высокими в надежности пакетов, не используют UDP, и рекомендуется использовать TCP напрямую. Конечно, вы также можете попробовать еще раз в слое приложений, чтобы обеспечить надежность

  • Если сервер обнаружен, сначала монитор нагрузки системы слишком высока, затем найдите нагрузку, чтобы уменьшить нагрузку и проиграть проблему исчезнула.

  • Если система нагрузки слишком высока, потеря пакета UDP не является эффективным решением. Если исключение приложения вызывает процессор, память, IO, своевременное расположение исключений и исправлений и исправлений; если недостаточно, мониторинг должен иметь возможность обнаружить и быстро расширяться во времени

  • Для системы большого количества приемных или отправки пакетов UDP вы можете уменьшить вероятность потери пакетов, регулируя размер буфера сокета системы и программы.

  • Когда приложение имеет дело с пакетами UDP, не имеют слишком много логики обработки между приемными сообщениями дважды.

рекомендую:


Базовые знания популяризации — инструмент захвата сети (TCPDUMP)

Сообщение с раздвижным окном TCP


Обратите внимание или «смотреть», искренняя благодарность!

    msm.ru

    Нравится ресурс?

    Помоги проекту!

    >
    send udp — ICMP error..

    • Подписаться на тему
    • Сообщить другу
    • Скачать/распечатать тему



    Сообщ.
    #1

    ,
    23.06.14, 18:09

      Senior Member

      ****

      Рейтинг (т): 17

      Вопрос таков.
      Есть сервер, с которого к клиенту валит трафик по UDP
      Банальным sendto

      ExpandedWrap disabled

        res = ::sendto(socket, data, data_length, 0, reinterpret_cast<sockaddr*>(&dst), sizeof(dst));

      идет передача, sendto возвращает количество байт, все шоколадно.
      Далее. Делаем клиенту kill -9
      Смотрим на происходящее в канале сниффером и наблюдаем, что трафик продолжает идти..
      Но при этом (внимание!!) С маршрутизатора, а говоря проще с моего мирового айпишника на мой локальный (192.168 … ) валит ICMP трафик,

      Цитата

      Internet Control Message Protocol
      Type: 3 (Destination unreachable)
      Code: 3 (Port unreachable)

      при этом sendto отчитывается о том что у него все нормально и вся дата отправляется в полном объеме,
      errno тоже success.
      Как ловить событие отваливания клиента ?
      Да, все безобразие происходит на ubuntu server


      Хрен



      Сообщ.
      #2

      ,
      23.06.14, 18:49

        Цитата nemez @ 23.06.14, 18:09

        Как ловить событие отваливания клиента ?
        Да, все безобразие происходит на ubuntu server

        Это же UDP, там нет соединения, подтверждения доставки, периодической проверки связи и т.д.
        Так что надо вручную реализовать подтверждение доставки, либо, если допустима потеря нескольких пакетов, сделать контрольные проверочные пакеты периодические, на которые от клиента должен будет прийти ответ.


        nemez



        Сообщ.
        #3

        ,
        23.06.14, 18:59

          Senior Member

          ****

          Рейтинг (т): 17

          Да ладно нету контроля
          вот дамп
          http://s019.radikal.ru/i618/1406/48/ef41ebe48822.jpg
          сверху UDP трафик, снизу — ICMP датаграмма, которая каждый из пакетов, отправляемых в никуда, дублирует вместе с заголовком.
          Система об этом знает и сокеты должны реагировать

          Сообщение отредактировано: nemez — 23.06.14, 19:01


          Хрен



          Сообщ.
          #4

          ,
          23.06.14, 19:08

            Цитата nemez @ 23.06.14, 18:59

            сверху UDP трафик

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

            Цитата nemez @ 23.06.14, 18:59

            снизу — ICMP датаграмма

            Не имеющая к UDP протоколу никакого отношения :)

            Цитата nemez @ 23.06.14, 18:59

            Система об этом знает и сокеты должны реагировать

            Система и сокеты не должны реагировать, т.к. UDP — протокол без подтверждения, контроля очерёдности и установления соединения.

            Добавлено 23.06.14, 19:11

            Цитата Хрен @ 23.06.14, 19:08

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

            Тут ошибся немного. ICMP приходит отправляющей стороне как информирование о недоступности адресата, но ICMP не попадает на UDP’шный сокет, т.к. он не имеет к нему никакого отношения.

            Добавлено 23.06.14, 19:15
            Если помнишь, в асько-клиентах (в частности в Миранде) был флажок «посылать контрольные пакеты серверу». Если его не установить, то клиент очень долго после фактического дисконнекта мог не знать о пропаже сервера и слать сообщения вникуда. Естественно, после этого они пропадали. Собственно, это из той же оперы — ICQ работает поверх UDP протокола.


            nemez



            Сообщ.
            #5

            ,
            23.06.14, 22:09

              Senior Member

              ****

              Рейтинг (т): 17

              Цитата

              Не имеющая к UDP протоколу никакого отношения

              еще и как имеющая — по крайней мере заголовок исходного UDP пакета в ней присутствует!

              Цитата

              но ICMP не попадает на UDP’шный сокет

              а ему туда попадать не надо — по факту таких передач должен быть получен код возврата соответствующий и при помощи errno получить код ошибки, который скажет, что ошибка либо в отвале клиента, либо во фрагментации, либо закрытом порту.
              Если такой трафик пришел, то сокет должен эту тему отработать. По крайней мере для этого есть все предпосылки.
              Да и на худой конец можно подвязать libpcap или некую ерунду на raw sockets, и это событие перехватить.
              Но хочется все сделать через систему. Только не знаю как.

              Добавлено 23.06.14, 22:10

              Цитата

              асько-клиентах (в частности в Миранде)

              ну это совсем не показатель — их писали кто попало левой ногой. Потому эта вся аська и накрылась медным тазом


              nemez



              Сообщ.
              #6

              ,
              24.06.14, 14:44

                Senior Member

                ****

                Рейтинг (т): 17

                и вот что пишет великая камасутра

                Цитата

                SO_BSDCOMPAT
                Enable BSD bug-to-bug compatibility. This is used by the UDP protocol module in Linux 2.0
                and 2.2. If enabled ICMP errors received for a UDP socket will not be passed to the user
                program.
                In later kernel versions, support for this option has been phased out: Linux 2.4
                silently ignores it, and Linux 2.6 generates a kernel warning (printk()) if a program uses
                this option. Linux 2.0 also enabled BSD bug-to-bug compatibility options (random header
                changing, skipping of the broadcast flag) for raw sockets with this option, but that was
                removed in Linux 2.2.


                Хрен



                Сообщ.
                #7

                ,
                24.06.14, 19:27

                  Цитата nemez @ 23.06.14, 22:09

                  Если такой трафик пришел, то сокет должен эту тему отработать. По крайней мере для этого есть все предпосылки.

                  Специально полистал первоначальный (1981 год) стандарт на эту тему. Именно первоначальный, т.к. сокеты были сделаны в 1983-м, и с того времени не менялись.
                  Дык вот…

                  Цитата

                  If, according to the information in the gateway’s routing tables, the network specified in the internet destination field of a datagram is unreachable, e.g., the distance to the network is infinity, the gateway may send a destination unreachable message to the internet source host of the datagram. In addition, in some networks, the gateway may be able to determine if the internet destination host is unreachable. Gateways in these networks may send destination unreachable messages to the source host when the destination host is unreachable.

                  If, in the destination host, the IP module cannot deliver the datagram because the indicated protocol module or process port is not active, the destination host may send a destination unreachable message to the source host.

                  Another case is when a datagram must be fragmented to be forwarded by a gateway yet the Don’t Fragment flag is on. In this case the gateway must discard the datagram and may return a destination unreachable message.

                  Вобщем, в этой версии маршрутизаторы не обязывают слать это подтверждение. Только уже позже, когда API сокетов было сформировано, «may» заменили на «should», а потом уже и на «must». Скорее всего, поэтому они и не умеют определять без ядерных костылей, о которых ты написал в последнем посте.
                  Но я смотрю, поведение этого костыля меняется от версии к версии ядра, не понятно вообще, как оно ведёт себя в 3-й версии, и уж тем более это сделает твою прогу непереносимой на другие платформы. Так что я бы эту опцию не использовал, а добавил в протокол периодические проверочные посылки.

                  Цитата nemez @ 23.06.14, 22:09

                  ну это совсем не показатель — их писали кто попало левой ногой. Потому эта вся аська и накрылась медным тазом

                  Аська накрылась не поэтому :)


                  Oleg2004



                  Сообщ.
                  #8

                  ,
                  24.06.14, 20:37

                    Во первых по поводу kill-9
                    Смотрите здесь
                    Не рекомендуют. Но это по большому счету к проблеме мало.

                    Цитата Хрен @ 23.06.14, 19:08

                    ICMP приходит отправляющей стороне как информирование о недоступности адресата, но ICMP не попадает на UDP’шный сокет, т.к. он не имеет к нему никакого отношения.

                    Совершенно справедливо. ICMP — к UDP-сокету не имеет никакого отношения.
                    Если нет RAW-сокета, куда модуль ICMP может послать свой пакет, то его путь заканчивается в стеке на сетевом уровне.

                    Цитата nemez @ 23.06.14, 22:09

                    Если такой трафик пришел, то сокет должен эту тему отработать. По крайней мере для этого есть все предпосылки.

                    Ваш UDP сокет описан как SOCK_DGRAM…
                    И никакого отношения к IPPROTO_ICMP

                    Ну а по сути — Хрен совершенно прав — это UDP, и коль скоро вы убили клиента — серверу это по барабану. Пока он не закончит отсылку своего буфера — он будет слать свои пакеты «На деревню к дедущке»


                    nemez



                    Сообщ.
                    #9

                    ,
                    24.06.14, 21:08

                      Senior Member

                      ****

                      Рейтинг (т): 17

                      Цитата

                      Ваш UDP сокет описан как SOCK_DGRAM…
                      И никакого отношения к IPPROTO_ICMP

                      имеет, при том самое непосредственное!

                      RFC 792 говорит нам что:

                      Type | Code | Checksum |
                      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                      | unused |
                      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                      | Internet Header + 64 bits of Original Data Datagra

                      что в свою очередь обозначает что на каждый такой пакет следует ICMP датаграмма с оригинальным заголовком.
                      Получив такую датаграмму, система знает номера портов и говорит сокету о том что с передачей происходит фигня.
                      Тот в свою очередь при send получает код ошибки и говорит юзеру что connection reset by peer.


                      Хрен



                      Сообщ.
                      #10

                      ,
                      24.06.14, 21:16

                        Цитата nemez @ 24.06.14, 21:08

                        Type | Code | Checksum |
                        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                        | unused |
                        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                        | Internet Header + 64 bits of Original Data Datagra

                        Это формат ICMP пакета. Причём тут UDP? И да, ICMP — это датаграммы. И да, на ICMP запрос приходит ответ с теми же данными, которые были отправлены. И да, с ICMP работает совсем другой тип сокета.

                        Сообщение отредактировано: Хрен — 24.06.14, 21:17


                        Oleg2004



                        Сообщ.
                        #11

                        ,
                        24.06.14, 21:25

                          Цитата nemez @ 24.06.14, 21:08

                          | Internet Header + 64 bits of Original Data Datagra
                          что в свою очередь обозначает что на каждый такой пакет следует ICMP датаграмма с оригинальным заголовком.
                          Получив такую датаграмму, система знает номера портов и говорит сокету о том что с передачей происходит фигня.

                          Не совсем так.
                          Сообщение ICMP получает сетевой уровень — т.е. модуль ICMP
                          Анализируя 64 бита, которые несет в себе ICMP-пакет, система знает — какому приложению послать сответствующее оповещение. Приложению….а не сокету.

                          Цитата

                          Тот в свою очередь при send получает код ошибки и говорит юзеру что connection reset by peer.

                          Нет в UDP соединения, а потому нет и «connection reset by peer»


                          nemez



                          Сообщ.
                          #12

                          ,
                          24.06.14, 21:40

                            Senior Member

                            ****

                            Рейтинг (т): 17

                            Цитата

                            Это формат ICMP пакета. Причём тут UDP?

                            Internet Header + 64 bits of Original Data Datagram — туда помещается UDP заголовок
                            При этом имеем цепочку. Датаграмму ICMP — Заголовок IP — Заголовок UDP.
                            Для каждого пакета, отправленного в никуда. Можно было бы говорить что UDP ни при чем, но его заголовок содержится в ICMP датаграмме. Это ЖЖЖЖЖЖ неспроста!

                            Цитата

                            Анализируя 64 бита, которые несет в себе ICMP-пакет, система знает — какому приложению послать сответствующее оповещение. Приложению….а не сокету.

                            а как получить это оповещение?

                            Добавлено 24.06.14, 21:45

                            Цитата

                            Нет в UDP соединения, а потому нет и «connection reset by peer»

                            зато есть «port unreachable» и кстати событие «connection reset by peer» в TCP отрабатывается именно таким способом — через ICMP

                            Сообщение отредактировано: nemez — 24.06.14, 21:45


                            Хрен



                            Сообщ.
                            #13

                            ,
                            24.06.14, 21:46

                              Цитата nemez @ 24.06.14, 21:40

                              туда помещается UDP заголовок

                              Он туда помещается не по стандарту, и помещает его туда роутер. Когда ICMP ответ приходит на отправляющую сторону, он не поступает на сокет, т.к. UDP и ICMP — это разные протоколы, которые инкапсулируются внутрь IP, они между собой никак не связаны на уровне сокетов.

                              Цитата nemez @ 24.06.14, 21:40

                              Почему их не отлавливает система, хотя она это делать обязана судя по мануалам?

                              С этого места поподробнее. Что за мануалы? Желаю лицезреть :)


                              nemez



                              Сообщ.
                              #14

                              ,
                              24.06.14, 21:55

                                Senior Member

                                ****

                                Рейтинг (т): 17


                                Хрен



                                Сообщ.
                                #15

                                ,
                                24.06.14, 22:09

                                  Цитата nemez @ 24.06.14, 21:55

                                  читать там где про SO_BSDCOMPAT

                                  Повторюсь:

                                  Цитата Хрен @ 24.06.14, 19:27

                                  поведение этого костыля меняется от версии к версии ядра, не понятно вообще, как оно ведёт себя в 3-й версии, и уж тем более это сделает твою прогу непереносимой на другие платформы.

                                  Т.е. в линуксе решили пойти против абстрагирования двух независимых протоколов и совместить их в этом плане на уровне сокетов. Но, как видно из цитаты

                                  Цитата

                                  In later kernel versions, support for this option has been phased out: Linux 2.4 silently ignores it, and Linux 2.6 generates a kernel warning (printk()) if a program uses this option.

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

                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                                  0 пользователей:

                                  • Предыдущая тема
                                  • C/C++: Сетевое программирование
                                  • Следующая тема

                                  Рейтинг@Mail.ru

                                  [ Script execution time: 0,0451 ]   [ 16 queries used ]   [ Generated: 10.02.23, 04:40 GMT ]  

                                  I recently encountered a server application UDP packet loss in my work, and after reviewing a lot of information in the process of troubleshooting, I summarized this article for more people’s reference.

                                  Before we start, let’s use a diagram to explain the process of receiving network messages on a linux system.

                                  1. first, the network message is sent to the NIC(Network Interface Controller) through the physical network cable
                                  2. the network driver reads the message from the network into the ring buffer, a process that uses DMA (Direct Memory Access) and does not require CPU participation
                                  3. the kernel reads the message from the ring buffer, processes it, executes the IP and TCP/UDP layer logic, and finally puts the message into the application’s socket buffer
                                  4. the application reads the message from the socket buffer for processing

                                  process of receiving network messages on a linux system

                                  In the process of receiving UDP messages, any of the processes in the diagram may actively or passively discard the messages, so packet loss may occur in the NIC and driver, or in the system and application.

                                  The reason why the send data process is not analyzed is because the send process is similar to the receive, only in the opposite direction; in addition the probability of losing messages in the send process is smaller than in the receive, and only occurs when the application sends messages at a rate greater than the kernel and NIC processing rate.

                                  This article assumes that the machine has only one interface with the name eth0, if there are more than one interface or the interface name is not eth0, please analyze it according to the actual situation.

                                  NOTE: RX (receive) in this article means receive message, TX (transmit) means send message.

                                  Confirm that a UDP packet drop is occurring

                                  To see if the NIC is dropping packets, use ethtool -S eth0 to see if there is data in the fields corresponding to bad or drop in the output, which should normally be 0. If you see the number growing, the NIC is dropping packets.

                                  Another command to check the packet loss data of the NIC is ifconfig, which will output statistics of RX (receive incoming packets) and TX (transmit outgoing packets).

                                  1
                                  2
                                  3
                                  4
                                  5
                                  6
                                  7
                                  
                                  ~# ifconfig eth0
                                  ...
                                          RX packets 3553389376  bytes 2599862532475 (2.3 TiB)
                                          RX errors 0  dropped 1353  overruns 0  frame 0
                                          TX packets 3479495131  bytes 3205366800850 (2.9 TiB)
                                          TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
                                  ...
                                  

                                  In addition, the linux system also provides packet loss information for each network protocol, which can be viewed using the netstat -s command, plus -udp to see only UDP-related packet data.

                                   1
                                   2
                                   3
                                   4
                                   5
                                   6
                                   7
                                   8
                                   9
                                  10
                                  11
                                  12
                                  13
                                  14
                                  15
                                  16
                                  17
                                  18
                                  19
                                  20
                                  21
                                  22
                                  23
                                  24
                                  25
                                  26
                                  
                                  [root@holodesk02 GOD]# netstat -s -u
                                  IcmpMsg:
                                      InType0: 3
                                      InType3: 1719356
                                      InType8: 13
                                      InType11: 59
                                      OutType0: 13
                                      OutType3: 1737641
                                      OutType8: 10
                                      OutType11: 263
                                  Udp:
                                      517488890 packets received
                                      2487375 packets to unknown port received.
                                      47533568 packet receive errors
                                      147264581 packets sent
                                      12851135 receive buffer errors
                                      0 send buffer errors
                                  UdpLite:
                                  IpExt:
                                      OutMcastPkts: 696
                                      InBcastPkts: 2373968
                                      InOctets: 4954097451540
                                      OutOctets: 5538322535160
                                      OutMcastOctets: 79632
                                      InBcastOctets: 934783053
                                      InNoECTPkts: 5584838675
                                  

                                  For the above output, look at the following information to see how UDP packet loss is occurring.

                                  • packet receive errors is not empty and keeps growing indicating that the system has UDP packet loss
                                  • packets to unknown port received indicates that the target port where the UDP message was received is not being listened to, which is usually caused by the service not being started and does not cause serious problems
                                  • receive buffer errors indicates the number of packets lost because the UDP receive buffer is too small

                                  NOTE : It is not a problem if the number of packets lost is not zero. For UDP, if there is a small amount of packet loss it is likely to be the expected behavior, such as a packet loss rate (number of packets lost/number of received messages) of 1 in 10,000 or less.

                                  NIC or driver packet loss

                                  As mentioned before, if there are rx_***_errors in ethtool -S eth0 then it is likely that there is a problem with the NIC that is causing the system to drop packets and you need to contact the server or NIC vendor to deal with it.

                                   1
                                   2
                                   3
                                   4
                                   5
                                   6
                                   7
                                   8
                                   9
                                  10
                                  11
                                  
                                  # ethtool -S eth0 | grep rx_ | grep errors
                                       rx_crc_errors: 0
                                       rx_missed_errors: 0
                                       rx_long_length_errors: 0
                                       rx_short_length_errors: 0
                                       rx_align_errors: 0
                                       rx_errors: 0
                                       rx_length_errors: 0
                                       rx_over_errors: 0
                                       rx_frame_errors: 0
                                       rx_fifo_errors: 0
                                  

                                  netstat -i will also provide the packet reception and drop of each NIC, normally the output should be 0 for error or drop.

                                  If there is no problem with the hardware or driver, usually the NIC drops packets because the ring buffer is too small, you can use the ethtool command to view and set the ring buffer of the NIC.

                                  ethtool -g can view the ring buffer of a particular NIC, like the example below.

                                   1
                                   2
                                   3
                                   4
                                   5
                                   6
                                   7
                                   8
                                   9
                                  10
                                  11
                                  12
                                  
                                  # ethtool -g eth0
                                  Ring parameters for eth0:
                                  Pre-set maximums:
                                  RX:        4096
                                  RX Mini:    0
                                  RX Jumbo:    0
                                  TX:        4096
                                  Current hardware settings:
                                  RX:        256
                                  RX Mini:    0
                                  RX Jumbo:    0
                                  TX:        256
                                  

                                  Pre-set indicates the maximum ring buffer value of the NIC, which can be set using ethtool -G eth0 rx 8192.

                                  There are many reasons for packet loss on linux systems, the common ones are: UDP message error, firewall, insufficient UDP buffer size, excessive system load, etc. Here we analyze these reasons for packet loss.

                                  UDP packet error

                                  If the UDP message is modified during transmission, it will lead to checksum error or length error, which will be verified by linux when receiving the UDP message, and the message will be discarded once the error is invented.

                                  If you want the UDP message checksum to be sent to the application even if there is an error, you can disable UDP checksum checking by using the socket parameter.

                                  1
                                  2
                                  
                                  int disable = 1;
                                  setsockopt(sock_fd, SOL_SOCKET, SO_NO_CHECK, (void*)&disable, sizeof(disable)
                                  

                                  Firewall

                                  If the system firewall drops packets, the behavior is generally all UDP messages are not received properly, of course, do not exclude the possibility that the firewall only drop a part of the message.

                                  If you encounter a very large packet loss rate, please check the firewall rules first to ensure that the firewall does not actively drop UDP messages.

                                  UDP buffer size is not enough

                                  After receiving a message, the linux system saves the message in the buffer. Since the size of the buffer is limited, if a UDP message is too large (exceeding the buffer size or MTU size), or if it is received at too fast a rate, it may cause linux to drop packets because the buffer is full.

                                  At the system level, linux sets the maximum value that can be configured for the receive buffer, which can be seen in the following file, and is generally an initial value set by linux at boot time based on memory size.

                                  • /proc/sys/net/core/rmem_max: the maximum value of receive buffer allowed to be set
                                  • /proc/sys/net/core/rmem_default: the default receive buffer value to be used
                                  • /proc/sys/net/core/wmem_max: the maximum value of send buffer allowed * /proc/sys/net/core/wmem_max: the maximum value of send buffer allowed
                                  • /proc/sys/net/core/wmem_dafault: the maximum value of send buffer to be used by default

                                  However, these initial values are not intended for heavy UDP traffic, and need to be increased if the application receives and sends a lot of UDP messages. You can use the sysctl command to make it effective immediately.

                                  1
                                  
                                  sysctl -w net.core.rmem_max=26214400 # 设置为 25M
                                  

                                  You can also modify the corresponding parameters in /etc/sysctl.conf to keep them in effect the next time you boot.

                                  If a message is too large, you can split the data on the sender side to ensure that each message is within the MTU size.

                                  Another parameter that can be configured is netdev_max_backlog, which indicates the number of messages that the linux kernel can cache after reading messages from the NIC driver, the default is 1000 and can be increased to, for example, 2000.

                                  1
                                  
                                  sudo sysctl -w net.core.netdev_max_backlog=2000
                                  

                                  System load is too high

                                  High system CPU, memory and IO load may cause network packet loss. For example, if the CPU load is too high, the system does not have time to perform checksum calculation of messages, copy memory and other operations, which may lead to packet loss from the NIC or socket buffer; if the memory load is too high, the application will be too slow to process messages in time; if the IO load is too high, the CPU is used to respond to IO wait and does not have time to process the UDP messages in the cache.

                                  The linux system itself is an interconnected system, and problems with any one component may affect the normal operation of other components. For excessive system load, either the application is faulty or the system is inadequate. For the former, you need to find, debug and fix it in time; for the latter, you also need to find and expand the capacity in time.

                                  Application packet loss

                                  Above mentioned the system UDP buffer size, the regulated sysctl parameter is only the maximum allowed by the system, each application needs to set its own socket buffer size value when creating a socket.

                                  The linux system puts the received messages into the socket’s buffer, and the application reads messages from the buffer continuously. So there are two application-related factors that affect packet loss: the socket buffer size and the speed at which the application reads the packets.

                                  For the first problem, you can set the socket receive buffer size when the application initializes the socket, for example, the following code sets the socket buffer to 20MB.

                                  1
                                  2
                                  
                                  uint64_t receive_buf_size = 20*1024*1024;  //20 MB
                                  setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &receive_buf_size, sizeof(receive_buf_size));
                                  

                                  If you do not write and maintain the program yourself, it is not a good or even possible thing to modify the application code. Many applications provide configuration parameters to adjust this value, please refer to the corresponding official documentation; if no configuration parameters are available, you can only raise an issue to the developer of the application.

                                  Obviously, increasing the receive buffer of the application will reduce the possibility of packet loss, but it will also cause the application to use more memory, so it needs to be used with caution.

                                  Another factor is the speed at which the application reads the messages in the buffer, which should be processed asynchronously for the application

                                  Where packets are dropped

                                  If you want to know in detail which function is dropping packets on your linux system, you can use the dropwatch utility, which listens for packet drops and prints out the address of the function where the drop occurred.

                                   1
                                   2
                                   3
                                   4
                                   5
                                   6
                                   7
                                   8
                                   9
                                  10
                                  11
                                  12
                                  13
                                  
                                  # dropwatch -l kas
                                  Initalizing kallsyms db
                                  dropwatch> start
                                  Enabling monitoring...
                                  Kernel monitoring activated.
                                  Issue Ctrl-C to stop monitoring
                                  
                                  1 drops at tcp_v4_do_rcv+cd (0xffffffff81799bad)
                                  10 drops at tcp_v4_rcv+80 (0xffffffff8179a620)
                                  1 drops at sk_stream_kill_queues+57 (0xffffffff81729ca7)
                                  4 drops at unix_release_sock+20e (0xffffffff817dc94e)
                                  1 drops at igmp_rcv+e1 (0xffffffff817b4c41)
                                  1 drops at igmp_rcv+e1 (0xffffffff817b4c41)
                                  

                                  By using this information and finding the corresponding kernel code, you can find out at which step the kernel drops the packet and the general reason for the packet drop.

                                  In addition, you can use the linux perf utility to listen for the kfree_skb (which is called when a network message is dropped) event.

                                  1
                                  2
                                  
                                  sudo perf record -g -a -e skb:kfree_skb
                                  sudo perf script
                                  

                                  There are many articles available on the web about the use and interpretation of the perf command.

                                  Summary

                                  • UDP is a connectionless and unreliable protocol, which is suitable for scenarios where occasional loss of messages does not affect the program state, such as video, audio, games, monitoring, etc. Of course, you can also do retry and de-duplication in the application layer to ensure reliability.
                                  • If you find that the server is losing packets, first check whether the system load is too high through monitoring, and then try to reduce the load to see if the packet loss problem disappears.
                                  • If the system load is too high, there is no effective solution for UDP packet loss. If the CPU, memory and IO are too high due to abnormal application, please locate the abnormal application and fix it in time; if the resources are not enough, the monitoring should be able to find it in time and expand the capacity quickly.
                                  • If the system receives or sends a lot of UDP messages, you can reduce the probability of packet loss by adjusting the socket buffer size of the system and the program.
                                  • Applications should use asynchronous methods when processing UDP messages, and not have too much processing logic between the two received messages

                                  Понравилась статья? Поделить с друзьями:
                                • Udp error 10049
                                • Ubuntu ttf mscorefonts installer error
                                • Udma crc error rate
                                • Ubuntu ssl err ssl protocol error
                                • Udma crc error count что это