LANMAR for IPv6 Jason Chen, Teresa Breyer Tutor: Zeng-Zhong Lee 1. Introduction and Background 1.1 LANMAR LANMAR is a routing scheme for wireless ad-hoc networks [1] which combines the ideas of both Fisheye State Routing (FSR) and Landmark Routing. Groups of nodes that move similarly are formed into a logical subnet and each such subnet elects a Landmark node to represent the group. Each node has, in addition to its physical identifier (e.g. Ethernet address), a logical identifier which consists of a subnet and a unique host field within the subnet. Each node stores Link State information and a Time Stamp for each destination within fisheye scope, as well as the Next Hop and distance to all known destinations within the scope and to each Landmark node as well. A node exchanges Link State only with nodes in its scope and the rate with which Link State packets are sent decreases as the hop distance increases. Consequently routes within Fisheye scope are accurate, and as hop distance increases, accuracy of the routing information degrades. The major difference to FSR is that in LANMAR the routing table includes only nodes within scope and all landmark nodes. This improves scalability by reducing the Routing Table size. Typically all members in a logical subnet are within fisheye scope. However, nodes that are out of the scope are called Drifters. However, a packet to a destination within neighbor scope is routed directly using the local routing table. A packet to a destination out of scope is routed towards the corresponding Landmark using the subnet field of the destination to look up the next hop in the landmark routing table. Once the packet reaches a node within the scope of the destination, the direct route to the destination can be found in that forwarding node’s local routing table and that route is applied. This means that a packet does not necessarily need to pass through the Landmark. [7] of a destinations subnet to reach the destination. Landmark Logical Subnet 1.2 IPv4 versus IPv6 In IPv4 addresses consist of 4 bytes or 32 bits. Each byte is written as a decimal number between 0 and 255 separated by a dot. That means there are 4,294,967,296 possible IP addresses. Initially these IPv4 addresses were split into four different classes. Addresses between 1.0.0.0 and 127.255.255.255 are class A, addresses between 128.0.0.0 and 191.255.255.255 are class B, addresses between 192.0.0.0 and 223.255.255.255 are class C, and between 224.0.0.0 and 239.255.255.255 are all Multicast addresses. The network field of A addresses has 7 bits, of B addresses 14 bits and of C addresses 21 bits. So obviously A and B addresses are in high demand and there is actually a shortage of IPv4 addresses. There have been several solutions proposed to alleviate this problem. The most efficient, but most difficult to deploy, is to increase the number of bytes used to represent an IP addresses as proposed in IPv6. IPv6 addresses consist of 16 bytes or 128 bits, so they are four times as long as IPv4 addresses. That means there are more than 3.4*1038 such addresses. There are 3 types of IPv6 addresses, unicast, anycast, and multicast. Unicast addresses are used for sending a unicast message from one interface to another interface. Multicast addresses are to send a packet to each member of a group of nodes. This multicast solution was proposed to replace broadcast in IPv4. Anycast addresses are used for sending packets to the closest node, distance wise, out of a set of nodes. An example of an IPv6 addresses has the format of: 2128-1: 0xffffffffffffffffffffffffffffffff This is not very legible, so a separator is inserted after every 16 bits, and the leading 0x may be omitted: 2128-1:ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff ffe80:0000:0000:0000:0202:2dff:fe2e:3ad6 Also, one sequence of adjacent 16 bit blocks of 0’s may be omitted using the double colon: fe80::0202:2dff:fe2e:3ad6 Finally, the leading zeros of each block can be omitted: fe80::202:2dff:fe2e:3ad6 Below one can see the differences in the IPv4 and IPv6 headers. While the IPv4 header is 20 bytes plus up to 40 bytes of options, the IPv6 header is 40 bytes by default [7]. IPv4: 32 bits ver head. type of Total length len service 16-bit identifier flgs fragment offset time to protocol IP header live checksum source IP address 20 bytes destination IP address Options (if any) Data Figure 1.1 -IPv4 packet header. IPv6: Version Priority Payload Length Flow Label Next Header Source Address (16 bytes) Destination Address (16 bytes) Figure 1.2 -IPv6 packet header. 1.3 Operating System Hop Limit The system that was used for our implementation was Mandrake 2.4.3 kernel. The Linux kernel series 2.2.x cannot be used, because it is not IPv6-up-to-date [4]. Thus, only kernels later than 2.2.x may be used for any implementations using IPv6 To load the IPv6 module use the command: # modprobe ipv6 To verify that the IPv6module was loaded correctly simply execute the following test: # lsmod |grep -w 'ipv6' && echo "IPv6 module successfully loaded" 1.4 Linux commands To view the routing table in IPv4 the following command is used: # route In IPv6: # route –A inet6 To view the IPv6 addresses the same command as in IPv6 may be used: # ifconfig The IPv6 address can be found directly under the IPv4 address using this. 2. Implementation 2.1 Introduction As mentioned in the first section, two complementary and cooperating routing schemes are used to form LANMAR. These schemes were implemented using three concurrent threads. A local “myopic” proactive routing scheme that operates within limited scope centered at each node and exchanges route information about nodes up to only a few hops corresponds to Fisheye Scope. A long haul distance vector routing scheme that propagates the elected landmark of each subnet and the path to it into entire network takes care of the global routing. Within our implementation Routing Information Protocol (RIP) was used but other routing protocols may be used as well. The first thread is used for sending these RIP messages. The second thread is used for sending information about Landmarks between nodes. The third thread is a common thread for receiving RIP and LANMAR messages and processing there messages accordingly. Since LANMAR is a proactive routing protocol, periodic routing update messages are sent. Landmark routing control packets have the following format: <LM_Address, LM_NextHop, LM_Distance, LM_Members, Seq#> Landmark routes are advertised to all nodes, so these packets are also sent to all nodes as well. In comparison, local routing control packet have this format: <Address, NextHop, Distance> Routes to destinations that are not Landmarks are only advertised to nodes within the scope. In our implementation the default maximum hop distance is set to 2 hops from any given node. When a message is received, a subnet mask is used to extract the group ID from a node’s IP address. Landmark election is performed only among nodes in the same LANMAR group. The subnet masks used for IPv4 and IPv6 are implemented as follows: LANMAR Group ID IPv4 Subnet Mask Version XXXXXXXX 11111111 11111111 48 bits IPv6 Network ID Subnet Mask Node ID XXXXXXXX XXXXXXXX 11111111 16 bits Grp ID 00000000 64 bits Node ID 00000000………0000000 111…11 000000……………………000000 Figure 2.1 & 2.2 -The two figures show how the subnets of nodes are calculated given a nodes IP address in both IPv4 and IPv6. In the IPv4 implementation the first 24-bits of the nodes IP address are used to elect the LANMAR group ID. However, in IPv6 the last 16-bits of the first half of the IP address are used thus taking advantage of the fact that IPv6 has dedicated this selection to identify the groups ID of an IP address. The Unicast Routing Table stores routing information for all unicast routing protocols running on router. For LANMAR the Routing Table has two sub tables, a Local routing table which is flat without the concept of a group or subnet, and the Landmark routing table keeps one entry from each group (subnet). 2.2 Challenges 2.2.1 Data Structures Various data structures are different for IPv4 and IPv6 [6]. For socket addresses the following structure struct sockaddr_in6 { sa_family_t sin6_family; /*AF_INET6*/ in_port_t sin6_port; /*Port number*/ uint32_t sin6_flowinfo; /*IPv6 traffic class and flow information*/ struct in6_addr sin6_addr; /*IPv6 address */ uint32_t sin6_scope_id; /*Set of interfaces for a scope*/ } replaces struct sockaddr { sa_family_t sin_family; /*AF_INET*/ in_port_t sin_port; /*Port number*/ struct in_addr sin_addr; /*IP address*/ } Here one can see that not only were new elements added to the structure, but also the types of some of them have changed. E.g. the type that stores an IP address has become struct in6_addr instead of struct in_addr. Below we can see that struct in6_addr has a member called s6_addr, which is an array of sixteen unsigned char, while in_addr has a member called s_addr of type unsigned int. This means that all occurences of ==, =,!=, <, >, &,and | operators that can be used for s_addr as a uint32_t can not be used for s6_addr which is a uint8_t array. struct in6_addr { uint8_t s6_addr[16]; } typedef unsigned char uint8_t; struct in_addr { in_addr_t s_addr; } typedef uint32_t in_addr_t; typedef unsigned int uint32_t; To overcome this problem a library performing all these operations was required. Here are the definitions of all the functions: void uintcpy(uint8_t array1[], const uint8_t array2[], int n); This function copies the elements of array2 into array1. int uintcmp(const uint8_t array1[], const uint8_t array2[], int n); This function returns -1 if array1 < array2, 0 if array1 = array2, 1 if array1 > array2. void uintand(uint8_t result[], const uint8_t array1[], const uint8_t array2[], int n); This function stores bitwise & of array1 and array2 in result. void uintor(uint8_t result[], const uint8_t array1[], const uint8_t array2[], int n); This function stores bitwise | of array1 and array2 in result. int uintzero(const uint8_t array[], int n); This function returns 1 if array is all 0s, and 0 otherwise. 2.2.2 Multicasting For Multicasting IPv4 uses: struct ip_mreq { struct in_addr imr_multiaddr; /* multicast group to join */ struct in_addr imr_interface; /* interface on which to join */ }; The following syntax is used for IPv6: struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast address */ unsigned int ipv6mr_interface; /* interface index; 0 => * pick a default interface * that supports IP multicast*/ }; Again the new type in6_addr for storing IPv6 addresses is used. Also instead of the actual interface, which was also of type in_addr, an integer storing the index of the interface is used. In IPv4, to use the default interface the option the interface had to be sent to inaddr_any, while in IPv6 the index is simply set to 0. Also Multicast options changed from IPv4 to IPv6. IP_MULTICAST_LOOP specifies whether or not subsequent IPv4 datagrams are looped back, giving the sender explicit control. Here is an example: u_char loop; /* 0 = disable, 1 = enable (default) */ setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)); For IPv6 this option becomes IPV6_MULTICAST_LOOP and the syntax is the following: u_int on = 0; /* 0 = disable, 1 = enable; default = 1 */ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on)) < 0){ perror("setsockopt IPV6_MULTICAST_LOOP "); } Here, in addition to appending ‘6’ to the options there is also a minuscule difference that has a major impact. The type of the variable indicating whether datagrams are looped back changed from u_char to u_int. If this minor change is not fixed, even though the variable is set to 0, datagrams will be looped back to the sender. To join an IPv4 multicast group, the option IP_ADD_MEMBERSHIP was used, such as in: struct ip_mreq mreq; setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); In IPv6 this simple becomes IPV6_ADD_MEMBERSHIP, and the corresponding IPv6 structures are used. struct ipv6_mreq imr6; imr6.ipv6mr_interface = if_index; if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&imr6, sizeof(imr6)) < 0) { perror("setsockopt IPV6_JOIN_GROUP"); } 2.2.3 Functions Some functions that only support IPv4 addresses had to be replaced with the newer versions that support both [8] IPv4 and IPv6. Address and protocol family constants are used to indicate whether IPv4 or IPv6 will be used. AF_INET6 stands for the IPv6 address family, and PF_INET6 for the IPv6 protocol family. They replace AF_INET and PF_INET which correspond to IPv4. gethostbyname() retrieves the network host entry referenced by a host name with an IPv4 address. This had to be replaced with gethostbyname2(), which retrieves the network host entry referenced by a host name and its address family, which will be AF_INET6 . inet_addr() interprets a character string representing an address in Internet dot notation (IPv4) and returns a value suitable for use as an Internet address. inet_pton() performs the same operation for both IPv4 and IPv6 address notations. This is the synopsis for both these functions: in_addr_t inet_addr(const char *cp); char *inet_pton(int af, const char *src, void *dst); af specifies the address family and src points to the presentation-format address. The format of the address is interpreted according to af. dst points to the buffer into which the converted address is stored. While inet_addr returnes the address, inet_pton stores the result in the buffer pointed to by dst and returns 1 if successfull, 0 if the address was not parsable in the specified address family, and -1 otherwise. inet_ntoa() interprets an IPv4 internet address and converts it to a character string. inet_ntop() performs the same operation for both IPv4 and IPv6 addresses. The following is the synopsis for both functions: char *inet_ntoa(struct in_addr in); char *inet_ ntop(int af, const void *src, char *dst, size_t size); in is the internet host address to convert. af specifies the address family and src points to the address. The format of the address is interpreted according to af. dst points to the buffer where the converted address is stored. size is the size of dst, in bytes. The inet_ntoa() function returns a pointer to the network address in Internet standard dot notation. On success, the inet_ntop() function returns dst, otherwise it returns a null pointer 2.2.4 Routing Table and IP address configuration The IPv6 addresses for the local interfaces are found in the file /proc/net/if_inet6 after the IPv6 module has been loaded. The format of this file is: 00000000000000000000000000000001 01 Figure 2.3 10 80 01 lo - Format of the file /proc/net/if_inet6 The following is a list of the functions of each of the columns enumerated from left to right: 1.) IPv6 addresses in 32-bit hexadecimal. 2.) Interface device index number in hexadecimal. 3.) IPv6 address prefix in hexadecimal. 4.) Scope value. 5.) Flags set. 6.) Device name. The IPv6 routing table can be found in the file /proc/net/ipv6_route. The format of the file is: 00000000000000000000000000000000 00000000000000000000000000000000 Figure 2.4 00 00000000000000000000000000000000 ffffffff 00000001 00000001 00000000 -Format of the file /proc/net/ipv6_route *All of the information is given on a single row in the actual file. It is given in two rows here because of formatting constraints. The following is the list of what the fields are for enumerated from left to right and top to bottom: 1.) IPv6 destination addresses given in 32-bit hexadecimal. 2.) Destination prefix given in hexadecimal. 3.) IPv6 source address given in 32-bit hexadecimal. 4.) Source prefix given in hexadecimal. 5.) IPv6 next hop address given in 32-bit hexadecimal. 6.) Metric in hexadecimal. 7.) Reference count. 8.) Use count. 9.) Flags set. 10.) Device name. As one can see there are various changes to the IPv6 routing table from the IPv4 routing table. One challenge that the new routing table presented was the introduction of the 00 lo prefix fields for both the destination and the source addresses. The prefix could not be calculated from the IP after masking it because of the short cuts that IPv6 uses to represent addresses (section 1.2) because it is impossible to determine whether the user wanted a short cut section as part of the subnet or not. Thus, in our implementation the prefix of the subnet is calculated from the hard-coded LANDMARK_MASK6. Thus, the developer can specify all the bits that are to be used in the mask without short cuts which makes calculation of the prefix possible. Another issue that the prefix brought about was in the implementation of RIP. IPv4 does not use prefix’s but rather mask’s. Since this mask field was eliminated from IPv6 a prefix had to be calculated to add to the IPv6 routing messages before adding it to the routing table. There were two solutions to this problem. The first solution was to add the nodes prefix along with the IP address to the RIP messages. This would have worked but this would require that RIP messages be larger to accommodate the prefix. Thus, another solution was proposed that the prefix of all IP addresses that are received by RIP all have the prefix of 128. This solution works since the unicast address of any node will require that all 128 bits of the address be used to determine the correct node. Also, this solution would not require extraneous modifications to the RIP messages. 2.2.5 Adding, Deleting and Updating Routes. Changes had to be made to the IPv4 implementation so that the system knew to make changes to the IPv6 routing table instead of the IPv4 one. The linux command ioctl was used in the IPv4 implementation to send routing commands to the kernel. This function is still used in the IPv6 implementation but instead of sending it struct rtentry this is replaced with struct in6_rtmsg otherwise everything else remains unchanged. The format of the structure is as follows: struct in6_rtmsg { struct in6_addr rtmsg_dst; struct in6_addr rtmsg_src; struct in6_addr rtmsg_gateway; u_int32_t rtmsg_type; u_int16_t rtmsg_dst_len; u_int16_t rtmsg_src_len; u_int32_t rtmsg_metric; unsigned long int rtmsg_info; u_int32_t rtmsg_flags; int rtmsg_ifindex; }; Clearly, there are numerous changes to the routing message that the kernel receives to update the table. One note worthy change to the routing message is that the IPv6 message no longer takes the name of the interface device in a char* but now it take the index of the device thus the index of the device must be found within the application and explicitly added to the in6_rtmsg structure before calling ioctl with the new routing message. 3. Conclusion & Future work This project proved to be a great challenge given the fact that documentation of IPv6 was scarce in addition to being very parse. The greatest implementation challenge was simply determining how changes from IPv4 to IPv6 would affect other parts of the implementations. The most obvious example of this would be replacing the old IPv4 addresses with the new IPv6 addresses. Not only did the syntax have to be changed throughout all of the code to accommodate IPv6 addresses but this change also affected how the landmark subnet was calculated. Also, this affected how IP addresses were compared (see section 2.1.3), the size of lanmar and routing messages sent to other nodes, and the way messages received by nodes were parsed. Further more this, affected how addresses were parsed and represented to the user on top of numerous other minuscule changes. So as you can see from just this one example a minor change can affect numerous things and thus this was the axiom throughout the entire project. However, in the end we were able to complete the entire implementation of LANMAR in IPv6. Testing of this implementation was done mainly using ping6 and simply outputting all the packets received by all the nodes to the screen. We were able to test this implementation with variations on three nodes thus allowing us to verify that the implementation followed the LANMAR scheme as expected. However, large amounts of traffic with a large sample of nodes were not tested nor were samples taken of round trip time or throughput and thus these are areas for future work. References [1] G. Pei. M.Gerla, and X. Hong, " LANMAR: Landmark Routing for Large Scale Wireless Ad Hoc Networks with Group Mobility, " In Proceedings of IEEE/ACM MobiHOC 2000, Boston, MA, Aug. 2000. [2] Xiaoyan Hong,Li Ma, Mario Gerla, " Multiple-Landmark Routing for Large Groups in Ad Hoc Networks, " In Proceedings of MILCOM 2002 Military Communications Conferences, Anaheim, CA, Oct.7-10,2002. [3] Kaixin Xu,Xiaoyan Hong, and Mario Gerla, " Landmark Routing in Ad Hoc Networks with Mobile Backbones, " In Journal of Parallel and Distributed Computing (JPDC), Special Issues on Ad Hoc Networks, 2002. [4] http://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ [5] http://keetweej.vanheusden.com/~folkert/porting_ipv4_to_ipv6.html [6] http://www.opengroup.org/onlinepubs/007904975/basedefs/netinet/in.h.html [7] Lecture slides from cs118 and cs218 http://www.cs.ucla.edu/classes/spring03/cs118/slides.html http://www.cs.ucla.edu/classes/fall03/cs218/slides.html [8] http://www.mkssoftware.com/docs/man3/inet_pton.3.asp http://www.mkssoftware.com/docs/man3/inet_addr.3.asp http://www.mkssoftware.com/docs/man3/inet_ntop.3.asp http://www.mkssoftware.com/docs/man3/inet_ntoa.3.asp Landm ark routing table [9] http://sources.redhat.com/ml/libc-hacker/2002-10/txt00000.txt [10] http://www.linux.org/docs/ldp/howto/Linux+IPv6-HOWTO/proc-net.html [11] Structures for new routing entry in IPv6 http://sources.redhat.com/ml/libc-hacker/2002-10/txt00000.txt [12] Yeng-Zhong Lee “How to implement routing protocols on Linux”