Пример #1
0
    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)
Пример #2
0
    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)
Пример #3
0
    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)