|
117 | 117 |
|
118 | 118 | // check this is TCP |
119 | 119 | u16 protocol = 0; |
120 | | - // workaround for reading the sk_protocol bitfield: |
121 | | -
|
122 | | - // Following comments add by Joe Yin: |
123 | | - // Unfortunately,it can not work since Linux 4.10, |
124 | | - // because the sk_wmem_queued is not following the bitfield of sk_protocol. |
125 | | - // And the following member is sk_gso_max_segs. |
126 | | - // So, we can use this: |
127 | | - // bpf_probe_read_kernel(&protocol, 1, (void *)((u64)&newsk->sk_gso_max_segs) - 3); |
128 | | - // In order to diff the pre-4.10 and 4.10+ ,introduce the variables gso_max_segs_offset,sk_lingertime, |
129 | | - // sk_lingertime is closed to the gso_max_segs_offset,and |
130 | | - // the offset between the two members is 4 |
131 | 120 |
|
132 | | - int gso_max_segs_offset = offsetof(struct sock, sk_gso_max_segs); |
133 | | - int sk_lingertime_offset = offsetof(struct sock, sk_lingertime); |
134 | | -
|
135 | | -
|
136 | | - // Since kernel v5.6 sk_protocol is its own u16 field and gso_max_segs |
137 | | - // precedes sk_lingertime. |
138 | | - if (sk_lingertime_offset - gso_max_segs_offset == 2) |
139 | | - protocol = newsk->sk_protocol; |
140 | | - else if (sk_lingertime_offset - gso_max_segs_offset == 4) |
141 | | - // 4.10+ with little endian |
142 | | -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
143 | | - protocol = *(u8 *)((u64)&newsk->sk_gso_max_segs - 3); |
144 | | - else |
145 | | - // pre-4.10 with little endian |
146 | | - protocol = *(u8 *)((u64)&newsk->sk_wmem_queued - 3); |
147 | | -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
148 | | - // 4.10+ with big endian |
149 | | - protocol = *(u8 *)((u64)&newsk->sk_gso_max_segs - 1); |
150 | | - else |
151 | | - // pre-4.10 with big endian |
152 | | - protocol = *(u8 *)((u64)&newsk->sk_wmem_queued - 1); |
153 | | -#else |
154 | | -# error "Fix your compiler's __BYTE_ORDER__?!" |
155 | | -#endif |
| 121 | + ##GET_SK_PROTOCOL## |
156 | 122 |
|
157 | 123 | if (protocol != IPPROTO_TCP) |
158 | 124 | return 0; |
|
196 | 162 | } |
197 | 163 | """ |
198 | 164 |
|
| 165 | +get_sk_protocol_field = """ |
| 166 | + protocol = newsk->sk_protocol; |
| 167 | +""" |
| 168 | + |
| 169 | +get_sk_protocol_bitfield = """ |
| 170 | + // workaround for reading the sk_protocol bitfield: |
| 171 | +
|
| 172 | + // Following comments add by Joe Yin: |
| 173 | + // Unfortunately,it can not work since Linux 4.10, |
| 174 | + // because the sk_wmem_queued is not following the bitfield of sk_protocol. |
| 175 | + // And the following member is sk_gso_max_segs. |
| 176 | + // So, we can use this: |
| 177 | + // bpf_probe_read_kernel(&protocol, 1, (void *)((u64)&newsk->sk_gso_max_segs) - 3); |
| 178 | + // In order to diff the pre-4.10 and 4.10+ ,introduce the variables gso_max_segs_offset,sk_lingertime, |
| 179 | + // sk_lingertime is closed to the gso_max_segs_offset,and |
| 180 | + // the offset between the two members is 4 |
| 181 | +
|
| 182 | + int gso_max_segs_offset = offsetof(struct sock, sk_gso_max_segs); |
| 183 | + int sk_lingertime_offset = offsetof(struct sock, sk_lingertime); |
| 184 | +
|
| 185 | +
|
| 186 | + // Since kernel v5.6 sk_protocol is its own u16 field and gso_max_segs |
| 187 | + // precedes sk_lingertime. |
| 188 | + // We keep this workaround in case BTF is unavailable |
| 189 | + if (sk_lingertime_offset - gso_max_segs_offset == 2) |
| 190 | + protocol = newsk->sk_protocol; |
| 191 | + else if (sk_lingertime_offset - gso_max_segs_offset == 4) |
| 192 | + // 4.10+ with little endian |
| 193 | +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| 194 | + protocol = *(u8 *)((u64)&newsk->sk_gso_max_segs - 3); |
| 195 | + else |
| 196 | + // pre-4.10 with little endian |
| 197 | + protocol = *(u8 *)((u64)&newsk->sk_wmem_queued - 3); |
| 198 | +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
| 199 | + // 4.10+ with big endian |
| 200 | + protocol = *(u8 *)((u64)&newsk->sk_gso_max_segs - 1); |
| 201 | + else |
| 202 | + // pre-4.10 with big endian |
| 203 | + protocol = *(u8 *)((u64)&newsk->sk_wmem_queued - 1); |
| 204 | +#else |
| 205 | +# error "Fix your compiler's __BYTE_ORDER__?!" |
| 206 | +#endif |
| 207 | +""" |
| 208 | + |
| 209 | + |
199 | 210 | bpf_text += bpf_text_kprobe |
200 | 211 |
|
201 | 212 | # code substitutions |
|
216 | 227 | bpf_text = bpf_text.replace('##FILTER_FAMILY##', |
217 | 228 | 'if (family != AF_INET6) { return 0; }') |
218 | 229 |
|
| 230 | +if BPF.kernel_struct_has_field("sock", "sk_protocol") == 1: |
| 231 | + bpf_text = bpf_text.replace('##GET_SK_PROTOCOL##', get_sk_protocol_field) |
| 232 | +else: |
| 233 | + bpf_text = bpf_text.replace('##GET_SK_PROTOCOL##', get_sk_protocol_bitfield) |
| 234 | + |
219 | 235 | bpf_text = filter_by_containers(args) + bpf_text |
220 | 236 | if debug or args.ebpf: |
221 | 237 | print(bpf_text) |
|
0 commit comments