diff --git a/tools/network_simulator/config.py b/tools/network_emulator/config.py similarity index 96% rename from tools/network_simulator/config.py rename to tools/network_emulator/config.py index ac450f6b9..60fa485db 100644 --- a/tools/network_simulator/config.py +++ b/tools/network_emulator/config.py @@ -7,7 +7,7 @@ # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. -"""Configuration class for network simulation.""" +"""Configuration class for network emulation.""" class ConnectionConfig(object): diff --git a/tools/network_simulator/simulate.py b/tools/network_emulator/emulate.py similarity index 80% rename from tools/network_simulator/simulate.py rename to tools/network_emulator/emulate.py index b1b3e67a6..e25670574 100755 --- a/tools/network_simulator/simulate.py +++ b/tools/network_emulator/emulate.py @@ -16,12 +16,12 @@ import socket import sys import config -import network_simulator +import network_emulator _DEFAULT_LOG_LEVEL = logging.INFO # Default port range to apply network constraints on. -_DEFAULT_PORT_RANGE = (30000, 65535) +_DEFAULT_PORT_RANGE = (32768, 65535) _PRESETS = [ config.ConnectionConfig(1, 'Generic, Bad', 95, 95, 250, 2, 100), @@ -133,7 +133,7 @@ def _set_logger(verbose): def _main(): - """Checks arguments, permissions and runs a network simulation.""" + """Checks arguments, permissions and runs a network emulation.""" if os.name != 'posix': print >> sys.stderr, 'This script is only supported on Linux and Mac.' return 1 @@ -154,11 +154,11 @@ def _main(): if options.queue: connection_config.queue_slots = options.queue - simulator = network_simulator.NetworkSimulator(connection_config, - options.port_range) + emulator = network_emulator.NetworkEmulator(connection_config, + options.port_range) try: - simulator.check_permissions() - except network_simulator.NetworkSimulatorError as e: + emulator.check_permissions() + except network_emulator.NetworkEmulatorError as e: logging.error('Error: %s\n\nCause: %s', e.msg, e.error) return -1 @@ -167,28 +167,32 @@ def _main(): else: external_ip = options.target_ip - logging.info('Simulating traffic to/from IP: %s', external_ip) - simulator.simulate(external_ip) - logging.info('Started network simulation with the following configuration:\n' - ' Receive bandwidth: %s kbps (%s kB/s)\n' - ' Send bandwidth : %s kbps (%s kB/s)\n' - ' Delay : %s ms\n' - ' Packet loss : %s %%\n' - ' Queue slots : %s', - connection_config.receive_bw_kbps, - connection_config.receive_bw_kbps/8, - connection_config.send_bw_kbps, - connection_config.send_bw_kbps/8, - connection_config.delay_ms, - connection_config.packet_loss_percent, - connection_config.queue_slots) - logging.info('Affected traffic: IP traffic on ports %s-%s', - options.port_range[0], options.port_range[1]) - raw_input('Press Enter to abort Network simulation...') - logging.info('Flushing all Dummynet rules...') - simulator.cleanup() - logging.info('Completed Network Simulation.') - return 0 + logging.info('Constraining traffic to/from IP: %s', external_ip) + try: + emulator.emulate(external_ip) + logging.info('Started network emulation with the following configuration:\n' + ' Receive bandwidth: %s kbps (%s kB/s)\n' + ' Send bandwidth : %s kbps (%s kB/s)\n' + ' Delay : %s ms\n' + ' Packet loss : %s %%\n' + ' Queue slots : %s', + connection_config.receive_bw_kbps, + connection_config.receive_bw_kbps/8, + connection_config.send_bw_kbps, + connection_config.send_bw_kbps/8, + connection_config.delay_ms, + connection_config.packet_loss_percent, + connection_config.queue_slots) + logging.info('Affected traffic: IP traffic on ports %s-%s', + options.port_range[0], options.port_range[1]) + raw_input('Press Enter to abort Network Emulation...') + logging.info('Flushing all Dummynet rules...') + emulator.cleanup() + logging.info('Completed Network Emulation.') + return 0 + except network_emulator.NetworkEmulatorError as e: + logging.error('Error: %s\n\nCause: %s', e.msg, e.error) + return -2 if __name__ == '__main__': sys.exit(_main()) diff --git a/tools/network_simulator/network_simulator.py b/tools/network_emulator/network_emulator.py similarity index 83% rename from tools/network_simulator/network_simulator.py rename to tools/network_emulator/network_emulator.py index 3518999c2..2876939ea 100644 --- a/tools/network_simulator/network_simulator.py +++ b/tools/network_emulator/network_emulator.py @@ -12,10 +12,11 @@ import logging import os import subprocess +import sys -class NetworkSimulatorError(BaseException): - """Exception raised for errors in the network simulator. +class NetworkEmulatorError(BaseException): + """Exception raised for errors in the network emulator. Attributes: msg: User defined error message. @@ -35,15 +36,15 @@ class NetworkSimulatorError(BaseException): self.error = error -class NetworkSimulator(object): - """A network simulator that can constrain the network using Dummynet.""" +class NetworkEmulator(object): + """A network emulator that can constrain the network using Dummynet.""" def __init__(self, connection_config, port_range): """Constructor. Args: connection_config: A config.ConnectionConfig object containing the - characteristics for the connection to be simulated. + characteristics for the connection to be emulation. port_range: Tuple containing two integers defining the port range. """ self._pipe_counter = 0 @@ -51,8 +52,8 @@ class NetworkSimulator(object): self._port_range = port_range self._connection_config = connection_config - def simulate(self, target_ip): - """Starts a network simulation by setting up Dummynet rules. + def emulate(self, target_ip): + """Starts a network emulation by setting up Dummynet rules. Args: target_ip: The IP address of the interface that shall be that have the @@ -71,7 +72,7 @@ class NetworkSimulator(object): self._connection_config.queue_slots) logging.debug('Created send pipe: %s', send_pipe_id) - # Adding the rules will start the simulation. + # Adding the rules will start the emulation. incoming_rule_id = self._create_dummynet_rule(receive_pipe_id, 'any', target_ip, self._port_range) logging.debug('Created incoming rule: %s', incoming_rule_id) @@ -83,7 +84,7 @@ class NetworkSimulator(object): """Checks if permissions are available to run Dummynet commands. Raises: - NetworkSimulatorError: If permissions to run Dummynet commands are not + NetworkEmulatorError: If permissions to run Dummynet commands are not available. """ if os.geteuid() != 0: @@ -93,17 +94,17 @@ class NetworkSimulator(object): 'root or have password-less sudo access to this command.')) def cleanup(self): - """Stops the network simulation by flushing all Dummynet rules. + """Stops the network emulation by flushing all Dummynet rules. Notice that this will flush any rules that may have been created previously - before starting the simulation. + before starting the emulation. """ self._run_shell_command(['sudo', 'ipfw', '-f', 'flush'], 'Failed to flush Dummynet rules!') def _create_dummynet_rule(self, pipe_id, from_address, to_address, port_range): - """Creates a network simulation rule and returns its ID. + """Creates a network emulation rule and returns its ID. Args: pipe_id: integer ID of the pipe. @@ -144,7 +145,11 @@ class NetworkSimulator(object): 'delay', '%sms' % delay_ms, 'plr', (packet_loss_percent/100.0), 'queue', queue_slots] - self._run_shell_command(cmd, 'Failed to create Dummynet pipe') + error_message = 'Failed to create Dummynet pipe. ' + if sys.platform.startswith('linux'): + error_message += ('Make sure you have loaded the ipfw_mod.ko module to ' + 'your kernel (sudo insmod /path/to/ipfw_mod.ko)') + self._run_shell_command(cmd, error_message) return self._pipe_counter def _run_shell_command(self, command, msg=None): @@ -158,7 +163,7 @@ class NetworkSimulator(object): The standard output from running the command. Raises: - NetworkSimulatorError: If command fails. Message is set by the msg + NetworkEmulatorError: If command fails. Message is set by the msg parameter. """ cmd_list = [str(x) for x in command] @@ -169,5 +174,5 @@ class NetworkSimulator(object): stderr=subprocess.PIPE) output, error = process.communicate() if process.returncode != 0: - raise NetworkSimulatorError(msg, cmd, process.returncode, output, error) + raise NetworkEmulatorError(msg, cmd, process.returncode, output, error) return output.strip()