[PATCH 1/2] BCC: Python: Support 'fmod_ret' method for eBPF

Gang Yan posted 2 patches 8 months, 2 weeks ago
There is a newer version of this series
[PATCH 1/2] BCC: Python: Support 'fmod_ret' method for eBPF
Posted by Gang Yan 8 months, 2 weeks ago
In kernel, there exists a lot of 'fmod_ret' functions, such as
'update_socket_protocol'. But it cannot be attached in BCC-python
directly, so this patch provides an interface for Python to use
'fmod_ret' attaching method.

Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
 src/python/bcc/__init__.py | 43 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py
index 8bc85516..96de3d40 100644
--- a/src/python/bcc/__init__.py
+++ b/src/python/bcc/__init__.py
@@ -461,6 +461,7 @@ class BPF(object):
         self.raw_tracepoint_fds = {}
         self.kfunc_entry_fds = {}
         self.kfunc_exit_fds = {}
+        self.fmod_ret_fds = {}
         self.lsm_fds = {}
         self.perf_buffers = {}
         self.open_perf_events = {}
@@ -1157,6 +1158,21 @@ class BPF(object):
             return True
         return False
 
+    @staticmethod
+    def support_fmod_ret():
+        if not BPF.support_kfunc():
+            return False
+
+        kernel_version = platform.release()
+        major, minor, _ = kernel_version.split(".")
+
+        if int(major) > 5:
+            return True
+        elif int(major) ==5 and int(minor) >= 6:
+            return True
+        else:
+            return False
+
     def detach_kfunc(self, fn_name=b""):
         fn_name = _assert_is_bytes(fn_name)
         fn_name = BPF.add_prefix(b"kfunc__", fn_name)
@@ -1166,6 +1182,15 @@ class BPF(object):
         os.close(self.kfunc_entry_fds[fn_name])
         del self.kfunc_entry_fds[fn_name]
 
+    def detach_fmod_ret(self, fn_name=b""):
+        fn_name = _assert_is_bytes(fn_name)
+        fn_name = BPF.add_prefix(b"kmod_ret__", fn_name)
+
+        if fn_name not in self.fmod_ret_fds:
+            raise Exception("Fmod_ret func %s is not attached" % fn_name)
+        os.close(self.fmod_ret_fds[fn_name])
+        del self.fmod_ret_fds[fn_name]
+
     def detach_kretfunc(self, fn_name=b""):
         fn_name = _assert_is_bytes(fn_name)
         fn_name = BPF.add_prefix(b"kretfunc__", fn_name)
@@ -1189,6 +1214,22 @@ class BPF(object):
         self.kfunc_entry_fds[fn_name] = fd
         return self
 
+    def attach_fmod_ret(self, fn_name=b""):
+        fn_name = _assert_is_bytes(fn_name)
+        fn_name = BPF.add_prefix(b"kmod_ret__", fn_name)
+
+        if fn_name in self.fmod_ret_fds:
+            raise Exception("Fmod_ret func %s has been attached" % fn_name)
+
+        fn = self.load_func(fn_name, BPF.TRACING)
+        fd = lib.bpf_attach_kfunc(fn.fd)
+
+        if fd < 0:
+            raise Exception("Failed to attach BPF to fmod_ret kernel func")
+        self.fmod_ret_fds[fn_name] = fd
+
+        return self
+
     def attach_kretfunc(self, fn_name=b""):
         fn_name = _assert_is_bytes(fn_name)
         fn_name = BPF.add_prefix(b"kretfunc__", fn_name)
@@ -1824,6 +1865,8 @@ class BPF(object):
             self.detach_kretfunc(k)
         for k, v in list(self.lsm_fds.items()):
             self.detach_lsm(k)
+        for k, v in list(self.fmod_ret_fds.items()):
+            self.detach_fmod_ret(k)
 
         # Clean up opened perf ring buffer and perf events
         table_keys = list(self.tables.keys())
-- 
2.25.1
Re: [PATCH 1/2] BCC: Python: Support 'fmod_ret' method for eBPF
Posted by Matthieu Baerts 8 months, 1 week ago
Hi Gang,

On 07/04/2025 04:37, Gang Yan wrote:
> In kernel, there exists a lot of 'fmod_ret' functions, such as
> 'update_socket_protocol'. But it cannot be attached in BCC-python
> directly, so this patch provides an interface for Python to use
> 'fmod_ret' attaching method.
> 
> Signed-off-by: Gang Yan <yangang@kylinos.cn>
> ---
>  src/python/bcc/__init__.py | 43 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
> 
> diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py
> index 8bc85516..96de3d40 100644
> --- a/src/python/bcc/__init__.py
> +++ b/src/python/bcc/__init__.py
> @@ -461,6 +461,7 @@ class BPF(object):
>          self.raw_tracepoint_fds = {}
>          self.kfunc_entry_fds = {}
>          self.kfunc_exit_fds = {}
> +        self.fmod_ret_fds = {}
>          self.lsm_fds = {}
>          self.perf_buffers = {}
>          self.open_perf_events = {}
> @@ -1157,6 +1158,21 @@ class BPF(object):
>              return True
>          return False
>  
> +    @staticmethod
> +    def support_fmod_ret():
> +        if not BPF.support_kfunc():
> +            return False
> +
> +        kernel_version = platform.release()
> +        major, minor, _ = kernel_version.split(".")
> +
> +        if int(major) > 5:
> +            return True
> +        elif int(major) ==5 and int(minor) >= 6:

Was it not introduced in v5.7 instead of v5.6?

  return int(major) > 5 or (int(major) == 5 and int(minor) >= 7)


https://lore.kernel.org/20200304191853.1529-1-kpsingh@chromium.org


But also, it feels wrong to look at the kernel version, in case of
backports, etc. Can you not look at something else? e.g. kallsyms?

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.
Re: [PATCH 1/2] BCC: Python: Support 'fmod_ret' method for eBPF
Posted by Gang Yan 8 months, 1 week ago
On Mon, Apr 07, 2025 at 11:07:41AM +0200, Matthieu Baerts wrote:
Hi Matt,


> Hi Gang,
> 
> On 07/04/2025 04:37, Gang Yan wrote:
> > In kernel, there exists a lot of 'fmod_ret' functions, such as
> > 'update_socket_protocol'. But it cannot be attached in BCC-python
> > directly, so this patch provides an interface for Python to use
> > 'fmod_ret' attaching method.
> > 
> > Signed-off-by: Gang Yan <yangang@kylinos.cn>
> > ---
> >  src/python/bcc/__init__.py | 43 ++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 43 insertions(+)
> > 
> > diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py
> > index 8bc85516..96de3d40 100644
> > --- a/src/python/bcc/__init__.py
> > +++ b/src/python/bcc/__init__.py
> > @@ -461,6 +461,7 @@ class BPF(object):
> >          self.raw_tracepoint_fds = {}
> >          self.kfunc_entry_fds = {}
> >          self.kfunc_exit_fds = {}
> > +        self.fmod_ret_fds = {}
> >          self.lsm_fds = {}
> >          self.perf_buffers = {}
> >          self.open_perf_events = {}
> > @@ -1157,6 +1158,21 @@ class BPF(object):
> >              return True
> >          return False
> >  
> > +    @staticmethod
> > +    def support_fmod_ret():
> > +        if not BPF.support_kfunc():
> > +            return False
> > +
> > +        kernel_version = platform.release()
> > +        major, minor, _ = kernel_version.split(".")
> > +
> > +        if int(major) > 5:
> > +            return True
> > +        elif int(major) ==5 and int(minor) >= 6:
> 
> Was it not introduced in v5.7 instead of v5.6?
> 
>   return int(major) > 5 or (int(major) == 5 and int(minor) >= 7)
> 
I think v5.7 is right, the 5.6 is from the bcc repo:

bcc/example/cpp/KModRetExample.cc:
	 * Kfunc modify_ret support is only available at kernel version 5.6 and later.

Maybe this is also need to be fixed later?

> 
> https://lore.kernel.org/20200304191853.1529-1-kpsingh@chromium.org
> 
> 
> But also, it feels wrong to look at the kernel version, in case of
> backports, etc. Can you not look at something else? e.g. kallsyms?
>

Do you think we can do this after making a PR first?

> Cheers,
> Matt
> -- 
> Sponsored by the NGI0 Core fund.
> 
>
Re: [PATCH 1/2] BCC: Python: Support 'fmod_ret' method for eBPF
Posted by Matthieu Baerts 8 months, 1 week ago
Hi Gang,

On 08/04/2025 03:56, Gang Yan wrote:
> On Mon, Apr 07, 2025 at 11:07:41AM +0200, Matthieu Baerts wrote:
> Hi Matt,
> 
> 
>> Hi Gang,
>>
>> On 07/04/2025 04:37, Gang Yan wrote:
>>> In kernel, there exists a lot of 'fmod_ret' functions, such as
>>> 'update_socket_protocol'. But it cannot be attached in BCC-python
>>> directly, so this patch provides an interface for Python to use
>>> 'fmod_ret' attaching method.
>>>
>>> Signed-off-by: Gang Yan <yangang@kylinos.cn>
>>> ---
>>>  src/python/bcc/__init__.py | 43 ++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 43 insertions(+)
>>>
>>> diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py
>>> index 8bc85516..96de3d40 100644
>>> --- a/src/python/bcc/__init__.py
>>> +++ b/src/python/bcc/__init__.py
>>> @@ -461,6 +461,7 @@ class BPF(object):
>>>          self.raw_tracepoint_fds = {}
>>>          self.kfunc_entry_fds = {}
>>>          self.kfunc_exit_fds = {}
>>> +        self.fmod_ret_fds = {}
>>>          self.lsm_fds = {}
>>>          self.perf_buffers = {}
>>>          self.open_perf_events = {}
>>> @@ -1157,6 +1158,21 @@ class BPF(object):
>>>              return True
>>>          return False
>>>  
>>> +    @staticmethod
>>> +    def support_fmod_ret():
>>> +        if not BPF.support_kfunc():

(I don't know if this dependence is needed here.)

>>> +            return False
>>> +
>>> +        kernel_version = platform.release()
>>> +        major, minor, _ = kernel_version.split(".")
>>> +
>>> +        if int(major) > 5:
>>> +            return True
>>> +        elif int(major) ==5 and int(minor) >= 6:
>>
>> Was it not introduced in v5.7 instead of v5.6?
>>
>>   return int(major) > 5 or (int(major) == 5 and int(minor) >= 7)
>>
> I think v5.7 is right, the 5.6 is from the bcc repo:
> 
> bcc/example/cpp/KModRetExample.cc:
> 	 * Kfunc modify_ret support is only available at kernel version 5.6 and later.
> 
> Maybe this is also need to be fixed later?

Maybe this bit is supported since v5.6 and fmod_ret from 5.7? I didn't
check.

>> https://lore.kernel.org/20200304191853.1529-1-kpsingh@chromium.org
>>
>>
>> But also, it feels wrong to look at the kernel version, in case of
>> backports, etc. Can you not look at something else? e.g. kallsyms?
>>
> 
> Do you think we can do this after making a PR first?

I don't know the BCC project, but I think checking the version will not
be accepted. I think it would be better to do something like that instead:

  @staticmethod
  def support_fmod_ret():
      # It is not clear what can be used to check if 'fmod_ret'
      # supported by the kernel. Assuming checking kfunc is enough.
      return BPF.support_kfunc():

And add a note about that in the commit message, asking BCC devs for
ideas. You can also say you considered checking the kernel version.

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.