- Русские Блоги
- Понимание сетевого стека Linux (1): краткое описание стека сетевых протоколов Linux
- 1. Сетевой путь Linux
- 1.1 отправитель
- 1.1.1 Уровень приложения
- 1.1.2 Транспортный уровень
- 1.1.3 IP-сетевой уровень — добавление заголовка и контрольной суммы, обработка маршрутизации, IP-фрагментация
- 1.1.5 Инкапсуляция и передача физического уровня на физическом уровне
- 1.1.6 Краткое резюме
- 1.2 Ресивер
- 1.2.1 Физический уровень и уровень канала данных
- 1.2.2 Сетевой уровень
- 1.2.3 Транспортный уровень (TCP / UDP)
- 1.2.4 Уровень приемника-приложения
- 1.2.5 Краткое описание процесса получения сообщения
- 2. Linux структура данных sk_buff struct и очередь (очередь)
- 2.1 sk_buff
- 2.1.1 Что такое sk_buff
- 2.1.2 Основная операция skb
- 2.2 Очередь драйверов, используемая сетевым стеком Linux (очередь драйверов)
- 2.2.1 Очередь
- 2.2.2 размер skb — максимальный размер по умолчанию — NIC MTU
Русские Блоги
Понимание сетевого стека Linux (1): краткое описание стека сетевых протоколов Linux
В этой серии статей описывается сетевой стек Linux, в том числе:
(4) Технология разгрузки сегментации в среде QEMU / KVM + VxLAN (принимающая сторона)
1. Сетевой путь Linux
1.1 отправитель
1.1.1 Уровень приложения
(1) Socket
Различные сетевые приложения на прикладном уровне в основном взаимодействуют со стеком сетевых протоколов пространства ядра через программный интерфейс Linux Socket. Linux Socket разработан на основе BSD Socket, является одной из важных частей операционной системы Linux и основой сетевых приложений. На иерархическом уровне он расположен на уровне приложений и представляет собой API, предоставляемый операционной системой для программистов приложений, через который приложения могут получить доступ к протоколу транспортного уровня.
- Сокет расположен над протоколом транспортного уровня, что позволяет скрыть различия между разными сетевыми протоколами.
- Socket — это вход в сетевое программирование. Он обеспечивает большое количество системных вызовов и составляет основную часть сетевых программ.
- В системе Linux сокеты являются частью файловой системы, а сетевое взаимодействие можно рассматривать как чтение файлов, что делает управление сетью таким же удобным, как управление файлами.
Процесс обработки сокета UDP (источник) Процесс обработки сокета TCP (источник)
(2) Поток обработки на уровне приложений
- Веб-приложение вызывает Socket APIsocket (int family, int type, int protocol) Чтобы создать сокет, вызов в конечном итоге вызовет системный вызов Linux socket () и, наконец, метод sock_create () ядра Linux. Этот метод возвращает файловый дескриптор созданного сокета. Для каждого сокета, созданного сетевым приложением пользовательского пространства, в ядре есть соответствующая структура сокета и структура сокета. Среди них struct sock имеет три очереди (очереди), а именно rx, tx и err. Когда структура sock инициализируется, эти буферные очереди также инициализируются; в процессе приема и отправки квитанций каждая очередь сохраняется для отправки или получения Экземпляр skb структуры данных сетевого стека Linux sk_buffer, соответствующий каждому пакету.
- Для сокета TCP приложение вызывает API connect (), чтобы клиент и сервер установили виртуальное соединение через сокет. В этом процессе стек протокола TCP устанавливает TCP-соединение посредством трехстороннего рукопожатия. По умолчанию API будет ждать, пока квитирование TCP завершит установление соединения, прежде чем вернуться. Важным шагом в процессе установления соединения является определение максимального размера сегмента (MSS), используемого обеими сторонами. Поскольку UDP — протокол без установления соединения, этот шаг не требуется.
- Приложение вызывает API отправки или записи Linux Socket для отправки сообщения принимающей стороне.
- вызывается sock_sendmsg, он использует дескриптор сокета для получения структуры sock и создает заголовок сообщения и сообщение управления сокетом
- Вызывается _sock_sendmsg, и в соответствии с типом протокола сокета вызывается функция отправки соответствующего протокола.
- Для TCP вызовите функцию tcp_sendmsg.
- Для UDP приложение пользовательского пространства может вызвать любой из трех системных вызовов send () / sendto () / sendmsg () для отправки сообщений UDP, и в конечном итоге они вызовут функцию udp_sendmsg () в ядре.
1.1.2 Транспортный уровень
Конечная цель транспортного уровня — предоставить своим пользователям эффективные, надежные и экономичные услуги передачи данных.Основные функции включают (1) построение сегмента TCP (2) вычисление контрольной суммы (3) отправку пакета ответа (ACK) (4) Операция, гарантирующая надежность, например, скользящий отвод. Общий процесс обработки стека протоколов TCP показан на следующем рисунке:
Краткий процесс работы стека TCP:
- Функция tcp_sendmsg сначала проверяет статус установленного TCP-соединения, затем получает MSS соединения и запускает процесс отправки сегмента.
- Создайте загрузку сегмента TCP: он создает экземпляр skb структуры данных sk_buffer пакета в пространстве ядра и копирует данные пакета из буфера пространства пользователя в буфер skb.
- Создайте заголовок TCP.
- Вычислить контрольную сумму TCP (контрольную сумму) и порядковый номер (порядковый номер).
- Контрольная сумма TCP — это сквозная контрольная сумма, вычисляемая отправителем и затем проверяемая получателем. Его цель — обнаруживать любые изменения в заголовке TCP и данных от отправителя к получателю. Если получатель обнаруживает ошибку в контрольной сумме, сегмент TCP будет напрямую отброшен. Контрольная сумма TCP покрывает заголовок TCP и данные TCP.
- Требуется контрольная сумма TCP
- Отправить на уровень IP для обработки: вызвать дескриптор IP-обработчика ip_queue_xmit и передать skb в поток обработки IP.
Краткий процесс работы стека UDP:
- UDP инкапсулирует сообщение в дейтаграмму UDP
- Вызовите метод ip_append_data (), чтобы отправить пакет на уровень IP для обработки.
1.1.3 IP-сетевой уровень — добавление заголовка и контрольной суммы, обработка маршрутизации, IP-фрагментация
Задача сетевого уровня — выбрать подходящие узлы маршрутизации и коммутации между сетями для обеспечения своевременной передачи данных. Сетевой уровень составляет пакеты данных из кадров, предоставленных канальным уровнем.Заголовок сетевого уровня инкапсулируется в пакет, который содержит информацию о логическом адресе — сетевые адреса исходного сайта и адреса конечного сайта. В его основные задачи входит (1) обработка маршрутизации, то есть выбор следующего перехода (2) добавление IP-заголовка (3) вычисление контрольной суммы IP-заголовка, которая используется для определения того, содержит ли заголовок IP-пакета ошибку во время процесса распространения (4), если возможно, продолжить После обработки IP-фрагментации (5) получите MAC-адрес следующего перехода, установите заголовок канального уровня и затем передайте на канальный уровень для обработки.
Базовый процесс обработки IP-стека показан на следующем рисунке:
- Сначала ip_queue_xmit (skb) проверит информацию о маршрутизации skb-> dst. Если нет, например, первый пакет сокета, используйте ip_route_output () для выбора маршрута.
- Затем заполните различные поля IP-пакета, такие как версия, длина заголовка, TOS и т. Д.
- Некоторые средние фрагменты можно найти в соответствующих документах. Основная идея состоит в том, что когда длина сообщения больше, чем mtu, а длина gso не равна 0, для фрагментации будет вызываться ip_fragment, иначе для отправки данных будет вызван ip_finish_output2. В функции ip_fragment будет проверяться бит флага IP_DF, Если пакет IP-данных, подлежащий фрагментированию, не может быть фрагментирован, вызовите icmp_send () отправляет отправителю причину необходимости Фрагментация и цель установки флага отсутствия фрагментации недоступны Пакеты ICMP и отбросить пакеты, то есть установить статус IP В случае сбоя фрагментации отпустите skb, и возвращаемое сообщение будет слишком длинным код ошибки. Чтобы
- Затем используйте ip_finish_ouput2, чтобы установить заголовок канального уровня. Если буфер заголовка канального уровня есть (то есть hh не пуст), скопируйте его в skb. Если нет, то вызовите neigh_resolve_output и используйте ARP для его получения.
1.1.4 Уровень канала передачи данных
Функционально, на основе услуги потока битов, предоставляемой физическим уровнем, устанавливается канал данных между соседними узлами, обеспечивается безошибочная передача кадров данных (Frame) по каналу посредством контроля ошибок, и выполняются действия в каждой цепи. серии. Уровень канала передачи данных обеспечивает надежную передачу на ненадежных физических носителях. Роль этого уровня включает: адресацию физических адресов, формирование кадров данных, управление потоком, обнаружение ошибок данных, повторную передачу и т. Д. На этом уровне единица данных называется кадром. Представители протоколов уровня звена данных включают: SDLC, HDLC, PPP, STP, Frame Relay и т. Д.
С точки зрения реализации, Linux предоставляет уровень абстракции сетевого устройства, фактически это теперь linux / net / core / dev.c. Конкретные физические сетевые устройства должны реализовывать виртуальные функции в драйвере устройства (driver.c). Уровень абстракции сетевого устройства вызывает функции определенных сетевых устройств.
、
1.1.5 Инкапсуляция и передача физического уровня на физическом уровне
- После получения запроса на отправку физический уровень копирует данные из основной памяти во внутреннюю RAM (буфер) через DMA. В копию данных одновременно добавляются соответствующий заголовок, IFG, преамбула и CRC, соответствующие протоколу Ethernet. Для сетей Ethernet CSMA / CD используется для передачи на физическом уровне, то есть конфликты каналов отслеживаются во время передачи.
- После того, как сетевая карта завершит передачу сообщения, будет сгенерировано прерывание для уведомления ЦП, а затем обработчик прерывания на уровне драйвера может удалить сохраненный skb.
1.1.6 Краткое резюме
(источник)
1.2 Ресивер
1.2.1 Физический уровень и уровень канала данных
- Когда пакет поступает на физический сетевой адаптер машины, когда он получает фрейм данных, он инициирует прерывание и передает его rx_ring в памяти ядра Linux через DMA.
- Сетевая карта выдает прерывание, чтобы уведомить ЦП о наличии пакета, который необходимо обработать. Обработчик прерывания в основном выполняет следующие операции, включая выделение структуры данных skb_buff и копирование полученного кадра данных из порта ввода-вывода сетевого адаптера в буфер skb_buff; извлечение некоторой информации из кадра данных и установка соответствующего skb_buff Параметры, эти параметры будут использоваться сетевым протоколом верхнего уровня, например skb-> protocol;
- После простой обработки программа терминальной обработки отправляет мягкое прерывание (NET_RX_SOFTIRQ), чтобы уведомить ядро о получении нового кадра данных.
- В ядре 2.5 представлен набор новых API-интерфейсов для обработки полученного фрейма данных, а именно NAPI. Следовательно, у драйвера есть два способа уведомить ядро: (1) через предыдущую функцию netif_rx; (2) через механизм NAPI. Обработчик прерывания вызывает функцию netif_rx_schedule сетевого устройства, входит в поток обработки мягкого прерывания, а затем вызывает функцию net_rx_action.
- Эта функция закрывает прерывание, получает все пакеты в rx_ring каждого сетевого устройства, и, наконец, pacakage удаляется из rx_ring и входит в поток обработки netif _receive_skb.
- netif_receive_skb — это последняя станция, на которой канальный уровень принимает дейтаграммы. В соответствии с типами дейтаграмм сетевого уровня, зарегистрированными в глобальных массивах ptype_all и ptype_base, он доставляет датаграммы приемным функциям различных протоколов сетевого уровня (в основном ip_rcv и arp_rcv в домене INET). Эта функция в основном предназначена для вызова функции приема протокола третьего уровня для обработки пакета skb и перехода на третий сетевой уровень для обработки.
1.2.2 Сетевой уровень
- Функция входа уровня IP находится в функции ip_rcv. Эта функция сначала выполняет различные проверки, включая контрольную сумму пакета, и, если необходимо, дефрагментирует IP (объединяет несколько фрагментов), затем пакет вызывает зарегистрированный обработчик netfilter предварительной маршрутизации и, наконец, после завершения достигает функции ip_rcv_finish.
- Функция ip_rcv_finish вызовет функцию ip_router_input для входа в процесс маршрутизации. Сначала он вызовет ip_route_input для обновления маршрута, а затем Найдите маршрут и решите, будет ли пакет отправлен на локальную машину, перенаправлен или отклонен:
- Если он отправляется на локальный компьютер, вызовите функцию ip_local_deliver, которая может де-фрагментировать (объединить несколько IP-пакетов), а затем вызовите функцию ip_local_deliver. Эта функция вызывает интерфейс следующего уровня в соответствии с номером протокола следующего уровня обработки пакета, включая tcp_v4_rcv (TCP), udp_rcv (UDP), icmp_rcv (ICMP), igmp_rcv (IGMP). Для TCP вызывается функция tcp_v4_rcv, так что поток обработки входит в стек TCP.
- Если требуется пересылка, войдите в процесс пересылки. Этот процесс должен обработать TTL, а затем вызвать функцию dst_input. Эта функция (1) обработает Netfilter Hook (2) выполнит IP-фрагментацию (3) вызовет dev_queue_xmit и войдет в поток обработки канального уровня.
1.2.3 Транспортный уровень (TCP / UDP)
- Запись обработки TCP транспортного уровня находится в функции tcp_v4_rcv (находится в файле linux / net / ipv4 / tcp ipv4.c), которая выполняет проверку заголовка TCP и другую обработку.
- Вызовите _tcp_v4_lookup, чтобы найти открытый сокет пакета. Если его не найти, пакет будет удален. Затем проверьте состояние сокета и подключения.
- Если для сокета и соединения все в порядке, вызовите tcp_prequeue, чтобы пакет вошел в пользовательское пространство из ядра и поместил его в очередь приема сокета. Затем сокет будет разбужен, вызовет системный вызов и, наконец, вызовет функцию tcp_recvmsg, чтобы получить сегмент из очереди приема сокета.
1.2.4 Уровень приемника-приложения
- Каждый раз, когда пользовательское приложение вызывает read или recvfrom, этот вызов будет сопоставлен с системным вызовом sys_recv в /net/socket.c и преобразован в вызов sys_recvfrom, а затем будет вызвана функция sock_recgmsg.
- Для сокетов INET будет вызван метод inet_recvmsg в / net / ipv4 / af inet.c, который вызовет метод получения данных соответствующего протокола.
- Для TCP вызовите tcp_recvmsg. Эта функция копирует данные из буфера сокета в пользовательский буфер.
- Для UDP любой из трех системных вызовов recv () / recvfrom () / recvmsg () может быть вызван из пользовательского пространства для получения пакета UDP, и эти системные вызовы в конечном итоге вызовут метод udp_recvmsg в ядре.
1.2.5 Краткое описание процесса получения сообщения
2. Linux структура данных sk_buff struct и очередь (очередь)
2.1 sk_buff
2.1.1 Что такое sk_buff
Когда сетевой пакет обрабатывается ядром, данные нижележащего протокола передаются на более высокий уровень, и при передаче данных процесс меняется на противоположный. Данные (включая заголовок и нагрузку), генерируемые различными протоколами, непрерывно передаются на нижний уровень, пока они не будут окончательно отправлены. Поскольку скорость этих операций критична для производительности сетевого уровня, ядро использует специальную структуру, называемую sk_buff, файл определения которой находится вskbuffer.h. Буферы сокетов используются для обмена данными на уровне реализации сети без копирования или депакетирования пакетов данных — это значительный выигрыш в скорости. Чтобы
- sk_buff — это основная структура данных сети Linux, и ее файл определения находится вskbuffer.h。
- Буфер ядра сокета (skb) — это буфер, используемый сетевым стеком ядра Linux (от L2 до L4) для обработки сетевых пакетов (пакетов), его тип — sk_buffer. Проще говоря, один skb представляет пакет в сетевом стеке Linux; несколько skb, созданных сегментацией TCP, и IP-пакет хранятся в виде списка skb.
- struct sock имеет три очереди skb (очередь sk_buffer): rx, tx и err.
Его основные конструктивные элементы:
2.1.2 Основная операция skb
(1) Размещение skb = alloc_skb (len, GFP_KERNEL)
(2) Добавить полезную нагрузку (skb_put (skb, user_data_len))
(3) Используйте skb-> push, чтобы добавить заголовок протокола, или skb-> pull, чтобы удалить заголовок.
2.2 Очередь драйверов, используемая сетевым стеком Linux (очередь драйверов)
(Выдержки из этой главыQueueing in the Linux Network Stack by Dan Siemon)
2.2.1 Очередь
Между стеком IP и драйвером сетевого адаптера существует очередь драйверов. Обычно он реализуется как кольцевой буфер FIFO, который можно рассматривать просто как фиксированный размер. Эта очередь не содержит пакетных данных. Напротив, она сохраняет только указатель буфера ядра сокета (skb), а использование skb описано в предыдущем разделе на протяжении всей обработки сетевого стека ядра.
Пакеты, обрабатываемые стеком IP при вводе очереди. Эти пакеты либо генерируются приложением на локальном компьютере, либо поступают на локальный компьютер и маршрутизируются. Пакеты, добавленные в очередь IP-стеком, будут извлечены драйвером сетевого устройства (драйвером оборудования) и отправлены на аппаратное устройство NIC через шину данных и переданы.
Если TSO / GSO не используется, длина пакетов, отправленных из IP-стека в эту очередь, должна быть меньше MTU.
2.2.2 размер skb — максимальный размер по умолчанию — NIC MTU
Большинство сетевых карт имеют атрибут фиксированной максимальной единицы передачи (MTU), который представляет собой размер самого большого кадра, который может передать сетевое устройство. Для Ethernet значение по умолчанию составляет 1500 байт, но некоторые сети Ethernet могут поддерживать кадры jumbo размером до 9000 байт. В стеке IP-сети MTU указывает размер самого большого пакета, который может быть отправлен на NIC. Например, если приложение записывает 2000 байтов данных в сокет TCP, стеку IP необходимо создать два IP-пакета, чтобы размер каждого пакета был равен или меньше 1500 байтов. Можно видеть, что для передачи больших объемов данных относительно небольшой MTU приведет к передаче большого количества небольших пакетов в очередь драйвера. Это называется фрагментацией IP.
На следующем рисунке показана фрагментация IP-пакета с полезной нагрузкой 1500 байтов при MTU 1000 и 600:
- Приведенная выше информация составлена из различной информации, полученной из Интернета.
- Сама эта часть более сложная, и между разными версиями ядра Linux есть различия, содержание статьи требует доработки, и ошибки неизбежны.
Источник