Router Simulation as client of generic HashTable
Educational Objectives: After completing this assignment, the student should be able to accomplish the following:
Explain the concept of Internet Router and Route Table
Implement a Route Table using the ADT Table (and, in particular, using an implementation using hash tables.
Code functions operating at the bit level using masks and bitwise operations.
Background Knowledge Required: Be sure that you have mastered the material in these chapters before beginning the assignment:
Introduction to Sets, Introduction to Maps, Hashing, and Hash Tables.
Operational Objectives: Implement the class Router as well as stand-alone IP utility functions to be used with the distributed client program ipmain.cpp to simulate the operation of an Internet router.
Deliverables: Four files:
iprouter.cpp # contains Router implementations and supporting function implementations
iputil.cpp # contains IP utility function implementations
log.txt # your project work log
hashtbl.h # deliverable from previous project (should be identical to previous submission)
Procedural Requirements:
The official development/testing/assessment environment is specified in the Course Organizer.
Create and work within a separate subdirectory cop4530/proj7.
Do your own work. Variations of this project have been used in previous courses. You are not permitted to seek help from former students or their work products. For this and all other projects, it is a violation of course ethics and the student honor code to use, or attempt to use, code from any source other than that explicitly distributed in the course code library, or to give or receive help on this project from anyone other than the course instruction staff. See Introduction/Work Rules.
Begin by copying the entire directory LIB/proj7 into your proj7 directory. At this point you should see these files in your directory (along with others):
iprouter.h # classes Router and ipHash
iprouter.cpp.start # starting point for iprouter.cpp
iputil.h # ip utility function prototypes
iputil.cpp.start # starting point for iputil.cpp
ipmain.cpp # internet router simulator
ip_ranmap.cpp # random ip map generator
ip_ranmsg.cpp # random ip msg generator
makefile.ip # build ip router project
deliverables.sh # submission configuration file
Then copy these relevant executables:
LIB/area51/iprouter_i.x # sample iprouter executable
LIB/area51/ip_ranmap_i.x # random ip map generator
LIB/area51/ip_ranmsg_i.x # random ip traffic generator
The executables in area51 are distributed only for your information and experimentation, as well as the exercises in the lecture notes. You will not use these files in your own project, but they will help you understand hashing and hash tables and are very useful in preparing for the final exam. When you have questions about behavior of either hash tables or the router simulation, use these executable to find the answer.
You are to implement the core functionalities of the iprouter simulation: class Router (in iprouter.cpp) and ip utilities (in iputil.cpp). These are used with the distributed client program ipmain.cpp.
File iprouter.cpp should contain implementations of Router methods. The startup file contains all of the boiler plate and some other methods already completed.
File iputil.cpp should contain implementations of ip utility functions prototyped in iputil.h. Again, the startup file contains all of the boiler plate and some of the implementations.
The makefile makefile.ip builds the executables iprouter.x, ip_ranmap.x, and ip_ranmsg.x. You can test different targets individually by naming them as an argument to the make command.
Submit the assignment using the script LIB/scripts/submit.sh.
IP Addressing:
There are two ways to represent ip addresses: the 4-number "dot" notation and the 32-bit (4-byte) "number" notation. The dot notation we store as a String object (typedef ipString) and the number notation we store as an uint32_t object (typedef ipNumber). Generally, a router uses ipNumber as its internal representation, while externally across the Internet the ipString representation is used.
The ipString representation consists of four numerical fields separated by (three) dots. For example, 128.186.121.211 is the ip address of a machine in the computer science department. Each numerical field in this address represents a number in the range [0, 255]. (Numbers 256 or greater make an invalid ipString. We also define the zero address 0.0.0.0 as invalid.) This number in turn denotes an 8-bit (one byte) quantity. The four numerical fields, concatenated, represent 32 bits or 4 bytes. This 4-byte number is the internal ipNumber representation. In general, we use hexadecimal (base 16) representation to denote ipNumber objects. The ipNumber representation of the address above is 10000000101110100111100111010011 (bin) = 80BA79D3 (hex).
The ipClass of an ip address is defined in terms of the bits in its ipNumber representation. There are three recognized classes of ipNumbers: A, B, and C. An ipNumber that is not one of these classes is called bad and cannot be used. Class A consists of ipNumbers beginning (on the left) with bit '0'. Class B begins with bits '10'. Class C begins with bits '110'. All other ipNumbers are bad. (Note that bad ipNumbers are not the same as invalid ipStrings.) A good (i.e., not bad) ipNumber contains information in fields called netID and hostID. The ranges of these fields depend on the class, as shown in the following table (numbering the bits from the left, starting with 1):
Class A: netID = bits 2..8; hostID = bits 9..32
Class B: netID = bits 3..16; hostID = bits 17..32
Class C: netID = bits 4..24; hostID = bits 25..32
The netID and hostID are full 32-bit words with the irrelevant bits masked to zero. For example, the address 80BA79D3 is class B with netID = 00BA0000 and hostID = 000079D3. netID and hostID are used by a router to forward messages. We do not express netID and hostID in "dot" notation. The following summarizes the calculations:
ipString 128.186.121.211
ipNumber (bin) 1000 0000 1011 1010 0111 1001 1101 0011
ipNumber (hex) 8 0 B A 7 9 D 3 = 80BA79D3
ipClass class B
netMaskB (bin) 0011 1111 1111 1111 0000 0000 0000 0000
netMaskB (hex) 3 F F F 0 0 0 0 = 3FFF0000
netID (bin) 0000 0000 1011 1010 0000 0000 0000 0000
netID (hex) 0 0 B A 0 0 0 0 = 00BA0000
hostMaskB (bin) 0000 0000 0000 0000 1111 1111 1111 1111
hostMaskB (hex) 0 0 0 0 F F F F = 0000FFFF
hostID (bin) 0000 0000 0000 0000 0111 1001 1101 0011
hostID (hex) 0 0 0 0 7 9 D 3 = 000079D3
Question: What is the largest allowed first field for a good ipString? Are any of the other fields constrained?
Real Routers:
Routers are special-purpose computers that monitor Internet traffic, either rejecting or accepting messages. Accepted messages are forwarded and rejected messages are ignored. For example, the Love Building router run by the Computer Science department rejects incoming messages that are not addressed to a machine in the building, and accepts and forwards messages addressed to one of the machines in the building. It also forwards outgoing messages to another router for further routing. Much of the computation has direct hardware support, enabling speed (bandwidth) to excede 1 gigabit. The route tables, in contrast, need to be software tables so that the router can be programmed as both internal and external machine configurations and addresses evolve. Hash tables/maps are the only data structure that guarantees fast enough lookup for today's high-bandwidth routers.
Code Requirements and Specifications - class Router and supporting utilities
1) Router Types. The following type definitions facilitate both code and comprehension of the Internet Router simulation: in iputil.h.
typedef uint32_t ipNumber;
typedef fsu::String ipString;
enum ipClass
{
classA, classB, classC, badClass
} ;
2) Output operator. The output operator <<() is overloaded for type ipClass using the following prototype:
std::ostream& operator << (std::ostream& os, ipClass ipc);
// sends 'A', 'B', 'C', or 'D' to os depending on ipClass value
3) Router API. The API consists of the public interface of class Router (in iprouter.h) together with the utility functions prototyped in iputil.h:
class Router
{
public:
void Load (const char* loadfile);
void Save (const char* savefile);
void Insert (const ipString& dS, const ipString& rS, bool verify = 0);
void Remove (const ipString& dS);
void Go (const char* msgfile, bool verbose = 0, const char* logfile = nullptr);
void Clear ();
void Dump (const char* dumpfile);
void Analysis ();
void Rehash (size_t numBuckets = 0);
Router (size_t sizeEstimate);
~Router ();
...
};
ipClass ipInterpret
(
const ipNumber& address, // the only "input"
ipNumber& netID, // calculated netID of address
ipNumber& hostID // calculated hostID of address
);
// pre: none
// post: netID and hostID for address are set (these are set to 0 in case address is badClass)
// return: the ipClass of the address
ipNumber ipS2ipN (const ipString& ips); // converts ipString to ipNumber
ipString ipN2ipS (ipNumber ipn); // converts ipNumber to ipString
Go() performs a simulation as described in more detail below.
Load() and Save() build/save the route table from/to an external file.
Insert() and Remove() are similar to the standard table operations, except that they must translate input from ipString to ipNumber prior to accessing the underlying table.
The "verify = true" option for Insert displays the inserted pair twice: first as entered by the user, and second as retrieved from the table and translated back to ipString notation. This provides a visual check that the translations and insertions are working correctly.
Go() and Dump() send output to screen when passed a 0 pointer as output file parameter; otherwise all char* parameters are treated as external file names.
Analysis, Rehash, and Dump just pass the command through to the underlying hash table interface.
4) Data Structures. Class Router uses a private HashTable object as the primary data structure supporting the route table.
Note: This object needs to be created dynamically in order to set the number of buckets. Class ipHash is a function class used to instantiate the hash table.
5) Data, Table, and File Format. Router objects use three distinct kinds of files: table files, message files, and log files.
A table file (extension .map) consists of pairs of ipNumber (one pair per line) written in hex notation with '0' fill, so that all entries have 8 characters. The Load(filename) method of a RouteTable object reads data from a table file and inserts the data into its internal table. The Save(filename) method writes all data in the internal table to a table file.
The internal table also uses ipNumber representation of addresses.
The ipNumber pairs in a route table are destination and route pairs. The destination is the key, and the route is the data in the table.
When individual entries are inserted, removed, or looked up (via the Router public interface) in the internal table, the external ipString representation is used for input.
The message file (extension .msg) consists of two strings per line. The first string of the packet (line) is an ip address in dot notation (intended to be the destination of the message) and the second is a message ID (simulating the body or content of a real message). Each line of this file represents one "message packet" coming in to the router.
The log file (extension .log) should contain one line for each message packet in the message file. The log entry for a message should begin with the message ID, followed by the ipNumber of the destination (8-digit hex), then the ipClass and the routing information (netID and hostID) for the message.
6) Go. The Go(msgfile, verbose, logfile) method is the method that simulates a router in operational mode. The incoming internet traffic is simulated by a message file. Each line of the message file can be thought of as a "packet" with a destination and a message body. If (verbose == true) the result of routing this traffic is logged. If (logfile == nullptr) the traffic log is standard output, otherwise it is in the file named.
Go() should read message packets (lines) one at a time from a message file. For each message packet (line of the message file), the router (1) reads the destination address and converts it to ipNumber form; (2) does not attempt to process the packet if the ipClass is bad; otherise (3) looks up the packet destination in the internal table; (4) if not found, rejects the packet; (5) otherwise routes the packet using the netID and hostID of the route retrieved from the table; (6) (if verbose == true) writes the disposition of the message packet to the log file (or the screen if logfile == nullptr).
At the end of processing a message file Go should report summary data to screen. The screen should look something like this when Go(ip.1000000.msg, 0) is called:
Router simulation started
Packets processed: 1000000
Packets routed: 900253
route class A: 513386
route class B: 258446
route class C: 128421
Packets rejected: 87160
Packets bad: 12587
Router simulation stopped
7) Running a Simulation. Your Router class and ip utilities should work with the supplied client program ipmain.cpp, which simulates the operation of a router.
Hints:
The client program ipmain.cpp is distributed in the project directory, along with a small selection of table files and message files. More can be generated with the supplied random map and message generators.
You can assume that the table files contain only good ipNumbers, since in principle they are all created by a properly operating router.
Note that the random ip table generator ensures that (1) no entry is a badClass, and (2) entries are not redundant. These are constraints that would be ensured by creating the table using Router::Save.
Note that the random ip traffic generator works with a given ip table file to ensure that (1) most traffic generated has destinations in the table. In addition (2) the percentage of bad ipStrings is limited to fewer than 10%.
You can assume that incoming messages will have valid dot-notation strings as destinations, but you cannot assume that incoming message destination strings denote good ipClasses.
You cannot assume that user entries are either valid or good. This implies that Router::Insert must check validity and goodness after translating the ipString to an ipNumber, and refusing invalid and bad entries.
To read and write the hex codes correctly, you will need (1) to manipulate the std::ios:: flags hex and uppercase for both input and output streams; (2) to set the fill character using the manipulator std::setfill(); and (3) to use the std::setw() manipulator to set the column width in output.
The hash function class ipHash is defined and implemented as follows:
// in file iprouter.h
class ipHash
{
public:
unsigned int operator () (const ipNumber&) const;
} ;
// in file iprouter.cpp
#include
uint32_t ipHash::operator () (const ipNumber& ipn) const
{
return hashfunction::KISS(ipn);
}
You need a hash function object to instantiate a hash table object.
You need only one private data item in RouteTable: a pointer to a HashTable<> object.
Sample executables iprouter_i.x, ip_ranmap.x, and ip_ranmsg.x are supplied in LIB/area51. A few sample route table and message files are supplied in LIB/proj7. Others can be generated with the two random generators.
Attachment:- ip-router.rar