Mathematics, philosophy, programming, in-line skating and everything in between. More about me…

My Blog

My Latest Tweets

Follow me on Twitter…
English | Czech
Choose your language. I write in English, but I translate most of my articles to Czech as well. Zvolte si jazyk. Píšu anglicky, ale většinu svých článků překládám i do češtiny.

Visualizing Linux Traffic Control Setup

In the past six months I had to deal with Linux traffic control (TC) a lot. I was literally blown away by the advanced features of the system. Of course, the versatility comes for the usual price: complexity. I definitely do not regret the time spent on understanding the principles of classes, qdiscs, filters, major and minor numbers, etc. However, I think I have found a way to work with them more easily.

When you want to see your TC configuration in full, you normally have to list qdiscs, classes, and filters separately and mentally piece the outputs together. For example:

$ tc qdisc show dev eth0
qdisc htb 1: root r2q 10 default 10 direct_packets_stat 0
qdisc sfq 10: parent 1:10 limit 127p quantum 1514b perturb 10sec
qdisc sfq 11: parent 1:11 limit 127p quantum 1514b perturb 10sec
qdisc sfq 19: parent 1:19 limit 127p quantum 1514b perturb 10sec
qdisc sfq 31: parent 1:31 limit 127p quantum 1514b perturb 10sec
$ tc class show dev eth0
class htb 1:11 parent 1:1 leaf 11: prio 0 rate 256000bit ceil 256000bit burst 15Kb cburst 1599b
class htb 1:10 parent 1:1 leaf 10: prio 0 rate 128000bit ceil 128000bit burst 15Kb cburst 1599b
class htb 1:1 root rate 10000Kbit ceil 10000Kbit burst 15Kb cburst 1600b
class htb 1:31 parent 1:1 leaf 31: prio 0 rate 128000bit ceil 128000bit burst 15Kb cburst 1599b
class htb 1:19 parent 1:1 leaf 19: prio 0 rate 512000bit ceil 512000bit burst 15Kb cburst 1599b
$ tc filter show dev eth0
filter parent 1: protocol ip pref 1 fw
filter parent 1: protocol ip pref 1 fw handle 0x1 classid 1:11
filter parent 1: protocol ip pref 1 fw handle 0x9 classid 1:19
filter parent 1: protocol ip pref 1 fw handle 0x15 classid 1:31

Since there is a certain hierarchy in TC configurations, I soon found myself drawing TC setups in trees. The idea to replace paper and pencil with Graphviz came not long after. Writing a simple script that parses the output of tc and converts it into a graph turned out to be surprisingly easy. Behold the glory of 181 lines of Python that beareth the name tcviz.

Note: Actually, I found a PERL script somewhere on the net that was doing precisely the same. However, the output was dead ugly for my eye. Tweaking the script was out of question since the PERL source looked even uglier. Hence, I took owls to Athens and wrote my own piece of software. It was fun.

The above configuration can be magically translated by tcviz into this picture:

tcviz-generated graph example

Qdiscs and classes are displayed as boxes and ellipses, respectively. Filters are represented by arrows that point from the parent to the target of the filter.

The script only generates commands for dot (a part of Graphviz). To actually generate the graph, the output of tcviz has to be passed to dot. For instance:

$ ./tcviz.py eth0 | dot -Tpng > tc.png

To display the graph without saving it, one could use display from the ImageMagick package:

$ ./tcviz.py eth0 | dot -Tpng | display

tcviz is still in early stage of development. I have only tested it with tc versions iproute2-ss060323 and iproute2-ss071016. It’s possible that the format of tc’s output is different in other versions and tcviz won’t understand it. Bug reports are welcome. I even have a vague development plan, so there might be some new features in the future (not just bug-fix releases).

Feel free to give tcviz a try. I’ll be happy to hear your opinions and suggestions.

Project site

P.S.: The best resource on TC out there is Linux Advanced Routing & Traffic Control.

April 5, MMIX — Linux, Programming, Projects and Python. 11 comments.

11 comments Add your own…

(avatar) Dave May 22, MMIX
Hi,

 When I try you program it gives me an error at:
[root@BuffyTheVampireSlayer tcviz-1.0]# python tcviz.py eth0 | dot -Tpng  tc.png
-bash: dot: command not found
Traceback (most recent call last):
 File "tcviz.py", line 12, in ?
   from Node import Node
 File "/var/www/html/scripts/tcviz-1.0/Node.py", line 32
   self.__parent = '1:0' if self.__nodeType == 'class' else None
                          ^
SyntaxError: invalid syntax

Do you have any ideas as to why?

This looks extremely promising.  Thanks Dave:)
(avatar) Vita May 22, MMIX

Hello Dave,

there seem to be two distinct errors:

  1. -bash: dot: command not found means that you don't have Graphviz installed on your system. If you're on Debian or Ubuntu, try apt-get install graphviz to get it. Other distros will surely have the package, too.
  2. The SyntaxError comes from Python and seems to indicate that you have a bit outdated version of Python. The ternary operator that appears on line 32 has been introduced in Python 2.5. Try running python -V (that's uppercase V) to see what version of Python you have.

Hope this helps,

~ Vita

(avatar) Ivan July 29, MMIX
Hey I'm really excited to see this script since it's exactly what I've been looking for.

There's just one MAJOR problem. It won't work in my setup. And I'm very bad at python. In fact I never took the time to learn anything about it.

So, I thought you'd be able to help understand what's wrong from the verbatim copy of ./tcviz.py run that is following right below:

nondescript:~/tcviz/tcviz-1.0# ./tcviz.py ifb0 | dot -Tpng  tc.png
Traceback (most recent call last):
 File "./tcviz.py", line 63, in
   sys.exit(main())
 File "./tcviz.py", line 29, in main
   filters = parse(f, Filter)
 File "./tcviz.py", line 45, in parse
   object = constructor(line)
 File "/root/tcviz/tcviz-1.0/Filter.py", line 23, in __init__
   self.parseSpec(spec)
 File "/root/tcviz/tcviz-1.0/Filter.py", line 28, in parseSpec
   self.__parent = self.__idNormalizer(spec.pop(0))
 File "/root/tcviz/tcviz-1.0/Node.py", line 50, in normalizeId
   return (id if id[-1] != ':' else id + '0')
IndexError: string index out of range

I have "Python 2.5.2 (r252:60911, Jan  4 2009, 17:40:26)"

and

nondescript:~/tcviz/tcviz-1.0# dpkg -l |grep iproute
ii  iproute                            20080725-2

Looking forward to your reply!

Btw BIG thanks for making this script available to everyone!
(avatar) Vita July 29, MMIX

Hi Ivan,

it seems that the script is crashing on some kind of setup that I haven't thought of. Could you please send me the output of these three commands?

  • tc qdisc show dev ifb0
  • tc class show dev ifb0
  • tc filter show dev ifb0

I hope I will be able to fix the script quickly. Thanks!

(avatar) Ivan July 29, MMIX
I sent those to your e-mail address. You should probably answer here so that others could also benefit from your response.
(avatar) Vita July 30, MMIX

Hi,

I've got good news and bad news. The good news is that your TC setup pointed me in the direction of several bugs. These are now fixed in tcviz 1.1 (announcement, project site). The script now generates Graphviz commands correctly.

The bad news is that Graphviz (dot) is choking on a graph of this size (about 190 classes and 280 filters). I tried Graphviz 2.16 and 2.20.2. Version 2.16 just creates a large but completely blank PNG. Version 2.20 complains that the width is too large (60,267px) and then segfaults.

I'm not sure how to tackle this. Maybe Graphviz could be persuaded to stack the nodes vertically as well as horizontally, so that the width wouldn't be getting so huge. However, my knowledge of Graphviz is rather limited. I don't know how to do it or if it is indeed possible...

(avatar) Ivan July 31, MMIX
It seems like there's some kind of patch out there or at least it was said it had been added into graphviz CVS repository. Check this out:  https://mailman.research.att.com/pipermail/graphviz-devel/2008/000750.html
(avatar) Tom McMillan December 23, MMIX
I found a bug, of sorts.

One of my major:minor strings contained hexadecimal numbers:

qdisc ingress ffff: parent ffff:fff1 ----------------

Node.py:setId() choked on this (actually, map() choked on this:
ValueError).

So I hacked the code to do this:

       def hexint(self, value):
               try:
                   x = int(value)
                   return x
               except ValueError:
                   return int(value, 16)

       def setId(self, value):
               (self.__major, self.__minor) = map(self.hexint,
                                                    self.normalizeId(value).s$

You can probably so this more elegantly than I can.  In any case,
thanks for the very useful code.  The pictures are quite nice.

Tom



(avatar) Vita December 28, MMIX

[VIII]

Hello Tom, and thanks for the report! I've (hopefully) fixed the bug in tcviz 1.2 (announcement, project site). Please let me know if you encounter any problems.

(avatar) Tom McMillan December 29, MMIX
Thanks, Vita.  Yes, it works just fine for me.  Thanks for the quick turnaround.  I am very fond of this script, now that I am working
with Linux TC...
(avatar) Charan November 8, MMXI
Hi Friends,

I am unable to show the output for filter in linux. Please help me any one. I am configured below rule.
"tc filter add dev eth0 parent ffff: protocol ip prio 50 u32 match ip dst 0.0.0.1/0 match ip dport 250 0xffff police rate 256kbit burst 10k drop flowid :1"

My doubt is,
Is there any problem in rule ?
or
Is there any problem in my Linux m/c?

Let me know good documents for TC.

Thanks......

Speak your mind

Allowed HTML tags are a, blockquote, em, code, li, ol, p, pre, strong, ul. Links to other comments in the form “[IV]” or “[4]” are detected automatically.