netlink icon indicating copy to clipboard operation
netlink copied to clipboard

Qdisc Loss/Latency Values Incorrect

Open myst3k opened this issue 5 years ago • 5 comments

Hello!

I admit I am a bit new to GoLang, but I am trying to create a program that lists out the output of "tc qdisc show" across all the interfaces. I seem to be getting some weird values for the Loss and Latency. I made a sample program to test it based on some of the test code.

Expecting: Latency: 5000, Limit: 1000, Loss: 5.0 Receive: Latency: 78125, Limit: 1000, Loss: 214748368

Am I doing something wrong?

My system is a fresh installed virtualbox of Ubuntu 18.04. With Go 1.12.9

package main

import (
	"github.com/vishvananda/netlink"
	"log"
	"os/exec"
)

func main() {
	const main_int_name = "enp0s3"
	link, err := netlink.LinkByName(main_int_name)
	if err != nil {
		log.Fatal(err)
	}
	qdiscs, err := netlink.QdiscList(link)
	if err != nil {
		log.Fatal(err)
	}
	for _, qdisc := range qdiscs {
		log.Println("NO NETEM: ",qdisc)
	}

	qattrs := netlink.QdiscAttrs{
		LinkIndex: link.Attrs().Index,
		Handle:    netlink.MakeHandle(0x2, 0),
		Parent:    netlink.HANDLE_ROOT,
	}

	nattrs := netlink.NetemQdiscAttrs{
		Latency: 5000,
		Loss:    5.0,
	}

	qdiscnetem := netlink.NewNetem(qattrs, nattrs)
	if err := netlink.QdiscAdd(qdiscnetem); err != nil {
		log.Fatal("unable to add qdisc: ", err)
	}

	qdiscs, err = netlink.QdiscList(link)
	for _, qdisc := range qdiscs {
		log.Println("WITH NETEM: ", qdisc)
		cmd, _ := exec.Command("tc", "qdisc", "show", "dev", main_int_name).Output()
		log.Printf("TC SHOW COMMAND: %s", cmd)
		netlink.QdiscDel(qdisc)
	}

}

Output:

chris@chris-VirtualBox:~/go/src/awesomeProject$ go build && sudo ./awesomeProject 
2019/09/03 13:37:30 NO NETEM:  {{LinkIndex: 2, Handle: none, Parent: root, Refcnt: 2} -- Target: 4999, Limit: 10240, Interval: 99999, ECM: 1, Flows: 1024, Quantum: 1514}
2019/09/03 13:37:30 WITH NETEM:  {Latency: 78125, Limit: 1000, Loss: 214748368, Gap: 0, Duplicate: 0, Jitter: 0}
2019/09/03 13:37:30 TC SHOW COMMAND: qdisc netem 2: root refcnt 2 limit 1000 delay 5.0ms loss 5%

myst3k avatar Sep 03 '19 17:09 myst3k

This also occurs just listing already created by using the tc command.

myst3k avatar Sep 03 '19 17:09 myst3k

I haven't looked at this in a while, but I seem to remember there being some really weird logic for how these things are calculated that the tc command does behind the scenes, so there isn't an exact match for the values that tc shows in the underlying structures. I'll have to try to find a reference doc.

vishvananda avatar Sep 09 '19 18:09 vishvananda

Ah my memory was about something else. The issue is that the Qdisc that is returned has the values as u32 so they just need to be converted back into a percentage which could be done using something like: qdisc.Loss / math.MaxUint32 * 100 which will give you approx 5.000

vishvananda avatar Sep 09 '19 18:09 vishvananda

The latency also goes through a time2tick conversion which converts the value into clock ticks. Basically there should probably be a way included to convert these back to human readable values which we don't currently provide. there is a method called tick2Time which converts back but it isn't exposed in an easy manner. I think there should be a NetEm.ToNetemQdiscAttrs() that converts the values back to milliseconds and percentages for you.

vishvananda avatar Sep 09 '19 18:09 vishvananda

Hi, I also encountered this problem related to the latency field. I found a workaround by adjusting the Latency field with TickInUsec(). However, I noticed that there was a time2Tick(latency) function in the library, but it was not exposed. So I used TickInUsec() as an alternative.

I'm concerned that this workaround may break if someone fixes the time correction bug in the future. Can we expect a fix for this issue, and if so, can maintainers notify to this issue?

// Add a new qdisc: tc qdisc add dev eth0 root netem delay 14ms
qdisc := &netlink.Netem{
  QdiscAttrs: netlink.QdiscAttrs{
    LinkIndex: link.Attrs().Index,
    Handle:    netlink.MakeHandle(0x1, 0),
    Parent:    netlink.HANDLE_ROOT,
  },
  Latency: uint32(14 * 1000 * netlink.TickInUsec()), // 14ms
}

bc-lee avatar Jul 18 '23 10:07 bc-lee