github.com/cilium/cilium@v1.16.2/bpf/tests/tc_l2_announcement.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  /* Enable debug output */
     7  #define DEBUG
     8  
     9  /* Set THIS_INTERFACE_MAC equal to mac_two */
    10  #define THIS_INTERFACE_MAC { .addr = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37} }
    11  
    12  #define SECCTX_FROM_IPCACHE 1
    13  
    14  /* Set the LXC source address to be the address of pod one */
    15  #define LXC_IPV4 (__be32)v4_pod_one
    16  
    17  /* Enable CT debug output */
    18  #undef QUIET_CT
    19  
    20  #include <bpf/ctx/skb.h>
    21  #include "pktgen.h"
    22  
    23  /* Set ETH_HLEN to 14 to indicate that the packet has a 14 byte ethernet header */
    24  #define ETH_HLEN 14
    25  
    26  /* Enable code paths under test */
    27  #define ENABLE_IPV4
    28  #define ENABLE_L2_ANNOUNCEMENTS
    29  
    30  #include <bpf_host.c>
    31  
    32  struct {
    33  	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
    34  	__uint(key_size, sizeof(__u32));
    35  	__uint(max_entries, 2);
    36  	__array(values, int());
    37  } entry_call_map __section(".maps") = {
    38  	.values = {
    39  		[0] = &cil_from_netdev,
    40  	},
    41  };
    42  
    43  /* Setup for this test:
    44   * +-------------------------+   +--------------------------------------+    +--------------------------+
    45   * |L2:mac_one, L3:v4_ext_one|---| ARP Request broadcast for v4_svc_one |--->|L2:mac_two, L3:v4_node_one|
    46   * +-------------------------+   +--------------------------------------+    +--------------------------+
    47   *             ^   +-------------------------------------------------------------------+    |
    48   *             \---|ARP Reply, SHR:mac_two, SIP:v4_svc_one, DHR:mac_one, DIP:v4_ext_one|---/
    49   *                 +-------------------------------------------------------------------+
    50   */
    51  
    52  static volatile const __u8 mac_bcast[] =   {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    53  
    54  static __always_inline int build_packet(struct __ctx_buff *ctx)
    55  {
    56  	struct pktgen builder;
    57  	volatile const __u8 *src = mac_one;
    58  	volatile const __u8 *dst = mac_bcast;
    59  	struct ethhdr *l2;
    60  	struct arphdreth *l3;
    61  
    62  	/* Init packet builder */
    63  	pktgen__init(&builder, ctx);
    64  
    65  	/* Push ethernet header */
    66  	l2 = pktgen__push_ethhdr(&builder);
    67  
    68  	if (!l2)
    69  		return TEST_ERROR;
    70  
    71  	ethhdr__set_macs(l2, (__u8 *)src, (__u8 *)dst);
    72  
    73  	/* Push ARP header */
    74  	l3 = pktgen__push_default_arphdr_ethernet(&builder);
    75  
    76  	if (!l3)
    77  		return TEST_ERROR;
    78  
    79  	l3->ar_op = bpf_htons(ARPOP_REQUEST);
    80  	memcpy(l3->ar_sha, (__u8 *)mac_one, ETH_ALEN);
    81  	l3->ar_sip = v4_ext_one;
    82  	memcpy(l3->ar_tha, (__u8 *)mac_bcast, ETH_ALEN);
    83  	l3->ar_tip = v4_svc_one;
    84  
    85  	/* Calc lengths, set protocol fields and calc checksums */
    86  	pktgen__finish(&builder);
    87  
    88  	return 0;
    89  }
    90  
    91  PKTGEN("tc", "0_no_entry")
    92  int l2_announcement_arp_no_entry_pktgen(struct __ctx_buff *ctx)
    93  {
    94  	return build_packet(ctx);
    95  }
    96  
    97  /* Test that sending a ARP broadcast request without entries in the map.
    98   */
    99  SETUP("tc", "0_no_entry")
   100  int l2_announcement_arp_no_entry_setup(struct __ctx_buff *ctx)
   101  {
   102  	/* Jump into the entrypoint */
   103  	tail_call_static(ctx, entry_call_map, 0);
   104  	/* Fail if we didn't jump */
   105  	return TEST_ERROR;
   106  }
   107  
   108  CHECK("tc", "0_no_entry")
   109  int l2_announcement_arp_no_entry_check(__maybe_unused const struct __ctx_buff *ctx)
   110  {
   111  	void *data;
   112  	void *data_end;
   113  	__u32 *status_code;
   114  	struct ethhdr *l2;
   115  	struct arphdreth *l3;
   116  
   117  	test_init();
   118  
   119  	data = ctx_data(ctx);
   120  	data_end = ctx_data_end(ctx);
   121  
   122  	if (data + sizeof(__u32) > data_end)
   123  		test_fatal("status code out of bounds");
   124  
   125  	status_code = data;
   126  
   127  	/* The program should pass unknown ARP messages to the stack */
   128  	assert(*status_code == TC_ACT_OK);
   129  
   130  	l2 = data + sizeof(__u32);
   131  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   132  		test_fatal("l2 out of bounds");
   133  
   134  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   135  
   136  	if ((void *)l3 + sizeof(struct arphdreth) > data_end)
   137  		test_fatal("l3 out of bounds");
   138  
   139  	assert(memcmp(l2->h_source, (__u8 *)mac_one, ETH_ALEN) == 0);
   140  	assert(memcmp(l2->h_dest, (__u8 *)mac_bcast, ETH_ALEN) == 0);
   141  	assert(l3->ar_op == bpf_htons(ARPOP_REQUEST));
   142  	assert(l3->ar_sip == v4_ext_one);
   143  	assert(l3->ar_tip == v4_svc_one);
   144  	assert(memcmp(l3->ar_sha, (__u8 *)mac_one, ETH_ALEN) == 0);
   145  	assert(memcmp(l3->ar_tha, (__u8 *)mac_bcast, ETH_ALEN) == 0);
   146  
   147  	test_finish();
   148  }
   149  
   150  PKTGEN("tc", "1_happy_path")
   151  int l2_announcement_arp_happy_path_pktgen(struct __ctx_buff *ctx)
   152  {
   153  	return build_packet(ctx);
   154  }
   155  
   156  /* Test that sending a ARP broadcast request matching an entry in the
   157   * L2_RESPONDER_MAP4 results in a valid ARP reply.
   158   */
   159  SETUP("tc", "1_happy_path")
   160  int l2_announcement_arp_happy_path_setup(struct __ctx_buff *ctx)
   161  {
   162  	struct l2_responder_v4_key key;
   163  	struct l2_responder_v4_stats value = {0};
   164  	__u32 index;
   165  	__u64 time;
   166  
   167  	key.ifindex = 0;
   168  	key.ip4 = v4_svc_one;
   169  	map_update_elem(&L2_RESPONDER_MAP4, &key, &value, BPF_ANY);
   170  
   171  	index = RUNTIME_CONFIG_AGENT_LIVENESS;
   172  	time = ktime_get_ns();
   173  	map_update_elem(&CONFIG_MAP, &index, &time, BPF_ANY);
   174  
   175  	/* Jump into the entrypoint */
   176  	tail_call_static(ctx, entry_call_map, 0);
   177  	/* Fail if we didn't jump */
   178  	return TEST_ERROR;
   179  }
   180  
   181  CHECK("tc", "1_happy_path")
   182  int l2_announcement_arp_happy_path_check(__maybe_unused const struct __ctx_buff *ctx)
   183  {
   184  	void *data;
   185  	void *data_end;
   186  	__u32 *status_code;
   187  	struct ethhdr *l2;
   188  	struct arphdreth *l3;
   189  
   190  	test_init();
   191  
   192  	data = (void *)(long)ctx->data;
   193  	data_end = (void *)(long)ctx->data_end;
   194  
   195  	if (data + sizeof(__u32) > data_end)
   196  		test_fatal("status code out of bounds");
   197  
   198  	status_code = data;
   199  
   200  	assert(*status_code == TC_ACT_REDIRECT);
   201  
   202  	l2 = data + sizeof(__u32);
   203  	if ((void *)l2 + sizeof(struct ethhdr) > data_end)
   204  		test_fatal("l2 out of bounds");
   205  
   206  	l3 = data + sizeof(__u32) + sizeof(struct ethhdr);
   207  
   208  	if ((void *)l3 + sizeof(struct arphdreth) > data_end)
   209  		test_fatal("l3 out of bounds");
   210  
   211  	assert(memcmp(l2->h_source, (__u8 *)mac_two, ETH_ALEN) == 0);
   212  	assert(memcmp(l2->h_dest, (__u8 *)mac_one, ETH_ALEN) == 0);
   213  	assert(l3->ar_op == bpf_htons(ARPOP_REPLY));
   214  	assert(l3->ar_sip == v4_svc_one);
   215  	assert(l3->ar_tip == v4_ext_one);
   216  	assert(memcmp(l3->ar_sha, (__u8 *)mac_two, ETH_ALEN) == 0);
   217  	assert(memcmp(l3->ar_tha, (__u8 *)mac_one, ETH_ALEN) == 0);
   218  
   219  	test_finish();
   220  }