File: try.h

package info (click to toggle)
mimic 0.7.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,204 kB
  • sloc: ansic: 484,549; sh: 490; makefile: 268
file content (198 lines) | stat: -rw-r--r-- 7,291 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#ifndef MIMIC_COMMON_TRY_H
#define MIMIC_COMMON_TRY_H

#ifdef MIMIC_BPF
#include "bpf/vmlinux.h"

#include <bpf/bpf_helpers.h>
#else
#include <errno.h>
#include <stddef.h>
#include <string.h>  // IWYU pragma: keep
#include "common/log.h"
#endif

#include "common/defs.h"

static __always_inline void* skb_data_end(const struct __sk_buff* ctx) {
  void* data_end;
  asm volatile("%[res] = *(u32 *)(%[base] + %[offset])"
               : [res] "=r"(data_end)
               : [base] "r"(ctx), [offset] "i"(offsetof(struct __sk_buff, data_end)), "m"(*ctx));
  return data_end;
}

static __always_inline void* xdp_data_end(const struct xdp_md* ctx) {
  void* data_end;
  asm volatile("%[res] = *(u32 *)(%[base] + %[offset])"
               : [res] "=r"(data_end)
               : [base] "r"(ctx), [offset] "i"(offsetof(struct xdp_md, data_end)), "m"(*ctx));
  return data_end;
}

#define redecl(_type, _name, _off, _ctx, _ret, _method)                            \
  _name = ({                                                                       \
    _type* _ptr = (void*)(__u64)(_ctx)->data + (_off);                             \
    if (unlikely((__u64)_ptr + sizeof(_type) > (__u64)_method(_ctx))) return _ret; \
    _ptr;                                                                          \
  })
#define redecl_skb(_type, _name, _off, _ctx, _ret) \
  redecl(_type, _name, _off, _ctx, _ret, skb_data_end)
#define redecl_xdp(_type, _name, _off, _ctx, _ret) \
  redecl(_type, _name, _off, _ctx, _ret, xdp_data_end)

#define redecl_ok(type, name, off, skb) redecl_skb(type, name, off, skb, TC_ACT_OK)
#define redecl_shot(type, name, off, skb) redecl_skb(type, name, off, skb, TC_ACT_SHOT)
#define redecl_pass(type, name, off, xdp) redecl_xdp(type, name, off, xdp, XDP_PASS)
#define redecl_drop(type, name, off, xdp) redecl_xdp(type, name, off, xdp, XDP_DROP)

#define decl_skb(type, name, off, ctx, ret) type* redecl_skb(type, name, off, ctx, ret)
#define decl_xdp(type, name, off, ctx, ret) type* redecl_xdp(type, name, off, ctx, ret)
#define decl_ok(type, name, off, skb) decl_skb(type, name, off, skb, TC_ACT_OK)
#define decl_shot(type, name, off, skb) decl_skb(type, name, off, skb, TC_ACT_SHOT)
#define decl_pass(type, name, off, xdp) decl_xdp(type, name, off, xdp, XDP_PASS)
#define decl_drop(type, name, off, xdp) decl_xdp(type, name, off, xdp, XDP_DROP)

#define _get_macro(_0, _1, _2, _3, _4, _5, NAME, ...) NAME

// Returns _ret while printing error.
#define ret(...) \
  _get_macro(_0, ##__VA_ARGS__, _ret_fmt, _ret_fmt, _ret_fmt, _ret_fmt, _ret, )(__VA_ARGS__)
#define _ret(ret) return (ret)
#define _ret_fmt(ret, ...)  \
  ({                        \
    log_error(__VA_ARGS__); \
    return (ret);           \
  })

// Jumps to `cleanup`, returning _ret while printing error.
//
// Requires `cleanup` label, `retcode` to be defined inside function scope, and `retcode` to be
// returned after cleanup.
#define cleanup(...)                                                                    \
  _get_macro(_0, ##__VA_ARGS__, _cleanup_fmt, _cleanup_fmt, _cleanup_fmt, _cleanup_fmt, \
             _cleanup, )(__VA_ARGS__)
#define _cleanup(ret) \
  ({                  \
    retcode = (ret);  \
    goto cleanup;     \
  })
#define _cleanup_fmt(ret, ...) \
  ({                           \
    log_error(__VA_ARGS__);    \
    retcode = (ret);           \
    goto cleanup;              \
  })

#define _get_macro(_0, _1, _2, _3, _4, _5, NAME, ...) NAME

// Tests int return value from a function. Used for functions that returns non-zero error.
#define try(expr, ...)                                \
  ({                                                  \
    long _ret = (expr);                               \
    if (unlikely(_ret < 0)) ret(_ret, ##__VA_ARGS__); \
    _ret;                                             \
  })

// Same as `try` with one arguments, but runs XDP subroutine
#define try_tc(expr)                              \
  ({                                              \
    long _ret = (expr);                           \
    if (unlikely(_ret != TC_ACT_OK)) return _ret; \
    _ret;                                         \
  })

// Same as `try` with one arguments, but runs XDP subroutine
#define try_xdp(expr)                            \
  ({                                             \
    long _ret = (expr);                          \
    if (unlikely(_ret != XDP_PASS)) return _ret; \
    _ret;                                        \
  })

// `try` but `cleanup`.
#define try2(expr, ...)                                   \
  ({                                                      \
    long _ret = (expr);                                   \
    if (unlikely(_ret < 0)) cleanup(_ret, ##__VA_ARGS__); \
    _ret;                                                 \
  })

// `errno` is not available in BPF
#ifndef MIMIC_BPF

// Same as `try`, but returns -errno
#define try_e(expr, ...)          \
  ({                              \
    long _ret = (expr);           \
    if (unlikely(_ret < 0)) {     \
      _ret = -errno;              \
      ret(-errno, ##__VA_ARGS__); \
    }                             \
    _ret;                         \
  })

// `try_e` but `cleanup`.
#define try2_e(expr, ...)           \
  ({                                \
    long _ret = (expr);             \
    if (unlikely(_ret < 0)) {       \
      _ret = -errno;                \
      cleanup(_ret, ##__VA_ARGS__); \
    }                               \
    _ret;                           \
  })

// Similar to `try_e`, but for function that returns a pointer.
#define try_p(expr, ...)        \
  ({                            \
    void* _ptr = (expr);        \
    if (unlikely(!_ptr)) {      \
      long _ret = -errno;       \
      ret(_ret, ##__VA_ARGS__); \
    }                           \
    _ptr;                       \
  })

// Similar to `try2_e`, but for function that returns a pointer.
#define try2_p(expr, ...)           \
  ({                                \
    void* _ptr = (expr);            \
    if (unlikely(!_ptr)) {          \
      long _ret = -errno;           \
      cleanup(_ret, ##__VA_ARGS__); \
    }                               \
    _ptr;                           \
  })

#endif  // MIMIC_BPF

// Tests int return value from a function, but return a different value when failed.
#define try_ret(expr, ret)              \
  ({                                    \
    int _val = (expr);                  \
    if (unlikely(_val < 0)) return ret; \
    _val;                               \
  })

#define try_ok(x) try_ret(x, TC_ACT_OK)
#define try_shot(x) try_ret(x, TC_ACT_SHOT)
#define try_pass(x) try_ret(x, XDP_PASS)
#define try_drop(x) try_ret(x, XDP_DROP)

// Tests pointer return value from a function, but return a different value when failed.
#define try_p_ret(expr, ret)         \
  ({                                 \
    void* _ptr = (expr);             \
    if (unlikely(!_ptr)) return ret; \
    _ptr;                            \
  })

#define try_p_ok(x) try_p_ret(x, TC_ACT_OK)
#define try_p_shot(x) try_p_ret(x, TC_ACT_SHOT)
#define try_p_pass(x) try_p_ret(x, XDP_PASS)
#define try_p_drop(x) try_p_ret(x, XDP_DROP)

#define strret strerror(-_ret)

#endif  // MIMIC_COMMON_TRY_H