Part II: Supporting Emulation
5. Design and Implementation
5.3 Design of Emulation Daemon for External Host
Besides capturing packets from the kernel, the emulation daemon has another important task. This is to direct packets to the correct direction. This section will
describe how to divert packets from real-world hosts to the simulation machine and how to divert packets from the simulation machine to real-world hosts.
5.3.1 Adding Routing Entries
In figure II-5.1(a), the external host (the real-world host) is equipped with a Fast Ethernet interface and this interface is configured with an IP address 10.0.0.2. The simulation machine’s Fast Ethernet interface is configured with an IP address 10.0.0.1.
In simulation network, the external host node 1 represents the external host and the external host node 1 has a tunnel interface with an assigned IP address 1.0.1.1 (in our simulator, the IP address format is always 1.0.X.X. [1]). In figure II-5.1(a), if a TCP sender that is running on the external host wants to communicate with the TCP receiver that is running on host node 2, it should use 1.0.1.2 as the destination IP address. On the other hand, if a TCP sender running on host node 2, it should use 1.0.1.1 as the destination IP address to establish a TCP connection with the TCP receiver that is run on the external host (Note: we can not and should not use 10.0.0.2 as the destination IP address. We will explain this in section 5.3.2). As such, when the external host wants to send packets to the simulation machine, we can simply add a routing entry at the external host:
# route add 1.0/16 10.0.0.1
(Assuming that the external host is a FreeBSD system)
The above command indicates that all outgoing packets whose destination IP address is 1.0.X.X should be first sent to the gateway whose IP address is 10.0.0.1.
Because the simulation machine is configured with the IP address 10.0.1.1. As such, if any packet matches this rule, it will be sent to the simulation machine.
5.3.2 Translate IP Address
Until now, readers may be confused with the two IP address: 1.0.1.1 and 10.0.0.2. This is also the reason why the emulation daemon has to translate IP addresses. In figure II-5.1(a), the TCP sender establishes a TCP connection with the TCP receiver that binds 1.0.1.2 as its source IP address. Therefore, the TCP sender would think that the TCP connection is built between 10.0.0.2 and 1.0.1.2. However, when the TCP sender sends its packets to 1.0.1.2, these packets will be captured and delivered to the emulation daemon and their source IP address may be modified from 10.0.0.2 to 1.0.1.1. This is because the external host node 1 represents the external host in the simulation network and node 1’s IP address is 1.0.1.1. All packets generated by the external host should be treated as that they were sent out from 1.0.1.1. If we do not do this, the simulation network will not know which node 10.0.0.2 belongs to. With this modification, the TCP receiver will think that the TCP connection is built between 1.0.1.1 and 1.0.1.2. The TCP receiver will return a TCP ack packet with destination IP address 1.0.1.1 (Of course, the source IP address is 1.0.1.2).
When the TCP ACK packet comes back to the external host node 1 (figure II-5.1(b)), the packets will be captured and delivered to the emulation daemon by the IP filter II. Then, the daemon will modify the destination IP address 1.0.1.1 to 10.0.0.2. In the mean time, its source IP address is still 1.0.1.2. Therefore, the ack packet can easily reach the external host and the TCP sender will not know that its packets’ IP addresses have been modified.
5.3.3 Translate Port Number
Why does the emulation daemon need to translate the port number that is inside the UDP/TCP header? This is due to the design of NCTUns network simulator. In section 4.3.4 of part I, we have explained why to do port number mapping and translation in the kernel. In figure II-5.1(a), we assume that the TCP receiver’s virtual port number is 8000 and the real port number is 5000. We also assume that the TCP sender’s port number is 4000 (The TCP sender does not have virtual port number because it is run on a real-world host.). When the TCP sender sends out a TCP data packet A, the packet’s destination port number will be 8000, and its source port number is 4000. Then, when the packet A arrives at host node 2, the destination port number will need to be modified to 5000 (Source port number will still be 4000 because the kernel can not find any virtual port corresponding to port number 4000 in external host node 1). Continuing with figure II-5.1(b), the kernel will just exchange the destination/source port number pair of packet A to be as the TCP ack packet B’s destination/source port number pair. Therefore, the ack packet B’s destination/source port number pair will be 4000/5000. If we do not modify packet B’s port number, the TCP sender may think the TCP receiver is bound at port number 5000. However, the TCP sender originally expects to establish a TCP connection with the foreign port number 8000, not 5000. Therefore, this connection can not be set up. For this reason, when the packet B is captured by the emulation daemon, we should modify its source port number from 5000 to 8000.
Here, a problem happens. How the emulation daemon knows how to modify the packet B’s port number? It is simple. When the packet A is captured by the emulation daemon, the emulation daemon records the packet’s destination/source port number
pair and destination/source IP address pair. If any packet B is captured by the emulation daemon, we just compare B’s destination/source IP address and destination port number with the emulation daemon’s record table. If a record is matched, we fill the record’s destination port number into B’s source port number.
5.3.4 Setting Packet Filter Rules
In figure II-5.1 (a), the IP filter rule used by IP filter I should be set like the following:
# ipfw add divert 2000 ip from 10.0.0.2 to any in
This is very obviously. All packets from 10.0.0.2 should be captured to the emulation daemon that creates a divert socket with divert port number 2000.
In figure II-5.1 (b), the IP filter rule used by IP filter II should be set like the following:
# ipfw add divert 2000 ip from any to 1.0.1.1 in
This means that all packets whose destination IP address is 1.0.1.1 should be captured to the emulation daemon. Here, readers may find a problem: when host node 2 sends out the packet B (we describe it in section 5.3.3), its destination IP address will be 1.0.1.1 (In section 5.3.2, we already explain why the destination IP address is 1.0.1.1 instead of 10.0.0.2). It is possible that packet B is captured at host node 2 instead of the external host node 1 and as such the packet B will not experience the simulation of the two virtual links and a switch node. However, this situation will not happen.
This is because we use the S.S.D.D IP scheme in the kernel, packet B’s destination IP address is 1.2.1.1 rather than 1.0.1.1. Only when packet B reaches the tunnel interface 1.0.1.1 (when the packet arrives at the destination node), the destination IP address
will be modified back to 1.0.1.1.