github.com/cilium/cilium@v1.16.2/bpf/tests/bpf_ct_tests.c (about) 1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright Authors of Cilium */ 3 4 #include "common.h" 5 6 #include <bpf/ctx/skb.h> 7 #include <bpf/api.h> 8 9 #define ENABLE_IPV4 10 #define ENABLE_NODEPORT 11 #include <node_config.h> 12 13 #undef EVENTS_MAP 14 #define EVENTS_MAP test_events_map 15 #define DEBUG 16 17 #include <lib/dbg.h> 18 #include <lib/conntrack.h> 19 #include <lib/conntrack_map.h> 20 #include <lib/time.h> 21 22 __always_inline int mkpkt(void *dst, bool first) 23 { 24 void *orig = dst; 25 struct ethhdr *l2 = dst; 26 27 l2->h_proto = bpf_htons(ETH_P_IP); 28 29 if (first) { 30 char src[6] = {1, 0, 0, 3, 0, 10}; 31 char dest[6] = {1, 0, 0, 3, 0, 20}; 32 33 memcpy(l2->h_source, src, sizeof(src)); 34 memcpy(l2->h_dest, dest, sizeof(dest)); 35 } else { 36 char src[6] = {1, 0, 0, 3, 0, 20}; 37 char dest[6] = {1, 0, 0, 3, 0, 10}; 38 39 memcpy(l2->h_source, src, sizeof(src)); 40 memcpy(l2->h_dest, dest, sizeof(dest)); 41 } 42 43 dst += sizeof(struct ethhdr); 44 45 struct iphdr *l3 = dst; 46 47 l3->version = 4; 48 l3->ihl = 5; 49 l3->protocol = IPPROTO_TCP; 50 51 if (first) { 52 l3->saddr = 0x0A00030A; /* 10.3.0.10 */ 53 l3->daddr = 0x1400030A; /* 10.3.0.20 */ 54 } else { 55 l3->saddr = 0x1400030A; /* 10.3.0.20 */ 56 l3->daddr = 0x0A00030A; /* 10.3.0.10 */ 57 } 58 59 dst += sizeof(struct iphdr); 60 61 char tcp_data[11] = "pizza! :-)"; 62 63 struct tcphdr *l4 = dst; 64 65 l4->doff = 5; 66 if (first) { 67 l4->source = __bpf_htons(3010); 68 l4->dest = __bpf_htons(3020); 69 l4->syn = 1; 70 } else { 71 l4->source = __bpf_htons(3020); 72 l4->dest = __bpf_htons(3010); 73 l4->rst = 1; 74 } 75 dst += sizeof(struct tcphdr); 76 77 memcpy(dst, tcp_data, sizeof(tcp_data)); 78 dst += sizeof(tcp_data); 79 80 return dst - orig; 81 } 82 83 static char pkt[100]; 84 85 CHECK("tc", "ct4") 86 int test_ct4_rst1_check(__maybe_unused struct __ctx_buff *ctx) 87 { 88 test_init(); 89 90 int pkt_size = mkpkt(pkt, true); 91 92 { 93 unsigned int data_len = ctx->data_end - ctx->data; 94 int offset = pkt_size - 256 - 320 - data_len; 95 96 ctx_adjust_troom(ctx, offset); 97 98 void *data = (void *)(long)ctx->data; 99 void *data_end = (void *)(long)ctx->data_end; 100 101 if (data + pkt_size > data_end) 102 return TEST_ERROR; 103 104 memcpy(data, pkt, pkt_size); 105 } 106 107 TEST("ct4_syn", { 108 struct ipv4_ct_tuple tuple = {}; 109 void *data; 110 void *data_end; 111 struct iphdr *ip4; 112 int l3_off = ETH_HLEN; 113 int l4_off; 114 struct ct_state ct_state = {}; 115 struct ct_state ct_state_new = {}; 116 __u16 proto; 117 __u32 monitor = 0; 118 int ret; 119 120 bpf_clear_meta(ctx); 121 assert(validate_ethertype(ctx, &proto)); 122 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 123 124 tuple.nexthdr = ip4->protocol; 125 tuple.daddr = ip4->daddr; 126 tuple.saddr = ip4->saddr; 127 l4_off = l3_off + ipv4_hdrlen(ip4); 128 129 ret = ct_lookup4(get_ct_map4(&tuple), &tuple, ctx, ip4, l4_off, 130 CT_EGRESS, &ct_state, &monitor); 131 switch (ret) { 132 case CT_NEW: 133 ct_state_new.node_port = ct_state.node_port; 134 ct_state_new.ifindex = ct_state.ifindex; 135 ret = ct_create4(get_ct_map4(&tuple), &CT_MAP_ANY4, &tuple, ctx, 136 CT_EGRESS, &ct_state_new, NULL); 137 break; 138 139 default: 140 test_log("ct_lookup4, expected CT_NEW, got %d", ret); 141 test_fail(); 142 } 143 144 struct ct_entry *entry = map_lookup_elem(get_ct_map4(&tuple), &tuple); 145 146 assert(entry); 147 assert(entry->tx_flags_seen == tcp_flags_to_u8(TCP_FLAG_SYN)); 148 149 if (data + pkt_size > data_end) 150 test_fatal("packet shrank"); 151 152 /* unexpected data modification */ 153 assert(memcmp(pkt, data, pkt_size) == 0); 154 }); 155 156 pkt_size = mkpkt(pkt, false); 157 { 158 void *data = (void *)(long)ctx->data; 159 void *data_end = (void *)(long)ctx->data_end; 160 161 if (data + pkt_size > data_end) 162 return TEST_ERROR; 163 164 memcpy(data, pkt, pkt_size); 165 } 166 167 #define TEST_LOG 168 169 TEST("ct4_rst", { 170 struct ipv4_ct_tuple tuple = {}; 171 void *data; 172 void *data_end; 173 struct iphdr *ip4; 174 int l3_off = ETH_HLEN; 175 int l4_off; 176 __u16 proto; 177 __u32 monitor = 0; 178 179 bpf_clear_meta(ctx); 180 assert(validate_ethertype(ctx, &proto)); 181 assert(revalidate_data(ctx, &data, &data_end, &ip4)); 182 183 tuple.nexthdr = ip4->protocol; 184 tuple.daddr = ip4->daddr; 185 tuple.saddr = ip4->saddr; 186 l4_off = l3_off + ipv4_hdrlen(ip4); 187 188 ct_lookup4(get_ct_map4(&tuple), &tuple, ctx, ip4, l4_off, 189 CT_INGRESS, NULL, &monitor); 190 191 if (data + pkt_size > data_end) 192 test_fatal("packet shrank"); 193 194 /* unexpected data modification */ 195 assert(memcmp(pkt, data, pkt_size) == 0); 196 197 tuple.nexthdr = IPPROTO_TCP; 198 tuple.saddr = 0x1400030A; /* 10.3.0.20 */ 199 tuple.daddr = 0x0A00030A; /* 10.3.0.10 */ 200 tuple.sport = __bpf_htons(3010); 201 tuple.dport = __bpf_htons(3020); 202 tuple.flags = 0; 203 204 struct ct_entry *entry = map_lookup_elem(get_ct_map4(&tuple), &tuple); 205 206 assert(entry); 207 assert(entry->rx_flags_seen == tcp_flags_to_u8(TCP_FLAG_SYN | TCP_FLAG_RST)); 208 209 __u32 expires = entry->lifetime - bpf_ktime_get_sec(); 210 211 if (expires > 10) 212 test_fatal("Expiration is %ds even if RST flag was set", expires); 213 214 }); 215 216 test_finish(); 217 } 218 219 BPF_LICENSE("Dual BSD/GPL");