On 03/22/2018 04:41 PM, Alexei Starovoitov wrote:
> On 3/22/18 2:43 AM, Daniel Borkmann wrote:
>> On 03/21/2018 07:54 PM, Alexei Starovoitov wrote:
>> [...]
>>> @@ -546,6 +556,53 @@ extern void ftrace_profile_free_filter(struct 
>>> perf_event *event);
>>>  void perf_trace_buf_update(void *record, u16 type);
>>>  void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp);
>>>
>>> +void bpf_trace_run1(struct bpf_prog *prog, u64 arg1);
>>> +void bpf_trace_run2(struct bpf_prog *prog, u64 arg1, u64 arg2);
>>> +void bpf_trace_run3(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3);
>>> +void bpf_trace_run4(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4);
>>> +void bpf_trace_run5(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5);
>>> +void bpf_trace_run6(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6);
>>> +void bpf_trace_run7(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7);
>>> +void bpf_trace_run8(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +            u64 arg8);
>>> +void bpf_trace_run9(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +            u64 arg8, u64 arg9);
>>> +void bpf_trace_run10(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10);
>>> +void bpf_trace_run11(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11);
>>> +void bpf_trace_run12(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12);
>>> +void bpf_trace_run13(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13);
>>> +void bpf_trace_run14(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13, u64 arg14);
>>> +void bpf_trace_run15(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13, u64 arg14, u64 arg15);
>>> +void bpf_trace_run16(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13, u64 arg14, u64 arg15, u64 arg16);
>>> +void bpf_trace_run17(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13, u64 arg14, u64 arg15, u64 arg16, u64 arg17);
>>>  void perf_trace_run_bpf_submit(void *raw_data, int size, int rctx,
>>>                     struct trace_event_call *call, u64 count,
>>>                     struct pt_regs *regs, struct hlist_head *head,
>> [...]
>>> @@ -896,3 +976,206 @@ int perf_event_query_prog_array(struct perf_event 
>>> *event, void __user *info)
>>>
>>>      return ret;
>>>  }
>>> +
>>> +static __always_inline
>>> +void __bpf_trace_run(struct bpf_prog *prog, u64 *args)
>>> +{
>>> +    rcu_read_lock();
>>> +    preempt_disable();
>>> +    (void) BPF_PROG_RUN(prog, args);
>>> +    preempt_enable();
>>> +    rcu_read_unlock();
>>> +}
>>> +
>>> +#define EVAL1(FN, X) FN(X)
>>> +#define EVAL2(FN, X, Y...) FN(X) EVAL1(FN, Y)
>>> +#define EVAL3(FN, X, Y...) FN(X) EVAL2(FN, Y)
>>> +#define EVAL4(FN, X, Y...) FN(X) EVAL3(FN, Y)
>>> +#define EVAL5(FN, X, Y...) FN(X) EVAL4(FN, Y)
>>> +#define EVAL6(FN, X, Y...) FN(X) EVAL5(FN, Y)
>>> +
>>> +#define COPY(X) args[X - 1] = arg##X;
>>> +
>>> +void bpf_trace_run1(struct bpf_prog *prog, u64 arg1)
>>> +{
>>> +    u64 args[1];
>>> +
>>> +    EVAL1(COPY, 1);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run1);
>>> +void bpf_trace_run2(struct bpf_prog *prog, u64 arg1, u64 arg2)
>>> +{
>>> +    u64 args[2];
>>> +
>>> +    EVAL2(COPY, 1, 2);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run2);
>>> +void bpf_trace_run3(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3)
>>> +{
>>> +    u64 args[3];
>>> +
>>> +    EVAL3(COPY, 1, 2, 3);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run3);
>>> +void bpf_trace_run4(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4)
>>> +{
>>> +    u64 args[4];
>>> +
>>> +    EVAL4(COPY, 1, 2, 3, 4);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run4);
>>> +void bpf_trace_run5(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5)
>>> +{
>>> +    u64 args[5];
>>> +
>>> +    EVAL5(COPY, 1, 2, 3, 4, 5);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run5);
>>> +void bpf_trace_run6(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6)
>>> +{
>>> +    u64 args[6];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run6);
>>> +void bpf_trace_run7(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7)
>>> +{
>>> +    u64 args[7];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL1(COPY, 7);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run7);
>>> +void bpf_trace_run8(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +            u64 arg8)
>>> +{
>>> +    u64 args[8];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL2(COPY, 7, 8);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run8);
>>> +void bpf_trace_run9(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +            u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +            u64 arg8, u64 arg9)
>>> +{
>>> +    u64 args[9];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL3(COPY, 7, 8, 9);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run9);
>>> +void bpf_trace_run10(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10)
>>> +{
>>> +    u64 args[10];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL4(COPY, 7, 8, 9, 10);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run10);
>>> +void bpf_trace_run11(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11)
>>> +{
>>> +    u64 args[11];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL5(COPY, 7, 8, 9, 10, 11);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run11);
>>> +void bpf_trace_run12(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12)
>>> +{
>>> +    u64 args[12];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL6(COPY, 7, 8, 9, 10, 11, 12);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run12);
>>> +void bpf_trace_run17(struct bpf_prog *prog, u64 arg1, u64 arg2,
>>> +             u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7,
>>> +             u64 arg8, u64 arg9, u64 arg10, u64 arg11, u64 arg12,
>>> +             u64 arg13, u64 arg14, u64 arg15, u64 arg16, u64 arg17)
>>> +{
>>> +    u64 args[17];
>>> +
>>> +    EVAL6(COPY, 1, 2, 3, 4, 5, 6);
>>> +    EVAL6(COPY, 7, 8, 9, 10, 11, 12);
>>> +    EVAL5(COPY, 13, 14, 15, 16, 17);
>>> +    __bpf_trace_run(prog, args);
>>> +}
>>> +EXPORT_SYMBOL_GPL(bpf_trace_run17);
>>
>> Would be nice if we could generate all these above via macro, e.g. when we 
>> define
>> a hard upper limit for max number of tracepoint args anyway, so this gets 
>> automatically
>> adjusted as well. Maybe some of the logic from BPF_CALL_*() macros could be 
>> borrowed
>> for this purpose.
> 
> I've thought about it, but couldn't figure out how to do it.
> Suggestions are welcome.
> The preprocessor cannot expand a constant N into N statements.
> There gotta be something like:
> ...
> #define EVAL5(FN, X, Y...) FN(X) EVAL4(FN, Y)
> #define EVAL6(FN, X, Y...) FN(X) EVAL5(FN, Y)
> for whatever maximum we will pick.

Right.

> I picked 6 as a good compromise and used it twice in bpf_trace_run1x()
> Similar thing possible for u64 arg1, u64 arg2, ...
> but it will be harder to read.
> Looking forward what you can come up with.

Just took a quick look, so the below one would work for generating the
signature and function. I did till 9 here:

#define UNPACK(...)                     __VA_ARGS__
#define REPEAT_1(FN, DL, X, ...)        FN(X)
#define REPEAT_2(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_1(FN, DL, 
__VA_ARGS__)
#define REPEAT_3(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_2(FN, DL, 
__VA_ARGS__)
#define REPEAT_4(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_3(FN, DL, 
__VA_ARGS__)
#define REPEAT_5(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_4(FN, DL, 
__VA_ARGS__)
#define REPEAT_6(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_5(FN, DL, 
__VA_ARGS__)
#define REPEAT_7(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_6(FN, DL, 
__VA_ARGS__)
#define REPEAT_8(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_7(FN, DL, 
__VA_ARGS__)
#define REPEAT_9(FN, DL, X, ...)        FN(X) UNPACK DL REPEAT_8(FN, DL, 
__VA_ARGS__)
#define REPEAT(X, FN, DL, ...)          REPEAT_##X(FN, DL, __VA_ARGS__)

#define SARG(X)         u64 arg##X
#define COPY(X)         args[X] = arg##X

#define __DL_COM        (,)
#define __DL_SEM        (;)

#define __SEQ           0, 1, 2, 3, 4, 5, 6, 7, 8, 9

#define BPF_TRACE_DECL_x(x)                                             \
        void bpf_trace_run##x(struct bpf_prog *prog,                    \
                              REPEAT(x, SARG, __DL_COM, __SEQ))
#define BPF_TRACE_DEFN_x(x)                                             \
        void bpf_trace_run##x(struct bpf_prog *prog,                    \
                              REPEAT(x, SARG, __DL_COM, __SEQ))         \
        {                                                               \
                u64 args[x];                                            \
                REPEAT(x, COPY, __DL_SEM, __SEQ);                       \
                __bpf_trace_run(prog, args);                            \
        }                                                               \
        EXPORT_SYMBOL_GPL(bpf_trace_run##x)

So doing a ...

BPF_TRACE_DECL_x(5);
BPF_TRACE_DEFN_x(5);

... will generate in kernel/trace/bpf_trace.i:

void bpf_foo_trace_run5(struct bpf_prog *prog, u64 arg0 , u64 arg1 , u64 arg2 , 
u64 arg3 , u64 arg4);
void bpf_foo_trace_run5(struct bpf_prog *prog, u64 arg0 , u64 arg1 , u64 arg2 , 
u64 arg3 , u64 arg4)
{
        u64 args[5];
        args[0] = arg0 ;
        args[1] = arg1 ;
        args[2] = arg2 ;
        args[3] = arg3 ;
        args[4] = arg4;
        __bpf_trace_run(prog, args);
} [...]

Meaning, the EVALx() macros could be removed from there, too. Potentially, the
REPEAT() macro could sit in its own include/linux/ header for others to reuse
or such.

Cheers,
Daniel

Reply via email to