- Для системного администратора
- Анатомия сетевого стека в Linux
- Русские Блоги
- Понимание сетевого стека 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
Одна из величайших возможностей операционной системы Linux® — ее сетевой стек. Он является производной стека BSD и хорошо оснащен добротным набором интерфейсов, которые варьируются от протоколо-независимых (protocol agnostic), таких как интерфейс уровня общих сокетов или уровня устройств, до специальных интерфейсов конкретных сетевых протоколов. В этой статье исследуется структура сетевого стека Linux с точки зрения его уровней, а также рассматриваются некоторые из основных структур.
Введение в протоколы
В то время как формальное введение в работу в сети отсылает нас к модели взаимодействия открытых систем (OSI — Open Systems Interconnection), это введение в основной сетевой стек в Linux использует четырехуровневую модель, известную как модель Интернет (Internet model) (смотрите рисунок 1).
Рисунок 1. Интернет-модель сетевого стека
Внизу стека располагается канальный уровень. Канальный уровень относится к драйверам устройств, обеспечивающим доступ к физическому уровню, который может состоять из многочисленных сред, таких как последовательные каналы или устройства Ethernet. Над канальным находится сетевой уровень, который отвечает за направление пакетов по назначению. Следующий уровень под названием транспортный отвечает за одноранговые (peer-to-peer) коммуникации (например, в пределах хоста). Сетевой уровень управляет связью между хостами, а транспортный — взаимодействием между конечными точками внутри этих хостов. Наконец, существует прикладной уровень, который обычно является семантическим и понимает перемещенные данные. К примеру, протокол передачи гипертекста (HTTP — Hypertext Transfer Protocol) перемещает запросы и ответы для содержимого Web между сервером и клиентом.
В сущности, уровни сетевого стека проходят под более узнаваемыми названиями. На канальном уровне вы найдете Ethernet, наиболее распространенную высокоскоростную среду. К более старым протоколам канального уровня относятся такие последовательные протоколы, как Internet-протокол для последовательной линии (SLIP — Serial Line Internet Protocol), Compressed SLIP (CSLIP) и Point-to-Point Protocol (PPP). Наиболее распространенным протоколом сетевого уровня является Internet Protocol (IP), но существуют и другие, которые удовлетворяют другим нуждам, такие как Протокол управляющих сообщений Internet (ICMP — Internet Control Message Protocol) и Протокол разрешения адресов (ARP — Address Resolution Protocol). На транспортном уровне это Протокол управления передачей (TCP — Transmission Control Protocol) и Протокол пользовательских датаграмм (UDP — User Datagram Protocol). Наконец, прикладной уровень включает в себя множество привычных нам протоколов, в том числе HTTP, стандартный Web-протокол, и SMTP (Simple Mail Transfer Protocol), протокол передачи электронной почты.
Архитектура базовой сети
Теперь перейдем к архитектуре сетевого стека Linux и посмотрим, как он реализует модель Internet. На рисунке 2 представлен высокоуровневый вид сетевого стека Linux. Наверху располагается уровень пользовательского пространства или прикладной уровень, который определяет пользователей сетевого стека. Внизу находятся физические устройства, которые обеспечивают возможность соединения с сетями (последовательные или высокоскоростные сети, как Ethernet). В центре, или в пространстве ядра, — сетевая подсистема, которая находится в центре внимания данной статьи. Через внутреннюю часть сетевого стека проходят буферы сокетов (sk_buffs), которые перемещают данные пакета между источниками и получателями. Кратко будет показана структура sk_buff.
Рисунок 2. Высокоуровневая архитектура сетевого стека Linux
Во-первых, вам предлагается краткий обзор основных элементов сетевой подсистемы Linux с подробностями в следующих разделах. Наверху (смотрите рисунок 2) находится система под названием интерфейс системного вызова. Она просто дает способ приложениям из пользовательского пространства получать доступ к сетевой подсистеме ядра. Следующим идет протоколо-независимый (protocol agnostic) уровень, который предоставляет общий способ работы с нижестоящими протоколами транспортного уровня. Дальше следуют фактические протоколы, к которым в системе Linux относятся встроенные протоколы TCP, UDP и, конечно же, IP. Следующий — еще один независимый уровень, который обеспечивает общий интерфейс к отдельным доступным драйверам устройств и от них, сопровождаемый в конце самими этими драйверами.
Интерфейс системного вызова
Интерфейс системного вызова может быть описан в двух ракурсах. Когда сетевой вызов производится пользователем, он мультиплексируется через системный вызов в ядро. Это заканчивается как вызов sys_socketcall в ./net/socket.c, который потом демультиплексирует вызов намеченной цели. Другой ракурс интерфейса системного вызова — использование нормальных файловых операций для сетевого ввода/вывода (I/O). Например, обычные операции чтения и записи могут быть выполнены на сетевом сокете (который представляется файловым дескриптором как нормальный файл). Поэтому пока существуют операции, специфичные для работы в сети (создание сокета вызовом socket, связывание его с дескриптором вызовом connect и так далее), есть также и некоторое количество стандартных файловых операций, которые применяются к сетевым объектам, как к обычным файлам. Наконец, интерфейс системного вызова предоставляет средства для передачи управления между приложением в пользовательском пространстве и ядром.
Протоколо-независимый интерфейс (Protocol agnostic interface)
Уровень сокетов является протоколо-независимым (protocol agnostic) интерфейсом, который предоставляет набор стандартных функций для поддержки ряда различных протоколов. Этот уровень не только поддерживает обычные TCP- и UDP-протоколы, но также и IP, raw Ethernet и другие транспортные протоколы, такие как Протокол управления передачей потоков данных (SCTP — Stream Control Transmission Protocol).
Взаимодействие через сетевой стек происходит посредством сокета. Структура сокета в Linux — struct sock, определенная в linux/include/net/sock.h. Эта большая структура содержит все необходимые состояния отдельного сокета, включая определенный протокол, используемый сокетом, и операции, которые можно над ним совершать.
Сетевая подсистема знает о доступных протоколах из специальной структуры, которая определяет ее возможности. Каждый протокол содержит структуру под названием proto (она находится в linux/include/net/sock.h). Эта структура определяет отдельные операции сокета, которые могут выполняться из уровня сокетов на транспортный уровень (например, как создать сокет, как установить соединение с сокетом, как закрыть сокет и т.д.).
Сетевые протоколы
Раздел сетевых протоколов определяет отдельные доступные сетевые протоколы (такие как TCP, UDP и так далее). Они инициализируются в начале дня в функции inet_init в linux/net/ipv4/af_inet.c (так как TCP и UDP относятся к семейству протоколов inet). Функция inet_init регистрирует каждый из встроенных протоколов, использующих функцию proto_register. Эта функция определена в linux/net/core/sock.c, и кроме добавления протокола в список действующих, если требуется, может выделять один или более slab-кэшей.
Можно увидеть, как отдельные протоколы идентифицируют сами себя посредством структуры proto в файлах tcp_ipv4.c, udp.c и raw.c, в linux/net/ipv4/. Каждая из этих структур протоколов отображается в виде типа и протокола в inetsw_array, который приписывает встроенные протоколы их операциям. Структура inetsw_array и его связи показаны на рисунке 3. Каждый из протоколов в этом массиве инициализируется в начале дня в inetsw вызовом inet_register_protosw из inet_init. Функция inet_init также инициализирует различные модули inet, такие как ARP, ICMP, IP-модули и TCP и UDP-модули.
Рисунок 3. Структура массива Internet-протокола
Обратите внимание на рисунке 3, что структура proto определяет транспортные методы сокета, в то время как структура proto_ops — общие. Дополнительные протоколы можно добавить в переключатель протоколов inetsw с помощью вызова inet_register_protosw. Например, SCTP добавляет себя вызовом sctp_init в linux/net/sctp/protocol.c.
Перемещение данных для сокетов происходит при помощи основной структуры под названием буфер сокета (sk_buff). В sk_buff содержатся данные пакета и данные о состоянии, которые охватывают несколько уровней стека протокола. Каждый отправленный или полученный пакет представлен в sk_buff. Структура sk_buff определяется в linux/include/linux/skbuff.h и показана на рисунке 4.
Рисунок 4. Буфер сокета и его связи с другими структурами
Как можно заметить, несколько структур sk_buff для данного соединения могут быть связаны вместе. Каждая из них идентифицирует структуру устройства (net_device), которому пакет посылается или от которого получен. Так как каждый пакет представлен в sk_buff, заголовки пакетов удобно определены набором указателей (th, iph и mac для Управления доступом к среде (заголовок Media Access Control или MAC). Поскольку структуры sk_buff являются центральными в организации данных сокета, для управления ими был создан ряд функций поддержки. Существуют функции для создания, разрушения, клонирования и управления очередностью sk_buff.
Буферы сокетов разработаны таким образом, чтобы связываться друг с другом для данного сокета и включать большой объем информации, в том числе ссылки на заголовки протоколов, временные метки (когда пакет был отправлен или получен) и соответствующее устройство.
Устройство-независимый интерфейс (Device agnostic interface)
Под уровнем протоколов располагается другой независимый уровень интерфейса, который связывает протоколы с различными драйверами физических устройств с разными возможностями. Этот уровень предоставляет стандартный набор функций, которые используются низко-уровневыми сетевыми устройствами, чтобы иметь возможность взаимодействовать с высоко-уровневым стеком протокола.
Прежде всего, драйверы устройств могут регистрировать и разрегистрировать себя в ядре вызовом register_netdevice или unregister_netdevice. Вызывающая команда сначала заполняет структуру net_device, а затем передает ее для регистрации. Ядро вызывает свою функцию init (если она определена), выполняет несколько проверок исправности, создает запись sysfs и потом добавляет новое устройство в список устройств (связанный список устройств, активных в ядре). Структуру net_device можно найти в linux/include/linux/netdevice.h. Некоторые функции находятся в linux/net/core/dev.c.
Для отправления sk_buff из уровня протокола устройству используется функция dev_queue_xmit. Она ставит в очередь sk_buff для возможной пересылки соответствующим драйвером устройства (устройством, определенным при помощи net_device или указателя sk_buff->dev в sk_buff). Структура dev содержит метод под названием hard_start_xmit, который хранит функцию драйвера для инициализации передачи sk_buff.
Получение пакета выполняется традиционно при помощи netif_rx. Когда драйвер устройства более низкого уровня получает пакет (содержащийся внутри выделенного sk_buff), sk_buff идет выше, на сетевой уровень, с помощью вызова netif_rx. Эта функция затем ставит sk_buff в очередь на более высокий уровень протоколов для дальнейшей обработки при помощи netif_rx_schedule. Функции dev_queue_xmit и netif_rx находятся в linux/net/core/dev.c.
Наконец, для взаимодействия с устройство-независимым уровнем (dev) в ядро был введен новый интерфейс прикладных программ (NAPI). Его используют некоторые драйверы, но подавляющее большинство все еще пользуется более старым интерфейсом получения кадров (по грубой оценке шесть из семи). NAPI может давать лучшую производительность при больших нагрузках, избегая при этом прерываний при каждом входящем кадре.
Драйверы устройств
Внизу сетевого стека находятся драйверы устройств, которые управляют физическими сетевыми устройствами. Примерами устройств этого уровня могут служить драйвер SLIP над последовательным интерфейсом или драйвер Ethernet над устройством Ethernet.
Во время инициализации драйвер устройства выделяет место для структуры net_device, а затем инициализирует ее необходимыми подпрограммами. Одна из них, с названием dev->hard_start_xmit, определяет, как верхний уровень должен поставить в очередь sk_buff для передачи. Ей передается sk_buff. Работа этой функции зависит от оборудования, но обычно пакет, описываемый в sk_buff, перемещается в так называемое “аппаратное кольцо” (hardware ring) или “очередь” (queue). Поступление кадра, как описано на устройство-независимом уровне, использует интерфейс netif_rx или netif_receive_skb для NAPI-совместимого сетевого драйвера. Драйвер NAPI накладывает ограничения на возможности базового оборудования.
После того как драйвер устройства настроил свои интерфейсы в структуре dev, вызов register_netdevice делает ее доступной для использования. В linux/drivers/net можно найти драйверы, характерные для сетевых устройств.
Идем дальше
Исходный код Linux — прекрасный способ узнать о конструкции драйверов для множества типов устройств, включая драйверы сетевых устройств. Вы обнаружите различия в конструкции и использовании доступных API ядра, но каждый будет полезен либо инструкциями, либо как отправная точка для нового драйвера. Остальной код в сетевом стеке стандартен и используется, пока не потребуется новый протокол. Но даже тогда реализации TCP (для потокового протокола) или UDP (для протокола на основе передачи сообщений) служат полезными моделями для начала новой разработки.
Автор: М. Тим Джонс, инженер-консультант, Emulex
Взято с ibm developerworks
Источник
Русские Блоги
Понимание сетевого стека 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 есть различия, содержание статьи требует доработки, и ошибки неизбежны.
Источник