donatas abraitis

One more anecdotal Internet Protocol version

I don’t think it’s the best place to put anecdots, but I see there are even more interesting proposals over the earth.

IP version 10 (IPv10) is a new version of the Internet Protocol, designed to allow IP version 6 to communicate to IP version 4 (IPv4) and vice versa.

First of all - it’s full of **. Why the hell invent one more protocol which is broken at the first phase.

It took almost twenty years for the global transition to IPv6, but the progress is visible today. There are a lot of techniques to allow comminication from IPv6 only hosts to reach both protocols outside. The main blockers are ISPs. They do not provide IPv6 connectivity for end-users.

Ok, let’s see what format do we have in IPv10 protocol:

|     32-bit    |  16-bit |  48-bit |    32-bit     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 00000......0  |   ASN   |   MAC   | IPv4 Address  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      128-bit                      |
  • Why the beginning of the IP address is zeroed (0x00000000)? It’s almost the same as we have with IPv4 mapped addressed within IPv6 (::ffff:192.168.1.1);
  • AS is limited to 16-bit, while today we have 4-bytes (32-bit) AS numbers;
  • MAC? The aforementioned document doesn’t tell anything about this field. Didn’t get it why is it written there;
  • Even current IPv4 hosts will need to transition to IPv10 format - that’s work only in carefully crafted slides (thum rule of Linux kernel - do not break user-space);
  • Why do not use existing advantage and exploit IPv4 mappings for globally routable addresses (2a02:4780:bad:c0de:153.92.2.10)?;
  • In both cases gateway must be involved between end-points in transforming those address variants.

Hence, IPv10 approach looks like a minor modification to existing IPv4 mapped address inside low order bits of IPv6 address. Except the format is a little bit different (not 0x000ffff), but 16-bits reserved for AS, 48-bits for MAC address.

I mentioned few times IPv4 mapped IP address within IPv6, let’s talk how it works in Linux kernel.

If you browse over Linux kernel source you will find that every connection handling function does translation to IPv6-like format, e.g.:

ipv4_connected:
                if (err)
                        goto out;

                ipv6_addr_set_v4mapped(inet->inet_daddr, &sk->sk_v6_daddr);

If connection to IPv4 address was successful - convert IPv4 address to be IPv6-like.

The function for transformation is trivial:

static inline void ipv6_addr_set_v4mapped(const __be32 addr,
                                          struct in6_addr *v4mapped)
{
        ipv6_addr_set(v4mapped,
                        0, 0,
                        htonl(0x0000FFFF),
                        addr);
}

The best friend for ipv6_addr_set_v4mapped() is ofcourse ipv6_addr_v4mapped():

static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
{
        return (
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
                *(unsigned long *)a |
#else
                (__force unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) |
#endif
                (__force unsigned long)(a->s6_addr32[2] ^
                                        cpu_to_be32(0x0000ffff))) == 0UL;
}

You should ask, why to call IPv4 inside IPv6 related functions? The answer is here:

~# stap -e 'probe kernel.function("tcp_v4_connect") { print_backtrace(); exit(); }'
 0xffffffff815d46d0 : tcp_v4_connect+0x0/0x4e0 [kernel]
 0xffffffff8165021a : tcp_v6_connect+0x60a/0x6c0 [kernel]
 0xffffffff815eb855 : __inet_stream_connect+0xb5/0x330 [kernel]
 0xffffffff815ebb08 : inet_stream_connect+0x38/0x50 [kernel]
 0xffffffff81555347 : SYSC_connect+0xe7/0x120 [kernel]
 0xffffffff8155614e : SyS_connect+0xe/0x10 [kernel]
 0xffffffff816968c9 : system_call_fastpath+0x16/0x1b [kernel]

It would be very nice to see tcp_v10_connect() in this trace ;-)

Sum up

facepalm