[cfe-dev] [llvm-dev] bpf compilation using clang
Sameeh Jubran via cfe-dev
cfe-dev at lists.llvm.org
Tue Sep 25 01:27:22 PDT 2018
On Mon, Sep 24, 2018 at 3:53 PM Tim Northover <t.p.northover at gmail.com> wrote:
>
> On Thu, 13 Sep 2018 at 10:58, Sameeh Jubran via llvm-dev
> <llvm-dev at lists.llvm.org> wrote:
> > I am not sure how to debug this error since the instructions are in
> > binary and the precompiled source code doesn't seem to contain any
> > weird loops or goto instructions...
> >
> > Is there a way to identify which line of source code is causing these errors?
>
> First step would be to look at the assembly and try to work out what
> instructions 363 and 364 are. If you add "-S" to the clang
> command-line it should get you some assembly. With luck the problem
> will be around line "363 + header rubbish" and there will be an
> obvious pair of instructions where the earlier one refers to the
> result of a later one; with even more luck it'll be easy to map those
> instructions back to your source (though it's probably an LLVM bug to
> produce them in the first place).
>
> If you send files reproducing the issue here people will have more
> information to give you advice.
>
> > and then were translated to bpf instructions using the BPFCparser tool
>
> You seem to be the only person on the internet to have mentioned this
> tool. If it's mangling the instruction stream it's also a candidate
> for introducing bugs.
It's a tool that I created for translating object files to
instructions. It already uses the -S flag
I couldn't find any other tool which does this!
* I have reworked he source code a bit since my last email and now the error is:
back-edge from insn 35 to 18
* The compilation command line:
clang -I ~/Builds/bpf_rss/iproute2/include -Wall -Wno-unused-value
-Wno-pointer-sign -Wno-compare-distinct-pointer-types
-Wno-gnu-variable-sized-type-not-at-end -Wno-tautological-compare
-Wno-unknown-warning-option -Wno-address-of-packed-member -target bpf
-O2 -emit-llvm -c upstream/qemu/hw/net/rss_tap_bpf_program.c -o - |
llc -march=bpf -filetype=obj -o tap_bpf_program.o
* Here you can find the source code:
/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
* Copyright 2017 Mellanox Technologies, Ltd
*/
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/in.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_tunnel.h>
#include <linux/filter.h>
#include <linux/bpf.h>
#include "tap_rss.h"
#include "bpf_api.h"
#include "rss_bpf_api.h"
/** Create IPv4 address */
#define IPv4(a, b, c, d) ((__u32)(((a) & 0xff) << 24) | \
(((b) & 0xff) << 16) | \
(((c) & 0xff) << 8) | \
((d) & 0xff))
#define PORT(a, b) ((__u16)(((a) & 0xff) << 8) | \
((b) & 0xff))
/*
* The queue number is offset by a unique QUEUE_OFFSET, to distinguish
* packets that have gone through this rule (skb->cb[1] != 0) from others.
*/
#define PIN_GLOBAL_NS 2
#define KEY_IDX 0
#define BPF_MAP_ID_KEY 1
struct vlan_hdr {
__be16 h_vlan_TCI;
__be16 h_vlan_encapsulated_proto;
};
struct virtio_net_hdr_rss {
__u32 rss_hash_function;
__u32 hash_function_flags;
uint8_t rss_hash_key[40];
__u32 rss_indirection_table_length;
uint8_t rss_indirection_table[128];
};
struct bpf_elf_map __attribute__((section("maps"), used))
map_rss = {
.type = BPF_MAP_TYPE_ARRAY,
.id = BPF_MAP_ID_KEY,
.size_key = sizeof(__u32),
.size_value = sizeof(struct virtio_net_hdr_rss),
.max_elem = 1,
.pinning = PIN_GLOBAL_NS,
};
struct ipv4_l3_l4_tuple {
__u32 src_addr;
__u32 dst_addr;
__u16 dport;
__u16 sport;
} __attribute__((packed));
struct ipv6_l3_l4_tuple {
__u8 src_addr[16];
__u8 dst_addr[16];
__u16 dport;
__u16 sport;
} __attribute__((packed));
static const __u8 def_rss_key[] = {
0xd1, 0x81, 0xc6, 0x2c,
0xf7, 0xf4, 0xdb, 0x5b,
0x19, 0x83, 0xa2, 0xfc,
0x94, 0x3e, 0x1a, 0xdb,
0xd9, 0x38, 0x9e, 0x6b,
0xd1, 0x03, 0x9c, 0x2c,
0xa7, 0x44, 0x99, 0xad,
0x59, 0x3d, 0x56, 0xd9,
0xf3, 0x25, 0x3c, 0x06,
0x2a, 0xdc, 0x1f, 0xfc,
};
static __u32 __attribute__((always_inline))
rte_softrss_be(const __u32 *input_tuple, const uint8_t *rss_key,
__u8 input_len)
{
__u32 i, j, hash = 0;
#pragma unroll
for (j = 0; j < input_len; j++) {
#pragma unroll
for (i = 0; i < 32; i++) {
if (input_tuple[j] & (1 << (31 - i))) {
hash ^= ((const __u32 *)rss_key)[j] << i |
(__u32)((uint64_t)
(((const __u32 *)rss_key)[j + 1])
>> (32 - i));
}
}
}
return hash;
}
static int __attribute__((always_inline))
rss_l3_l4(struct __sk_buff *skb)
{
__u64 proto = load_half(skb, 12);
__u64 nhoff = ETH_HLEN;
__u32 key_idx = 0xdeadbeef;
__u32 hash = 0;
struct virtio_net_hdr_rss * rss_conf;
struct rss_key *rsskey;
int j = 0;
__u8 *key = 0;
__u32 len = 0;
__u32 queue = 0;
__u32 q = 0;
rss_conf = (struct virtio_net_hdr_rss *)
map_lookup_elem(&map_rss, &key_idx);
if (!rss_conf) {
printt("hash(): rss key is not configured\n");
return -2;
}
key = (__u8 *)rss_conf->rss_hash_key;
if (proto == ETH_P_8021AD) {
proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
h_vlan_encapsulated_proto));
nhoff += sizeof(struct vlan_hdr);
}
if (proto == ETH_P_8021Q) {
proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
h_vlan_encapsulated_proto));
nhoff += sizeof(struct vlan_hdr);
}
if (likely(proto == ETH_P_IP)) {
struct ipv4_l3_l4_tuple v4_tuple = {
.src_addr = IPv4(load_byte(skb, nhoff +
offsetof(struct iphdr, saddr)),
load_byte(skb, nhoff +
offsetof(struct iphdr, saddr) + 1),
load_byte(skb, nhoff +
offsetof(struct iphdr, saddr) + 2),
load_byte(skb, nhoff +
offsetof(struct iphdr, saddr) + 3)),
.dst_addr = IPv4(load_byte(skb, nhoff +
offsetof(struct iphdr, daddr)),
load_byte(skb, nhoff +
offsetof(struct iphdr, daddr) + 1),
load_byte(skb, nhoff +
offsetof(struct iphdr, daddr) + 2),
load_byte(skb, nhoff +
offsetof(struct iphdr, daddr) + 3)),
.sport = PORT(load_byte(skb, nhoff +
sizeof(struct iphdr)),
load_byte(skb, nhoff +
sizeof(struct iphdr) + 1)),
.dport = PORT(load_byte(skb, nhoff +
sizeof(struct iphdr) + 2),
load_byte(skb, nhoff +
sizeof(struct iphdr) + 3))
};
__u8 input_len = sizeof(v4_tuple) / sizeof(__u32);
if (rss_conf->hash_function_flags & (1 << HASH_FIELD_IPV4_L3))
input_len--;
hash = rte_softrss_be((__u32 *)&v4_tuple, key, 3);
} else if (proto == htons(ETH_P_IPV6)) {
struct ipv6_l3_l4_tuple v6_tuple;
for (j = 0; j < 4; j++)
*((uint32_t *)&v6_tuple.src_addr + j) =
load_word(skb, nhoff + offsetof(struct
ipv6hdr, saddr) + j);
for (j = 0; j < 4; j++)
*((uint32_t *)&v6_tuple.dst_addr + j) =
load_word(skb, nhoff + offsetof(struct
ipv6hdr, daddr) + j);
v6_tuple.sport = PORT(load_byte(skb, nhoff +
sizeof(struct ipv6hdr)),
load_byte(skb, nhoff +
sizeof(struct ipv6hdr) + 1));
v6_tuple.dport = PORT(load_byte(skb, nhoff +
sizeof(struct ipv6hdr) + 2),
load_byte(skb, nhoff +
sizeof(struct ipv6hdr) + 3));
__u8 input_len = sizeof(v6_tuple) / sizeof(__u32);
if (rss_conf->hash_function_flags & (1 << HASH_FIELD_IPV6_L3))
input_len--;
hash = rte_softrss_be((__u32 *)&v6_tuple, key, 9);
} else {
return -1;
}
queue = rsskey->queues[(hash % rsskey->nb_queues) &
(TAP_MAX_QUEUES - 1)];
printt("queue: 0x%x hash: 0x%x\n" ,queue, hash);
return queue;
}
#define RSS(L) \
__section(#L) int \
L ## _hash(struct __sk_buff *skb) \
{ \
return rss_ ## L (skb); \
}
RSS(l3_l4)
BPF_LICENSE("Dual BSD/GPL");
_____________________________________________________________________________________
The first few instructions translated using the -S:
Disassembly of section l3_l4:
l3_l4_hash:
0: bf 16 00 00 00 00 00 00 r6 = r1
1: 28 00 00 00 0c 00 00 00 r0 = *(u16 *)skb[0xc]
2: bf 08 00 00 00 00 00 00 r8 = r0
3: 18 01 00 00 ef be ad de 00 00 00 00 00 00 00 00
r1 = 0xdeadbeef ll
5: 63 1a f8 ff 00 00 00 00 *(u32 *)(r10 - 0x8) = r1
6: bf a2 00 00 00 00 00 00 r2 = r10
7: 07 02 00 00 f8 ff ff ff r2 += -0x8
8: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
r1 = 0x0 ll
10: 85 00 00 00 01 00 00 00 call 0x1
11: 18 07 00 00 ff ff ff ff 00 00 00 00 00 00 00 00
r7 = 0xffffffff ll
13: 15 00 b0 05 00 00 00 00 if r0 == 0x0 goto
+0x5b0 <LBB0_149>
14: 7b 0a c0 ff 00 00 00 00 *(u64 *)(r10 - 0x40) = r0
15: b7 01 00 00 00 00 00 00 r1 = 0x0
16: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 0x4) = r1
17: b7 09 00 00 28 00 00 00 r9 = 0x28
LBB0_2:
18: bf a2 00 00 00 00 00 00 r2 = r10
19: 07 02 00 00 fc ff ff ff r2 += -0x4
20: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00
r1 = 0x0 ll
22: 85 00 00 00 01 00 00 00 call 0x1
23: b7 01 00 00 30 00 00 00 r1 = 0x30
24: 15 00 01 00 00 00 00 00 if r0 == 0x0 goto +0x1 <LBB0_4>
25: 71 01 00 00 00 00 00 00 r1 = *(u8 *)(r0 + 0x0)
LBB0_4:
26: 61 a2 fc ff 00 00 00 00 r2 = *(u32 *)(r10 - 0x4)
27: bf a3 00 00 00 00 00 00 r3 = r10
28: 07 03 00 00 d0 ff ff ff r3 += -0x30
29: 0f 23 00 00 00 00 00 00 r3 += r2
30: 73 13 00 00 00 00 00 00 *(u8 *)(r3 + 0x0) = r1
31: 07 02 00 00 01 00 00 00 r2 += 0x1
32: 63 2a fc ff 00 00 00 00 *(u32 *)(r10 - 0x4) = r2
33: 67 02 00 00 20 00 00 00 r2 <<= 0x20
34: 77 02 00 00 20 00 00 00 r2 >>= 0x20
35: 2d 29 ee ff 00 00 00 00 if r9 > r2 goto -0x12 <LBB0_2>
36: b7 09 00 00 0e 00 00 00 r9 = 0xe
37: 55 08 03 00 a8 88 00 00 if r8 != 0x88a8 goto
+0x3 <LBB0_7>
38: b7 09 00 00 12 00 00 00 r9 = 0x12
_______________________________________________________________________________
>
> Cheers.
>
> Tim.
--
Respectfully,
Sameeh Jubran
Linkedin
Software Engineer @ Daynix.
More information about the cfe-dev
mailing list