Tracing mlx5e_setup_tc()

Semidragon·2023년 7월 17일
0
post-thumbnail

Now that I have succeeded in finding which function is beeing called for the tc, I now need to duplicate the behavior.
Yet, when I debug logs using printk, the outputs of the logs where not that useful:

The 3 ultimate goal of the log that were needed is:

TC caller function    **(1) Which function calls** 
|
|  **(2) Variables input to the caller function**
|
---> int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
		   void *type_data)    **(3) Member Variables**

(1) and (2) seems to be able to be found together, and (3) should be defined somewhere in the source code.

1. Finding the caller function

1.1 Using Ftrace

First, I tried to use ftrace to trace the call stack.
This was useful to understand the call stack of what mlx5e_setup_tc() calls:

However, the problem was that in order to see "which function" called, we needed to filter the output, as without the filter, our function was not printed at all:

Thus I have tried filtering with set_ftrace_filter with mlx* and *_tc*, however only showed results like:

1.2 Using __builtin_return_address(0)

Then, from this site,
I was able to find a possible answer.
I added the follwing code block:

	printk("my_function was called by %pF\n", __builtin_return_address(0));

Yet, this as shown gave me the return address, which was also not sufficient enough to understand the caller function's name.

1.3 Using __func__

#define mlx5e_setup_tc(dev, type,type_data) mlx5e_setup_tc_DEBUG(dev, type,type_data, __func__)

#ifdef HAVE_TC_SETUP_CB_EGDEV_REGISTER
int mlx5e_setup_tc_DEBUG(struct net_device *dev, enum tc_setup_type type,
		void *type_data, const char* caller_name)
#else
static int mlx5e_setup_tc_DEBUG(struct net_device *dev, enum tc_setup_type type,
			void *type_data, const char* caller_name)
#endif
{
	printk( "a was called from %s", caller_name );
	#ifdef HAVE_TC_SETUP_CB_EGDEV_REGISTER
	return mlx5e_setup_tc(dev, type,type_data)
	#else
	return mlx5e_setup_tc(dev,type,type_data);
	#endif
}

#define mlx5e_setup_tc(dev, type,type_data) mlx5e_setup_tc_DEBUG(dev, type,type_data, __func__)

2. Understanding the source code

From this source,
I was able to get the brief picture of tc:

the last ndo_setup_tc was linked to our mlx5e_setup_tc() as:

2.1 Digging into ndo_setup_tc

Here is one of the example using ndo_setup_tc.


And one thing we notice is that in the net_device *dev and enum tc_setup_type type field is the same.
Also, although the dev variable is passed, the tc_setup_type is fixed with TC_QUERY_CAPS. Because we know which type(5) we are being printed, it would be best to first understand enum tc_setup_type type.

2.2 enum tc_setup_type type

From include/linux/netdevice.h, I found the declaration of tc_setup_type.

Thus, I believe that the "5" for the type shown stands for TC_SETUP_CLSBPF.

Kinda wierd since all type showed "5". Are they all using BPF..?

2.3 Finding who uses TC_SETUP_CLSBPF

With doubts, I first searched for places that use TC_SETUP_CLSBPF.
And thankfully, I was able to find that it was only used in 1 place: net/sched/cls_bpf.c (Ignoring the drivers folder)

At net/sched/cls_bpf.c, it was being used at:

and

and

The term "cls" in the context of the Linux kernel often refers to classifiers used in the kernel's networking subsystem, specifically as part of its traffic control mechanism.

In Linux, traffic control encompasses shaping, scheduling, policing, and dropping. To perform these tasks, the Linux kernel needs to be able to categorize or classify network packets. This is where classifiers come in.

Classifiers are used to categorize packets into different "classes" based on various fields in the packet header. This categorization allows the kernel to apply different traffic control rules to different types of traffic. For example, one class of traffic might be given higher priority, while another might be rate-limited.

So I decided to dig in deeper.

Take tc_setup_cb_add for example at /net/sched/cls_api.c.

enum tc_setup_type type is passed to 1 place:

Then, in __tc_setup_cb_call, enum tc_setup_type type is passed to 1 place:

This is taking forever...

Thus, I analyzed the flow_block_cb:
at /include/net/flow_offload.h,

We can see that flow_block_cb has a member variable *cb with type flow_setup_cb_t (probably a function pointer type)

여기서 막힘 ..
flow_setup_cb_t
cb

profile
Semidragon's network [CS undergrad @ Sungkyunkwan University | Networks + System @ CSI]

0개의 댓글