#
import sys, os, re, getopt
-from sets import Set
import pwd
# bwmin should be small enough that it can be considered negligibly
# slow compared to the hardware. 8 bits/second appears to be the
# smallest value supported by tc.
-bwmin = 8
+bwmin = 1000
# bwmax should be large enough that it can be considered at least as
# fast as the hardware.
# | |
# 1:10 (8bit, 5mbit) 1:20 (8bit, 1gbit)
# | |
+# 1:100 (8bit, 5mbit) |
+# | |
# 1:1000 (8bit, 5mbit), 1:2000 (8bit, 1gbit),
# 1:1001 (8bit, 5mbit), 1:2001 (8bit, 1gbit),
# 1:1002 (1mbit, 5mbit), 1:2002 (1mbit, 1gbit),
# be off by a small fraction.
suffixes = {
"": 1,
- "bit": 1,
- "kibit": 1024,
- "kbit": 1000,
- "mibit": 1024*1024,
- "mbit": 1000000,
- "gibit": 1024*1024*1024,
- "gbit": 1000000000,
- "tibit": 1024*1024*1024*1024,
- "tbit": 1000000000000,
- "bps": 8,
- "kibps": 8*1024,
- "kbps": 8000,
- "mibps": 8*1024*1024,
- "mbps": 8000000,
- "gibps": 8*1024*1024*1024,
- "gbps": 8000000000,
- "tibps": 8*1024*1024*1024*1024,
- "tbps": 8000000000000
+ "bit": 1,
+ "kibit": 1024,
+ "kbit": 1000,
+ "mibit": 1024*1024,
+ "mbit": 1000000,
+ "gibit": 1024*1024*1024,
+ "gbit": 1000000000,
+ "tibit": 1024*1024*1024*1024,
+ "tbit": 1000000000000,
+ "bps": 8,
+ "kibps": 8*1024,
+ "kbps": 8000,
+ "mibps": 8*1024*1024,
+ "mbps": 8000000,
+ "gibps": 8*1024*1024*1024,
+ "gbps": 8000000000,
+ "tibps": 8*1024*1024*1024*1024,
+ "tbps": 8000000000000
}
else:
return -1
+def format_bytes(bytes, si = True):
+ """
+ Formats bytes into a string
+ """
+ if si:
+ kilo = 1000.
+ else:
+ # Officially, a kibibyte
+ kilo = 1024.
+
+ if bytes >= (kilo * kilo * kilo):
+ return "%.1f GB" % (bytes / (kilo * kilo * kilo))
+ elif bytes >= 1000000:
+ return "%.1f MB" % (bytes / (kilo * kilo))
+ elif bytes >= 1000:
+ return "%.1f KB" % (bytes / kilo)
+ else:
+ return "%.0f bytes" % bytes
def format_tc_rate(rate):
"""
return run(TC + " " + cmd)
+def stop(dev = dev):
+ '''
+ Turn off all queing. Stops all slice HTBS and reverts to pfifo_fast (the default).
+ '''
+ try:
+ for i in range(0,2):
+ tc("qdisc del dev %s root" % dev)
+ except: pass
+
+
def init(dev = dev, bwcap = bwmax):
"""
(Re)initialize the bandwidth limits on this node
tc("class add dev %s parent 1:1 classid 1:10 htb rate %dbit ceil %dbit" % \
(dev, bwmin, bwcap))
+ # Set up a subclass for DRL(Distributed Rate Limiting).
+ # DRL will directly modify that subclass implementing the site limits.
+ tc("class add dev %s parent 1:10 classid 1:100 htb rate %dbit ceil %dbit" % \
+ (dev, bwmin, bwcap))
+
+
# Set up a subclass that represents "exemption" from the node
# bandwidth cap. Once the node bandwidth cap is reached, bandwidth
# to exempt destinations can still be fairly shared up to bwmax.
minexemptrate = maxexemptrate
# Set up subclasses for the slice
- tc("class replace dev %s parent 1:10 classid 1:%x htb rate %dbit ceil %dbit quantum %d" % \
+ tc("class replace dev %s parent 1:100 classid 1:%x htb rate %dbit ceil %dbit quantum %d" % \
(dev, default_minor | xid, minrate, maxrate, share * quantum))
tc("class replace dev %s parent 1:20 classid 1:%x htb rate %dbit ceil %dbit quantum %d" % \
(dev, exempt_minor | xid, exempt_minor | xid))
-def set(xid, share = None, minrate = None, maxrate = None, minexemptrate = None, maxexemptrate = None):
- on(xid = xid, share = share,
+def set(xid, share = None, minrate = None, maxrate = None, minexemptrate = None, maxexemptrate = None, dev = dev ):
+ on(xid = xid, dev = dev, share = share,
minrate = minrate, maxrate = maxrate,
minexemptrate = minexemptrate, maxexemptrate = maxexemptrate)
(burst) cap.
"""
- # Clean up
- iptables = "/sbin/iptables -t mangle %s POSTROUTING"
- run(iptables % "-F")
- run("/sbin/ipset -X " + group_name)
-
- # Create a hashed IP set of all of these destinations
- lines = ["-N %s iphash" % group_name]
- add_cmd = "-A %s " % group_name
- lines += [(add_cmd + ip) for ip in node_ips]
- lines += ["COMMIT"]
- restore = "\n".join(lines) + "\n"
- run("/sbin/ipset -R", restore)
-
- # Add rule to match on destination IP set
- run((iptables + " -m set --set %s dst -j CLASSIFY --set-class 1:%x") %
- ("-A", group_name, exempt_minor))
+ # Check of set exists
+ set = run("/sbin/ipset -S " + group_name)
+ if set == None:
+ # Create a hashed IP set of all of these destinations
+ lines = ["-N %s iphash" % group_name]
+ add_cmd = "-A %s " % group_name
+ lines += [(add_cmd + ip) for ip in node_ips]
+ lines += ["COMMIT"]
+ restore = "\n".join(lines) + "\n"
+ run("/sbin/ipset -R", restore)
+ else: # set exists
+ # Check all hosts and add missing.
+ for nodeip in node_ips:
+ if not run("/sbin/ipset -T %s %s" % (group_name, nodeip)):
+ run("/sbin/ipset -A %s %s" % (group_name, nodeip))
def usage():
%s [OPTION]... [COMMAND] [ARGUMENT]...
Options:
- -d device Network interface (default: %s)
+ -d device Network interface (default: %s)
-r rate Node bandwidth cap (default: %s)
-q quantum Share multiplier (default: %d bytes)
-n Print rates in numeric bits per second
elif opt == '-h':
usage()
+ if bwcap == -1:
+ return 0
+
if len(argv):
if argv[0] == "init" or (argv[0] == "on" and len(argv) == 1):
# (Re)initialize
minexemptrate, maxexemptrate,
bytes, exemptbytes)
else:
- print "%s %d %s %s %s %s %d %d" % \
+ print "%s %d %s %s %s %s %s %s" % \
(slice, share,
format_tc_rate(minrate), format_tc_rate(maxrate),
format_tc_rate(minexemptrate), format_tc_rate(maxexemptrate),
- bytes, exemptbytes)
+ format_bytes(bytes), format_bytes(exemptbytes))
elif len(argv) >= 2:
# slice, ...