0

There is a userspace util called tc(8) for traffic shaping, i.e.

tc qdisc add dev eth0 root tbf rate 10mbit latency 100ms burst 5000.

The internal implementation of the tc command uses netlink to send specific messages to the kernel which in turn will change things accordingly. However, there is no public interface for the kernel code for this specific procedure - as in, there is no public API like tc_qdisc_add(x,y,z) - as everything is depending on the data from the netlink message itself.

So, is there a trick to simplify the process and simulate a message from the kernel? Is there a way to bypass the userspace call to tc and get the same outcome just from a kernel context?

red0ct
  • 4,840
  • 3
  • 17
  • 44
elasticman
  • 641
  • 8
  • 20

1 Answers1

0

is there a trick to simplify the process and simulate a message from the kernel?

I don't see any way to make it simple.

If we do not go into the details of the implementation of specific tc-commands, just to contemplate an existing API inside kernel, we can see that all the related to netlink talking and qdiscs adding code is located in /net/sched subdirectory. The main function for registering qdisc is located in /net/sched/sch_api.c and called register_qdisc(). Also we can see registering basic qdiscs and netlink ops in pktsched_init().

Qdisc operations are described via struct Qdisc_ops and comprise such like init, enqueue, change, etc.

Knowing this we can take a look at how is this implemented in tbf module (net/sched/sch_tbf.c). It has several operations described with tbf_qdisc_ops. Here there is operation to change called which normally is invoked like tc_modify_qdisc() -> qdisc_change() -> tbf_change().

So depending on what exactly you want to tune, you can somehow obtain the particular qdisc, build an appropriate netlink message (struct nlmsghdr, as it is done in usermode) and invoke e.g. ->change(...) method of qdisc.

The answer does not claim to be correct. I just tried to clarify the situation a little bit.

red0ct
  • 4,840
  • 3
  • 17
  • 44
  • Thanks for your answer. I already digged into the net/sched/ code and found the functions you mentioned, but in the end it all boils down to grabbing the received netlink messages and fill it into endless structures. The problem is that there was quite a huge change from 3.x to 4.x and 5.x, which will result in broken code when hardcoding the netlink messages and using the internal (private) functions. As it seems the payload which contains all information for qdisc change isn't documented anywhere in the kernel source. – elasticman Dec 02 '20 at 16:08
  • *"which will result in broken code when hardcoding the netlink messages and using the internal (private) functions"* - absolutely yep. That is why it is a kinda bad idea to do this from kernel if the special organized utility is present. Can't imagine why you're trying to achieve such a goal from kernel-space. This looks like a dubious architectural decision. – red0ct Dec 02 '20 at 16:15
  • Because it is executed from a module from within the kernel and I don't want to invoke the userspace when I don't need it. To be more clear: the underlying module is ONLY available in the kernel (low level). – elasticman Dec 02 '20 at 16:45
  • I understand that this is module and this is in the kernel. But why don't you want to spawn some usermode process or daemon to do usermode things? And connect it to your module via netlink/ioctl/procfs/... I.e. event-oriented usermode handling: your module generates event - usermode process handles it. – red0ct Dec 02 '20 at 17:05
  • *"when I don't need it"* - but seems that you need :) – red0ct Dec 02 '20 at 17:08