Routing API (IPv6 Unicast Routing Protocols) Part 2

plen2mask() Function

The plen2mask() function (Listing 1-7) is a subroutine called from the main part of the rtadd6 program. This function performs the straightforward conversion from an IPv6 prefix length to the corresponding bit mask.

Listing 1-7

Listing 1-7

convertscope() Function

The convertscope() function (Listing 1-8) is one of the most tricky parts of IPv6 routing programs on BSD variants. If the sin6_scope_id field of the given sockaddr_in6{} structure is non-zero, this function embeds this value as a 16-bit integer in network byte order into the third and fourth bytes of the sin6_addr field(*). The sin6_scope_id field is then cleared with 0. As emphasized in Section 1.8.1, and as commented in the code, this is a bad practice for many reasons. Unfortunately, this is an inevitable workaround for any applications that perform IPv6 routing via a routing socket on BSD variant systems.

(*) Since the sin6_scope_id field is a 32-bit integer, this conversion may result in an overflow. The error handling is omitted for brevity, but a careful implementation should catch the case. This is another reason why this conversion is a bad practice.


Listing 1-8

Listing 1-8

 

 

 

 

Listing 1-8

Dumping Routing Table via sysctl()

The sysctl interface provides access to various types of system information maintained in the kernel. For example, with sysctl we can dump the entire kernel routing table.

Some network applications in fact use this interface. In particular, routing daemons such as route6d, Quagga (http://quagga.net/) and xorp (http://www.xorp.org/) are common users of this API. They use sysctl to synchronize their internal state with the forwarding information in the kernel (i.e., FIB).

Listing 1-9 is a code segment of the route6d program, which is a typical usage example of dumping the kernel routing table.

Listing 1-9

Listing 1-9

 

 

 

 

 

Listing 1-9

2514-2519 To dump the routing table, the NET_RT_DUMP sysctl name is specified at the fifth level (mib[4]) under the CTL_NET/PF_ROUTE level (mib[0] and mib[1]). By specifying AF_INET6 for mib[3], route6d tells the kernel that it only needs IPv6 routing table entries.

2520-2537 The sysctl() library function must normally be called at least twice. The third argument for the first call (line 2525) is NULL, indicating the caller only wants to estimate the necessary buffer length, which is stored in variable msize. A buffer of that size is allocated, then the second call to sysctl() (line 2533) with the allocated buffer copies the routing table into the buffer. Since there can be a change to the routing table between those two calls, although atypical, the second call can fail. Unfortunately, there is no guaranteed way to make the second call successful, and the program must try the process again. The maximum number of attempts, 5 (including the first one), is just an arbitrary chosen value.

2545-2549 The buffer now consists of a set of rt_msghdr{} structures, each of which corresponds to a single routing table entry. Figure 1-45 is an example of the received buffer for the routing table shown in Listing 1-1.There are several remarkable points in this example:

1. Network mask for the default route is a special case. This is effectively single-byte data, containing 0, which means the prefix length is 0. The 1-byte data requires the following empty field for padding.

2. The network mask for the second message is actually truncated as shown in Figure 1-42, and the sin6_len field is decreased (e.g., to 16). The parser must prepare for such truncated addresses.

3. It contains two additional address types as specified by the RTA_IFP and RTA_IFA flags. These mean the outgoing interface for the route and an IPv6 address assigned on that interface (which is usually a link-local address), respectively.

4. IPv6 link-local addresses in the address fields (corresponding to the RTA_IFA flag) are represented in the kernel-internal form which embeds the link index into the sin6_addr field.

The rt_entry() function (not described in this topic) is called for each entry, and incorporates some of the route entries into route6d’s internal database (RIB).

FIGURE 1-1

FIGURE 1-1

Next post:

Previous post: