https://velog.io/@brian11hwang/Tracing-mlx5esetuptc
#include <linux/kmod.h>
#device name and Gbit limit should be variables.
char *argv[] = { "/sbin/tc", "qdisc", "add", "dev", "enp6s0", "root", "handle", "1:", "htb", "default", "10", NULL };
static char* envp[] = {
"HOME=/",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
NULL
};
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
Yet, when trying to test tc, the driver would die, due placing the code inside the __init functions, which:
1) states all initialization functions
2) runs them in thread workqueue
Thus, tc applications are executed before device is fully ready.
Therefore, we will first test with a simple logger:
char *argv[] = { "/usr/bin/logger", "help!", NULL };
static char *envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };ㅓㅓ
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
Or, we could also run .sh files
printk("IS AFTER ALL FINISH?");
char *argv[] = { "/usr/bin/tc.sh", NULL };
static char *envp[] = {
"HOME=/",
"TERM=linux",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
where .sh file is:
#!/bin/bash
sudo logger -p kern.notice "Test for call usermodhelper"
Therefore, once the backchannel is made, we can do something like:
#include <linux/kmod.h>
// Define interface and bandwidth limit
char *interface = "enp6s0";
char *bw_limit = "20Gbit";
// Define command arrays
char *argv1[] = { "/sbin/tc", "qdisc", "del", "dev", interface, "root", NULL };
char *argv2[] = { "/sbin/tc", "qdisc", "add", "dev", interface, "root", "handle", "1:", "htb", "default", "10", NULL };
char *argv3[] = { "/sbin/tc", "class", "add", "dev", interface, "parent", "1:", "classid", "1:1", "htb", "rate", bw_limit, NULL };
char *argv4[] = { "/sbin/tc", "class", "add", "dev", interface, "parent", "1:1", "classid", "1:10", "htb", "rate", bw_limit, NULL };
// Define environment
static char* envp[] = {
"HOME=/",
"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
NULL
};
// Run the commands
call_usermodehelper(argv1[0], argv1, envp, UMH_WAIT_PROC);
call_usermodehelper(argv2[0], argv2, envp, UMH_WAIT_PROC);
call_usermodehelper(argv3[0], argv3, envp, UMH_WAIT_PROC);
call_usermodehelper(argv4[0], argv4, envp, UMH_WAIT_PROC);
which will run:
This approach is to create a user-space application (daemon) which monitors a sysfs or procfs file, and when a change is noted, it will apply the tc command. The kernel module will write to the sysfs/procfs file to trigger the application.
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/module.h>
static ssize_t my_sysfs_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
return count;
}
static struct kobj_attribute my_sysfs_attribute =
__ATTR(my_sysfs_file, 0220, NULL, my_sysfs_store);
static struct kobject *my_kobject;
static int __init my_module_init (void)
{
int error = 0;
my_kobject = kobject_create_and_add("my_kobject", kernel_kobj);
if(!my_kobject)
return -ENOMEM;
error = sysfs_create_file(my_kobject, &my_sysfs_attribute.attr);
if (error) {
printk("failed to create the my_sysfs_file file in /sys/kernel/my_kobject \n");
}
return error;
}
my_sysfs_store
is a function that is called when data is written to themy_sysfs_file
file in sysfs. The parameters are:
-kobj
points to the struct kobject that the attribute belongs to.
-attr
points to the struct kobj_attribute for the specific attribute that was written.
-buf
points to the buffer that contains the written data.
-count
is the number of bytes that were written.
my_sysfs_attribute
is a struct of typestruct kobj_attribute
. The__ATTR
macro is used to initialize it. The macro takes four arguments:
- The name of the attribute (my_sysfs_file
).
- The mode of the attribute (0220
, write permission for owner and group).
- A pointer to theshow
method for the attribute (not used here, set toNULL
).
- A pointer to thestore
method for the attribute (my_sysfs_store
).
#!/bin/bash
interface="enp6s0"
bw_limit="20Gbit"
while inotifywait -e modify /sys/kernel/my_kobject/my_sysfs_file; do
/sbin/tc qdisc del dev $interface root
/sbin/tc qdisc add dev $interface root handle 1: htb default 10
/sbin/tc class add dev $interface parent 1: classid 1:1 htb rate $bw_limit
/sbin/tc class add dev $interface parent 1:1 classid 1:10 htb rate $bw_limit
done
소중한 정보 감사드립니다!