This section summarizes the additions and changes made to the InterNiche code to support IPv6. It should be noted that to a large extent these changes allow IPv6 to replace IPv4, as well as to supplement it.
Great care has been taken to ease the process of adding InterNiche IPv6 to legacy IPv4 builds. The use of "makefiles", automated build tools, and the global "ipport.h_h
" file (compiler flags) are identical. Most aspects of adding IPv6 are no different than adding another IPv4 feature. This manual is designed to address those areas where there are (or may be) issues the porting engineer should be aware of.
This does not mean you should continue to use your old IPv4 InterNiche code. Networking code in directories such as "net
" and "tcp
", "misclib
" need numerous "ifdefs" to support IPv6. So all the directories in your original InterNiche build should be updated to the code in the newer IPv6 build.
Older IPv4 applications will continue to run on the IPv4 portion of dual-mode builds without modification, however support for native IPv6 will have to be added to the application manually.
Legacy MAC drivers may work with IPv6 "as is", however because of the scatter/gather buffer design, performance of the MAC driver may be somewhat slower than when performing similar IPv4 tasks. Optimizations to get around this are discussed in the Chapter 15. Keep in mind that MAC drivers must be able to both send and receive multicast packets to support IPv6.
It's also possible that some of the default IPv4 options/features used in legacy systems can't be used for IPv6 builds. There are two known examples of this: IP multicast and binary tree routine. Each of these issues is discussed later in this document.
IP multicast was an option on IPv4 systems. IPv6 requires it. Since IP multicast was historically an extra-cost option (and not a popular one), most InterNiche stacks were shipped without the IP multicast code; and without the support for multicast in the ipport.h
file. Details for using IP multicast are in the standard NicheStack documentation.
Several #define
s are introduced to support IPv6. The #define
s are designed to allow the build to be IPv6 only, IPv4 only, or both (the "dual mode" stack). Note that although some marketing literature describes three products (v4, v6, and "dual mode"), there are technically only two code bases involved (v4 and v6). Including both creates "Dual mode".
The # defines related to IPv6 are:
* Feature pre-dates IPv6 release | ||
#define | purpose | Requirement/note |
---|---|---|
IP_V6 | Includes support for IPv6 | Requires LINKED_PKTS , BTREE_ROUTES , and IP_MULTICAST |
IP_V4 | Includes support for IPv4 | Defaults to "defined" if IP_V6 is not defined. |
LINKED_PKTS | Includes code for creating linked lists of PACKET structures. (scatter/gather) | Required for IPv6 |
IPV6_TUNNEL | Include code for IPv6 tunnels. | Requires IP_V6 |
INCLUDE_6TO4 | Include code for specifically for RFC3056 "6to4" tunnels | Requires IP_V6 and IPV6_TUNNEL |
BTREE_ROUTES * | Include binary-tree routine code (IPv6 cannot use the older "static sized table" routing. | Required for IPv6 |
IP_MULTICAST * | Include support for IP Multicast packets and IGMP. | Required for IPv6 |
A single new directory has been added to support IPv6 - "ipv6
". This is a peer to the "net
" and "ip
" directories. Note that the older "ip
" directory is still required in an IP_V6
build even if IP_V4
is not #define
d, since some of the code is common to both v4 and v6.
The following files are included in the ipv6 directory:
icmp6.c | ICMPv6 implementation, except for ND code |
ip6.c | IPv6 send ... receive routines, and support routines |
ip62mac.c | link layer support for Ethernet and PPP |
ip6frags.c | IPv6 fragmentation and reassembly |
ip6menu.c | diagnostic menus for IPv6 |
ip6route.c | routine code for IPv6 |
ip6tun.c | IPv6 tunnel code, including 6to4 |
ip6_pcb.c | IPv6 supplement to tcp/in_pcb.c |
nd.c | Neighbor Discovery (ND) code |
ping6.c | ping client for IPv6 |
tcp6.c | TCP conversions for IPv6 |
udp6.c | UDP conversions for IPv6 |
Additionally, the following IPv6 files are added to the "h
" directory:
ip6mibs.h | Generic IPv6 MIB structures |
socket6.h | IPv6-specific sockets definition |
icmp6.h | ICMPv6 definitions |
ip6.h | IPv6 core protocol definitions |
The PACKET ("struct net
") object has several new fields added for scatter/gather support. These fields are included when the build is compiled with LINKED_PKTS
defined. The fields are:
struct netbuf * pk_prev; /* previous pkt in chain */ struct netbuf * pk_next; /* next ptk in chain */ int nb_tlen; /* total length of nb_prots in pk_next list */
The first two fields above are used to implement a bi-directional linked list. The last field, nb_tlen
, is the total length of all the packets in the list. nb_tlen
is only required in the first packet in the list, and should be the sum of all the nb_plen
fields in the list of packet structures.
The nb_tlen
field is only guaranteed to be accurate in the first PACKET
of a linked list. This PACKET
is can be identified by the tk_prev
field being NULL
.
Received packets at the IP layer are generally not stored in these lists - only packets being formed for sending. The exception is datagrams that are received in IPv6 fragments, which may be assembled into these lists by the IPv6 reassembly code. Currently the only use of this is in large ICMP and UDP packets; TCP is designed to use the TCP MSS option to avoid fragmentation and thus should not need to process received "scattered" packets.
Historically, InterNiche IPv4 code avoided the added complexity of fragmentation by requiring the transport layer to prepend space in the packet buffers for the IP and MAC layer headers. IPv6 presents multiple new motivations for using a scatter/gather approach to sending packets. First, there is the possibility of a range of IP "extension" headers being inserted between the IP and transport headers by the IP code. These include the IP fragment header, which was built into the IP header in IPv4. Another reason for scatter/gather is the (anticipated) widespread use of tunneling on IPv6, which requires additional headers inserted between the IPv6 header and the MAC layer header.
One major drawback of using scatter/gather is the added complexity required for a MAC device driver (i.e. Ethernet) to support it. This issue is examined further in Chapter 15 (MAC Drivers).
Another drawback of this system is that it can become difficult for code to reliably locate protocol headers in the packets. This problem can become especially serious on systems with a wide deviation in requirements for buffer space in front of the IP header, for example a system with one IPv4 tunneling interface and one raw Ethernet interface. The Ethernet interface will require 14 bytes (or perhaps 16 for alignment purposes), whereas the tunnel will require room for the tunnel header, the IPv6 header, and the Ethernet.
To facilitate readily finding the IPv6 header in such systems, the PACKET
structure contains an #ifdef
field, "ip6_hdr
", that always points to the IPv6 header. This field is required in the first PACKET
of any chain of packets.
The ip6_hdr
field is set by the pktdemux()
routine for every PACKET
processed through the received queue. Transport layers preparing to send IPv6 packet should set this field prior to sending the PACKET
down to the IP layer. The IP send code is required to move the ip6_hdr
pointer if it moves the IP header in order to insert IP extension headers. Similarly, tunneling code should move the ip6_hdr
pointer to the correct IPv6 header for "downstream" processing.
Other (non-IP) headers must be located algorithmically by starting with the IP header. Transport headers (TCP and UDP) may not directly follow the IP header in the buffer - programmers should use both the IP header's ip_nexthdr
and the PACKET
's nb_prot
and nb_plen
fields to check this. Even if ip_nexthdr
indicates a certain type follows the IP header (for example 6
indicates a TCP header) if nb_prot
plus nb_plen
point to the end of the IP header, then the TCP header is in the next linked packet.
To facilitate rapid processing by transport layers, the InterNiche IPv6 layer sets the PACKET
's nb_prot
pointer to the transport header before calling the transport layer receiver code. For example tcp_rcv(pkt)
is called with pkt->nb_prot
pointing to the TCP header, and pkt->nb_plen
indicating the amount of valid data at that pointer.
IPv6 introduces two new porting macros. These macros were introduced because address copying, and comparing operations, that were very efficient on 32-bit IPv4 addresses, had the potential to be very inefficient in 128-bit IPv6 addresses. Both operations take place frequently throughout the networking code, so they are performed by the above macros, rather than using algorithms hard-coded in C code. The intention is for the porting engineer to provide implementations that are efficient on the target system and tool chain.
At their simplest, these two macros may be left to the default definitions from ip6.h
file. These definitions map the macros to memcpy()
and memcmp()
as follows:
#define IP6EQ(addr1, addr2) (!MEMCMP(addr1, addr2, sizeof(ip6_addr))) #define IP6CPY(addrptr1, addrptr2) MEMCPY(addrptr1, addrptr2, sizeof(ip6_addr))
Both macros may be optimized by using inline assembly, and by taking advantage of the fact that the blocks to be copied/compared are always 16 bytes long. IP6EQ()
may be further optimized by comparing the data at the end of the blocks first, since that is the data most likely to differ.
CPU architectures with alignment sensitivity issues (such as ARM) may assume that the IPv6 addresses are always properly aligned in memory and dispense with alignment tests.