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");