Index: tools/telemetry/third_party/webpagereplay/trafficshaper.py |
diff --git a/tools/telemetry/third_party/webpagereplay/trafficshaper.py b/tools/telemetry/third_party/webpagereplay/trafficshaper.py |
deleted file mode 100644 |
index 0078218ef68b3cab2d86e20e72a3dc2789678c79..0000000000000000000000000000000000000000 |
--- a/tools/telemetry/third_party/webpagereplay/trafficshaper.py |
+++ /dev/null |
@@ -1,186 +0,0 @@ |
-#!/usr/bin/env python |
-# Copyright 2010 Google Inc. All Rights Reserved. |
-# |
-# Licensed under the Apache License, Version 2.0 (the "License"); |
-# you may not use this file except in compliance with the License. |
-# You may obtain a copy of the License at |
-# |
-# http://www.apache.org/licenses/LICENSE-2.0 |
-# |
-# Unless required by applicable law or agreed to in writing, software |
-# distributed under the License is distributed on an "AS IS" BASIS, |
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-# See the License for the specific language governing permissions and |
-# limitations under the License. |
- |
-import logging |
-import platformsettings |
-import re |
- |
- |
-# Mac has broken bandwitdh parsing, so double check the values. |
-# On Mac OS X 10.6, "KBit/s" actually uses "KByte/s". |
-BANDWIDTH_PATTERN = r'0|\d+[KM]?(bit|Byte)/s' |
- |
- |
-class TrafficShaperException(Exception): |
- pass |
- |
- |
-class BandwidthValueError(TrafficShaperException): |
- def __init__(self, value): # pylint: disable=super-init-not-called |
- self.value = value |
- |
- def __str__(self): |
- return 'Value, "%s", does not match regex: %s' % ( |
- self.value, BANDWIDTH_PATTERN) |
- |
- |
-class TrafficShaper(object): |
- """Manages network traffic shaping.""" |
- |
- # Pick webpagetest-compatible values (details: http://goo.gl/oghTg). |
- _UPLOAD_PIPE = '10' # Enforces overall upload bandwidth. |
- _UPLOAD_QUEUE = '10' # Shares upload bandwidth among source ports. |
- _UPLOAD_RULE = '5000' # Specifies when the upload queue is used. |
- _DOWNLOAD_PIPE = '11' # Enforces overall download bandwidth. |
- _DOWNLOAD_QUEUE = '11' # Shares download bandwidth among destination ports. |
- _DOWNLOAD_RULE = '5100' # Specifies when the download queue is used. |
- _QUEUE_SLOTS = 100 # Number of packets to queue. |
- |
- _BANDWIDTH_RE = re.compile(BANDWIDTH_PATTERN) |
- |
- def __init__(self, |
- dont_use=None, |
- host='127.0.0.1', |
- ports=None, |
- up_bandwidth='0', |
- down_bandwidth='0', |
- delay_ms='0', |
- packet_loss_rate='0', |
- init_cwnd='0', |
- use_loopback=True): |
- """Start shaping traffic. |
- |
- Args: |
- host: a host string (name or IP) for the web proxy. |
- ports: a list of ports to shape traffic on. |
- up_bandwidth: Upload bandwidth |
- down_bandwidth: Download bandwidth |
- Bandwidths measured in [K|M]{bit/s|Byte/s}. '0' means unlimited. |
- delay_ms: Propagation delay in milliseconds. '0' means no delay. |
- packet_loss_rate: Packet loss rate in range [0..1]. '0' means no loss. |
- init_cwnd: the initial cwnd setting. '0' means no change. |
- use_loopback: True iff shaping is done on the loopback (or equiv) adapter. |
- """ |
- assert dont_use is None # Force args to be named. |
- self.host = host |
- self.ports = ports |
- self.up_bandwidth = up_bandwidth |
- self.down_bandwidth = down_bandwidth |
- self.delay_ms = delay_ms |
- self.packet_loss_rate = packet_loss_rate |
- self.init_cwnd = init_cwnd |
- self.use_loopback = use_loopback |
- if not self._BANDWIDTH_RE.match(self.up_bandwidth): |
- raise BandwidthValueError(self.up_bandwidth) |
- if not self._BANDWIDTH_RE.match(self.down_bandwidth): |
- raise BandwidthValueError(self.down_bandwidth) |
- self.is_shaping = False |
- |
- def __enter__(self): |
- if self.use_loopback: |
- platformsettings.setup_temporary_loopback_config() |
- if self.init_cwnd != '0': |
- platformsettings.set_temporary_tcp_init_cwnd(self.init_cwnd) |
- try: |
- ipfw_list = platformsettings.ipfw('list') |
- if not ipfw_list.startswith('65535 '): |
- logging.warn('ipfw has existing rules:\n%s', ipfw_list) |
- self._delete_rules(ipfw_list) |
- except Exception: |
- pass |
- if (self.up_bandwidth == '0' and self.down_bandwidth == '0' and |
- self.delay_ms == '0' and self.packet_loss_rate == '0'): |
- logging.info('Skipped shaping traffic.') |
- return |
- if not self.ports: |
- raise TrafficShaperException('No ports on which to shape traffic.') |
- |
- ports = ','.join(str(p) for p in self.ports) |
- half_delay_ms = int(self.delay_ms) / 2 # split over up/down links |
- |
- try: |
- # Configure upload shaping. |
- platformsettings.ipfw( |
- 'pipe', self._UPLOAD_PIPE, |
- 'config', |
- 'bw', self.up_bandwidth, |
- 'delay', half_delay_ms, |
- ) |
- platformsettings.ipfw( |
- 'queue', self._UPLOAD_QUEUE, |
- 'config', |
- 'pipe', self._UPLOAD_PIPE, |
- 'plr', self.packet_loss_rate, |
- 'queue', self._QUEUE_SLOTS, |
- 'mask', 'src-port', '0xffff', |
- ) |
- platformsettings.ipfw( |
- 'add', self._UPLOAD_RULE, |
- 'queue', self._UPLOAD_QUEUE, |
- 'ip', |
- 'from', 'any', |
- 'to', self.host, |
- self.use_loopback and 'out' or 'in', |
- 'dst-port', ports, |
- ) |
- self.is_shaping = True |
- |
- # Configure download shaping. |
- platformsettings.ipfw( |
- 'pipe', self._DOWNLOAD_PIPE, |
- 'config', |
- 'bw', self.down_bandwidth, |
- 'delay', half_delay_ms, |
- ) |
- platformsettings.ipfw( |
- 'queue', self._DOWNLOAD_QUEUE, |
- 'config', |
- 'pipe', self._DOWNLOAD_PIPE, |
- 'plr', self.packet_loss_rate, |
- 'queue', self._QUEUE_SLOTS, |
- 'mask', 'dst-port', '0xffff', |
- ) |
- platformsettings.ipfw( |
- 'add', self._DOWNLOAD_RULE, |
- 'queue', self._DOWNLOAD_QUEUE, |
- 'ip', |
- 'from', self.host, |
- 'to', 'any', |
- 'out', |
- 'src-port', ports, |
- ) |
- logging.info('Started shaping traffic') |
- except Exception: |
- logging.error('Unable to shape traffic.') |
- raise |
- |
- def __exit__(self, unused_exc_type, unused_exc_val, unused_exc_tb): |
- if self.is_shaping: |
- try: |
- self._delete_rules() |
- logging.info('Stopped shaping traffic') |
- except Exception: |
- logging.error('Unable to stop shaping traffic.') |
- raise |
- |
- def _delete_rules(self, ipfw_list=None): |
- if ipfw_list is None: |
- ipfw_list = platformsettings.ipfw('list') |
- existing_rules = set( |
- r.split()[0].lstrip('0') for r in ipfw_list.splitlines()) |
- delete_rules = [r for r in (self._DOWNLOAD_RULE, self._UPLOAD_RULE) |
- if r in existing_rules] |
- if delete_rules: |
- platformsettings.ipfw('delete', *delete_rules) |