2016-06-04 12:15:57 +00:00
|
|
|
import math
|
2015-01-06 14:47:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MpLinkCharacteristics:
|
2015-01-20 11:23:57 +00:00
|
|
|
|
2016-05-08 17:48:39 +00:00
|
|
|
tcNetemParent = "1:1"
|
2016-05-08 17:08:59 +00:00
|
|
|
tcHtbClassid = "10"
|
2016-05-08 17:48:39 +00:00
|
|
|
tcNetemHandle = "1:10"
|
2015-01-20 11:23:57 +00:00
|
|
|
|
2016-06-04 12:15:57 +00:00
|
|
|
def bandwidthDelayProductDividedByMTU(self):
|
|
|
|
rtt = 2 * float(self.delay)
|
|
|
|
""" Since bandwidth is in Mbps and rtt in ms """
|
|
|
|
bandwidthDelayProduct = (float(self.bandwidth) * 125000.0) * (rtt / 1000.0)
|
|
|
|
return int(math.ceil(bandwidthDelayProduct * 1.0 / 1500.0))
|
|
|
|
|
2019-11-28 15:22:53 +00:00
|
|
|
def bufferSize(self):
|
|
|
|
return (1500.0 * self.bandwidthDelayProductDividedByMTU()) + (float(self.bandwidth) * 1000.0 * float(self.queuingDelay) / 8)
|
|
|
|
|
2017-09-28 08:11:54 +00:00
|
|
|
def extractQueuingDelay(self, queueSize, bandwidth, delay, mtu=1500):
|
2017-09-28 07:21:05 +00:00
|
|
|
rtt = 2 * float(delay)
|
2017-09-28 07:55:29 +00:00
|
|
|
bdp_queue_size = int((float(rtt) * float(bandwidth) * 1024 * 1024) / (int(mtu) * 8 * 1000))
|
2017-09-28 07:21:05 +00:00
|
|
|
if int(queueSize) <= bdp_queue_size:
|
2017-09-28 14:57:41 +00:00
|
|
|
# Returning 0 seems to bypass everything, then only limited by CPU.
|
|
|
|
# This is not what we want...
|
|
|
|
return 1
|
2017-09-28 07:21:05 +00:00
|
|
|
|
|
|
|
queuingQueueSize = int(queueSize) - bdp_queue_size
|
2017-09-28 07:55:29 +00:00
|
|
|
queuingDelay = (queuingQueueSize * int(mtu) * 8 * 1000) / (float(bandwidth) * 1024 * 1024)
|
2017-09-28 14:57:41 +00:00
|
|
|
return max(int(queuingDelay), 1)
|
2017-09-28 07:21:05 +00:00
|
|
|
|
2015-12-08 15:50:49 +00:00
|
|
|
def __init__(self, id, delay, queueSize, bandwidth, loss, back_up=False):
|
2015-01-06 14:47:15 +00:00
|
|
|
self.id = id
|
|
|
|
self.delay = delay
|
|
|
|
self.queueSize = queueSize
|
|
|
|
self.bandwidth = bandwidth
|
2015-12-08 15:50:49 +00:00
|
|
|
self.loss = loss
|
2017-09-28 07:39:38 +00:00
|
|
|
self.queuingDelay = str(self.extractQueuingDelay(queueSize, bandwidth, delay))
|
2015-01-20 10:04:36 +00:00
|
|
|
self.netemAt = []
|
2015-05-18 14:54:18 +00:00
|
|
|
self.back_up = back_up
|
2015-01-20 10:04:36 +00:00
|
|
|
|
|
|
|
def addNetemAt(self, n):
|
|
|
|
if len(self.netemAt) == 0:
|
2015-01-20 11:23:57 +00:00
|
|
|
n.delta = n.at
|
2015-01-20 10:04:36 +00:00
|
|
|
self.netemAt.append(n)
|
|
|
|
else:
|
|
|
|
if n.at > self.netemAt[-1].at:
|
|
|
|
n.delta = n.at - self.netemAt[-1].at
|
|
|
|
self.netemAt.append(n)
|
|
|
|
else:
|
|
|
|
print("Do not take into account " + n.__str__() + \
|
|
|
|
"because ooo !")
|
|
|
|
pass
|
2015-02-26 16:43:45 +00:00
|
|
|
|
2019-11-28 15:22:53 +00:00
|
|
|
def buildBwCmd(self, ifname):
|
|
|
|
cmd = ""
|
|
|
|
for n in self.netemAt:
|
|
|
|
cmd = cmd + "sleep {}".format(n.delta)
|
2019-11-28 16:03:05 +00:00
|
|
|
cmd = cmd + " && tc qdisc add dev {} root handle 5:0 tbf rate {}mbit burst 15000 limit {} &&".format(ifname, self.bandwidth, int(self.bufferSize()))
|
2019-11-28 15:22:53 +00:00
|
|
|
|
|
|
|
cmd = cmd + " true &"
|
|
|
|
return cmd
|
|
|
|
|
2015-01-20 11:23:57 +00:00
|
|
|
def buildNetemCmd(self, ifname):
|
2015-01-20 10:04:36 +00:00
|
|
|
cmd = ""
|
|
|
|
for n in self.netemAt:
|
|
|
|
cmd = cmd + "sleep " + str(n.delta)
|
2016-06-04 12:15:57 +00:00
|
|
|
cmd = cmd + " && tc qdisc del dev " + ifname + " root "
|
2019-11-28 16:03:05 +00:00
|
|
|
cmd = cmd + " && tc qdisc add dev {} root handle 10: netem {} delay {}ms limit {} &&".format(ifname, n.cmd, self.delay, int(2 * self.bufferSize() // 1500))
|
2019-11-27 12:29:45 +00:00
|
|
|
|
2015-01-20 10:04:36 +00:00
|
|
|
cmd = cmd + " true &"
|
2015-01-16 02:59:52 +00:00
|
|
|
return cmd
|
2015-01-20 10:04:36 +00:00
|
|
|
|
2019-11-28 08:32:49 +00:00
|
|
|
def buildPolicingCmd(self, ifname):
|
|
|
|
cmd = ""
|
|
|
|
for n in self.netemAt:
|
|
|
|
cmd = cmd + "sleep {}".format(n.delta)
|
|
|
|
cmd = cmd + " && tc qdisc del dev {} ingress".format(ifname)
|
2019-11-28 10:22:35 +00:00
|
|
|
cmd = cmd + " ; tc qdisc add dev {} handle ffff: ingress".format(ifname)
|
2019-11-28 16:03:05 +00:00
|
|
|
cmd = cmd + " && tc filter add dev {} parent ffff: u32 match u32 0 0 police rate {}mbit burst {} drop && ".format(ifname, self.bandwidth, int(self.bufferSize() * 8))
|
2019-11-28 08:32:49 +00:00
|
|
|
|
|
|
|
cmd = cmd + " true &"
|
|
|
|
return cmd
|
|
|
|
|
2015-01-07 13:44:44 +00:00
|
|
|
def asDict(self):
|
|
|
|
d = {}
|
2015-01-16 02:59:52 +00:00
|
|
|
d['bw'] = float(self.bandwidth)
|
2015-01-07 13:52:43 +00:00
|
|
|
d['delay'] = self.delay + "ms"
|
2015-12-08 15:50:49 +00:00
|
|
|
d['loss'] = float(self.loss)
|
2015-01-07 13:52:43 +00:00
|
|
|
d['max_queue_size'] = int(self.queueSize)
|
2015-01-07 13:44:44 +00:00
|
|
|
return d
|
2015-01-06 14:47:15 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
s = "Link id : " + str(self.id) + "\n"
|
|
|
|
s = s + "\tDelay : " + str(self.delay) + "\n"
|
|
|
|
s = s + "\tQueue Size : " + str(self.queueSize) + "\n"
|
2015-01-20 10:04:36 +00:00
|
|
|
s = s + "\tBandwidth : " + str(self.bandwidth) + "\n"
|
2015-12-08 15:50:49 +00:00
|
|
|
s = s + "\tLoss : " + str(self.loss) + "\n"
|
2015-05-18 14:54:18 +00:00
|
|
|
s = s + "\tBack up : " + str(self.back_up) + "\n"
|
2015-01-20 10:04:36 +00:00
|
|
|
for l in self.netemAt:
|
|
|
|
s = s + "\t" + l.__str__() + "\n"
|
2015-01-06 14:47:15 +00:00
|
|
|
return s
|