Simulating Network Lag for Testing Games

In devel­op­ing a net­worked game, some­times one needs to be able to test fea­tures run­ning over spe­cific net­work con­di­tions. How does the game hold up under high latency and/or packet loss? What about in cases of vary­ing net­work jit­ter, where the latency is ever-changing? Answer­ing these ques­tions is cru­cial to test­ing net­work code and mak­ing sure that it will per­form well against what­ever chaos the Inter­net might throw at you.

As a pro­gram­mer rel­a­tively new to net­work­ing, my first thought was to build a net­work sim­u­la­tion that could be directly inte­grated into our bud­ding engine. For exam­ple, a quick perusal of Valve’s devel­oper wiki shows built-in net_fakelag, net_fakejitter, and net_fakeloss vari­ables for con­trol­ling arti­fi­cial lag, jit­ter, and packet loss, respec­tively. Being able to con­fig­ure these para­me­ters within the engine cer­tainly has its advan­tages, but rolling your own sim­u­la­tion prob­a­bly requires a good bit of time and effort, and nobody likes rein­vent­ing wheels.

For any­one look­ing to get some­thing up and run­ning quickly, a bet­ter option is to use an exter­nal tool to alter traf­fic to and from your game with­out mod­i­fy­ing the code. I’ve found Dum­mynet to be pretty use­ful for my own pur­poses, and I’ll be dis­cussing some exam­ples of how it might be used. It comes pre­in­stalled on FreeBSD and Mac OS X, and is avail­able for down­load on other systems.

The Basics

Dum­mynet is con­trolled mostly through ipfw, a command-line util­ity for fire­wall con­fig­u­ra­tion. The ipfw tool itself is very com­plex, and I do not claim to have any real degree of mas­tery over it, but a few sim­ple com­mands and a bit of script­ing is all we really need to get a decent sim­u­la­tion. Be warned, how­ever, that mess­ing with the fire­wall can lead to acci­den­tal lack of Inter­net, so you might want to make sure you have a com­fort­able level of doc­u­men­ta­tion at hand before doing any­thing hasty.

The ipfw tool processes pack­ets accord­ing to a con­fig­urable list of num­bered rules called a rule­set. We can start by view­ing the cur­rent rule­set using the list command.

$ sudo ipfw list
65535 1136838 609191629 allow ip from any to any

Note that your out­put may dif­fer based on your fire­wall con­fig­u­ra­tion. We can see that by default the rule­set con­tains a manda­tory rule num­bered 65535, which in this case allows pack­ets match­ing any IP pro­to­col from any source address to any des­ti­na­tion. Pack­ets are processed by com­par­ing them to each rule in ascend­ing order by num­ber and exe­cut­ing the action of the first rule for which there is a match.

Adding Latency

We can con­trol traf­fic by adding rules that match spe­cific packet data, and then send the pack­ets through a Dum­mynet pipe with added delay or packet loss. For exam­ple, we could add a 100 ms delay to all traf­fic head­ing to xkcd.com like so:

$ sudo ipfw pipe 1 config delay 100ms
$ sudo ipfw add 100 pipe 1 ip from any to xkcd.com
00100 pipe 1 ip from any to any dst-ip 107.6.106.82

The first com­mand here con­fig­ures a Dum­mynet pipe with id 1, cre­at­ing the pipe if it did not already exist. The sec­ond com­mand cre­ates a rule num­bered 100, which matches pack­ets with the desired des­ti­na­tion address and routes them through the pipe. Note that any rule that attempts to pass pack­ets through a non-existant pipe will block traf­fic and throw an error, so do not for­get to con­fig­ure pipes before using them. Using list again allows us to view the updated ruleset.

$ sudo ipfw list
00100 pipe 1 ip from any to 107.6.106.82
65535 allow ip from any to any

Ping­ing xkcd.com should show a round-trip time of 100 ms plus what­ever the actual cur­rent latency is across the connection.

$ ping xkcd.com
PING xkcd.com (107.6.106.82): 56 data bytes
64 bytes from 107.6.106.82: icmp_seq=0 ttl=55 time=117.092 ms
64 bytes from 107.6.106.82: icmp_seq=1 ttl=55 time=124.583 ms
64 bytes from 107.6.106.82: icmp_seq=2 ttl=55 time=117.916 ms
64 bytes from 107.6.106.82: icmp_seq=3 ttl=55 time=121.067 ms

In most cases, we would want to sim­u­late a full duplex con­nec­tion by adding a cor­re­spond­ing rule for pack­ets com­ing from the remote host, so that the delay is applied in both direc­tions. When we are done play­ing with our new rule, we can delete it and the pipe as follows.

$ sudo ipfw delete 100
$ sudo ipfw pipe 1 delete

Sim­u­lat­ing on the Same Machine

One nice thing about using Dum­mynet is that we can actu­ally sim­u­late con­di­tions on con­nec­tions between processes run­ning on the same machine. For exam­ple, we could cre­ate a rule match­ing pack­ets trav­el­ing over the loop­back inter­face like so:

$ sudo ipfw pipe 1 config delay 100ms
$ sudo ipfw add 100 pipe 1 ip from 127.0.0.1 to 127.0.0.1

Page 1 of 2 | Next page