4

I can not set the "don't fragment" flag for the IPv6/ICMPv6 packets. I am doing PMTUD and I want to force the router to drop packets bigger then the MTU. Using setsockopt with IPV6_MTU_DISCOVER is not working.

int on = IPV6_PMTUDISC_DO; // tried also IPV6_PMTUDISC_PROBE
setsockopt(socket, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &on, sizeof(on));

result: wireshark

I also can not use setosckopt with IPV6_DONTFRAG as described in Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming because I have the netinet/in6.h header included and IPV6_DONTFRAG is defined in linux/in6.h. Including linux/in6.h in my source code causes these redefinition errors.

In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:30:8: error: redefinition of ‘struct in6_addr’ In file included from /usr/include/netdb.h:28:0,
                 from mypmtud.cc:23: /usr/include/netinet/in.h:198:8: error: previous definition of ‘struct in6_addr’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:46:8: error: redefinition of ‘struct sockaddr_in6’ In file included from /usr/include/netdb.h:28:0,
                 from mypmtud.cc:23: /usr/include/netinet/in.h:239:8: error: previous definition of ‘struct sockaddr_in6’ In file included from mypmtud.cc:30:0: /usr/include/linux/in6.h:54:8: error: redefinition of ‘struct ipv6_mreq’ In file included from /usr/include/netdb.h:28:0,
                 from mypmtud.cc:23: /usr/include/netinet/in.h:275:8: error: previous definition of ‘struct ipv6_mreq’ make: *** [mypmtud] Error 1

Environment: Ubuntu 12.10 on VirtualBox 4.26 and GNS3 for the virtual network. The virtual Cisco C3660 router has just basic configuration: ip, ipv6 address, no shut and set mtu.

EDIT: I need the IPv6 stack/OS kernel to drop packets that are bigger than the link MTU or to signalize "this packet needs fragmentation". How can I achieve this behavior?

I tried setsockopt with IPV6_DONTFRAG (defined it in my code #define IPV6_DONTFRAG 62 ), setsockopt with IPV6_MTU_DISCOVER, int on = IPV6_PMTUDISC_DO and setsockopt with IPV6_RECVPATHMTU.

But I am not getting the PACKET TOO BIG reply or ancillary data with cmsg_level == IPPROTO_IPV6 and cmsg_type == IPV6_PATHMTU.

Part of my code:

/** sending ICMP packet*/
 if (((length = sendto(mysocket, packet, lengthBuff, 0, result->ai_addr, result->ai_addrlen)) < 0) && (errno == EMSGSIZE)){

     // works for IPv4, doesn't work with IPv6
     cout << "changing maxBuff and lengthBuff size" << endl;

        maxBuff = lengthBuff;
        lengthBuff = (minBuff + maxBuff) / 2;

        if (packet) {
            delete(packet);
            packet = NULL;
        }


    } else if (length < 0){

     cerr << "Error: sending data." << endl;

            freeaddrinfo(result);
            close(mysocket);

            if (packet) {
                delete(packet);
                packet = NULL;
            }

            exit(1);
    } else if(((recvmsg(mysocket, &msg, 0)) != -1) && (errno != EINTR)) {

        // reading ancillary dada as described in  *Unix-Linux Addison-Wesley - Stevens2003 - Unix Network Programming, page 736*
        cmsgh = CMSG_FIRSTHDR(&msg);    

        if(cmsgh != NULL) {
            cout << "getting msg " << endl;
            cout << "msg len " << msg.msg_controllen << endl;


            if(cmsgh->cmsg_level == IPPROTO_ICMPV6 && cmsgh->cmsg_type == IPV6_PATHMTU)
            {
                cout << "CMSGHEADER - GOOD" << endl;
                //mtustruct = CMSG_DATA(&msg); 

            maxBuff = lengthBuff;
            lengthBuff = (minBuff + maxBuff) / 2;

            if (packet) {
                delete(packet);
                packet = NULL;
            }

            }
            else{

                cout << "different ancillary data. " << endl;
                cout << " level " << cmsgh->cmsg_level << " type " << cmsgh->cmsg_type << endl;
            }
        }

    } else {

        cout << "no ERROR with sendto and no RESCVMSG" << endl;
    } 

    /** receiving ICMP data */
    tv.tv_sec = 3;
    tv.tv_usec = 0;

    int retval; // select

        FD_ZERO(&mySet);
        FD_SET(mysocket, &mySet);

        retval = select(mysocket + 1, &mySet, NULL, NULL, &tv);

        if (retval == -1) {
            cerr << "select failed" << endl;
            //break;
            exit(1);
        } else if (retval) {
            if ((length = recvfrom(mysocket, buffer, MAX, 0, result->ai_addr, &(result->ai_addrlen))) == -1) {
                cerr << "Error: receiving data." << endl;
            } else {
                icmpRec = (struct icmp6_hdr*) buffer;

                if((icmpRec->icmp6_type == ICMP6_PACKET_TOO_BIG)) {


                    cout << "next hop MTU: " << ntohl(icmpRec->icmp6_mtu) << endl;
                    maxBuff = ntohl(icmpRec->icmp6_mtu);                       

                } else if ((icmpRec->icmp6_type == ICMP6_ECHO_REPLY) && (ntohs(icmpRec->icmp6_id) == pid) && (ntohs(icmpRec->icmp6_seq) == (seq - 1))) {
                    cout << "code " << ntohs(icmpRec->icmp6_code) << endl;
                    cout << "ICMP ECHO REPLY" << endl;
                    minBuff = lengthBuff;

                }
            }
        }

EDIT2: I realized, setsockopt with defined IPV6_DONTFRAG is not working for me, but setsockopt with IPV6_MTU_DISCOVER is working for the own interface. The eth1 interface MTU is 1500 (default) and if sendto wants to send packets with bigger size, errno is set to EMSGSIZE. Also after some time I get PACKET TOO BIG message for these not send messages fom the own kernel/OS.

My real problem is, I am not getting (Ubuntu 12.10 running on VirtualBox 4.2.6) PACKET TOO BIG messages from the virtual router (Cisco c3660) running on GNS3.

4

1 に答える 1

5

and I want to force the router to drop packets bigger then the MTU

In IPv6 packets bigger than the MTU will always be dropped. Unlike in IPv4, IPv6 routers don't fragment packets. Instead, the source is expected to perform PMTU and:

  • Have the transport layer protocol produce adequate-sized datagrams
  • Fragment packets locally and attach a fragment extension

Linux does indeed have full support for IPV6_DONTFRAG (I think it was added in 2.6.35) although it only affects local behavior.

于 2013-01-06T19:02:24.887 に答える