During the implementation, we had to make several architectural decisions such as where within the NCTUns framework our implementation would be fitted in or how user and/or application interaction would be provided. Also we had to choose the most appropriate programming model for a seamless and problem-free integrating with the NCTUns framework.
Implementation layer
The existing protocol stack of NCTUns allows us to integrate geonetworking protocol layer in parallel to the existing WAVE Short Messages Protocol (WSMP) and on top of the IEEE 802.11p. However, in order to avoid many changes or adaptations, researchers in GeoNet project implemented their geonetworing layer in the application layer [13]. Following their footsteps, we also implemented the ETSI compliant geonetworking protocol layer as an user-space application (see Figure 1).
Application interface
We based our implementation of the application interface on the well know Berkeley socket API in order to make its use as seamless as possible for the applications (see Figure 2). Applications, using our geonetworking layer, would connect to a predefined port in order to send and receive packets. Packets exchanged between the application and the geonetworking layer consists of two parts, namely, the control block and the payload. The control block holds the packet type and addressing information, whereas the payload block holds the actual data. Algorithm 1 shows the flow of a simple traffic generator application for the proposed framework.
Architecture
The ETSI complaint Geonetworking protocol layer can be implemented using either a multi-threaded or monolithic single process programming model. Both programming models have their advantages and disadvantages, such as a multi-threaded approach can handle concurrent packets, while a single process approach is easier to implement. We based our implementation on the monolithic single process programming model, as initial tests showed that, multi-threaded extensions to the NCTUns framework were causing instability issues. We employed a modular approach and realized each module as a function.
Algorithm 1 Flow of a simple traffic generator program, which is using our framework for routing packets
A block diagram of our implementation is given in Figure 3, where each module is represented with a block. Our implementation consists of 10 different modules, which perform specific tasks. The packet receiver module listens for incoming packets, and performs type checking using the HT field in the common header of the packets, and then puts them into the respective queue. Each packet type is handled by a packet handler module specific to the that type. Thus, we implemented 5 different packet handler modules, namely; beacon handler, geounicast handler, geoanycast handler, geobroadcast handler and topo-broadcast handler. Each packet handler module has a circular buffer for incoming packets. On the other hand, they use a shared circular buffer for outgoing packets.
Beacon handler first checks the validity of a received beacon, and then searches for a Location table entry (LocTE) related to the sender of that beacon. If no match is found, a new LocTE is added to the location table (LocT). If a match is found, a timestamp checking is performed to validate the freshness of the received information. If the received packet is newer, then the LocTE is updated with the fresh information. Otherwise, the beacon packet is discarded. The beacon handler is also responsible of generating beacon packets and handing them over to the packet sender for broadcasting. Flow of the beacon handler module is given in Algorithm 2.
Algorithm 2 Flow of beacon handler module
Other packet handler modules work in a similar fashion to each other. Each module first performs a duplicate packet checking, then updates LocT by using the position information of the source, the destination, and the previous node. If the packet’s final destination is the node itself, then the packet is passed to the upper layer for further processing. If the packet is destined to an other node or a geographical location, it is enqueued to be forwarded by the packet sender module with a new next hop. A generic flow for tha packet handler modules is given in Algorithm 3.
Algorithm 3 General flow of the packet handler modules
The packet sender module scans the shared circular output buffer of the packet handling modules and sends packets, which are labeled as ready, to their next hop. It also takes care of pending packets, which are missing their next hops. It scans the LocT to find an appropriate next hop.
LocTEs are created by packet handling modules and maintained by the LocT management service. The location table management module checks the validity of LocTEs by comparing the timestamp field of the LocTEs with the current timestamp. The location table management module is also responsible of updating the self position information. Basically it gets the position information from the simulation API and applies the cartesian to geodesic conversion, which is discussed in detail, in Section 1.
The management console shown in the left hand side of the Figure 3 is not part of the ETSI specification, but we added it to our implementation for management and testing purposes. It provides a user interface to fully manage, configure and track the execution of each module. The management console makes it possible to enable or disable individual modules or change their operating parameters, such as beacon interval, location table entry expiration time.
ETSI geonetworking specification includes a location service to obtain the position information of other nodes. Whenever a node requires the position information of a node other than its neighbors, it starts a location service query by broadcasting an LS Request packet. Neighbors, receiving this request, reply with the position information of the requested node, or forward this query to their neighbors by broadcast. As it was not our primary concern, we implemented the location query service in a more simplified way. Each node updates its current position information in a shared buffer. This buffer is only used to obtain the position information of a destination, before starting a communication. While forwarding packets, nodes make use of the LocT.
Logging mechanisms
Along a realistic and accurate simulation of any given IVC application, it is also important to gather crucial simulation data for offline processing and evaluation. Therefore, we paid special attention to the logging mechanism. Our primary logging implementation was a simple file system based mechanism. However we observed that this method decreased the performance of the simulation drastically, especially as the number of the vehicles in the simulation increased. Thus, we switched to a database oriented logging system.
Instead of embedding blocking SQL statements into the application, we provided the applications with a UDP based access to the SQL logging. The SQL based logging server runs outside of the simulation environment as a separate process. It receives performance data regarding to simulation from the application in the form of UDP messages and commits them into the database. The benefit of this approach is two fold. First, SQL coding is decoupled from the geonetworking layer, second geonetworking layer does not block on time consuming SQL transactions.
Node configuration
In our framework, we employed Unix-like text based configuration files to configure characteristics and behavior of each node in the simulation. In the configuration files, mechanisms are provided to set the role of the node as either OBU or RSU, or to define the number of RSU, and their unique IDs. A script is also provided for generating configuration files automatically for large deployments of VANETs.
Time measurements
There are two mechanisms to get accurate time measurements. The first mechanism is to use the time() function, which can be used by the inclusion of the <time.h> library. However, this function only supplies the current timestamp with a second-level precision. Thus, another mechanism is required to make more precise delay calculations.
Therefore, we employed a tick mechanism to make these precise measurements. Whenever the application goes into the run mode from the sleep mode, it increases a variable, which is named as tick. This tick variable, together with the time() function, enables us to perform high precision timing measurements. These mechanisms are also used in the calculation of end-to-end delays and to achieve a global synchronize among the processes representing the vehicles.