11/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
22/* Copyright Authors of Cilium */
33
4+ #pragma once
5+
46#include <bpf/ctx/skb.h>
57#include "common.h"
68#include "pktgen.h"
79
8- #define ENABLE_SCTP
9- #define ENABLE_IPV4
10- #define ENABLE_IPV6
11- #define ENABLE_NODEPORT
10+ #define ENABLE_SCTP 1
11+ #define ENABLE_IPV4 1
12+ #define ENABLE_IPV6 1
13+ #define ENABLE_NODEPORT 1
1214#define ENABLE_MASQUERADE_IPV6 1
1315
14- #include "lib/bpf_host.h"
16+ #define NODE_ONE6 { .addr = v6_node_one_addr }
17+ #define EXT_IP6 { .addr = v6_ext_node_one_addr }
18+ #define POD_IP6 { .addr = v6_pod_one_addr }
19+
20+ #define POD6_SEC_IDENTITY 112244
1521
1622#include <bpf/config/node.h>
1723
2228#include <lib/nat.h>
2329#include <lib/time.h>
2430
25- #include <bpf/helpers.h>
26- #include <bpf/api.h>
27-
28- #include <bpf/ctx/skb.h>
29- #include <bpf/api.h>
30- #include <bpf/config/node.h>
31-
32- #define DEBUG
31+ ASSIGN_CONFIG (union v6addr , nat_ipv6_masquerade , { .addr = v6_node_one_addr })
3332
34- #include <lib/dbg.h>
35- #include <lib/eps.h>
36- #include <lib/nat.h>
37- #include <lib/time.h>
33+ #include "scapy.h"
3834
3935#include "bpf_nat_tuples.h"
4036
41- #define NODE_ONE { .addr = v6_node_one_addr }
42- #define EXT_IP { .addr = v6_ext_node_one_addr }
43- #define POD_IP { .addr = v6_pod_one_addr }
37+ #include "lib/endpoint.h"
4438
4539/*
4640 * Input packet represents a device sending a PKT_TOO_BIG response ICMPv6
8781 *
8882 * Ref: https://datatracker.ietf.org/doc/html/rfc4443#section-3.2
8983 */
90- __always_inline int gen_pmtu_pkt (struct pktgen * builder , int l4_type )
84+ const __u8 icmp6_err_revnat_egress_tcp [] = {
85+ SCAPY_BUF_BYTES (icmp6_err_revnat_egress_tcp )
86+ };
87+ const __u8 icmp6_err_revnat_egress_post_tcp [] = {
88+ SCAPY_BUF_BYTES (icmp6_err_revnat_egress_post_tcp )
89+ };
90+ const __u8 icmp6_err_revnat_egress_udp [] = {
91+ SCAPY_BUF_BYTES (icmp6_err_revnat_egress_udp )
92+ };
93+ const __u8 icmp6_err_revnat_egress_post_udp [] = {
94+ SCAPY_BUF_BYTES (icmp6_err_revnat_egress_post_udp )
95+ };
96+ const __u8 icmp6_err_revnat_full_tcp [] = {
97+ SCAPY_BUF_BYTES (icmp6_err_revnat_full_tcp )
98+ };
99+ const __u8 icmp6_err_revnat_full_tcp_after [] = {
100+ SCAPY_BUF_BYTES (icmp6_err_revnat_full_tcp_after )
101+ };
102+ const __u8 icmp6_err_revnat_full_udp [] = {
103+ SCAPY_BUF_BYTES (icmp6_err_revnat_full_udp )
104+ };
105+ const __u8 icmp6_err_revnat_full_udp_after [] = {
106+ SCAPY_BUF_BYTES (icmp6_err_revnat_full_udp_after )
107+ };
108+
109+ /*
110+ * Push an egressing pod->external TCP packet through to-netdev and let the
111+ * datapath set up nat mappings due to node ip masquerading.
112+ * Exploit the fact that tests are run in alphabetical order to ensure this
113+ * happens before we check the icmp pmtud revSNAT mappings.
114+ */
115+ PKTGEN (PROG_TYPE , "00_snat_v6_tcp_egress" )
116+ int snat_v6_egress_pktgen (struct __ctx_buff * ctx )
91117{
92- struct ipv6hdr * inner_l3 = NULL ;
93- struct icmp6hdr * l4 = NULL ;
94- struct tcphdr * inner_l4 = NULL ;
95- struct udphdr * inner_l4_udp = NULL ; /* compiler complains if this isn't init to null? */
96- struct sctphdr * inner_l4_sctp = NULL ;
97- void * data = NULL ;
98-
99- l4 = pktgen__push_ipv6_icmp6_packet (builder ,
100- (__u8 * )mac_one ,
101- (__u8 * )mac_two ,
102- (__u8 * )v6_ext_node_one ,
103- (__u8 * )v6_node_one ,
104- ICMPV6_PKT_TOOBIG );
105- if (!l4 )
106- return TEST_FAIL ;
118+ struct pktgen builder ;
107119
108- inner_l3 = pktgen__push_default_ipv6hdr (builder );
109- if (!inner_l3 )
110- return TEST_FAIL ;
120+ pktgen__init (& builder , ctx );
121+ scapy_push_data (& builder ,
122+ icmp6_err_revnat_egress_tcp ,
123+ sizeof (icmp6_err_revnat_egress_tcp ));
124+ pktgen__finish (& builder );
125+ return TEST_PASS ;
126+ }
111127
112- inner_l3 -> nexthdr = (__u8 )l4_type ;
113- ipv6hdr__set_addrs (inner_l3 , (__u8 * )v6_node_one , (__u8 * )v6_ext_node_one );
114-
115- switch (l4_type ) {
116- case IPPROTO_TCP :
117- inner_l4 = pktgen__push_default_tcphdr (builder );
118- if (!inner_l4 )
119- return TEST_FAIL ;
120- /* original source */
121- inner_l4 -> dest = 1234 ;
122- inner_l4 -> source = 30001 ;
123- break ;
124- case IPPROTO_UDP :
125- inner_l4_udp = pktgen__push_default_udphdr (builder );
126- if (!inner_l4_udp )
127- return TEST_FAIL ;
128- inner_l4_udp -> dest = 1234 ;
129- inner_l4_udp -> source = 30001 ;
130- break ;
131- case IPPROTO_SCTP :
132- inner_l4_sctp = pktgen__push_default_sctphdr (builder );
133- if (!inner_l4_udp )
134- return TEST_FAIL ;
135- inner_l4_sctp -> dest = 1234 ;
136- inner_l4_sctp -> source = 30001 ;
137- break ;
138- default :
139- return TEST_FAIL ;
140- }
128+ SETUP (PROG_TYPE , "00_snat_v6_tcp_egress" )
129+ int snat_v6_egress_setup (struct __ctx_buff * ctx )
130+ {
131+ union v6addr pod_ip = POD_IP6 ;
141132
142- data = pktgen__push_data (builder , default_data , sizeof (default_data ));
143- if (!data )
144- return TEST_FAIL ;
133+ endpoint_v6_add_entry (& pod_ip , 0 , 0 , 0 , POD6_SEC_IDENTITY ,
134+ (__u8 * )mac_one , (__u8 * )mac_one );
145135
146- return TEST_PASS ;
136+ return netdev_send_packet ( ctx ) ;
147137}
148138
149- int snat_v6_insert_ct_nat (__u8 proto )
139+ /*
140+ * Add a check prior to moving onto actual icmp pmtu icmp testing
141+ * to quickly fail if priror steps did not setup expected nat state
142+ */
143+ CHECK (PROG_TYPE , "00_snat_v6_tcp_egress" )
144+ int snat_v6_egress_check (const struct __ctx_buff * ctx )
150145{
151- struct ipv6_nat_entry entry = {
152- .to_daddr = POD_IP ,
146+ test_init ();
147+
148+ ASSERT_CTX_BUF_OFF ("snat_v6_egress" , "Ether" , ctx , sizeof (__u32 ),
149+ icmp6_err_revnat_egress_post_tcp ,
150+ sizeof (icmp6_err_revnat_egress_post_tcp ));
151+
152+ union v6addr pod_ip = POD_IP6 ;
153+ struct ipv6_ct_tuple tuple = {
154+ .daddr = NODE_ONE6 ,
155+ .saddr = EXT_IP6 ,
156+ .dport = tcp_src_two ,
157+ .sport = tcp_dst_one ,
158+ .nexthdr = IPPROTO_TCP ,
159+ .flags = NAT_DIR_INGRESS ,
153160 };
154- entry .to_sport = 0 ;
155- entry .to_dport = 20 ;
161+ struct ipv6_nat_entry * entry = map_lookup_elem (& cilium_snat_v6_external ,
162+ & tuple );
163+
164+ if (!entry )
165+ test_fatal ("no revSNAT entry created by to-netdev" );
166+ if (!ipv6_addr_equals (& entry -> to_daddr , & pod_ip ))
167+ test_fatal ("revSNAT entry to_daddr is not the pod IP" );
168+ if (entry -> to_dport != tcp_src_two )
169+ test_fatal ("revSNAT entry to_dport is not the pod source port" );
170+
171+ test_finish ();
172+ }
173+
174+ PKTGEN (PROG_TYPE , "01_snat_v6_udp_egress" )
175+ int snat_v6_egress_udp_pktgen (struct __ctx_buff * ctx )
176+ {
177+ struct pktgen builder ;
178+
179+ pktgen__init (& builder , ctx );
180+ scapy_push_data (& builder ,
181+ icmp6_err_revnat_egress_udp ,
182+ sizeof (icmp6_err_revnat_egress_udp ));
183+ pktgen__finish (& builder );
184+ return TEST_PASS ;
185+ }
186+
187+ SETUP (PROG_TYPE , "01_snat_v6_udp_egress" )
188+ int snat_v6_egress_udp_setup (struct __ctx_buff * ctx )
189+ {
190+ return netdev_send_packet (ctx );
191+ }
192+
193+ CHECK (PROG_TYPE , "01_snat_v6_udp_egress" )
194+ int snat_v6_egress_udp_check (const struct __ctx_buff * ctx )
195+ {
196+ test_init ();
197+
198+ ASSERT_CTX_BUF_OFF ("snat_v6_egress_udp" , "Ether" , ctx , sizeof (__u32 ),
199+ icmp6_err_revnat_egress_post_udp ,
200+ sizeof (icmp6_err_revnat_egress_post_udp ));
201+
202+ union v6addr pod_ip = POD_IP6 ;
156203 struct ipv6_ct_tuple tuple = {
157- .daddr = NODE_ONE ,
158- .saddr = EXT_IP ,
159- .dport = 30001 , /* SNAT remapped port */
160- .sport = 1234 ,
161- .nexthdr = proto ,
162- .flags = TUPLE_F_IN ,
204+ .daddr = NODE_ONE6 ,
205+ .saddr = EXT_IP6 ,
206+ .dport = tcp_src_two ,
207+ .sport = tcp_dst_one ,
208+ .nexthdr = IPPROTO_UDP ,
209+ .flags = NAT_DIR_INGRESS ,
163210 };
164- return map_update_elem (& cilium_snat_v6_external , & tuple , & entry , BPF_ANY );
211+ struct ipv6_nat_entry * entry = map_lookup_elem (& cilium_snat_v6_external ,
212+ & tuple );
213+
214+ if (!entry )
215+ test_fatal ("no revSNAT entry created by to-netdev" );
216+ if (!ipv6_addr_equals (& entry -> to_daddr , & pod_ip ))
217+ test_fatal ("revSNAT entry to_daddr is not the pod IP" );
218+ if (entry -> to_dport != tcp_src_two )
219+ test_fatal ("revSNAT entry to_dport is not the pod source port" );
220+
221+ test_finish ();
165222}
166223
167224int do_icmp6_pkt_too_big_check (const struct __ctx_buff * ctx )
@@ -200,9 +257,9 @@ int do_icmp6_pkt_too_big_check(const struct __ctx_buff *ctx)
200257 l4 = (void * )(data + sizeof (__u32 ) +
201258 sizeof (struct ethhdr ) + sizeof (struct ipv6hdr ) +
202259 sizeof (struct icmp6hdr ) + sizeof (struct ipv6hdr ));
203- if (* ((__u16 * )l4 ) != 20 )
260+ if (* ((__u16 * )l4 ) != bpf_htons ( 20 ) )
204261 return TEST_FAIL ;
205- if (* ((__u16 * )(l4 + sizeof (__u16 ))) != 1234 )
262+ if (* ((__u16 * )(l4 + sizeof (__u16 ))) != bpf_htons ( 1234 ) )
206263 return TEST_FAIL ;
207264 return 0 ;
208265}
@@ -213,28 +270,26 @@ int snat_v6_pmtu_pktgen(struct __ctx_buff *ctx)
213270 struct pktgen builder ;
214271
215272 pktgen__init (& builder , ctx );
216- gen_pmtu_pkt (& builder , IPPROTO_TCP );
273+ scapy_push_data (& builder ,
274+ icmp6_err_revnat_full_tcp ,
275+ sizeof (icmp6_err_revnat_full_tcp ));
217276 pktgen__finish (& builder );
218277 return TEST_PASS ;
219278}
220279
221280SETUP (PROG_TYPE , "snat_v6_tcp_pmtu" )
222281int snat_v6_pmtu_setup (struct __ctx_buff * ctx )
223282{
224- int ret ;
225-
226- ret = snat_v6_insert_ct_nat (IPPROTO_TCP );
227- if (ret < 0 )
228- return TEST_FAIL ;
229-
230283 return netdev_receive_packet (ctx );
231284}
232285
233286CHECK (PROG_TYPE , "snat_v6_tcp_pmtu" )
234287int snat_v6_pmtu_check (const struct __ctx_buff * ctx )
235288{
236289 test_init ();
237- assert (do_icmp6_pkt_too_big_check (ctx ) == 0 );
290+ ASSERT_CTX_BUF_OFF ("snat_v6_tcp_pmtu" , "Ether" , ctx , sizeof (__u32 ),
291+ icmp6_err_revnat_full_tcp_after ,
292+ sizeof (icmp6_err_revnat_full_tcp_after ));
238293 test_finish ();
239294
240295 return 0 ;
@@ -246,28 +301,26 @@ int snat_v6_pmtu_udp_pktgen(struct __ctx_buff *ctx)
246301 struct pktgen builder ;
247302
248303 pktgen__init (& builder , ctx );
249- gen_pmtu_pkt (& builder , IPPROTO_UDP );
304+ scapy_push_data (& builder ,
305+ icmp6_err_revnat_full_udp ,
306+ sizeof (icmp6_err_revnat_full_udp ));
250307 pktgen__finish (& builder );
251308 return TEST_PASS ;
252309}
253310
254311SETUP (PROG_TYPE , "snat_v6_udp_pmtu" )
255312int snat_v6_pmtu_udp_setup (struct __ctx_buff * ctx )
256313{
257- int ret ;
258-
259- ret = snat_v6_insert_ct_nat (IPPROTO_UDP );
260- if (ret < 0 )
261- return TEST_FAIL ;
262-
263314 return netdev_receive_packet (ctx );
264315}
265316
266317CHECK (PROG_TYPE , "snat_v6_udp_pmtu" )
267318int snat_v6_pmtu_udp_check (const struct __ctx_buff * ctx )
268319{
269320 test_init ();
270- assert (do_icmp6_pkt_too_big_check (ctx ) == 0 );
321+ ASSERT_CTX_BUF_OFF ("snat_v6_udp_pmtu" , "Ether" , ctx , sizeof (__u32 ),
322+ icmp6_err_revnat_full_udp_after ,
323+ sizeof (icmp6_err_revnat_full_udp_after ));
271324 test_finish ();
272325
273326 return 0 ;
0 commit comments