1c803475fSMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
2c803475fSMartin KaFai Lau // Copyright (c) 2022 Meta
3c803475fSMartin KaFai Lau
4c803475fSMartin KaFai Lau #include <stddef.h>
5c803475fSMartin KaFai Lau #include <stdint.h>
6c803475fSMartin KaFai Lau #include <stdbool.h>
7c803475fSMartin KaFai Lau #include <linux/bpf.h>
8c803475fSMartin KaFai Lau #include <linux/stddef.h>
9c803475fSMartin KaFai Lau #include <linux/pkt_cls.h>
10c803475fSMartin KaFai Lau #include <linux/if_ether.h>
11c803475fSMartin KaFai Lau #include <linux/in.h>
12c803475fSMartin KaFai Lau #include <linux/ip.h>
13c803475fSMartin KaFai Lau #include <linux/ipv6.h>
14e6ff92f4SMartin KaFai Lau #include <linux/tcp.h>
15e6ff92f4SMartin KaFai Lau #include <linux/udp.h>
16c803475fSMartin KaFai Lau #include <bpf/bpf_helpers.h>
17c803475fSMartin KaFai Lau #include <bpf/bpf_endian.h>
18c803475fSMartin KaFai Lau
19c803475fSMartin KaFai Lau /* veth_src --- veth_src_fwd --- veth_det_fwd --- veth_dst
20c803475fSMartin KaFai Lau * | |
21c803475fSMartin KaFai Lau * ns_src | ns_fwd | ns_dst
22c803475fSMartin KaFai Lau *
23c803475fSMartin KaFai Lau * ns_src and ns_dst: ENDHOST namespace
24c803475fSMartin KaFai Lau * ns_fwd: Fowarding namespace
25c803475fSMartin KaFai Lau */
26c803475fSMartin KaFai Lau
27c803475fSMartin KaFai Lau #define ctx_ptr(field) (void *)(long)(field)
28c803475fSMartin KaFai Lau
29c803475fSMartin KaFai Lau #define ip4_src __bpf_htonl(0xac100164) /* 172.16.1.100 */
30c803475fSMartin KaFai Lau #define ip4_dst __bpf_htonl(0xac100264) /* 172.16.2.100 */
31c803475fSMartin KaFai Lau
32c803475fSMartin KaFai Lau #define ip6_src { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
33c803475fSMartin KaFai Lau 0x00, 0x01, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
34c803475fSMartin KaFai Lau #define ip6_dst { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
35c803475fSMartin KaFai Lau 0x00, 0x02, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
36c803475fSMartin KaFai Lau
37c803475fSMartin KaFai Lau #define v6_equal(a, b) (a.s6_addr32[0] == b.s6_addr32[0] && \
38c803475fSMartin KaFai Lau a.s6_addr32[1] == b.s6_addr32[1] && \
39c803475fSMartin KaFai Lau a.s6_addr32[2] == b.s6_addr32[2] && \
40c803475fSMartin KaFai Lau a.s6_addr32[3] == b.s6_addr32[3])
41c803475fSMartin KaFai Lau
42c803475fSMartin KaFai Lau volatile const __u32 IFINDEX_SRC;
43c803475fSMartin KaFai Lau volatile const __u32 IFINDEX_DST;
44c803475fSMartin KaFai Lau
45c803475fSMartin KaFai Lau #define EGRESS_ENDHOST_MAGIC 0x0b9fbeef
46c803475fSMartin KaFai Lau #define INGRESS_FWDNS_MAGIC 0x1b9fbeef
47c803475fSMartin KaFai Lau #define EGRESS_FWDNS_MAGIC 0x2b9fbeef
48c803475fSMartin KaFai Lau
49c803475fSMartin KaFai Lau enum {
50c803475fSMartin KaFai Lau INGRESS_FWDNS_P100,
51c803475fSMartin KaFai Lau INGRESS_FWDNS_P101,
52c803475fSMartin KaFai Lau EGRESS_FWDNS_P100,
53c803475fSMartin KaFai Lau EGRESS_FWDNS_P101,
54c803475fSMartin KaFai Lau INGRESS_ENDHOST,
55c803475fSMartin KaFai Lau EGRESS_ENDHOST,
56c803475fSMartin KaFai Lau SET_DTIME,
57c803475fSMartin KaFai Lau __MAX_CNT,
58c803475fSMartin KaFai Lau };
59c803475fSMartin KaFai Lau
60c803475fSMartin KaFai Lau enum {
61c803475fSMartin KaFai Lau TCP_IP6_CLEAR_DTIME,
62c803475fSMartin KaFai Lau TCP_IP4,
63c803475fSMartin KaFai Lau TCP_IP6,
64c803475fSMartin KaFai Lau UDP_IP4,
65c803475fSMartin KaFai Lau UDP_IP6,
66c803475fSMartin KaFai Lau TCP_IP4_RT_FWD,
67c803475fSMartin KaFai Lau TCP_IP6_RT_FWD,
68c803475fSMartin KaFai Lau UDP_IP4_RT_FWD,
69c803475fSMartin KaFai Lau UDP_IP6_RT_FWD,
70c803475fSMartin KaFai Lau UKN_TEST,
71c803475fSMartin KaFai Lau __NR_TESTS,
72c803475fSMartin KaFai Lau };
73c803475fSMartin KaFai Lau
74c803475fSMartin KaFai Lau enum {
75c803475fSMartin KaFai Lau SRC_NS = 1,
76c803475fSMartin KaFai Lau DST_NS,
77c803475fSMartin KaFai Lau };
78c803475fSMartin KaFai Lau
79c803475fSMartin KaFai Lau __u32 dtimes[__NR_TESTS][__MAX_CNT] = {};
80c803475fSMartin KaFai Lau __u32 errs[__NR_TESTS][__MAX_CNT] = {};
81c803475fSMartin KaFai Lau __u32 test = 0;
82c803475fSMartin KaFai Lau
inc_dtimes(__u32 idx)83c803475fSMartin KaFai Lau static void inc_dtimes(__u32 idx)
84c803475fSMartin KaFai Lau {
85c803475fSMartin KaFai Lau if (test < __NR_TESTS)
86c803475fSMartin KaFai Lau dtimes[test][idx]++;
87c803475fSMartin KaFai Lau else
88c803475fSMartin KaFai Lau dtimes[UKN_TEST][idx]++;
89c803475fSMartin KaFai Lau }
90c803475fSMartin KaFai Lau
inc_errs(__u32 idx)91c803475fSMartin KaFai Lau static void inc_errs(__u32 idx)
92c803475fSMartin KaFai Lau {
93c803475fSMartin KaFai Lau if (test < __NR_TESTS)
94c803475fSMartin KaFai Lau errs[test][idx]++;
95c803475fSMartin KaFai Lau else
96c803475fSMartin KaFai Lau errs[UKN_TEST][idx]++;
97c803475fSMartin KaFai Lau }
98c803475fSMartin KaFai Lau
skb_proto(int type)99c803475fSMartin KaFai Lau static int skb_proto(int type)
100c803475fSMartin KaFai Lau {
101c803475fSMartin KaFai Lau return type & 0xff;
102c803475fSMartin KaFai Lau }
103c803475fSMartin KaFai Lau
skb_ns(int type)104c803475fSMartin KaFai Lau static int skb_ns(int type)
105c803475fSMartin KaFai Lau {
106c803475fSMartin KaFai Lau return (type >> 8) & 0xff;
107c803475fSMartin KaFai Lau }
108c803475fSMartin KaFai Lau
fwdns_clear_dtime(void)109c803475fSMartin KaFai Lau static bool fwdns_clear_dtime(void)
110c803475fSMartin KaFai Lau {
111c803475fSMartin KaFai Lau return test == TCP_IP6_CLEAR_DTIME;
112c803475fSMartin KaFai Lau }
113c803475fSMartin KaFai Lau
bpf_fwd(void)114c803475fSMartin KaFai Lau static bool bpf_fwd(void)
115c803475fSMartin KaFai Lau {
116c803475fSMartin KaFai Lau return test < TCP_IP4_RT_FWD;
117c803475fSMartin KaFai Lau }
118c803475fSMartin KaFai Lau
get_proto(void)119e6ff92f4SMartin KaFai Lau static __u8 get_proto(void)
120e6ff92f4SMartin KaFai Lau {
121e6ff92f4SMartin KaFai Lau switch (test) {
122e6ff92f4SMartin KaFai Lau case UDP_IP4:
123e6ff92f4SMartin KaFai Lau case UDP_IP6:
124e6ff92f4SMartin KaFai Lau case UDP_IP4_RT_FWD:
125e6ff92f4SMartin KaFai Lau case UDP_IP6_RT_FWD:
126e6ff92f4SMartin KaFai Lau return IPPROTO_UDP;
127e6ff92f4SMartin KaFai Lau default:
128e6ff92f4SMartin KaFai Lau return IPPROTO_TCP;
129e6ff92f4SMartin KaFai Lau }
130e6ff92f4SMartin KaFai Lau }
131e6ff92f4SMartin KaFai Lau
132c803475fSMartin KaFai Lau /* -1: parse error: TC_ACT_SHOT
133c803475fSMartin KaFai Lau * 0: not testing traffic: TC_ACT_OK
134c803475fSMartin KaFai Lau * >0: first byte is the inet_proto, second byte has the netns
135c803475fSMartin KaFai Lau * of the sender
136c803475fSMartin KaFai Lau */
skb_get_type(struct __sk_buff * skb)137c803475fSMartin KaFai Lau static int skb_get_type(struct __sk_buff *skb)
138c803475fSMartin KaFai Lau {
139e6ff92f4SMartin KaFai Lau __u16 dst_ns_port = __bpf_htons(50000 + test);
140c803475fSMartin KaFai Lau void *data_end = ctx_ptr(skb->data_end);
141c803475fSMartin KaFai Lau void *data = ctx_ptr(skb->data);
142c803475fSMartin KaFai Lau __u8 inet_proto = 0, ns = 0;
143c803475fSMartin KaFai Lau struct ipv6hdr *ip6h;
144e6ff92f4SMartin KaFai Lau __u16 sport, dport;
145c803475fSMartin KaFai Lau struct iphdr *iph;
146e6ff92f4SMartin KaFai Lau struct tcphdr *th;
147e6ff92f4SMartin KaFai Lau struct udphdr *uh;
148e6ff92f4SMartin KaFai Lau void *trans;
149c803475fSMartin KaFai Lau
150c803475fSMartin KaFai Lau switch (skb->protocol) {
151c803475fSMartin KaFai Lau case __bpf_htons(ETH_P_IP):
152c803475fSMartin KaFai Lau iph = data + sizeof(struct ethhdr);
153c803475fSMartin KaFai Lau if (iph + 1 > data_end)
154c803475fSMartin KaFai Lau return -1;
155c803475fSMartin KaFai Lau if (iph->saddr == ip4_src)
156c803475fSMartin KaFai Lau ns = SRC_NS;
157c803475fSMartin KaFai Lau else if (iph->saddr == ip4_dst)
158c803475fSMartin KaFai Lau ns = DST_NS;
159c803475fSMartin KaFai Lau inet_proto = iph->protocol;
160e6ff92f4SMartin KaFai Lau trans = iph + 1;
161c803475fSMartin KaFai Lau break;
162c803475fSMartin KaFai Lau case __bpf_htons(ETH_P_IPV6):
163c803475fSMartin KaFai Lau ip6h = data + sizeof(struct ethhdr);
164c803475fSMartin KaFai Lau if (ip6h + 1 > data_end)
165c803475fSMartin KaFai Lau return -1;
166*c8ed6685SAndrii Nakryiko if (v6_equal(ip6h->saddr, (struct in6_addr){{ip6_src}}))
167c803475fSMartin KaFai Lau ns = SRC_NS;
168*c8ed6685SAndrii Nakryiko else if (v6_equal(ip6h->saddr, (struct in6_addr){{ip6_dst}}))
169c803475fSMartin KaFai Lau ns = DST_NS;
170c803475fSMartin KaFai Lau inet_proto = ip6h->nexthdr;
171e6ff92f4SMartin KaFai Lau trans = ip6h + 1;
172c803475fSMartin KaFai Lau break;
173c803475fSMartin KaFai Lau default:
174c803475fSMartin KaFai Lau return 0;
175c803475fSMartin KaFai Lau }
176c803475fSMartin KaFai Lau
177e6ff92f4SMartin KaFai Lau /* skb is not from src_ns or dst_ns.
178e6ff92f4SMartin KaFai Lau * skb is not the testing IPPROTO.
179e6ff92f4SMartin KaFai Lau */
180e6ff92f4SMartin KaFai Lau if (!ns || inet_proto != get_proto())
181c803475fSMartin KaFai Lau return 0;
182c803475fSMartin KaFai Lau
183e6ff92f4SMartin KaFai Lau switch (inet_proto) {
184e6ff92f4SMartin KaFai Lau case IPPROTO_TCP:
185e6ff92f4SMartin KaFai Lau th = trans;
186e6ff92f4SMartin KaFai Lau if (th + 1 > data_end)
187e6ff92f4SMartin KaFai Lau return -1;
188e6ff92f4SMartin KaFai Lau sport = th->source;
189e6ff92f4SMartin KaFai Lau dport = th->dest;
190e6ff92f4SMartin KaFai Lau break;
191e6ff92f4SMartin KaFai Lau case IPPROTO_UDP:
192e6ff92f4SMartin KaFai Lau uh = trans;
193e6ff92f4SMartin KaFai Lau if (uh + 1 > data_end)
194e6ff92f4SMartin KaFai Lau return -1;
195e6ff92f4SMartin KaFai Lau sport = uh->source;
196e6ff92f4SMartin KaFai Lau dport = uh->dest;
197e6ff92f4SMartin KaFai Lau break;
198e6ff92f4SMartin KaFai Lau default:
199e6ff92f4SMartin KaFai Lau return 0;
200e6ff92f4SMartin KaFai Lau }
201e6ff92f4SMartin KaFai Lau
202e6ff92f4SMartin KaFai Lau /* The skb is the testing traffic */
203e6ff92f4SMartin KaFai Lau if ((ns == SRC_NS && dport == dst_ns_port) ||
204e6ff92f4SMartin KaFai Lau (ns == DST_NS && sport == dst_ns_port))
205c803475fSMartin KaFai Lau return (ns << 8 | inet_proto);
206e6ff92f4SMartin KaFai Lau
207e6ff92f4SMartin KaFai Lau return 0;
208c803475fSMartin KaFai Lau }
209c803475fSMartin KaFai Lau
210c803475fSMartin KaFai Lau /* format: direction@iface@netns
211c803475fSMartin KaFai Lau * egress@veth_(src|dst)@ns_(src|dst)
212c803475fSMartin KaFai Lau */
213c803475fSMartin KaFai Lau SEC("tc")
egress_host(struct __sk_buff * skb)214c803475fSMartin KaFai Lau int egress_host(struct __sk_buff *skb)
215c803475fSMartin KaFai Lau {
216c803475fSMartin KaFai Lau int skb_type;
217c803475fSMartin KaFai Lau
218c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
219c803475fSMartin KaFai Lau if (skb_type == -1)
220c803475fSMartin KaFai Lau return TC_ACT_SHOT;
221c803475fSMartin KaFai Lau if (!skb_type)
222c803475fSMartin KaFai Lau return TC_ACT_OK;
223c803475fSMartin KaFai Lau
224c803475fSMartin KaFai Lau if (skb_proto(skb_type) == IPPROTO_TCP) {
2253daf0896SMartin KaFai Lau if (skb->tstamp_type == BPF_SKB_TSTAMP_DELIVERY_MONO &&
226c803475fSMartin KaFai Lau skb->tstamp)
227c803475fSMartin KaFai Lau inc_dtimes(EGRESS_ENDHOST);
228c803475fSMartin KaFai Lau else
229c803475fSMartin KaFai Lau inc_errs(EGRESS_ENDHOST);
230c803475fSMartin KaFai Lau } else {
2313daf0896SMartin KaFai Lau if (skb->tstamp_type == BPF_SKB_TSTAMP_UNSPEC &&
232c803475fSMartin KaFai Lau skb->tstamp)
233c803475fSMartin KaFai Lau inc_dtimes(EGRESS_ENDHOST);
234c803475fSMartin KaFai Lau else
235c803475fSMartin KaFai Lau inc_errs(EGRESS_ENDHOST);
236c803475fSMartin KaFai Lau }
237c803475fSMartin KaFai Lau
238c803475fSMartin KaFai Lau skb->tstamp = EGRESS_ENDHOST_MAGIC;
239c803475fSMartin KaFai Lau
240c803475fSMartin KaFai Lau return TC_ACT_OK;
241c803475fSMartin KaFai Lau }
242c803475fSMartin KaFai Lau
243c803475fSMartin KaFai Lau /* ingress@veth_(src|dst)@ns_(src|dst) */
244c803475fSMartin KaFai Lau SEC("tc")
ingress_host(struct __sk_buff * skb)245c803475fSMartin KaFai Lau int ingress_host(struct __sk_buff *skb)
246c803475fSMartin KaFai Lau {
247c803475fSMartin KaFai Lau int skb_type;
248c803475fSMartin KaFai Lau
249c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
250c803475fSMartin KaFai Lau if (skb_type == -1)
251c803475fSMartin KaFai Lau return TC_ACT_SHOT;
252c803475fSMartin KaFai Lau if (!skb_type)
253c803475fSMartin KaFai Lau return TC_ACT_OK;
254c803475fSMartin KaFai Lau
2553daf0896SMartin KaFai Lau if (skb->tstamp_type == BPF_SKB_TSTAMP_DELIVERY_MONO &&
256c803475fSMartin KaFai Lau skb->tstamp == EGRESS_FWDNS_MAGIC)
257c803475fSMartin KaFai Lau inc_dtimes(INGRESS_ENDHOST);
258c803475fSMartin KaFai Lau else
259c803475fSMartin KaFai Lau inc_errs(INGRESS_ENDHOST);
260c803475fSMartin KaFai Lau
261c803475fSMartin KaFai Lau return TC_ACT_OK;
262c803475fSMartin KaFai Lau }
263c803475fSMartin KaFai Lau
264c803475fSMartin KaFai Lau /* ingress@veth_(src|dst)_fwd@ns_fwd priority 100 */
265c803475fSMartin KaFai Lau SEC("tc")
ingress_fwdns_prio100(struct __sk_buff * skb)266c803475fSMartin KaFai Lau int ingress_fwdns_prio100(struct __sk_buff *skb)
267c803475fSMartin KaFai Lau {
268c803475fSMartin KaFai Lau int skb_type;
269c803475fSMartin KaFai Lau
270c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
271c803475fSMartin KaFai Lau if (skb_type == -1)
272c803475fSMartin KaFai Lau return TC_ACT_SHOT;
273c803475fSMartin KaFai Lau if (!skb_type)
274c803475fSMartin KaFai Lau return TC_ACT_OK;
275c803475fSMartin KaFai Lau
276c803475fSMartin KaFai Lau /* delivery_time is only available to the ingress
2773daf0896SMartin KaFai Lau * if the tc-bpf checks the skb->tstamp_type.
278c803475fSMartin KaFai Lau */
279c803475fSMartin KaFai Lau if (skb->tstamp == EGRESS_ENDHOST_MAGIC)
280c803475fSMartin KaFai Lau inc_errs(INGRESS_FWDNS_P100);
281c803475fSMartin KaFai Lau
282c803475fSMartin KaFai Lau if (fwdns_clear_dtime())
283c803475fSMartin KaFai Lau skb->tstamp = 0;
284c803475fSMartin KaFai Lau
285c803475fSMartin KaFai Lau return TC_ACT_UNSPEC;
286c803475fSMartin KaFai Lau }
287c803475fSMartin KaFai Lau
288c803475fSMartin KaFai Lau /* egress@veth_(src|dst)_fwd@ns_fwd priority 100 */
289c803475fSMartin KaFai Lau SEC("tc")
egress_fwdns_prio100(struct __sk_buff * skb)290c803475fSMartin KaFai Lau int egress_fwdns_prio100(struct __sk_buff *skb)
291c803475fSMartin KaFai Lau {
292c803475fSMartin KaFai Lau int skb_type;
293c803475fSMartin KaFai Lau
294c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
295c803475fSMartin KaFai Lau if (skb_type == -1)
296c803475fSMartin KaFai Lau return TC_ACT_SHOT;
297c803475fSMartin KaFai Lau if (!skb_type)
298c803475fSMartin KaFai Lau return TC_ACT_OK;
299c803475fSMartin KaFai Lau
300c803475fSMartin KaFai Lau /* delivery_time is always available to egress even
3013daf0896SMartin KaFai Lau * the tc-bpf did not use the tstamp_type.
302c803475fSMartin KaFai Lau */
303c803475fSMartin KaFai Lau if (skb->tstamp == INGRESS_FWDNS_MAGIC)
304c803475fSMartin KaFai Lau inc_dtimes(EGRESS_FWDNS_P100);
305c803475fSMartin KaFai Lau else
306c803475fSMartin KaFai Lau inc_errs(EGRESS_FWDNS_P100);
307c803475fSMartin KaFai Lau
308c803475fSMartin KaFai Lau if (fwdns_clear_dtime())
309c803475fSMartin KaFai Lau skb->tstamp = 0;
310c803475fSMartin KaFai Lau
311c803475fSMartin KaFai Lau return TC_ACT_UNSPEC;
312c803475fSMartin KaFai Lau }
313c803475fSMartin KaFai Lau
314c803475fSMartin KaFai Lau /* ingress@veth_(src|dst)_fwd@ns_fwd priority 101 */
315c803475fSMartin KaFai Lau SEC("tc")
ingress_fwdns_prio101(struct __sk_buff * skb)316c803475fSMartin KaFai Lau int ingress_fwdns_prio101(struct __sk_buff *skb)
317c803475fSMartin KaFai Lau {
318c803475fSMartin KaFai Lau __u64 expected_dtime = EGRESS_ENDHOST_MAGIC;
319c803475fSMartin KaFai Lau int skb_type;
320c803475fSMartin KaFai Lau
321c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
322c803475fSMartin KaFai Lau if (skb_type == -1 || !skb_type)
323c803475fSMartin KaFai Lau /* Should have handled in prio100 */
324c803475fSMartin KaFai Lau return TC_ACT_SHOT;
325c803475fSMartin KaFai Lau
326c803475fSMartin KaFai Lau if (skb_proto(skb_type) == IPPROTO_UDP)
327c803475fSMartin KaFai Lau expected_dtime = 0;
328c803475fSMartin KaFai Lau
3293daf0896SMartin KaFai Lau if (skb->tstamp_type) {
330c803475fSMartin KaFai Lau if (fwdns_clear_dtime() ||
3313daf0896SMartin KaFai Lau skb->tstamp_type != BPF_SKB_TSTAMP_DELIVERY_MONO ||
332c803475fSMartin KaFai Lau skb->tstamp != expected_dtime)
333c803475fSMartin KaFai Lau inc_errs(INGRESS_FWDNS_P101);
334c803475fSMartin KaFai Lau else
335c803475fSMartin KaFai Lau inc_dtimes(INGRESS_FWDNS_P101);
336c803475fSMartin KaFai Lau } else {
337c803475fSMartin KaFai Lau if (!fwdns_clear_dtime() && expected_dtime)
338c803475fSMartin KaFai Lau inc_errs(INGRESS_FWDNS_P101);
339c803475fSMartin KaFai Lau }
340c803475fSMartin KaFai Lau
3413daf0896SMartin KaFai Lau if (skb->tstamp_type == BPF_SKB_TSTAMP_DELIVERY_MONO) {
342c803475fSMartin KaFai Lau skb->tstamp = INGRESS_FWDNS_MAGIC;
343c803475fSMartin KaFai Lau } else {
3443daf0896SMartin KaFai Lau if (bpf_skb_set_tstamp(skb, INGRESS_FWDNS_MAGIC,
3453daf0896SMartin KaFai Lau BPF_SKB_TSTAMP_DELIVERY_MONO))
346c803475fSMartin KaFai Lau inc_errs(SET_DTIME);
3473daf0896SMartin KaFai Lau if (!bpf_skb_set_tstamp(skb, INGRESS_FWDNS_MAGIC,
3483daf0896SMartin KaFai Lau BPF_SKB_TSTAMP_UNSPEC))
349c803475fSMartin KaFai Lau inc_errs(SET_DTIME);
350c803475fSMartin KaFai Lau }
351c803475fSMartin KaFai Lau
352c803475fSMartin KaFai Lau if (skb_ns(skb_type) == SRC_NS)
353c803475fSMartin KaFai Lau return bpf_fwd() ?
354c803475fSMartin KaFai Lau bpf_redirect_neigh(IFINDEX_DST, NULL, 0, 0) : TC_ACT_OK;
355c803475fSMartin KaFai Lau else
356c803475fSMartin KaFai Lau return bpf_fwd() ?
357c803475fSMartin KaFai Lau bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0) : TC_ACT_OK;
358c803475fSMartin KaFai Lau }
359c803475fSMartin KaFai Lau
360c803475fSMartin KaFai Lau /* egress@veth_(src|dst)_fwd@ns_fwd priority 101 */
361c803475fSMartin KaFai Lau SEC("tc")
egress_fwdns_prio101(struct __sk_buff * skb)362c803475fSMartin KaFai Lau int egress_fwdns_prio101(struct __sk_buff *skb)
363c803475fSMartin KaFai Lau {
364c803475fSMartin KaFai Lau int skb_type;
365c803475fSMartin KaFai Lau
366c803475fSMartin KaFai Lau skb_type = skb_get_type(skb);
367c803475fSMartin KaFai Lau if (skb_type == -1 || !skb_type)
368c803475fSMartin KaFai Lau /* Should have handled in prio100 */
369c803475fSMartin KaFai Lau return TC_ACT_SHOT;
370c803475fSMartin KaFai Lau
3713daf0896SMartin KaFai Lau if (skb->tstamp_type) {
372c803475fSMartin KaFai Lau if (fwdns_clear_dtime() ||
3733daf0896SMartin KaFai Lau skb->tstamp_type != BPF_SKB_TSTAMP_DELIVERY_MONO ||
374c803475fSMartin KaFai Lau skb->tstamp != INGRESS_FWDNS_MAGIC)
375c803475fSMartin KaFai Lau inc_errs(EGRESS_FWDNS_P101);
376c803475fSMartin KaFai Lau else
377c803475fSMartin KaFai Lau inc_dtimes(EGRESS_FWDNS_P101);
378c803475fSMartin KaFai Lau } else {
379c803475fSMartin KaFai Lau if (!fwdns_clear_dtime())
380c803475fSMartin KaFai Lau inc_errs(EGRESS_FWDNS_P101);
381c803475fSMartin KaFai Lau }
382c803475fSMartin KaFai Lau
3833daf0896SMartin KaFai Lau if (skb->tstamp_type == BPF_SKB_TSTAMP_DELIVERY_MONO) {
384c803475fSMartin KaFai Lau skb->tstamp = EGRESS_FWDNS_MAGIC;
385c803475fSMartin KaFai Lau } else {
3863daf0896SMartin KaFai Lau if (bpf_skb_set_tstamp(skb, EGRESS_FWDNS_MAGIC,
3873daf0896SMartin KaFai Lau BPF_SKB_TSTAMP_DELIVERY_MONO))
388c803475fSMartin KaFai Lau inc_errs(SET_DTIME);
3893daf0896SMartin KaFai Lau if (!bpf_skb_set_tstamp(skb, INGRESS_FWDNS_MAGIC,
3903daf0896SMartin KaFai Lau BPF_SKB_TSTAMP_UNSPEC))
391c803475fSMartin KaFai Lau inc_errs(SET_DTIME);
392c803475fSMartin KaFai Lau }
393c803475fSMartin KaFai Lau
394c803475fSMartin KaFai Lau return TC_ACT_OK;
395c803475fSMartin KaFai Lau }
396c803475fSMartin KaFai Lau
397c803475fSMartin KaFai Lau char __license[] SEC("license") = "GPL";
398