Skip to content

Commit 9cfb6ba

Browse files
committedOct 9, 2024·
update kfunc example
1 parent ab0d1ee commit 9cfb6ba

File tree

4 files changed

+369
-201
lines changed

4 files changed

+369
-201
lines changed
 

‎src/43-kfuncs/README.md

+198-131
Large diffs are not rendered by default.

‎src/43-kfuncs/README_en.md

+122-55
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Have you ever felt constrained by eBPF's capabilities? Maybe you've run into situations where the existing eBPF features just aren't enough to accomplish your goals. Perhaps you need deeper interactions with the kernel, or you're facing performance issues that the standard eBPF runtime can't solve. If you've ever wished for more flexibility and power in your eBPF programs, this tutorial is for you.
44

5-
## Introduction: Breaking Free from eBPF Runtime Limitations with kfuncs
5+
## Introduction: Adding a `strstr` kfunc to Break Free from eBPF Runtime Limitations
66

77
**eBPF (extended Berkeley Packet Filter)** has revolutionized Linux system programming by allowing developers to run sandboxed programs inside the kernel. It's a game-changer for networking, security, and observability, enabling powerful functionalities without the need to modify kernel source code or load traditional kernel modules.
88

@@ -20,11 +20,13 @@ Enter **kfuncs (BPF Kernel Functions)**. By defining your own kfuncs within kern
2020
- **Customize Behavior:** Tailor kernel interactions to fit your specific needs.
2121
- **Boost Performance:** Optimize critical paths by executing custom code directly in the kernel context.
2222

23+
**In this tutorial, we'll specifically add a `strstr` kfunc.** While implementing a string search directly in eBPF is challenging due to verifier restrictions, defining it as a kfunc allows us to bypass these limitations and perform more complex operations safely and efficiently.
24+
2325
Best of all, you achieve this without modifying the core kernel, keeping your system stable and your code safe.
2426

2527
In this tutorial, we'll show you how to define custom kfuncs to fill any gaps in eBPF's capabilities. We'll walk through creating a kernel module that introduces new kfuncs and demonstrate how to use them in your eBPF programs. Whether you're looking to overcome performance bottlenecks or need features the eBPF runtime doesn't offer, custom kfuncs can unlock new possibilities for your projects.
2628

27-
## Understanding kfuncs: Extending eBPF Beyond Helpers
29+
## Understanding kfunc: Extending eBPF Beyond Helpers
2830

2931
### What Are kfuncs?
3032

@@ -40,7 +42,7 @@ In this tutorial, we'll show you how to define custom kfuncs to fill any gaps in
4042

4143
kfuncs serve as bridges between eBPF programs and deeper kernel functionalities. They allow eBPF programs to perform more intricate operations by either exposing existing kernel functions or introducing new wrappers specifically designed for eBPF interactions. This integration facilitates deeper kernel interactions while ensuring that eBPF programs remain safe and maintainable.
4244

43-
It's important to note that the Linux kernel already includes a plethora of kfuncs. These built-in kfuncs cover a wide range of functionalities, allowing most developers to accomplish their tasks without the need to define new ones. However, in cases where the existing kfuncs do not meet specific requirements, defining custom kfuncs becomes necessary. This tutorial demonstrates how to define new kfuncs to fill any gaps, ensuring that your eBPF programs can leverage the exact functionality you need. eBPF can also be extended to userspace. In the userspace eBPF runtime [bpftime](https://github.com/eunomia-bpf/bpftime), we are also implementing ufuncs, which are similar to kfuncs but extending userspace applications.
45+
It's important to note that the Linux kernel already includes a plethora of kfuncs. These built-in kfuncs cover a wide range of functionalities, allowing most developers to accomplish their tasks without the need to define new ones. However, in cases where the existing kfuncs do not meet specific requirements, defining custom kfuncs becomes necessary. This tutorial demonstrates how to define new kfuncs to fill any gaps, ensuring that your eBPF programs can leverage the exact functionality you need. eBPF can also be extended to userspace. In the userspace eBPF runtime [bpftime](https://github.com/eunomia-bpf/bpftime), we are also implementing ufuncs, which are similar to kfuncs but extend userspace applications.
4446

4547
## Overview of kfuncs and Their Evolution
4648

@@ -62,83 +64,112 @@ To harness the power of kfuncs, you'll need to define them within a kernel modul
6264

6365
### Writing the Kernel Module
6466

65-
Let's start by creating a simple kernel module that defines a kfunc. This kfunc will perform a basic arithmetic operation, serving as a foundation for understanding the mechanics.
67+
Let's start by creating a simple kernel module that defines a `strstr` kfunc. This kfunc will perform a substring search operation, serving as a foundation for understanding the mechanics.
6668

6769
#### **File: `hello.c`**
6870

6971
```c
70-
#include <linux/init.h> // Macros for module initialization
71-
#include <linux/module.h> // Core header for loading modules
72-
#include <linux/kernel.h> // Kernel logging macros
72+
#include <linux/init.h> // Macros for module initialization
73+
#include <linux/module.h> // Core header for loading modules
74+
#include <linux/kernel.h> // Kernel logging macros
7375
#include <linux/bpf.h>
7476
#include <linux/btf.h>
7577
#include <linux/btf_ids.h>
7678

77-
// Declare the kfunc
78-
__bpf_kfunc u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d);
79+
/* Declare the kfunc prototype */
80+
__bpf_kfunc int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz);
7981

80-
/* Define the kfunc functions */
82+
/* Begin kfunc definitions */
8183
__bpf_kfunc_start_defs();
8284

83-
__bpf_kfunc u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d)
85+
/* Define the bpf_strstr kfunc */
86+
__bpf_kfunc int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz)
8487
{
85-
return a + b + c + d;
88+
// Edge case: if substr is empty, return 0 (assuming empty string is found at the start)
89+
if (substr__sz == 0)
90+
{
91+
return 0;
92+
}
93+
// Edge case: if the substring is longer than the main string, it's impossible to find
94+
if (substr__sz > str__sz)
95+
{
96+
return -1; // Return -1 to indicate not found
97+
}
98+
// Iterate through the main string, considering the size limit
99+
for (size_t i = 0; i <= str__sz - substr__sz; i++)
100+
{
101+
size_t j = 0;
102+
// Compare the substring with the current position in the string
103+
while (j < substr__sz && str[i + j] == substr[j])
104+
{
105+
j++;
106+
}
107+
// If the entire substring was found
108+
if (j == substr__sz)
109+
{
110+
return i; // Return the index of the first match
111+
}
112+
}
113+
// Return -1 if the substring is not found
114+
return -1;
86115
}
87116

117+
/* End kfunc definitions */
88118
__bpf_kfunc_end_defs();
89119

90-
// Define the BTF kfunc ID set
120+
/* Define the BTF kfuncs ID set */
91121
BTF_KFUNCS_START(bpf_kfunc_example_ids_set)
92-
BTF_ID_FLAGS(func, bpf_kfunc_call_test)
122+
BTF_ID_FLAGS(func, bpf_strstr)
93123
BTF_KFUNCS_END(bpf_kfunc_example_ids_set)
94124

95-
// Register the kfunc ID set
125+
/* Register the kfunc ID set */
96126
static const struct btf_kfunc_id_set bpf_kfunc_example_set = {
97127
.owner = THIS_MODULE,
98128
.set = &bpf_kfunc_example_ids_set,
99129
};
100130

101-
// Module initialization
131+
/* Function executed when the module is loaded */
102132
static int __init hello_init(void)
103133
{
104134
int ret;
105135

106136
printk(KERN_INFO "Hello, world!\n");
107-
// Register the BTF kfunc ID set
137+
/* Register the BTF kfunc ID set for BPF_PROG_TYPE_KPROBE */
108138
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kfunc_example_set);
109-
if (ret) {
139+
if (ret)
140+
{
110141
pr_err("bpf_kfunc_example: Failed to register BTF kfunc ID set\n");
111142
return ret;
112143
}
113144
printk(KERN_INFO "bpf_kfunc_example: Module loaded successfully\n");
114-
return 0; // Success
145+
return 0; // Return 0 if successful
115146
}
116147

117-
// Module cleanup
148+
/* Function executed when the module is removed */
118149
static void __exit hello_exit(void)
119150
{
120-
// Unregister the BTF kfunc ID set (optional based on kernel version)
121-
// unregister_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kfunc_example_set);
151+
/* Unregister the BTF kfunc ID set */
152+
unregister_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kfunc_example_set);
122153
printk(KERN_INFO "Goodbye, world!\n");
123154
}
124155

125-
// Define module entry and exit points
156+
/* Macros to define the module’s init and exit points */
126157
module_init(hello_init);
127158
module_exit(hello_exit);
128159

129-
MODULE_LICENSE("GPL"); // License type
160+
MODULE_LICENSE("GPL"); // License type (GPL)
130161
MODULE_AUTHOR("Your Name"); // Module author
131162
MODULE_DESCRIPTION("A simple module"); // Module description
132163
MODULE_VERSION("1.0"); // Module version
133164
```
134165
135166
**Explanation of the Code:**
136167
137-
- **Declaring the kfunc:** The `__bpf_kfunc` macro declares a function that eBPF programs can invoke. Here, `bpf_kfunc_call_test` takes four parameters (`a`, `b`, `c`, `d`) and returns their sum.
168+
- **Declaring the kfunc:** The `__bpf_kfunc` macro declares a function that eBPF programs can invoke. Here, `bpf_strstr` performs a substring search within a given string.
138169
139170
- **BTF Definitions:** The `__bpf_kfunc_start_defs` and `__bpf_kfunc_end_defs` macros demarcate the beginning and end of kfunc definitions. The `BTF_KFUNCS_START` and related macros assist in registering the kfuncs with the BPF Type Format (BTF).
140171
141-
- **Module Initialization:** The `hello_init` function registers the kfunc ID set, making `bpf_kfunc_call_test` available to eBPF programs of type `BPF_PROG_TYPE_KPROBE`.
172+
- **Module Initialization:** The `hello_init` function registers the kfunc ID set, making `bpf_strstr` available to eBPF programs of type `BPF_PROG_TYPE_KPROBE`.
142173
143174
- **Module Cleanup:** The `hello_exit` function ensures that the kfunc ID set is unregistered upon module removal, maintaining system cleanliness.
144175
@@ -258,15 +289,15 @@ Skipping BTF generation for /root/bpf-developer-tutorial/src/43-kfuncs/module/he
258289

259290
This command copies the `vmlinux` file to the appropriate build directory, enabling successful BTF generation.
260291

261-
The complete code for this tutorial can be found in the link <https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/43-kfuncs> on GitHub. This is tested on Linux kernel version 6.11, and some modifications may be required for lower versions, referring to `compact.h`.
292+
The complete code for this tutorial can be found in the [bpf-developer-tutorial repository](https://github.com/eunomia-bpf/bpf-developer-tutorial/tree/main/src/43-kfuncs) on GitHub. This is tested on Linux kernel version 6.11, and some modifications may be required for lower versions, referring to `compact.h`.
262293

263294
## Utilizing Your Custom kfunc in an eBPF Program
264295

265-
With the kernel module defining your custom kfunc in place, the next step is to create an eBPF program that leverages this function. This interaction showcases the enhanced capabilities introduced by kfuncs.
296+
With the kernel module defining your custom `strstr` kfunc in place, the next step is to create an eBPF program that leverages this function. This interaction showcases the enhanced capabilities introduced by kfuncs.
266297

267298
### Writing the eBPF Program
268299

269-
Create an eBPF program that attaches to the `do_unlinkat` kernel function and uses the custom `bpf_kfunc_call_test` kfunc.
300+
Create an eBPF program that attaches to the `do_unlinkat` kernel function and uses the custom `bpf_strstr` kfunc.
270301

271302
#### **File: `kfunc.c`**
272303

@@ -278,33 +309,44 @@ Create an eBPF program that attaches to the `do_unlinkat` kernel function and us
278309
#include <bpf/bpf_tracing.h>
279310

280311
typedef unsigned int u32;
281-
typedef unsigned long long u64;
282-
typedef int pid_t;
312+
typedef long long s64;
283313

284-
// Declare the external kfunc
285-
extern u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d) __ksym;
314+
/* Declare the external kfunc */
315+
extern int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz) __ksym;
286316

287-
// License information
288317
char LICENSE[] SEC("license") = "Dual BSD/GPL";
289318

290-
// Attach to the do_unlinkat kernel function
291319
SEC("kprobe/do_unlinkat")
292-
int handle_kprobe(void *ctx)
320+
int handle_kprobe(struct pt_regs *ctx)
293321
{
294322
pid_t pid = bpf_get_current_pid_tgid() >> 32;
295-
u64 result = bpf_kfunc_call_test(1, 2, 3, 4);
296-
bpf_printk("BPF triggered do_unlinkat from PID %d. Result: %lld\n", pid, result);
323+
char str[] = "Hello, world!";
324+
char substr[] = "wor";
325+
int result = bpf_strstr(str, sizeof(str) - 1, substr, sizeof(substr) - 1);
326+
if (result != -1)
327+
{
328+
bpf_printk("'%s' found in '%s' at index %d\n", substr, str, result);
329+
}
330+
bpf_printk("Hello, world! (pid: %d) bpf_strstr %d\n", pid, result);
297331
return 0;
298332
}
299333
```
300334
301335
**Explanation of the eBPF Code:**
302336
303-
- **External kfunc Declaration:** The `extern` keyword declares the `bpf_kfunc_call_test` function, making it accessible within the eBPF program.
304-
337+
- **External kfunc Declaration:** The `extern` keyword declares the `bpf_strstr` function, making it accessible within the eBPF program.
338+
305339
- **Kprobe Attachment:** The `SEC("kprobe/do_unlinkat")` macro attaches the eBPF program to the `do_unlinkat` kernel function. Every time `do_unlinkat` is invoked, the `handle_kprobe` function executes.
306-
307-
- **Using the kfunc:** Within `handle_kprobe`, the eBPF program calls `bpf_kfunc_call_test` with four arguments (`1, 2, 3, 4`). The result, which should be the sum of these numbers, is then printed using `bpf_printk`, displaying both the PID and the result.
340+
341+
- **Using the kfunc:** Within `handle_kprobe`, the eBPF program calls `bpf_strstr` with four arguments:
342+
- `str`: The main string to search within.
343+
- `str__sz`: The size of the main string.
344+
- `substr`: The substring to search for.
345+
- `substr__sz`: The size of the substring.
346+
347+
The result, which is the index of the first occurrence of `substr` in `str` or `-1` if not found, is then printed using `bpf_printk`, displaying both the PID and the result.
348+
349+
**Important Note:** Implementing a `strstr`-like function directly in eBPF is challenging due to verifier restrictions that limit loops and complex memory accesses. By implementing `strstr` as a kfunc, we bypass these limitations, allowing for more complex and efficient string operations within eBPF programs.
308350
309351
### Compiling the eBPF Program
310352
@@ -316,39 +358,68 @@ To compile the eBPF program, ensure you have the necessary tools installed, such
316358
cd /path/to/bpf-developer-tutorial/src/43-kfuncs/
317359
```
318360

319-
2. **Compile the eBPF Program:**
361+
2. **Create a `Makefile` for the eBPF Program:**
362+
363+
```makefile
364+
# File: Makefile
365+
366+
CLANG ?= clang
367+
LLVM_STRIP ?= llvm-strip
368+
BPF_TARGET := bpf
369+
370+
CFLAGS := -O2 -g -target $(BPF_TARGET) -Wall -Werror -I/usr/include
371+
372+
all: kfunc.o
373+
374+
kfunc.o: kfunc.c
375+
$(CLANG) $(CFLAGS) -c $< -o $@
376+
377+
clean:
378+
rm -f kfunc.o
379+
```
380+
381+
3. **Compile the eBPF Program:**
320382

321383
```bash
322384
make
323385
```
324386

387+
This command will generate a file named `kfunc.o`, which is the compiled eBPF object file.
388+
325389
### Running the eBPF Program
326390

327391
Assuming you have a user-space application or a tool to load and attach the eBPF program, you can execute it to observe the interaction between the eBPF program and the custom kfunc.
328392

329393
**Sample Output:**
330394

331395
```bash
332-
$ sudo ./kfunc
396+
# sudo ./load_kfunc
333397
BPF program loaded and attached successfully. Press Ctrl-C to exit.
334-
node-9523 [004] ...21 7520.587718: bpf_trace_printk: BPF triggered do_unlinkat from PID 9523. Result: 10
398+
```
335399

336-
cpptools-11242 [003] ...21 7859.613060: bpf_trace_printk: BPF triggered do_unlinkat from PID 11235. Result: 10
400+
Then, when the `do_unlinkat` function is invoked (e.g., when a file is unlinked), you can check the kernel logs:
337401

338-
^C
339-
cpptools-11242 [002] ...21 7865.831074: bpf_trace_printk: BPF triggered do_unlinkat from PID 11235. Result: 10
402+
```bash
403+
dmesg | tail
404+
```
405+
406+
**Expected Output:**
407+
408+
```txt
409+
[ 1234.5678] 'wor' found in 'Hello, world!' at index 7
410+
[ 1234.5679] Hello, world! (pid: 2075) bpf_strstr 7
340411
```
341412

342413
**Explanation of the Output:**
343414

344-
Each time the `do_unlinkat` function is invoked in the kernel, the eBPF program prints a message indicating the PID of the process and the result of the kfunc call. In this example, the sum `1 + 2 + 3 + 4` results in `10`, which is reflected in the output.
415+
Each time the `do_unlinkat` function is invoked in the kernel, the eBPF program prints a message indicating the PID of the process and the result of the kfunc call. In this example, the substring `"wor"` is found at index `7` in the string `"Hello, world!"`.
345416

346417
## Summary and Conclusion
347418

348419
In this tutorial, we've delved deep into extending eBPF's capabilities by defining and utilizing custom kernel functions (kfuncs). Here's a recap of what we've covered:
349420

350421
- **Understanding kfuncs:** Grasped the concept of kfuncs and their role in enhancing eBPF beyond standard helper functions.
351-
- **Defining kfuncs:** Created a kernel module that defines a custom kfunc, ensuring it can be safely exposed to eBPF programs without altering the core kernel.
422+
- **Defining kfuncs:** Created a kernel module that defines a custom `strstr` kfunc, ensuring it can be safely exposed to eBPF programs without altering the core kernel.
352423
- **Writing eBPF Programs with kfuncs:** Developed an eBPF program that leverages the custom kfunc to perform specific operations, demonstrating the enhanced functionality.
353424
- **Compilation and Execution:** Provided a step-by-step guide to compile, load, and run both the kernel module and the eBPF program, ensuring you can replicate the setup on your own system.
354425
- **Error Handling:** Addressed potential compilation issues and offered solutions to ensure a smooth development experience.
@@ -371,8 +442,4 @@ Happy eBPF-ing!
371442

372443
## Additional Resources
373444

374-
If you'd like to learn more about eBPF knowledge and practices, you can visit our open source tutorial code repository at <https://github.com/eunomia-bpf/bpf-developer-tutorial> or website <https://eunomia.dev/tutorials/> for more examples and complete code.
375-
376-
## Conclusion
377-
378-
By following this detailed tutorial, you've equipped yourself with the knowledge to extend eBPF's capabilities using custom kfuncs. Whether you're aiming to perform advanced kernel interactions, overcome helper limitations, or enhance your observability tools, kfuncs provide the flexibility and power you need. Continue experimenting, stay curious, and contribute to the ever-evolving landscape of eBPF!
445+
If you'd like to learn more about eBPF knowledge and practices, you can visit our open-source tutorial code repository at [bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial) or our website [eunomia.dev/tutorials](https://eunomia.dev/tutorials/) for more examples and complete code.

‎src/43-kfuncs/kfunc.bpf.c

+9-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ typedef unsigned int u32;
88
typedef unsigned long long u64;
99
typedef int pid_t;
1010

11-
extern u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d) __ksym;
11+
extern int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz) __ksym;
1212

1313
char LICENSE[] SEC("license") = "Dual BSD/GPL";
1414

1515
SEC("kprobe/do_unlinkat")
1616
int handle_kprobe(void *ctx)
1717
{
1818
pid_t pid = bpf_get_current_pid_tgid() >> 32;
19-
u64 result = bpf_kfunc_call_test(1, 2, 3, 4);
20-
bpf_printk("BPF triggered do_unlinkat from PID %d. Result: %lld\n", pid, result);
19+
char str[] = "Hello, world!";
20+
char substr[] = "wor";
21+
u32 result = bpf_strstr(str, sizeof(str) - 1, substr, sizeof(substr) - 1);
22+
if (result != -1)
23+
{
24+
bpf_printk("'%s' found in '%s' at index %d\n", substr, str, result);
25+
}
26+
bpf_printk("Hello, world! (pid: %d) bpf_strstr %d\n", pid, result);
2127
return 0;
2228
}

‎src/43-kfuncs/module/hello.c

+40-12
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,51 @@
1-
#include <linux/init.h> // Macros for module initialization
2-
#include <linux/module.h> // Core header for loading modules
3-
#include <linux/kernel.h> // Kernel logging macros
1+
#include <linux/init.h> // Macros for module initialization
2+
#include <linux/module.h> // Core header for loading modules
3+
#include <linux/kernel.h> // Kernel logging macros
44
#include <linux/bpf.h>
55
#include <linux/btf.h>
66
#include <linux/btf_ids.h>
77

8-
__bpf_kfunc u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d);
8+
__bpf_kfunc int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz);
99

1010
/* Define a kfunc function */
1111
__bpf_kfunc_start_defs();
1212

13-
__bpf_kfunc u64 bpf_kfunc_call_test(u32 a, u64 b, u32 c, u64 d)
13+
__bpf_kfunc int bpf_strstr(const char *str, u32 str__sz, const char *substr, u32 substr__sz)
1414
{
15-
return a + b + c + d;
15+
// Edge case: if substr is empty, return 0 (assuming empty string is found at the start)
16+
if (substr__sz == 0)
17+
{
18+
return 0;
19+
}
20+
// Edge case: if the substring is longer than the main string, it's impossible to find
21+
if (substr__sz > str__sz)
22+
{
23+
return -1; // Return -1 to indicate not found
24+
}
25+
26+
// Iterate through the main string, considering the size limit
27+
for (size_t i = 0; i <= str__sz - substr__sz; i++)
28+
{
29+
size_t j = 0;
30+
// Compare the substring with the current position in the string
31+
while (j < substr__sz && str[i + j] == substr[j])
32+
{
33+
j++;
34+
}
35+
// If the entire substring was found
36+
if (j == substr__sz)
37+
{
38+
return i; // Return the index of the first match
39+
}
40+
}
41+
// Return -1 if the substring is not found
42+
return -1;
1643
}
1744

1845
__bpf_kfunc_end_defs();
1946

2047
BTF_KFUNCS_START(bpf_kfunc_example_ids_set)
21-
BTF_ID_FLAGS(func, bpf_kfunc_call_test)
48+
BTF_ID_FLAGS(func, bpf_strstr)
2249
BTF_KFUNCS_END(bpf_kfunc_example_ids_set)
2350

2451
// Register the kfunc ID set
@@ -35,12 +62,13 @@ static int __init hello_init(void)
3562
printk(KERN_INFO "Hello, world!\n");
3663
// Register the BTF kfunc ID set
3764
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kfunc_example_set);
38-
if (ret) {
65+
if (ret)
66+
{
3967
pr_err("bpf_kfunc_example: Failed to register BTF kfunc ID set\n");
4068
return ret;
4169
}
4270
printk(KERN_INFO "bpf_kfunc_example: Module loaded successfully\n");
43-
return 0; // Return 0 if successful
71+
return 0; // Return 0 if successful
4472
}
4573

4674
// Function executed when the module is removed
@@ -55,7 +83,7 @@ static void __exit hello_exit(void)
5583
module_init(hello_init);
5684
module_exit(hello_exit);
5785

58-
MODULE_LICENSE("GPL"); // License type (GPL)
59-
MODULE_AUTHOR("Your Name"); // Module author
86+
MODULE_LICENSE("GPL"); // License type (GPL)
87+
MODULE_AUTHOR("Your Name"); // Module author
6088
MODULE_DESCRIPTION("A simple module"); // Module description
61-
MODULE_VERSION("1.0"); // Module version
89+
MODULE_VERSION("1.0"); // Module version

0 commit comments

Comments
 (0)
Please sign in to comment.