Frequently Asked Questions about
Well, "frequently asked" is a bit of a misnomer, since no one has
actually asked any of these questions yet, and now with this information
provided here, presumably no one ever will. But somehow "Might Have
Been Frequently Asked Questions" sounds too awkward.
Q. What is NIST Net, and what is it for?
NIST Net is a network emulation package that runs on Linux. NIST Net
allows a single Linux box set up as a router to emulate a wide variety of
network conditions, such as packet loss, duplication, delay and jitter,
bandwidth limitations, and network congestion. This allows testing of
network-adaptive protocols and applications (or those which aren't,
but maybe should be) in a lab setting.
Q. What is "emulation," and how does it differ from "simulation"?
As the terms are used here, "emulation" is basically testing code inserted
into a "live" implementation, allowing the live implementation to emulate
(imitate) the performance characteristics of other networks. "Simulation"
is a totally synthetic test environment, without a live component.
Q. What do I need to run NIST Net?
- A Linux 2.0.XX installation, with XX >= 30. Actually, the emulator
itself should work with any 2.0 kernel, while the required kernel
patches install successfully on at least 2.0.27 - 2.0.37. I
personally only tend to install it on Slackware distributions, but
it does work for other distributions as well.
The new alpha version now installs on 2.0.27 - 2.0.38 and 2.2.5 - 2.2.16.
- One or more network interfaces. Typically, NIST Net is installed
on a box with two Ethernet cards which is routing between two subnets.
This allows it to munge all traffic flowing between the two networks.
It can also be set up on an end node, to munge traffic into that node.
There is no dependence on the interface type; token ring or PPP should
work as well as Ethernet.
- An X11R6 installation, for the user interface. The interface is
built on the Athena widget set, but any of the drop-in replacements
should work as well. I personally use
the NeXT-like libneXtaw widget set,
as seen in the included screen shots.
Q. What are the machine requirements for NIST Net?
Essentially, NIST Net needs enough kernel memory to store any delayed
packets, and enough processor speed such that the additional overhead
it introduces doesn't skew its delay properties too noticeably.
(Currently, NIST Net does not account for its own overhead in computing
delay factors, under the assumption this is negligible.)
As a couple of data points, NIST Net has been run successfully on a
25/50 MHz 486 with 16M of memory doing emulation on 10Mb Ethernet,
and on a 200MHz Pentium with 32M of memory doing emulation on 100Mb
Ethernet. Measured per-packet overhead for the first configuration was
around 28 microseconds, and for the second, around 5-7 microseconds.
Both values are well under the usual minimum inter-packet times on these
networks, so should not have any (inherent) adverse effect on packet
handling. (The emulator reports average observed overhead through the
HITIOCTL_GLOBALSTATS ioctl.)
The overhead for the new alpha is currently a bit higher, as are its
memory requirements. I will be working on these aspects over the next
few weeks.
Q. Will NIST Net be ported to a 2.1 or later kernel, or an operating system
other than Linux? How about other widget sets?
Yes, the new alpha version runs on 2.2.xx kernel, for at least
5 <= xx <=16.
There don't seem to be any compelling reasons
to port it to other operating systems or widget sets at this time. When
used as a router, NIST Net emulation can affect any IP traffic from any
source to any destination, regardless of their operating systems.
If you want something similar that runs on SunOS, NIST Net was partially
inspired by (and retains some of the interfaces of) the
hitbox emulator used by USC in testing TCP/Vegas.
If for some reason
you want something similar that runs on a MicroSoft Windows operating
system, I understand there are commercial packages along these lines.
I do not have any further details about them, though.
Q. Why does NIST Net emulation only affect incoming traffic and not
outgoing traffic?
Basically because it was easier (i.e., required less disruption of
the kernel code) to do it that way. When NIST Net is used on a router,
catching packets at receive time suffices to affect all traffic.
This isn't true on an end node, of course, but hopefully the
provided capabilities will be sufficient.
There are vague plans to redo the packet interception code to allow
handling outgoing traffic too. Don't expect this before summer 2000,
though.
For the purposes of the emulator, any congestion-dependant packet dropping
mechanism is really sufficient. The main problem with DRD in a router
implementation is that an instantaneous traffic burst could lead to a large
number of near-simultaneous drops, and hence correlation of the subsequent
restarts, from multiple TCP connections. But since this emulator can
treat any source/destination pair separately, there's no need to end up with
correlated drops.
Of course, if the goal is actually to test RED or some variant thereof,
it can be implemented as an "add-on" packet munger.
Q. Why are kernel patches required? Couldn't it all have been done
as a kernel module?
Well, in a certain sense anything could be done as a kernel module.
But there were a couple of areas where patching the base kernel
seemed like the most expeditious approach, even though it did add
a kernel version dependence:
- "Fast timer" code. In order to get fine enough granularity in
the timer for reasonably precise delay emulation, the timer chip is
reprogrammed to interrupt at a faster rate. In order not to affect
kernel code which relies on the normal rate, the interrupt handler
was somewhat reworked. This would have been rather difficult to do
outside this code.
- Network interface export. Not all the kernel network code
interfaces needed by the emulator were exported, for some reason.
There was also no interface to find existing packet handlers, for
cases (like this one) where we want to supplement, not replace,
the existing handler.
Q. Why didn't they implement a faster timer in ordinary Linux? Are there
bugs/problems with your approach?
Yes, there is a potential problem, which explains why the faster timer
wasn't implemented in ordinary Linux. The problem is that some Linux
device driver code can turn off interrupts for an indefinite period. If
this period is more than one timer tick, it's possible for timer interrupts
to be "lost" so the timer tick count will be off. For the ordinary
Linux timer tick interval of 1/100 of a second, this normally isn't a
much of a problem. With the code here increasing the rate by a factor of 76
(timer tick interval of 131 usec), this becomes more likely. How can
this be dealt with? Here are several approaches:
- Don't worry; be happy. The main effect of missed ticks from NIST
Net's point of view is that some packet delays are a bit longer than
they would be ideally. By and large, I haven't found this to be a major
problem. (NIST Net isn't really a "hard real-time" system.)
- On the machine with NIST Net, don't have a lot of device activity while
NIST Net is running.
- The biggest offender usually is the IDE controller. Try using
hdparm to get it to unmask interrupts sooner. I usually use the
following (put into rc.local, once for each IDE drive):
hdparm -m16 -u1 /dev/hda
See the hdparm manual entry for various caveats on its use, first.
If you can use these settings, do so; they will actually improve the
performance and responsiveness of your system. If you can't use them, though,
the "symptoms" may include massive disk corruption, so a little caution
is indicated...
-
The newest release of NIST Net for 2.0.xx kernels incorporate a number
of timer fixes, including the latest 2.1.XX fixes from Ingo Molnar
and Ulrich Windl's "Completely Mad Time"
(neither of whom are to be blamed blamed for my timer hacks!)
These seem to compensate quite well for any potential problems,
especially on Pentium machines without APM, where the
cycle counter can be used as a check on the clock.
Q. [This one was an actual asked question!]
I set a straight bandwidth limitation of 8000 bytes/second. For ping
packets 1472 or below in size, I see no delays. When the size reaches
1473, though, the delay suddenly jumps to around 190 ms. What's going
on?
This is a consequence of the way IP behaves, and the
way NIST Net implements bandwidth limitation. When you set
a maximum allowed bandwidth of 8000 bytes/second, then as long
as the bandwidth utilization is below that level, NIST Net won't do any
delaying. That's what you see with packet sizes 1472 and below -
since ping sends one packet per second, its bandwidth utilization is well
below 8000 bytes/second.
So why are there delays for packet sizes 1473 (and above)? Well,
including the IP header, the actual packet size is 1501 bytes. On most
LANs (most networks, in fact), the maximum allowed IP packet size (MTU)
is 1500. So when you try to send a larger packet, IP will fragment it
into two packets. If you trace the traffic (with hitbox -S
src dest), you'll see that for each ping, two packets are sent in
a row, of sizes 1500 and 46 bytes. (46 bytes is the minimum ping packet
size.) When the first packet arrives, NIST Net notes that 1500 bytes
have been sent through that connection; to keep the instantaneous
bandwidth utilization below 8000 bytes/second, it will then delay the
second packet for 1500/8000 of a second (187.5 ms). This delays the
reassembly of the packet fragments at the receiving end by the same
amount.
NIST Net delays the packet because it looks at instantaneous bandwidth
utilization, i.e., it's (roughly) emulating a network where at no time can
you send more than 1 byte per 1/8000 of a second. So the second packet is
delayed, even though the long term average utilization is only 1546
bytes/second. (By the way, you should see the delays stay about the same
value for ping packets of size up to 2952; at 2953, the packet gets
fragmented into three pieces, and the delay times will double.)
Now one quirk of the implementation is that it only takes bandwidth
utilization by the previous packets into account, not the current one. So
when you're only sending packets every second, like here, the first one
essentially gets a free ride. I had thought about taking the current
packet into account, but with sustained traffic this will tend to
overcount bandwidth utilization and delay packets too much.
Some people haven't been happy with this quirk, so I'm going to be
making it a configuration option in the alpha version.
Q. [Another actual asked question!]
When I put new entries into the NIST Net user interface, it seems to hang
for a long period, then finally comes back. What's going on?
Almost certainly this is due to a problem with domain name resolution on
your system. In an attempt to normalize the appearance of names, when
you enter a new name into the user interface, it does two DNS lookups:
- A forward lookup of name to IP address, to find the address it will
furnish to the kernel emulator.
- A reverse lookup of that IP address to name, to find the "standard"
form of the name it will then display.
Usually, it's the latter that gives problems. Try nslookup host
and nslookup IP address for the entry you're adding. If
one of them fails, you can either fix your DNS server, or as a quick hack
add the problem host/IP address to /etc/hosts on the NIST Net
machine.
This one seems to be a fairly common problem, especially affecting
people who are not in a position to fix their DNS servers. So, in the
new versions starting with the current 1.3bis, I have added a timeout
around the DNS lookups. If they don't succeed within a fairly short
period of time, they are aborted. The code sets this time period to
1 second; if your DNS server is slow, this may be too short. If so,
fix the alarm() calls in nistnet/monitor/hitutil.c to use a
longer period.
Heh, heh, turns out the fix in 1.3bis isn't quite right, in that you
can still end up with lookups hanging under certain circumstances.
The alpha has a definitive fix, which may get migrated back later.
The alpha also sets the timeout period to 5 seconds, which I think
should be fine under most circumstances.
Q. [Vaguely based on yet another actual asked question]
What's going on with the units for the various delay/drop/etc. parameters?
And how do random delay and DRD actually work?
Heh, heh, I changed my mind several times about what units to use for the
various parameters, and I'm afraid the X user interface, the command line,
and the API aren't completely consistent. Here's a quick table:
Quantity
| X interface
| Command line
| API
|
Delay times
| milliseconds (floating point)
| microseconds (integer)
| microseconds (integer)
|
Bandwidth
| bytes/second (integer)
| bytes/second (integer)
| bytes/second (integer)
|
Drop/dup probabilities
| percentage of packets (i.e. 100xfraction) dropped or duplicated
(floating point)
| fraction of packets (floating point)
| x/65536 of packets (integer)
|
The random delay stuff was done in a way to make it quick to implement,
though a little clumsy to explain. I use a random number to do a lookup
in a distribution table, generating a "number of standard deviations"
value (multiplied by a scaling factor of 8192 to make it integral). The
delay value is then:
specified (mean) delay + (# of std dev)*(size of std dev)/scale
This gives random values which have the specified mean and standard
deviation, and which match the specified distribution. It's perhaps a
slightly cheesy method (possibly not matching some second-order effects),
but seems good enough for this purpose.
One other slightly confusing note is that while I specify all times
in microseconds, internally, they're rounded off to the nearest "minijiffy"
(minor timer tick), which by default is set to 1/7600 sec, around 131
microseconds. (The weird value is because it needs to be an integral
divisor of the frequency of the 8253 timer chip. Otherwise, the
machine's clock will start drifting off due to roundoff errors. Here at
NIST we have to have precise clocks!)
All the API parameters are integers, so the percentages get converted
to fractions of 2^16. What I do is generate a random number between 0 and
2^16. If it's less than x, the packet is dropped or duplicated.
The DRD parameters are the minimum and maximum queue lengths for the DRD
algorithm. More precisely, if the number of packets queued is less than
the minimum specified, DRD won't drop any packets. When the minimum is
reached, DRD starts randomly dropping 10% of the incoming packets. This
percentage ramps up with an increase in queue length, reaching 95% when
the maximum is reached. (You can actually have more packets queued than
the "maximum," but with 95% of all new packets being dropped, you tend
not to get very much above the maximum.)
The new ECN (explicit congestion notification) parameter must be a value
between the minimum and maximum queue lengths (or 0, which means
congestion notification will not be used for this connection). When
this is set, if a packet arrives which is marked with the ECN_CAPABLE
bit (currently bit 1) and the queue length is between the minimum and
ECN parameter, then NIST Net will mark the packet with the ECN_NOTED bit
(currently bit 0) rather than drop it. Not all packets will be so
marked, but only those that would otherwise have been (randomly)
dropped. If the queue length rises above the ECN parameter, then NIST
Net will drop a packet whether or not it is marked as ECN_CAPABLE.
My reading of the ECN proposals is that the DRD ECN parameter should be
set equal to the DRD maximum. An ECN-capable router should only drop
ECN-enabled packets when it is in a condition of "distress," which is
what exceeding the DRD maximum should mean.
Q. I want to create my own delay distribution table. How should it be
set up to match the distribution I want?
The distribution used is governed by a table of short integers you
can load. The code generates a uniformly distributed "random" number
between 0 and the size of the table (4096 is what I used, which should
be more than good enough for any use I can imagine). This is used as an
index in looking up the table value, which is then divided by the table
"factor" to get a "number of standard deviations" value. In my tables,
the factor was always 8192, and hence the "number of standard deviations"
always between -4 and 4 (MAXSHORT/8192). Again, as mentioned above,
the generated delay time is then
(average) delay + (number of standard deviations)*delay sigma.
This table used for "synthesizing" the distribution amounts to a scaled,
translated, inverse to the cumulative distribution function.
Here's how to think about it: Let F() be the cumulative distribution
function for a probability distribution X. We'll assume we've scaled
things so that X has mean 0 and standard deviation 1, though that's not
so important here. Then:
F(x) = P(X <= x) =
where f is the probability density function.
F is monotonically increasing, so has an inverse function G,
with range 0 to 1. Here, G(t) = the x such that
P(X <= x) = t. (In general, G may have singularities
if X has point masses, i.e., points x such that
P(X = x) > 0.)
Now we create a tabular representation of G as follows:
Choose some table size N, and for the ith entry, put in
G(i/N). Let's call this table T.
The claim now is, I can create a (discrete) random variable Y
whose distribution has the same approximate "shape" as X, simply
by letting Y = T(U), where U is a discrete uniform
random variable with range 1 to N. To see this, it's enough to
show that Y's cumulative distribution function, (let's call it
H), is a discrete approximation to F. But
H(x) = P(Y <= x)
= (# of entries in T <= x) / N -- as Y chosen uniformly from T
= i/N, where i is the largest integer such that G(i/N) <= x
= i/N, where i is the largest integer such that i/N <= F(x)
-- since G and F are inverse functions (and F is
increasing)
= floor(N*F(x))/N
as desired.
How can we create this table in practice? In some cases, F may have a
simple expression which allows evaluating its inverse directly. The
pareto distribution is one example of this. In other cases, and
especially for matching an experimentally observed distribution, it's
easiest simply to create a table for F and "invert" it. Here, we give
a concrete example, namely how the new "experimental" distribution was
created. Note: starting with version 1.4, tools to do all the
operations described here are provided.
- Collect enough data points to characterize the distribution. Here, I
collected 25,000 "ping" roundtrip times to a "distant" point (www.ntt.co.jp).
That's far more data than is really necessary, but it was fairly painless to
collect it, so...
- Normalize the data so that it has mean 0 and standard deviation 1.
- Determine the cumulative distribution. The code I wrote creates a table
covering the range -4 to +4, with granularity .00002. Obviously, this
is absurdly over-precise, but since it's a one-time only computation, I
figured it hardly mattered.
- Invert the table: for each table entry F(x) = y, make the y*TABLESIZE
(here, 4096) entry be x*TABLEFACTOR (here, 8192). This creates a table
for the ("normalized") inverse of size TABLESIZE, covering its domain
0 to 1 with granularity 1/TABLESIZE. Note that even with the excessive
granularity used in creating the table for F, it's possible not all the
entries in the table for G will be filled in. So, make a pass through the
inverse's table, filling in any missing entries by linear interpolation.
To load a new distribution table, you can of course recompile the
NIST Net driver. However, the driver actually supports loading new
tables at runtime. Simply write the table, which must be an array
of 4096 short words (8192 bytes), to the device driver:
int readfd, writefd;
char buffer[8192];
/* Assume binary.table is your previously prepared table of 4096 short ints */
readfd = open("binary.table", O_RDONLY);
read(readfd, buffer, 8192);
writefd = open("/dev/hitbox", O_WRONLY);
write(writefd, buffer, 8192);
When updating the table by this means, you must use a table size of 4096
and a table factor of 8192. (More precisely, these must be the same as
whatever table is currently loaded.)
I had previously advised just using cat to write the table to the
device. This falls into the category of "things which seem like they
so obviously will work that they don't require testing, and of course
in practice will fail." The problem is that cat will try to break
the write into pieces of 4096 bytes, which will fail. So you have to
use a little program, as indicated above.
It just occurred to me (and I actually tested it this time) that dd
will do the job in writing the table. Just use this line:
dd if=binary.table of=/dev/hitbox bs=8192 count=1
Q. When I try to install the nistnet module with "insmod nistnet", I
get errors:
./nistnet.o: unresolved symbol dev_find_pack
./nistnet.o: unresolved symbol add_fast_timer
This indicates that you're not running a kernel with the NIST Net patches
configured. Make sure you've done all the following:
- Install a source tree in /usr/src/linux for a 2.0.27 - 2.0.37 level
kernel (should come with your Linux package). (For the alpha version, you
need a 2.0.27 - 2.0.38 or 2.2.5 - 2.2.16 source tree.)
- Add the NIST Net patches with the script Patch.Kernel. [Note: Don't
run this script twice! The second time, the "patch" command may try to
undo the patches!]
- Configure the patches by running "make xconfig" or "make menuconfig"
(or "make config" for diehards) in the /usr/src/linux directory.
Under the last menu, "Kernel hacking," should be two items, "Fast timer"
(CONFIG_FAST_TIMER) and "Packet routine hacking" (CONFIG_REPACK) Check
"yes" for both of these.
- Remake the dependencies by "make dep"
- Compile the kernel by "make." Check for any error messages during
the build!
- Install the kernel by "make install"
- Reboot and run the new kernel
Usually when people have had problems, it is with the last two steps.
They've compiled the new kernel successfully, but it turns out for some
reason this is not the kernel their system is running. Check out the file
/etc/lilo.conf (assuming you're using lilo). What kernel image does it
run by default? (I.e., what is the first "image =" line in the file?)
Some systems (e.g., most Slackware setups) are set up to have the default
kernel at /vmlinuz, and others (e.g., most RedHat setups) at
/boot/vmlinuz. Check the setting of INSTALL_PATH in the Makefile in
/usr/src/linux. Hopefully, it agrees with where lilo expects to find the
kernel! If not, fix it up and redo the install. Make sure the kernel
actually got installed in the right place. Rerun "lilo" if you want to
make extra-sure, then reboot.
OK, it also turns out there is currently a problem with module versioning.
This will be fixed in 2.0.5, but for right now you need
to turn versioning off, at least with 2.2.xx kernels.
Here's what your settings should be under "Loadable module support"
when doing kernel configuration:
- yes - "Enable loadable module support"
- no - "Set version information on all symbols for modules"
- either - "Kernel module loader"
Again, this will be fixed in 2.0.5, but for right now,
that's what you have to do. Note: after making this change, you
have to remake and reinstall both the kernel and all the modules
(including nistnet)!
Q. I was able to load the nistnet module, but when I try to load
mungemod or spymod, I get
./mungemod.o: unresolved symbol addmunge
./mungemod.o: unresolved symbol rmmunge
Two possibilities: The simple one is that you don't have the nistnet
module still loaded. It is a prerequisite for loading mungemod or
spymod.
The complex one is that you've run into the module versioning bug.
See the last answer.
Q. When is the next release coming out?
It's mostly ready, except for that nagging APIC bug. However, I'm
about to leave on a month-long vacation, so don't expect anything
new until after August 15.
Q. Tell me all that good legal stuff about copyrights and warranties.
As a U.S. government publication, so to speak, NIST Net is not
copyrighted. You can do whatever you want with it, including employing
its code in whole or in part in any other package or product.
You need not credit me or NIST (though not doing so would be a bit rude).
As is usual for code provided on this basis, there is absolutely no
warranty of any sort. We are interested in
receiving any reports
of problems or requests for improvements and will try to help,
but can't make any specific promises!
I had thought the above was fairly explicit, but apparently not explicit
enough. What the lack of copyright means is that you have a non-exclusive
right to use this code in any fashion you wish, including incorporating
it into a product without any further compensation or permission required.
"Non-exclusive" just means that other people can do it as well, so just
because you used NIST Net in your product doesn't mean somebody else can't.
Please note these remarks only apply to the code I originated; the patches
to the base Linux kernel are based on the existing Linux code and hence
carry exactly the same copyright restrictions as Linux does.
Comments? Questions? Let us know at
nistnet-dev@antd.nist.gov.
[
Home Page]
[Installing NISTNet]
[Using NISTNet]
[NISTNet FAQ]