diff mbox series

[bpf-next,09/13] bpf: Add BPF_FUNC_jiffies

Message ID 20191214004758.1653342-1-kafai@fb.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series Introduce BPF STRUCT_OPS | expand

Commit Message

Martin KaFai Lau Dec. 14, 2019, 12:47 a.m. UTC
This patch adds a helper to handle jiffies.  Some of the
tcp_sock's timing is stored in jiffies.  Although things
could be deduced by CONFIG_HZ, having an easy way to get
jiffies will make the later bpf-tcp-cc implementation easier.

While at it, instead of reading jiffies alone, it also takes a
"flags" argument to help converting between ns and jiffies.

This helper is available to CAP_SYS_ADMIN.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
---
 include/linux/bpf.h      |  1 +
 include/uapi/linux/bpf.h | 16 +++++++++++++++-
 kernel/bpf/core.c        |  1 +
 kernel/bpf/helpers.c     | 25 +++++++++++++++++++++++++
 net/core/filter.c        |  2 ++
 5 files changed, 44 insertions(+), 1 deletion(-)

Comments

Eric Dumazet Dec. 14, 2019, 1:59 a.m. UTC | #1
On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> This patch adds a helper to handle jiffies.  Some of the
> tcp_sock's timing is stored in jiffies.  Although things
> could be deduced by CONFIG_HZ, having an easy way to get
> jiffies will make the later bpf-tcp-cc implementation easier.
> 

...

> +
> +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> +{
> +	if (!flags)
> +		return get_jiffies_64();
> +
> +	if (flags & BPF_F_NS_TO_JIFFIES) {
> +		return nsecs_to_jiffies(in);
> +	} else if (flags & BPF_F_JIFFIES_TO_NS) {
> +		if (!in)
> +			in = get_jiffies_64();
> +		return jiffies_to_nsecs(in);
> +	}
> +
> +	return 0;
> +}

This looks a bit convoluted :)

Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.

We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.


Have you thought of finding a way to not duplicate the code for cubic and dctcp, maybe
by including a template ?

Maintaining two copies means that future changes need more maintenance work.
Neal Cardwell Dec. 14, 2019, 7:25 p.m. UTC | #2
On Fri, Dec 13, 2019 at 9:00 PM Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
>
>
> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> > This patch adds a helper to handle jiffies.  Some of the
> > tcp_sock's timing is stored in jiffies.  Although things
> > could be deduced by CONFIG_HZ, having an easy way to get
> > jiffies will make the later bpf-tcp-cc implementation easier.
> >
>
> ...
>
> > +
> > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> > +{
> > +     if (!flags)
> > +             return get_jiffies_64();
> > +
> > +     if (flags & BPF_F_NS_TO_JIFFIES) {
> > +             return nsecs_to_jiffies(in);
> > +     } else if (flags & BPF_F_JIFFIES_TO_NS) {
> > +             if (!in)
> > +                     in = get_jiffies_64();
> > +             return jiffies_to_nsecs(in);
> > +     }
> > +
> > +     return 0;
> > +}
>
> This looks a bit convoluted :)
>
> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
>
> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.

If the jiffies functionality stays, how about 3 simple functions that
correspond to the underlying C functions, perhaps something like:

  bpf_nsecs_to_jiffies(nsecs)
  bpf_jiffies_to_nsecs(jiffies)
  bpf_get_jiffies_64()

Separate functions might be easier to read/maintain (and may even be
faster, given the corresponding reduction in branches).

neal
Martin KaFai Lau Dec. 16, 2019, 7:14 p.m. UTC | #3
On Fri, Dec 13, 2019 at 05:59:54PM -0800, Eric Dumazet wrote:
> 
> 
> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> > This patch adds a helper to handle jiffies.  Some of the
> > tcp_sock's timing is stored in jiffies.  Although things
> > could be deduced by CONFIG_HZ, having an easy way to get
> > jiffies will make the later bpf-tcp-cc implementation easier.
> > 
> 
> ...
> 
> > +
> > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> > +{
> > +	if (!flags)
> > +		return get_jiffies_64();
> > +
> > +	if (flags & BPF_F_NS_TO_JIFFIES) {
> > +		return nsecs_to_jiffies(in);
> > +	} else if (flags & BPF_F_JIFFIES_TO_NS) {
> > +		if (!in)
> > +			in = get_jiffies_64();
> > +		return jiffies_to_nsecs(in);
> > +	}
> > +
> > +	return 0;
> > +}
> 
> This looks a bit convoluted :)
> 
> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
> 
> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
Thanks for the feedbacks!

I have a few questions that need some helps.

Does it mean tp->tcp_mstamp can be used as the "now" in cubic?
or tcp_clock_ns() should still be called in cubic, e.g. to replace
bictcp_clock() and tcp_jiffies32?

BPF currently has a helper calling ktime_get_mono_fast_ns() which looks
different from tcp_clock_ns().

The lsndtime is in jiffies.  I think it can probably be converted to ms before
using it in cubic.  There are some BICTCP_HZ logic in bictcp_update() that
is not obvious to me how to convet them to ms base also.

> 
> 
> Have you thought of finding a way to not duplicate the code for cubic and dctcp, maybe
> by including a template ?
> 
> Maintaining two copies means that future changes need more maintenance work.
At least for bpf_dctcp.c, I did not expect it could be that close to tcp_dctcp.c
when I just started converted it.  tcp_cubic/bpf_cubic still has some TBD
on jiffies/msec.

Agree that it is beneficial to have one copy.   It is likely
I need to make some changes on the tcp_*.c side also.  Hence, I prefer
to give it a try in a separate series, e.g. revert the kernel side
changes will be easier.
Martin KaFai Lau Dec. 16, 2019, 7:30 p.m. UTC | #4
On Sat, Dec 14, 2019 at 02:25:14PM -0500, Neal Cardwell wrote:
> On Fri, Dec 13, 2019 at 9:00 PM Eric Dumazet <eric.dumazet@gmail.com> wrote:
> >
> >
> >
> > On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> > > This patch adds a helper to handle jiffies.  Some of the
> > > tcp_sock's timing is stored in jiffies.  Although things
> > > could be deduced by CONFIG_HZ, having an easy way to get
> > > jiffies will make the later bpf-tcp-cc implementation easier.
> > >
> >
> > ...
> >
> > > +
> > > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> > > +{
> > > +     if (!flags)
> > > +             return get_jiffies_64();
> > > +
> > > +     if (flags & BPF_F_NS_TO_JIFFIES) {
> > > +             return nsecs_to_jiffies(in);
> > > +     } else if (flags & BPF_F_JIFFIES_TO_NS) {
> > > +             if (!in)
> > > +                     in = get_jiffies_64();
> > > +             return jiffies_to_nsecs(in);
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> >
> > This looks a bit convoluted :)
> >
> > Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
> >
> > We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
> 
> If the jiffies functionality stays, how about 3 simple functions that
> correspond to the underlying C functions, perhaps something like:
> 
>   bpf_nsecs_to_jiffies(nsecs)
>   bpf_jiffies_to_nsecs(jiffies)
>   bpf_get_jiffies_64()
> 
> Separate functions might be easier to read/maintain (and may even be
> faster, given the corresponding reduction in branches).
Yes.  It could be different bpf helpers.

I will take another look on these.
I may not need the nsecs <=> jiffies with CONFIG_HZ and
Andrii's recent extern var support.  The first attempt I tried
end-up a lot of codes on the bpf_prog side.  I may not have done
it right.  I will give it another try on this side.

Thanks for the feedbacks!
Eric Dumazet Dec. 16, 2019, 7:33 p.m. UTC | #5
On 12/16/19 11:14 AM, Martin Lau wrote:
> On Fri, Dec 13, 2019 at 05:59:54PM -0800, Eric Dumazet wrote:
>>
>>
>> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
>>> This patch adds a helper to handle jiffies.  Some of the
>>> tcp_sock's timing is stored in jiffies.  Although things
>>> could be deduced by CONFIG_HZ, having an easy way to get
>>> jiffies will make the later bpf-tcp-cc implementation easier.
>>>
>>
>> ...
>>
>>> +
>>> +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
>>> +{
>>> +	if (!flags)
>>> +		return get_jiffies_64();
>>> +
>>> +	if (flags & BPF_F_NS_TO_JIFFIES) {
>>> +		return nsecs_to_jiffies(in);
>>> +	} else if (flags & BPF_F_JIFFIES_TO_NS) {
>>> +		if (!in)
>>> +			in = get_jiffies_64();
>>> +		return jiffies_to_nsecs(in);
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>
>> This looks a bit convoluted :)
>>
>> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
>>
>> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
> Thanks for the feedbacks!
> 
> I have a few questions that need some helps.
> 
> Does it mean tp->tcp_mstamp can be used as the "now" in cubic?

TCP makes sure to update tp->tcp_mstamp at least once when handling
a particular packet. We did that to avoid calling possibly expensive
kernel time service (Some platforms do not have fast TSC) 

> or tcp_clock_ns() should still be called in cubic, e.g. to replace
> bictcp_clock() and tcp_jiffies32?

Yeah, there is this lsndtime and tcp_jiffies32 thing, but maybe
we can find a way to fetch jiffies32 without having to call a bpf helper ?

> 
> BPF currently has a helper calling ktime_get_mono_fast_ns() which looks
> different from tcp_clock_ns().

That's maybe because of NMI requirements. 

TCP in the other hand is in process or BH context.

But it should not matter, cubic could should not have to call them.
Martin KaFai Lau Dec. 16, 2019, 9:17 p.m. UTC | #6
On Mon, Dec 16, 2019 at 11:33:01AM -0800, Eric Dumazet wrote:
> 
> 
> On 12/16/19 11:14 AM, Martin Lau wrote:
> > On Fri, Dec 13, 2019 at 05:59:54PM -0800, Eric Dumazet wrote:
> >>
> >>
> >> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> >>> This patch adds a helper to handle jiffies.  Some of the
> >>> tcp_sock's timing is stored in jiffies.  Although things
> >>> could be deduced by CONFIG_HZ, having an easy way to get
> >>> jiffies will make the later bpf-tcp-cc implementation easier.
> >>>
> >>
> >> ...
> >>
> >>> +
> >>> +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> >>> +{
> >>> +	if (!flags)
> >>> +		return get_jiffies_64();
> >>> +
> >>> +	if (flags & BPF_F_NS_TO_JIFFIES) {
> >>> +		return nsecs_to_jiffies(in);
> >>> +	} else if (flags & BPF_F_JIFFIES_TO_NS) {
> >>> +		if (!in)
> >>> +			in = get_jiffies_64();
> >>> +		return jiffies_to_nsecs(in);
> >>> +	}
> >>> +
> >>> +	return 0;
> >>> +}
> >>
> >> This looks a bit convoluted :)
> >>
> >> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
> >>
> >> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
> > Thanks for the feedbacks!
> > 
> > I have a few questions that need some helps.
> > 
> > Does it mean tp->tcp_mstamp can be used as the "now" in cubic?
> 
> TCP makes sure to update tp->tcp_mstamp at least once when handling
> a particular packet. We did that to avoid calling possibly expensive
> kernel time service (Some platforms do not have fast TSC) 
> 
> > or tcp_clock_ns() should still be called in cubic, e.g. to replace
> > bictcp_clock() and tcp_jiffies32?
> 
> Yeah, there is this lsndtime and tcp_jiffies32 thing, but maybe
> we can find a way to fetch jiffies32 without having to call a bpf helper ?
Loading a kernel global variable is not yet supported.
Thus, helper is needed but it could be inlined like array_map_gen_lookup().
Alexei Starovoitov Dec. 16, 2019, 11:08 p.m. UTC | #7
On 12/16/19 11:14 AM, Martin Lau wrote:
> At least for bpf_dctcp.c, I did not expect it could be that close to tcp_dctcp.c
> when I just started converted it.  tcp_cubic/bpf_cubic still has some TBD
> on jiffies/msec.
> 
> Agree that it is beneficial to have one copy.   It is likely
> I need to make some changes on the tcp_*.c side also.  Hence, I prefer
> to give it a try in a separate series, e.g. revert the kernel side
> changes will be easier.

I've looked at bpf_cubic.c and bpf_dctcp.c as examples of what this
patch set can do. They're selftests of the feature.
What's the value of keeping them in sync with real kernel cc-s?
I think it's fine if they quickly diverge.
The value of them as selftests is important though. Quite a bit of BTF
and verifier logic is being tested.
May be add a comment saying that bpf_cubic.c is like cubic, but doesn't
have to be exactly cubic ?
Eric Dumazet Dec. 17, 2019, 12:34 a.m. UTC | #8
On 12/16/19 3:08 PM, Alexei Starovoitov wrote:
> On 12/16/19 11:14 AM, Martin Lau wrote:
>> At least for bpf_dctcp.c, I did not expect it could be that close to tcp_dctcp.c
>> when I just started converted it.  tcp_cubic/bpf_cubic still has some TBD
>> on jiffies/msec.
>>
>> Agree that it is beneficial to have one copy.   It is likely
>> I need to make some changes on the tcp_*.c side also.  Hence, I prefer
>> to give it a try in a separate series, e.g. revert the kernel side
>> changes will be easier.
> 
> I've looked at bpf_cubic.c and bpf_dctcp.c as examples of what this
> patch set can do. They're selftests of the feature.
> What's the value of keeping them in sync with real kernel cc-s?
> I think it's fine if they quickly diverge.
> The value of them as selftests is important though. Quite a bit of BTF
> and verifier logic is being tested.
> May be add a comment saying that bpf_cubic.c is like cubic, but doesn't
> have to be exactly cubic ?
> 

The reason I mentioned this is that I am currently working on a fix of Hystart
logic, which is quite broken at the moment.

(hystart_train detection triggers in cases it should not)

But yes, if we add a comment warning potential users, this should be fine.
Jakub Sitnicki Dec. 17, 2019, 8:26 a.m. UTC | #9
On Sat, Dec 14, 2019 at 08:25 PM CET, Neal Cardwell wrote:
> On Fri, Dec 13, 2019 at 9:00 PM Eric Dumazet <eric.dumazet@gmail.com> wrote:
>>
>>
>>
>> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
>> > This patch adds a helper to handle jiffies.  Some of the
>> > tcp_sock's timing is stored in jiffies.  Although things
>> > could be deduced by CONFIG_HZ, having an easy way to get
>> > jiffies will make the later bpf-tcp-cc implementation easier.
>> >
>>
>> ...
>>
>> > +
>> > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
>> > +{
>> > +     if (!flags)
>> > +             return get_jiffies_64();
>> > +
>> > +     if (flags & BPF_F_NS_TO_JIFFIES) {
>> > +             return nsecs_to_jiffies(in);
>> > +     } else if (flags & BPF_F_JIFFIES_TO_NS) {
>> > +             if (!in)
>> > +                     in = get_jiffies_64();
>> > +             return jiffies_to_nsecs(in);
>> > +     }
>> > +
>> > +     return 0;
>> > +}
>>
>> This looks a bit convoluted :)
>>
>> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
>>
>> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
>
> If the jiffies functionality stays, how about 3 simple functions that
> correspond to the underlying C functions, perhaps something like:
>
>   bpf_nsecs_to_jiffies(nsecs)
>   bpf_jiffies_to_nsecs(jiffies)
>   bpf_get_jiffies_64()
>
> Separate functions might be easier to read/maintain (and may even be
> faster, given the corresponding reduction in branches).

Having bpf_nsecs_to_jiffies() would be also handy for BPF sockops progs
that configure SYN-RTO timeout (BPF_SOCK_OPS_TIMEOUT_INIT).

Right now user-space needs to go look for CONFIG_HZ in /proc/config.gz
or /boot/config-`uname -r`, or derive it from clock resolution [0]

        clock_getres(CLOCK_REALTIME_COARSE, &res);
        jiffy = res.tv_nsec / 1000000;

to pass timeout in jiffies to the BPF prog.

-jkbs

[0] https://www.mail-archive.com/kernelnewbies@nl.linux.org/msg08850.html
Martin KaFai Lau Dec. 17, 2019, 6:22 p.m. UTC | #10
On Tue, Dec 17, 2019 at 09:26:31AM +0100, Jakub Sitnicki wrote:
> On Sat, Dec 14, 2019 at 08:25 PM CET, Neal Cardwell wrote:
> > On Fri, Dec 13, 2019 at 9:00 PM Eric Dumazet <eric.dumazet@gmail.com> wrote:
> >>
> >>
> >>
> >> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
> >> > This patch adds a helper to handle jiffies.  Some of the
> >> > tcp_sock's timing is stored in jiffies.  Although things
> >> > could be deduced by CONFIG_HZ, having an easy way to get
> >> > jiffies will make the later bpf-tcp-cc implementation easier.
> >> >
> >>
> >> ...
> >>
> >> > +
> >> > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
> >> > +{
> >> > +     if (!flags)
> >> > +             return get_jiffies_64();
> >> > +
> >> > +     if (flags & BPF_F_NS_TO_JIFFIES) {
> >> > +             return nsecs_to_jiffies(in);
> >> > +     } else if (flags & BPF_F_JIFFIES_TO_NS) {
> >> > +             if (!in)
> >> > +                     in = get_jiffies_64();
> >> > +             return jiffies_to_nsecs(in);
> >> > +     }
> >> > +
> >> > +     return 0;
> >> > +}
> >>
> >> This looks a bit convoluted :)
> >>
> >> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
> >>
> >> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
> >
> > If the jiffies functionality stays, how about 3 simple functions that
> > correspond to the underlying C functions, perhaps something like:
> >
> >   bpf_nsecs_to_jiffies(nsecs)
> >   bpf_jiffies_to_nsecs(jiffies)
> >   bpf_get_jiffies_64()
> >
> > Separate functions might be easier to read/maintain (and may even be
> > faster, given the corresponding reduction in branches).
> 
> Having bpf_nsecs_to_jiffies() would be also handy for BPF sockops progs
> that configure SYN-RTO timeout (BPF_SOCK_OPS_TIMEOUT_INIT).
> 
> Right now user-space needs to go look for CONFIG_HZ in /proc/config.gz
Andrii's extern variable work (already landed) allows a bpf_prog
to read CONFIG_HZ as a global variable.  It is the path that I am
pursuing now for jiffies/nsecs conversion without relying on
a helper.
Eric Dumazet Dec. 17, 2019, 9:04 p.m. UTC | #11
> Andrii's extern variable work (already landed) allows a bpf_prog
> to read CONFIG_HZ as a global variable.  It is the path that I am
> pursuing now for jiffies/nsecs conversion without relying on
> a helper.

I am traveling today, but plan sending a patch series for cubic,
switching to usec resolution to solve its inability to properly
detect ack trains in the datacenter.

But still it will use jiffies32 in some spots,
as you mentioned already because of tp->lsndtime.

This means bpf could also stick to tp->tcp_mstamp 

extract :

-static inline u32 bictcp_clock(void)
+static inline u32 bictcp_clock_us(const struct sock *sk)
 {
-#if HZ < 1000
-       return ktime_to_ms(ktime_get_real());
-#else
-       return jiffies_to_msecs(jiffies);
-#endif
+       return tcp_sk(sk)->tcp_mstamp;
 }
Jakub Sitnicki Dec. 18, 2019, 9:03 a.m. UTC | #12
On Tue, Dec 17, 2019 at 07:22 PM CET, Martin Lau wrote:
> On Tue, Dec 17, 2019 at 09:26:31AM +0100, Jakub Sitnicki wrote:
>> On Sat, Dec 14, 2019 at 08:25 PM CET, Neal Cardwell wrote:
>> > On Fri, Dec 13, 2019 at 9:00 PM Eric Dumazet <eric.dumazet@gmail.com> wrote:
>> >>
>> >>
>> >>
>> >> On 12/13/19 4:47 PM, Martin KaFai Lau wrote:
>> >> > This patch adds a helper to handle jiffies.  Some of the
>> >> > tcp_sock's timing is stored in jiffies.  Although things
>> >> > could be deduced by CONFIG_HZ, having an easy way to get
>> >> > jiffies will make the later bpf-tcp-cc implementation easier.
>> >> >
>> >>
>> >> ...
>> >>
>> >> > +
>> >> > +BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
>> >> > +{
>> >> > +     if (!flags)
>> >> > +             return get_jiffies_64();
>> >> > +
>> >> > +     if (flags & BPF_F_NS_TO_JIFFIES) {
>> >> > +             return nsecs_to_jiffies(in);
>> >> > +     } else if (flags & BPF_F_JIFFIES_TO_NS) {
>> >> > +             if (!in)
>> >> > +                     in = get_jiffies_64();
>> >> > +             return jiffies_to_nsecs(in);
>> >> > +     }
>> >> > +
>> >> > +     return 0;
>> >> > +}
>> >>
>> >> This looks a bit convoluted :)
>> >>
>> >> Note that we could possibly change net/ipv4/tcp_cubic.c to no longer use jiffies at all.
>> >>
>> >> We have in tp->tcp_mstamp an accurate timestamp (in usec) that can be converted to ms.
>> >
>> > If the jiffies functionality stays, how about 3 simple functions that
>> > correspond to the underlying C functions, perhaps something like:
>> >
>> >   bpf_nsecs_to_jiffies(nsecs)
>> >   bpf_jiffies_to_nsecs(jiffies)
>> >   bpf_get_jiffies_64()
>> >
>> > Separate functions might be easier to read/maintain (and may even be
>> > faster, given the corresponding reduction in branches).
>>
>> Having bpf_nsecs_to_jiffies() would be also handy for BPF sockops progs
>> that configure SYN-RTO timeout (BPF_SOCK_OPS_TIMEOUT_INIT).
>>
>> Right now user-space needs to go look for CONFIG_HZ in /proc/config.gz
> Andrii's extern variable work (already landed) allows a bpf_prog
> to read CONFIG_HZ as a global variable.  It is the path that I am
> pursuing now for jiffies/nsecs conversion without relying on
> a helper.

Thank yor for the pointer, and Andrii for implementing it.
Selftest [0] from extern-var-support series demonstrates it nicely.

[0] https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=330a73a7b6ca93a415de1b7da68d7a0698fe4937
diff mbox series

Patch

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 349cedd7b97b..00491961421e 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1371,6 +1371,7 @@  extern const struct bpf_func_proto bpf_get_local_storage_proto;
 extern const struct bpf_func_proto bpf_strtol_proto;
 extern const struct bpf_func_proto bpf_strtoul_proto;
 extern const struct bpf_func_proto bpf_tcp_sock_proto;
+extern const struct bpf_func_proto bpf_jiffies_proto;
 
 /* Shared helpers among cBPF and eBPF. */
 void bpf_user_rnd_init_once(void);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 602449a56dde..cf864a5f7d61 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2835,6 +2835,16 @@  union bpf_attr {
  *	Return
  *		0 on success, or a negative error in case of failure.
  *
+ * u64 bpf_jiffies(u64 in, u64 flags)
+ *	Description
+ *		jiffies helper.
+ *	Return
+ *		*flags*: 0, return the current jiffies.
+ *			 BPF_F_NS_TO_JIFFIES, convert *in* from ns to jiffies.
+ *			 BPF_F_JIFFIES_TO_NS, convert *in* from jiffies to
+ *			 ns.  If *in* is zero, it returns the current
+ *			 jiffies as ns.
+ *
  */
 #define __BPF_FUNC_MAPPER(FN)		\
 	FN(unspec),			\
@@ -2953,7 +2963,8 @@  union bpf_attr {
 	FN(probe_read_kernel),		\
 	FN(probe_read_user_str),	\
 	FN(probe_read_kernel_str),	\
-	FN(tcp_send_ack),
+	FN(tcp_send_ack),		\
+	FN(jiffies),
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -3032,6 +3043,9 @@  enum bpf_func_id {
 /* BPF_FUNC_sk_storage_get flags */
 #define BPF_SK_STORAGE_GET_F_CREATE	(1ULL << 0)
 
+#define BPF_F_NS_TO_JIFFIES		(1ULL << 0)
+#define BPF_F_JIFFIES_TO_NS		(1ULL << 1)
+
 /* Mode for BPF_FUNC_skb_adjust_room helper. */
 enum bpf_adj_room_mode {
 	BPF_ADJ_ROOM_NET,
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 2ff01a716128..0ffbda9a13e9 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2134,6 +2134,7 @@  const struct bpf_func_proto bpf_map_pop_elem_proto __weak;
 const struct bpf_func_proto bpf_map_peek_elem_proto __weak;
 const struct bpf_func_proto bpf_spin_lock_proto __weak;
 const struct bpf_func_proto bpf_spin_unlock_proto __weak;
+const struct bpf_func_proto bpf_jiffies_proto __weak;
 
 const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
 const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index cada974c9f4e..e87c332d1b61 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -11,6 +11,7 @@ 
 #include <linux/uidgid.h>
 #include <linux/filter.h>
 #include <linux/ctype.h>
+#include <linux/jiffies.h>
 
 #include "../../lib/kstrtox.h"
 
@@ -486,4 +487,28 @@  const struct bpf_func_proto bpf_strtoul_proto = {
 	.arg3_type	= ARG_ANYTHING,
 	.arg4_type	= ARG_PTR_TO_LONG,
 };
+
+BPF_CALL_2(bpf_jiffies, u64, in, u64, flags)
+{
+	if (!flags)
+		return get_jiffies_64();
+
+	if (flags & BPF_F_NS_TO_JIFFIES) {
+		return nsecs_to_jiffies(in);
+	} else if (flags & BPF_F_JIFFIES_TO_NS) {
+		if (!in)
+			in = get_jiffies_64();
+		return jiffies_to_nsecs(in);
+	}
+
+	return 0;
+}
+
+const struct bpf_func_proto bpf_jiffies_proto = {
+	.func		= bpf_jiffies,
+	.gpl_only	= false,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_ANYTHING,
+	.arg2_type	= ARG_ANYTHING,
+};
 #endif
diff --git a/net/core/filter.c b/net/core/filter.c
index fbb3698026bd..355746715901 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6015,6 +6015,8 @@  bpf_base_func_proto(enum bpf_func_id func_id)
 		return &bpf_spin_unlock_proto;
 	case BPF_FUNC_trace_printk:
 		return bpf_get_trace_printk_proto();
+	case BPF_FUNC_jiffies:
+		return &bpf_jiffies_proto;
 	default:
 		return NULL;
 	}