1 // SPDX-License-Identifier: GPL-2.0 2 #include <test_progs.h> 3 4 #define CHECK_FLOW_KEYS(desc, got, expected) \ 5 CHECK_ATTR(memcmp(&got, &expected, sizeof(got)) != 0, \ 6 desc, \ 7 "nhoff=%u/%u " \ 8 "thoff=%u/%u " \ 9 "addr_proto=0x%x/0x%x " \ 10 "is_frag=%u/%u " \ 11 "is_first_frag=%u/%u " \ 12 "is_encap=%u/%u " \ 13 "ip_proto=0x%x/0x%x " \ 14 "n_proto=0x%x/0x%x " \ 15 "sport=%u/%u " \ 16 "dport=%u/%u\n", \ 17 got.nhoff, expected.nhoff, \ 18 got.thoff, expected.thoff, \ 19 got.addr_proto, expected.addr_proto, \ 20 got.is_frag, expected.is_frag, \ 21 got.is_first_frag, expected.is_first_frag, \ 22 got.is_encap, expected.is_encap, \ 23 got.ip_proto, expected.ip_proto, \ 24 got.n_proto, expected.n_proto, \ 25 got.sport, expected.sport, \ 26 got.dport, expected.dport) 27 28 struct ipv4_pkt { 29 struct ethhdr eth; 30 struct iphdr iph; 31 struct tcphdr tcp; 32 } __packed; 33 34 struct svlan_ipv4_pkt { 35 struct ethhdr eth; 36 __u16 vlan_tci; 37 __u16 vlan_proto; 38 struct iphdr iph; 39 struct tcphdr tcp; 40 } __packed; 41 42 struct ipv6_pkt { 43 struct ethhdr eth; 44 struct ipv6hdr iph; 45 struct tcphdr tcp; 46 } __packed; 47 48 struct dvlan_ipv6_pkt { 49 struct ethhdr eth; 50 __u16 vlan_tci; 51 __u16 vlan_proto; 52 __u16 vlan_tci2; 53 __u16 vlan_proto2; 54 struct ipv6hdr iph; 55 struct tcphdr tcp; 56 } __packed; 57 58 struct test { 59 const char *name; 60 union { 61 struct ipv4_pkt ipv4; 62 struct svlan_ipv4_pkt svlan_ipv4; 63 struct ipv6_pkt ipv6; 64 struct dvlan_ipv6_pkt dvlan_ipv6; 65 } pkt; 66 struct bpf_flow_keys keys; 67 }; 68 69 #define VLAN_HLEN 4 70 71 struct test tests[] = { 72 { 73 .name = "ipv4", 74 .pkt.ipv4 = { 75 .eth.h_proto = __bpf_constant_htons(ETH_P_IP), 76 .iph.ihl = 5, 77 .iph.protocol = IPPROTO_TCP, 78 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 79 .tcp.doff = 5, 80 }, 81 .keys = { 82 .nhoff = 0, 83 .thoff = sizeof(struct iphdr), 84 .addr_proto = ETH_P_IP, 85 .ip_proto = IPPROTO_TCP, 86 .n_proto = __bpf_constant_htons(ETH_P_IP), 87 }, 88 }, 89 { 90 .name = "ipv6", 91 .pkt.ipv6 = { 92 .eth.h_proto = __bpf_constant_htons(ETH_P_IPV6), 93 .iph.nexthdr = IPPROTO_TCP, 94 .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), 95 .tcp.doff = 5, 96 }, 97 .keys = { 98 .nhoff = 0, 99 .thoff = sizeof(struct ipv6hdr), 100 .addr_proto = ETH_P_IPV6, 101 .ip_proto = IPPROTO_TCP, 102 .n_proto = __bpf_constant_htons(ETH_P_IPV6), 103 }, 104 }, 105 { 106 .name = "802.1q-ipv4", 107 .pkt.svlan_ipv4 = { 108 .eth.h_proto = __bpf_constant_htons(ETH_P_8021Q), 109 .vlan_proto = __bpf_constant_htons(ETH_P_IP), 110 .iph.ihl = 5, 111 .iph.protocol = IPPROTO_TCP, 112 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES), 113 .tcp.doff = 5, 114 }, 115 .keys = { 116 .nhoff = VLAN_HLEN, 117 .thoff = VLAN_HLEN + sizeof(struct iphdr), 118 .addr_proto = ETH_P_IP, 119 .ip_proto = IPPROTO_TCP, 120 .n_proto = __bpf_constant_htons(ETH_P_IP), 121 }, 122 }, 123 { 124 .name = "802.1ad-ipv6", 125 .pkt.dvlan_ipv6 = { 126 .eth.h_proto = __bpf_constant_htons(ETH_P_8021AD), 127 .vlan_proto = __bpf_constant_htons(ETH_P_8021Q), 128 .vlan_proto2 = __bpf_constant_htons(ETH_P_IPV6), 129 .iph.nexthdr = IPPROTO_TCP, 130 .iph.payload_len = __bpf_constant_htons(MAGIC_BYTES), 131 .tcp.doff = 5, 132 }, 133 .keys = { 134 .nhoff = VLAN_HLEN * 2, 135 .thoff = VLAN_HLEN * 2 + sizeof(struct ipv6hdr), 136 .addr_proto = ETH_P_IPV6, 137 .ip_proto = IPPROTO_TCP, 138 .n_proto = __bpf_constant_htons(ETH_P_IPV6), 139 }, 140 }, 141 }; 142 143 void test_flow_dissector(void) 144 { 145 struct bpf_object *obj; 146 int i, err, prog_fd; 147 148 err = bpf_flow_load(&obj, "./bpf_flow.o", "flow_dissector", 149 "jmp_table", &prog_fd); 150 if (err) { 151 error_cnt++; 152 return; 153 } 154 155 for (i = 0; i < ARRAY_SIZE(tests); i++) { 156 struct bpf_flow_keys flow_keys; 157 struct bpf_prog_test_run_attr tattr = { 158 .prog_fd = prog_fd, 159 .data_in = &tests[i].pkt, 160 .data_size_in = sizeof(tests[i].pkt), 161 .data_out = &flow_keys, 162 }; 163 164 err = bpf_prog_test_run_xattr(&tattr); 165 CHECK_ATTR(tattr.data_size_out != sizeof(flow_keys) || 166 err || tattr.retval != 1, 167 tests[i].name, 168 "err %d errno %d retval %d duration %d size %u/%lu\n", 169 err, errno, tattr.retval, tattr.duration, 170 tattr.data_size_out, sizeof(flow_keys)); 171 CHECK_FLOW_KEYS(tests[i].name, flow_keys, tests[i].keys); 172 } 173 174 bpf_object__close(obj); 175 } 176