Linux send raw ethernet packet

Raw Ethernet Пакеты

Генерирую Ethernet пакеты со своими MAC-адресами, Ethertype’ом и данными. Пример взял со следующего сайта.

Максимальный размер пакета не превышает 1500 байт. Могу ли я как-нибудь увеличить это число? Желательно не менее 10000 байт.

google: change mtu in linux

И да, нужно понимать что такой пакет не везде пролезет

Максимум, что возможно — это TCP пакет размером 64K. Размер идёт в шапку IP.

Вопрос в другом — хочешь ли ты этого, т.к. с большими пакетами у тебя будет фрагментация.

То есть фактически максимальный размер пакета ограничен возможностями железа, так я понял? А фрагментацию поддерживает только IP протокол. Следовательно, если я буду передавать Ethernet пакеты большого размера, то они просто будут отбрасываться?

Если пакеты через свич ходят, то потребуется jumbo frame включить.

Пакеты я отправляю на ПЛИС по гигабитному Ethernet. Мне нужно отправлять более 10 МБайт данных в секунду. Однако я достиг максимальной скорости только лишь 5 МБайт в секунду. Основные потери в скорости, как я понял, происходят из-за задержки между пакетами, поэтому я хочу увеличить размер этих пакетов.

«По стандартам Ethernet максимальный размер ethernet-кадра составляет 1518 байт.»

«Jumbo‑кадр — ethernet‑кадр, в котором поле «payload» может занимать от 1500 байт до 16 000 байт.»

У меня больше 9000 MTU установить не дает

Основные потери в скорости, как я понял, происходят из-за задержки между пакетами

поэтому я хочу увеличить размер этих пакетов.

Чет ничего не понятно. Так откуда именно задержки? Из-за tcp? юзай Udp. Из-за плиса? Ты уверен что на парсинг содержимого тратится времени меньше чем на парсинг заголовков и т.д.?

У меня нет TCP и нет UDP, у меня есть чистый Ethernet фрейм — 6 байт MAC адрес назначения, 6 байт MAC адрес отправителя, 2 байта тип протокола и дальше данные. Парсинг содержимого у меня производится в реальном времени, так что тут задержки минимальные.

Пакеты я отправляю на ПЛИС по гигабитному Ethernet. Мне нужно отправлять более 10 МБайт данных в секунду. Однако я достиг максимальной скорости только лишь 5 МБайт в секунду. Основные потери в скорости, как я понял, происходят из-за задержки между пакетами, поэтому я хочу увеличить размер этих пакетов.

У тебя точно что-то сильно не так в ПЛИСине. Всего 4% утилизации — простыми задержками это не объяснить

P.S. А, ты наоборот на ПЛИС отправляешь через sendto. Тогда понятно, почему тормозит. Целый сискол на каждые 1500 байт.

На всякий случай. При использовании raw ethernet для передачи данных часто совершается ошибка, когда предполагают, что это так же надёжно как, например, usb. На самом деле буфер может переполниться и пакеты пропасть без ошибок(!). Это одна из причин использования TCP. Т.е. даже при использовании raw ethernet необходимо нумеровать пакеты и проверять в fpga.

Однако я достиг максимальной скорости только лишь 5 МБайт в секунду.

Да, тут и 100 mbit ethernet ещё имеет 50+% запаса по прочности. А ты попробуй подключиться сначала к другому ПК с 1 gbit ethernet, переписать файлик: убедиться, что скорость >100 MB. Сделай серверную часть для своей проги для этого второго ПК. Потом погоняй свою прогу, убедись, что потребление CPU не зашкаливает до 100%. И если этот тест не пройдёт, значит будешь знать, что дело не в fpga. А если твоя прога справится, значит fpga тормозит.

Читайте также:  Как откатить обратно mac os

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

И еще вопрос: raw сокеты работают с select/epoll? Если да, то это норм решение.

Тоесть если я буду пытаться слать пакеты через raw сокет быстрее чем может интерфейс, то пакеты которые не успевают будут дропаться, и я не получу никаких ошибок?

Да тут raw socket в частности не причём. Ведь можно и udp пакеты терять. Фокус в том, что ethernet в общём — это не usb и не pci-e. Целостность данных в пакете проверяется, но не целостность доставки пакетов друг за дружкой.

И еще вопрос: raw сокеты работают с select/epoll? Если да, то это норм решение.

Ну, мы в linux’е — значит нам всё равно, com-порт ли это, udp-сокет, unix domain socket, или raw-socket. Если есть файловый дескриптор (а он есть для raw сокета), то функции его использующие должны работать. Хотя, и в linux’е есть всё ещё устаревшее отличие эмулятора терминала от фреймбуфера (которое уже давно преодолели в Plan 9). Туда же отсутствие /dev/eth0. Да и список можно, к сожалению, продолжать.

умеет далеко не всё оборудование, если передавать через Интернет — упрешься в фрагментацию как минимум на пакеты по 1500 байт(как минимум — потому что всякие ADSL-и и прочие инкапсуляции типа PPPoE и GRE добавляют своего треша и MTU может быть еще меньше).

А так в IPv6, например, джамбограммы могут быть по (4 Гб-1 байт). TCP и UDP ходить там смогут(я имею ввиду с учётом большого размера а не просто впритык по 64 кб), если их реализации в ОС поддерживают RFC 2675

Я говорю не о контроле доставки, а о контроле отправки. Я получу ошибку сли пакет вообще не попал на провод?

Он уточнил же немного. Он шлет пакеты через патчкорд на свою железку

Вот, что есть в доках:

errno == ENOBUFS
The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. (Normally, this does not occur in Linux. Packets are just silently dropped when a device queue overflows.)

Хотя железо, как правило, и сообщает о переполнении, хотя очередь в ядре естественно тоже сообщает о переполнении, пакеты в линуксе всё равно тихо удаляются. Интересно, почему так решили.

P.S. А, ты наоборот на ПЛИС отправляешь через sendto. Тогда понятно, почему тормозит. Целый сискол на каждые 1500 байт.

Я не видел, чтобы ТС упомянул sendto . Но если выяснится, что проблема в этом, то решение есть: sendmmsg: отправляет несколько пакетов за один системный вызов.

Получается у тс одна надежда на селект, который поможет понять когда можно отправлять очередной пакет. А может такое быть, что селект считает что в raw сокет можно отправлять всегда?

У разных карточек — разный аппаратный лимит. Это я для ТС-а пишу 🙂

Было бы интересно узнать зачем ему это.

Он решил что это хороший способ лить со скоростью 50 мегабит/сек на девайс

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

У разных карточек — разный аппаратный лимит

Это понятно, в вики пишут что больше 9000 не рекомендуется из-за CRC32

Читайте также:  Приложение календарь для windows 10 где находится

Кстати, насколько Jumbo frame сейчас поддерживается современным железом ? Раньше с этим было много проблем

Не знаю что у него за девайс, но даже на ПЛИС сделать простой парсер UDP не сложно. Равно как и в микроконтроллере можно очень просто сделать упрощенный быстрый парсер UDP чтобы избежать сложной обработки, которая может понизить скорость.

— перевір, чи не шле залізяка pause frames

— перепиши свій сішний код використовуючи packet_mmap

Источник

itsuwari / sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux.c

/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
# include arpa/inet.h >
# include linux/if_packet.h >
# include stdio.h >
# include string.h >
# include stdlib.h >
# include sys/ioctl.h >
# include sys/socket.h >
# include net/if.h >
# include netinet/ether.h >
# define MY_DEST_MAC0 0x00
# define MY_DEST_MAC1 0x00
# define MY_DEST_MAC2 0x00
# define MY_DEST_MAC3 0x00
# define MY_DEST_MAC4 0x00
# define MY_DEST_MAC5 0x00
# define DEFAULT_IF » eth0 «
# define BUF_SIZ 1024
int main ( int argc, char *argv[])
<
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
int tx_len = 0 ;
char sendbuf[BUF_SIZ];
struct ether_header *eh = ( struct ether_header *) sendbuf;
struct iphdr *iph = ( struct iphdr *) (sendbuf + sizeof ( struct ether_header));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
/* Get interface name */
if (argc > 1 )
strcpy (ifName, argv[ 1 ]);
else
strcpy (ifName, DEFAULT_IF);
/* Open RAW socket to send on */
if ((sockfd = socket (AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == — 1 ) <
perror ( » socket » );
>
/* Get the index of the interface to send on */
memset (&if_idx, 0 , sizeof ( struct ifreq));
strncpy (if_idx. ifr_name , ifName, IFNAMSIZ- 1 );
if ( ioctl (sockfd, SIOCGIFINDEX, &if_idx) 0 )
perror ( » SIOCGIFINDEX » );
/* Get the MAC address of the interface to send on */
memset (&if_mac, 0 , sizeof ( struct ifreq));
strncpy (if_mac. ifr_name , ifName, IFNAMSIZ- 1 );
if ( ioctl (sockfd, SIOCGIFHWADDR, &if_mac) 0 )
perror ( » SIOCGIFHWADDR » );
/* Construct the Ethernet header */
memset (sendbuf, 0 , BUF_SIZ);
/* Ethernet header */
eh-> ether_shost [ 0 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 0 ];
eh-> ether_shost [ 1 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 1 ];
eh-> ether_shost [ 2 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 2 ];
eh-> ether_shost [ 3 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 3 ];
eh-> ether_shost [ 4 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 4 ];
eh-> ether_shost [ 5 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 5 ];
eh-> ether_dhost [ 0 ] = MY_DEST_MAC0;
eh-> ether_dhost [ 1 ] = MY_DEST_MAC1;
eh-> ether_dhost [ 2 ] = MY_DEST_MAC2;
eh-> ether_dhost [ 3 ] = MY_DEST_MAC3;
eh-> ether_dhost [ 4 ] = MY_DEST_MAC4;
eh-> ether_dhost [ 5 ] = MY_DEST_MAC5;
/* Ethertype field */
eh-> ether_type = htons (ETH_P_IP);
tx_len += sizeof ( struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 0xde ;
sendbuf[tx_len++] = 0xad ;
sendbuf[tx_len++] = 0xbe ;
sendbuf[tx_len++] = 0xef ;
/* Index of the network device */
socket_address. sll_ifindex = if_idx. ifr_ifindex ;
/* Address length */
socket_address. sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address. sll_addr [ 0 ] = MY_DEST_MAC0;
socket_address. sll_addr [ 1 ] = MY_DEST_MAC1;
socket_address. sll_addr [ 2 ] = MY_DEST_MAC2;
socket_address. sll_addr [ 3 ] = MY_DEST_MAC3;
socket_address. sll_addr [ 4 ] = MY_DEST_MAC4;
socket_address. sll_addr [ 5 ] = MY_DEST_MAC5;
/* Send packet */
if ( sendto (sockfd, sendbuf, tx_len, 0 , ( struct sockaddr*)&socket_address, sizeof ( struct sockaddr_ll)) 0 )
printf ( » Send failed \n » );
return 0 ;
>

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Источник

twaldecker / sendRawEth.c

/*
* Added the command line arguments for interface and MAC Address
*
* Based on raw Ethernet from austinmarton: https://gist.github.com/1922600
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
# include arpa/inet.h >
# include linux/if_packet.h >
# include stdio.h >
# include string.h >
# include stdlib.h >
# include sys/ioctl.h >
# include sys/socket.h >
# include net/if.h >
# include netinet/ether.h >
# define DEFAULT_IF » eth0 «
# define BUF_SIZ 1024
int main ( int argc, char *argv[])
<
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
int tx_len = 0 ;
char sendbuf[BUF_SIZ];
struct ether_header *eh = ( struct ether_header *) sendbuf;
struct iphdr *iph = ( struct iphdr *) (sendbuf + sizeof ( struct ether_header));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
unsigned int mac[ 6 ]; // using as uint8_t
/* Get interface name */
if (argc > 1 ) <
strcpy (ifName, argv[ 1 ]);
if (argc > 2 ) < /* 2 arguments, second argument is mac */
sscanf (argv[ 2 ], » %02x : %02x : %02x : %02x : %02x : %02x » , &mac[ 0 ], &mac[ 1 ], &mac[ 2 ], &mac[ 3 ], &mac[ 4 ], &mac[ 5 ]);
// printf(«mac:\n»);
// printf(«%2x:%2x:%2x:%2x:%2x:%2x\n», mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
>
>
else
strcpy (ifName, DEFAULT_IF);
/* Open RAW socket to send on */
if ((sockfd = socket (AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == — 1 ) <
perror ( » socket » );
>
/* Get the index of the interface to send on */
memset (&if_idx, 0 , sizeof ( struct ifreq));
strncpy (if_idx. ifr_name , ifName, IFNAMSIZ- 1 );
if ( ioctl (sockfd, SIOCGIFINDEX, &if_idx) 0 )
perror ( » SIOCGIFINDEX » );
/* Get the MAC address of the interface to send on */
memset (&if_mac, 0 , sizeof ( struct ifreq));
strncpy (if_mac. ifr_name , ifName, IFNAMSIZ- 1 );
if ( ioctl (sockfd, SIOCGIFHWADDR, &if_mac) 0 )
perror ( » SIOCGIFHWADDR » );
/* Construct the Ethernet header */
memset (sendbuf, 0 , BUF_SIZ);
/* Ethernet header */
eh-> ether_shost [ 0 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 0 ];
eh-> ether_shost [ 1 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 1 ];
eh-> ether_shost [ 2 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 2 ];
eh-> ether_shost [ 3 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 3 ];
eh-> ether_shost [ 4 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 4 ];
eh-> ether_shost [ 5 ] = (( uint8_t *)&if_mac. ifr_hwaddr . sa_data )[ 5 ];
eh-> ether_dhost [ 0 ] = mac[ 0 ];
eh-> ether_dhost [ 1 ] = mac[ 1 ];
eh-> ether_dhost [ 2 ] = mac[ 2 ];
eh-> ether_dhost [ 3 ] = mac[ 3 ];
eh-> ether_dhost [ 4 ] = mac[ 4 ];
eh-> ether_dhost [ 5 ] = mac[ 5 ];
/* Ethertype field */
eh-> ether_type = htons (ETH_P_IP);
tx_len += sizeof ( struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 0xde ;
sendbuf[tx_len++] = 0xad ;
sendbuf[tx_len++] = 0xbe ;
sendbuf[tx_len++] = 0xef ;
/* Index of the network device */
socket_address. sll_ifindex = if_idx. ifr_ifindex ;
/* Address length */
socket_address. sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address. sll_addr [ 0 ] = mac[ 0 ];
socket_address. sll_addr [ 1 ] = mac[ 1 ];
socket_address. sll_addr [ 2 ] = mac[ 2 ];
socket_address. sll_addr [ 3 ] = mac[ 3 ];
socket_address. sll_addr [ 4 ] = mac[ 4 ];
socket_address. sll_addr [ 5 ] = mac[ 5 ];
/* Send packet */
if ( sendto (sockfd, sendbuf, tx_len, 0 , ( struct sockaddr*)&socket_address, sizeof ( struct sockaddr_ll)) 0 )
printf ( » Send failed \n » );
return 0 ;
>
Читайте также:  Материнская плата зависает при загрузке windows

This comment has been minimized.

Copy link Quote reply

radumos commented Apr 10, 2016

Hello.
Is it hard to write a code so it will send frames(from a certain mac/ip) back with only the source and destination swapped? in sort of a loopback from sender. Thank you.

You can’t perform that action at this time.

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.

Источник

Оцените статью