| 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)
|
|
|