简体   繁体   中英

How to send packets according to the MTU value

I'm trying to implement my own protocol over UDP.

As suggested by many manuals in Internet, it's better to avoid IP fragmentation by sending packets with their sizes less than MTU.

I wonder what is the best way to get the optimal size of the message? Should I somehow get MTU value (like this , for example) or should I just set it to smth like 1300 or 1400 and hope that it won't be less or change over time?

I heard that there are some problems with getting MTU value ( https://en.wikipedia.org/wiki/Path_MTU_Discovery ) and as far as I know it highly depends on the current route and other factors that can change over time.

For obtaining the MTU in your interface, not for Path MTU discovery, you have struct ifreq. One of its fields is ifr_mtu and this field will provide you the MTU. You read this field with ioctl, SIOCGIFMTU for the proper interface. ( http://man7.org/linux/man-pages/man7/netdevice.7.html )

struct ifreq {
   char ifr_name[IFNAMSIZ]; /* Interface name */
   union {
       struct sockaddr ifr_addr;
       struct sockaddr ifr_dstaddr;
       struct sockaddr ifr_broadaddr;
       struct sockaddr ifr_netmask;
       struct sockaddr ifr_hwaddr;
       short           ifr_flags;
       int             ifr_ifindex;
       int             ifr_metric;
       int             ifr_mtu;
       struct ifmap    ifr_map;
       char            ifr_slave[IFNAMSIZ];
       char            ifr_newname[IFNAMSIZ];
       char           *ifr_data;
   };
};

Example:

#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>


int main(void)
{
    int sock;
    char *name = "enp0s3";
    struct ifreq ifr;

    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        printf("Creating socket: %d\n", errno); 
        exit(-1);
    }

    ifr.ifr_addr.sa_family = AF_INET;
    strcpy(ifr.ifr_name, name);
    if (ioctl(sock, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
        printf("Error ioctl: %d\n", errno);
        exit(-2);
    }

    printf("MTU is %d.\n", ifr.ifr_mtu);

    close(sock);

    return 0;
}

Today, in general you can trust an MTU of 1,500 in the Internet unless you use specific connection technologies like Bluetooth or Zigbee. You can use Path MTU Discovery and implement your UDP-based protocol with an ACK to check the other side has received the message. Now, implementing an ACK and features of connection-oriented protocol is not the same as using TCP. If you can do everything with UDP it is lighter than TCP.

Edit: For using Path MTU Discovery, you can also use getsockopt with option IP_PMTUDISC_DO:

IP_MTU_DISCOVER (since Linux 2.2)
              Set or receive the Path MTU Discovery setting for a socket.
              When enabled, Linux will perform Path MTU Discovery as defined
              in RFC 1191 on SOCK_STREAM sockets.  For non-SOCK_STREAM
              sockets, IP_PMTUDISC_DO forces the don't-fragment flag to be
              set on all outgoing packets.  It is the user's responsibility
              to packetize the data in MTU-sized chunks and to do the
              retransmits if necessary.  The kernel will reject (with
              EMSGSIZE) datagrams that are bigger than the known path MTU.
              IP_PMTUDISC_WANT will fragment a datagram if needed according
              to the path MTU, or will set the don't-fragment flag
              otherwise.

See more here: http://man7.org/linux/man-pages/man7/ip.7.html

The recommended size for IPv4 UDP is 576 octets. Each Internet router is supposed to guarantee an IPv4 MTU of at least that size, and since UDP is a connectionless, fire-and-forget, best-effort, no-guaranteed-delivery protocol, you will risk less data with each packet that may be lost, and there will be lost packets.

IPv6 has a minimum MTU requirement of 1280 octets, and no fragmentation in the path.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM