def linkconfig( self, netif: CoreInterface, bw: float = None, delay: float = None, loss: float = None, duplicate: float = None, jitter: float = None, netif2: float = None, devname: str = None, ) -> None: """ Configure link parameters by applying tc queuing disciplines on the interface. :param netif: interface one :param bw: bandwidth to set to :param delay: packet delay to set to :param loss: packet loss to set to :param duplicate: duplicate percentage to set to :param jitter: jitter to set to :param netif2: interface two :param devname: device name :return: nothing """ if devname is None: devname = netif.localname tc = f"{TC_BIN} qdisc replace dev {devname}" parent = "root" changed = False if netif.setparam("bw", bw): # from tc-tbf(8): minimum value for burst is rate / kernel_hz if bw is not None: burst = max(2 * netif.mtu, bw / 1000) # max IP payload limit = 0xFFFF tbf = f"tbf rate {bw} burst {burst} limit {limit}" if bw > 0: if self.up: cmd = f"{tc} {parent} handle 1: {tbf}" netif.host_cmd(cmd) netif.setparam("has_tbf", True) changed = True elif netif.getparam("has_tbf") and bw <= 0: if self.up: cmd = f"{TC_BIN} qdisc delete dev {devname} {parent}" netif.host_cmd(cmd) netif.setparam("has_tbf", False) # removing the parent removes the child netif.setparam("has_netem", False) changed = True if netif.getparam("has_tbf"): parent = "parent 1:1" netem = "netem" changed = max(changed, netif.setparam("delay", delay)) if loss is not None: loss = float(loss) changed = max(changed, netif.setparam("loss", loss)) if duplicate is not None: duplicate = int(duplicate) changed = max(changed, netif.setparam("duplicate", duplicate)) changed = max(changed, netif.setparam("jitter", jitter)) if not changed: return # jitter and delay use the same delay statement if delay is not None: netem += f" delay {delay}us" if jitter is not None: if delay is None: netem += f" delay 0us {jitter}us 25%" else: netem += f" {jitter}us 25%" if loss is not None and loss > 0: netem += f" loss {min(loss, 100)}%" if duplicate is not None and duplicate > 0: netem += f" duplicate {min(duplicate, 100)}%" delay_check = delay is None or delay <= 0 jitter_check = jitter is None or jitter <= 0 loss_check = loss is None or loss <= 0 duplicate_check = duplicate is None or duplicate <= 0 if all([delay_check, jitter_check, loss_check, duplicate_check]): # possibly remove netem if it exists and parent queue wasn't removed if not netif.getparam("has_netem"): return if self.up: cmd = f"{TC_BIN} qdisc delete dev {devname} {parent} handle 10:" netif.host_cmd(cmd) netif.setparam("has_netem", False) elif len(netem) > 1: if self.up: cmd = ( f"{TC_BIN} qdisc replace dev {devname} {parent} handle 10: {netem}" ) netif.host_cmd(cmd) netif.setparam("has_netem", True)
def linkconfig(self, iface: CoreInterface, options: LinkOptions, iface2: CoreInterface = None) -> None: """ Configure link parameters by applying tc queuing disciplines on the interface. :param iface: interface one :param options: options for configuring link :param iface2: interface two :return: nothing """ # determine if any settings have changed changed = any([ iface.setparam("bw", options.bandwidth), iface.setparam("delay", options.delay), iface.setparam("loss", options.loss), iface.setparam("duplicate", options.dup), iface.setparam("jitter", options.jitter), iface.setparam("buffer", options.buffer), ]) if not changed: return # delete tc configuration or create and add it devname = iface.localname if all([ options.delay is None or options.delay <= 0, options.jitter is None or options.jitter <= 0, options.loss is None or options.loss <= 0, options.dup is None or options.dup <= 0, options.bandwidth is None or options.bandwidth <= 0, options.buffer is None or options.buffer <= 0, ]): if not iface.getparam("has_netem"): return if self.up: cmd = f"{TC} qdisc delete dev {devname} root handle 10:" iface.host_cmd(cmd) iface.setparam("has_netem", False) else: netem = "" if options.bandwidth is not None: limit = 1000 bw = options.bandwidth / 1000 if options.buffer is not None and options.buffer > 0: limit = options.buffer elif options.delay and options.bandwidth: delay = options.delay / 1000 limit = max(2, math.ceil( (2 * bw * delay) / (8 * iface.mtu))) netem += f" rate {bw}kbit" netem += f" limit {limit}" if options.delay is not None: netem += f" delay {options.delay}us" if options.jitter is not None: if options.delay is None: netem += f" delay 0us {options.jitter}us 25%" else: netem += f" {options.jitter}us 25%" if options.loss is not None and options.loss > 0: netem += f" loss {min(options.loss, 100)}%" if options.dup is not None and options.dup > 0: netem += f" duplicate {min(options.dup, 100)}%" if self.up: cmd = f"{TC} qdisc replace dev {devname} root handle 10: netem {netem}" iface.host_cmd(cmd) iface.setparam("has_netem", True)
def linkconfig(self, iface: CoreInterface, options: LinkOptions, iface2: CoreInterface = None) -> None: """ Configure link parameters by applying tc queuing disciplines on the interface. :param iface: interface one :param options: options for configuring link :param iface2: interface two :return: nothing """ devname = iface.localname tc = f"{TC} qdisc replace dev {devname}" parent = "root" changed = False bw = options.bandwidth if iface.setparam("bw", bw): # from tc-tbf(8): minimum value for burst is rate / kernel_hz burst = max(2 * iface.mtu, int(bw / 1000)) # max IP payload limit = 0xFFFF tbf = f"tbf rate {bw} burst {burst} limit {limit}" if bw > 0: if self.up: cmd = f"{tc} {parent} handle 1: {tbf}" iface.host_cmd(cmd) iface.setparam("has_tbf", True) changed = True elif iface.getparam("has_tbf") and bw <= 0: if self.up: cmd = f"{TC} qdisc delete dev {devname} {parent}" iface.host_cmd(cmd) iface.setparam("has_tbf", False) # removing the parent removes the child iface.setparam("has_netem", False) changed = True if iface.getparam("has_tbf"): parent = "parent 1:1" netem = "netem" delay = options.delay changed = max(changed, iface.setparam("delay", delay)) loss = options.loss if loss is not None: loss = float(loss) changed = max(changed, iface.setparam("loss", loss)) duplicate = options.dup if duplicate is not None: duplicate = int(duplicate) changed = max(changed, iface.setparam("duplicate", duplicate)) jitter = options.jitter changed = max(changed, iface.setparam("jitter", jitter)) if not changed: return # jitter and delay use the same delay statement if delay is not None: netem += f" delay {delay}us" if jitter is not None: if delay is None: netem += f" delay 0us {jitter}us 25%" else: netem += f" {jitter}us 25%" if loss is not None and loss > 0: netem += f" loss {min(loss, 100)}%" if duplicate is not None and duplicate > 0: netem += f" duplicate {min(duplicate, 100)}%" delay_check = delay is None or delay <= 0 jitter_check = jitter is None or jitter <= 0 loss_check = loss is None or loss <= 0 duplicate_check = duplicate is None or duplicate <= 0 if all([delay_check, jitter_check, loss_check, duplicate_check]): # possibly remove netem if it exists and parent queue wasn't removed if not iface.getparam("has_netem"): return if self.up: cmd = f"{TC} qdisc delete dev {devname} {parent} handle 10:" iface.host_cmd(cmd) iface.setparam("has_netem", False) elif len(netem) > 1: if self.up: cmd = f"{TC} qdisc replace dev {devname} {parent} handle 10: {netem}" iface.host_cmd(cmd) iface.setparam("has_netem", True)