/* * Copyright (c) 2016-2024 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef _SKYWALK_TEST_UTILS_H_ #define _SKYWALK_TEST_UTILS_H_ #include #include #include #include #include #include #include #include typedef enum sktu_if_type { SKTU_IFT_UTUN = 1, SKTU_IFT_IPSEC = 2, SKTU_IFT_FETH = 3, } sktu_if_type_t; #define SKTU_IFF_ENABLE_NETIF 0x00000001 // no-netif (txstart bsd interface) by default #define SKTU_IFF_NO_ATTACH_FSW 0x00000002 // auto-attach fsw for netif by default typedef uint32_t sktu_if_flag_t; typedef struct sktc_nexus_handles { nexus_controller_t controller; uuid_t fsw_prov_uuid; uuid_t fsw_nx_uuid; uuid_t fsw_nx_host_attach_uuid; uuid_t fsw_nx_dev_attach_uuid; uuid_t netif_prov_uuid; uuid_t netif_nx_uuid; uuid_t netif_nx_attach_uuid; char netif_ifname[IFNAMSIZ]; struct in_addr netif_addr; struct in_addr netif_mask; struct in6_addr netif_ip6_addr; uint8_t netif_ip6_prefix_len; } * sktu_nexus_t; typedef struct ip_udp_hdr { struct ip ip; struct udphdr udp; } ip_udp_header_t; typedef struct ip6_udp_hdr { struct ip6_hdr ip6; struct udphdr udp; } ip6_udp_header_t; typedef struct udp_pseudo_hdr { struct in_addr src_ip; struct in_addr dst_ip; char zero; char proto; unsigned short length; } udp_pseudo_hdr_t; struct ipv4_udp_pseudo_hdr { struct in_addr src_ip; struct in_addr dst_ip; uint8_t zero; uint8_t proto; unsigned short length; }; struct ipv6_udp_pseudo_hdr { struct in6_addr src_ip; struct in6_addr dst_ip; uint32_t length; uint8_t zero[3]; uint8_t proto; }; typedef struct tcp_pseudo_hdr { struct in_addr src_ip; struct in_addr dst_ip; uint8_t zero; uint8_t proto; unsigned short length; } tcp_pseudo_hdr_t; struct ipv4_tcp_pseudo_hdr { struct in_addr src_ip; struct in_addr dst_ip; uint8_t zero; uint8_t proto; uint16_t length; }; struct ipv6_tcp_pseudo_hdr { struct in6_addr src_ip; struct in6_addr dst_ip; uint32_t length; uint8_t zero[3]; uint8_t proto; }; typedef struct { struct ip ip; struct tcphdr tcp; } ip_tcp_header_t; typedef union { ip_udp_header_t udp; ip_tcp_header_t tcp; } ip_udp_tcp_header_u; #define SKTU_MAX_MTU_PAYLOAD_LEN (1500 - (sizeof(struct ip6_hdr) + sizeof(struct tcphdr) - sizeof(uint32_t))) typedef struct { uint32_t packet_number; char data[SKTU_MAX_MTU_PAYLOAD_LEN]; } my_payload, *my_payload_t; // sktu_frame is a universal container that holds packet buffer and metadata. // It's used when packet_t isn't available (like for utun fd), or isn't // available yet (like before packet gets allocated from channel). #define SKTU_FRAME_BUF_SIZE (16 * 1024) typedef struct sktu_frame { // meta data uuid_t flow_uuid; bool csum_offload; uint16_t csum_flags; uint16_t csum_start; uint16_t csum_stuff; size_t len; // data char bytes[SKTU_FRAME_BUF_SIZE]; } *sktu_frame_t; typedef struct { channel_t chan; int fd; nexus_port_t port; channel_ring_t rx_ring; channel_ring_t tx_ring; struct in_addr ip_addr; struct in6_addr ip6_addr; struct ether_addr mac_addr; boolean_t user_packet_pool; } channel_port, *channel_port_t, *sktu_channel_port_t; struct sktu_flow; #define CSUM_OFFLOAD true #define NO_CSUM_OFFLOAD false struct sktu_flow_ops { size_t (*create_input_frames)(struct sktu_flow *flow, struct sktu_frame **frames, size_t max_frames, const void *data, size_t data_len); size_t (*create_output_frames)(struct sktu_flow *flow, struct sktu_frame **frames, size_t max_frames, const void *data, size_t data_len, bool csum_offload); }; typedef struct sktu_flow { bool is_nexus_flow; uint8_t ipver; void *src_ip; void *dst_ip; size_t ip_addr_len; uint16_t sport; uint16_t dport; uint8_t ip_protocol; size_t mtu; // nexus flow fields struct nx_flow_req nfr; sktu_nexus_t nexus; nexus_port_t nx_port; uuid_t uuid; // socket flow fields int sock_fd; // ops struct sktu_flow_ops _flow_ops; #define create_input_frames _flow_ops.create_input_frames #define create_output_frames _flow_ops.create_output_frames } *sktu_nexus_flow_t; channel_t sktu_channel_create_extended(const uuid_t uuid, const nexus_port_t port, const ring_dir_t dir, const ring_id_t rid, const channel_attr_t attr, uint64_t exclusive, uint64_t monitor, uint64_t txlowatunit, uint64_t txlowatval, uint64_t rxlowatunit, uint64_t rxlowatval, uint64_t userpacketpool, uint64_t defunctok, uint64_t event_ring, uint64_t low_latency); void permutefuncP(int n, int *permute, void (*func)(int, int *permute)); void permutefuncH(int n, int *permute, void (*func)(int, int *permute)); void permutefuncR(int n, int *permute, void (*func)(int, int *permute), int total, unsigned seed); void permutefuncZ(int n, int *permute, void (*func)(int, int *permute)); void sktc_create_flowswitch(struct sktc_nexus_handles *handles, int i); void sktc_create_flowswitch_no_address(struct sktc_nexus_handles *handles, uint64_t tx_slots, uint64_t rx_slots, uint64_t buf_size, uint64_t max_frags, uint64_t anonymous); void sktc_nexus_handles_assign_address(struct sktc_nexus_handles *handles); void sktc_cleanup_flowswitch(struct sktc_nexus_handles *handles); int sktc_bind_tcp4_flow(nexus_controller_t ncd, const uuid_t fsw, in_port_t in_port, nexus_port_t nx_port, const uuid_t flow); int sktc_unbind_flow(nexus_controller_t ncd, const uuid_t fsw, const uuid_t flow); char * skt_nfr_print(struct nx_flow_req *nfr, char *buf, size_t buf_max); struct sktu_flow * _sktu_create_nexus_flow(sktu_nexus_t nexus, nexus_port_t nx_port, uint8_t af, void *src, void *dst, uint8_t proto, uint16_t sport, uint16_t dport, uint32_t flags); struct sktu_flow * sktu_create_nexus_flow(sktu_nexus_t nexus, uint8_t af, void *src, void *dst, uint8_t proto, uint16_t sport, uint16_t dport); struct sktu_flow * sktu_create_nexus_low_latency_flow(sktu_nexus_t nexus, uint8_t af, void *src, void *dst, uint8_t proto, uint16_t sport, uint16_t dport); struct sktu_flow * sktu_create_nexus_flow_with_nx_port(sktu_nexus_t nexus, nexus_port_t nx_port, uint8_t af, void *src, void *dst, uint8_t proto, uint16_t sport, uint16_t dport); void _sktu_destroy_nexus_flow(struct sktu_flow *flow); #define sktu_destroy_nexus_flow(f) \ do { \ _sktu_destroy_nexus_flow(f); \ f = NULL; \ } while (0) int sktu_get_nexus_flow_stats(uuid_t flow_uuid, struct sk_stats_flow *sf); int sktu_get_nexus_flowswitch_stats(struct sk_stats_flow_switch **sfsw, size_t *len); void __fsw_stats_print(struct fsw_stats *s); uint32_t sktc_chew_random(channel_t channel, channel_ring_t ring, sync_mode_t mode, bool dosync, uint32_t avail); void sktc_pump_ring_nslots_kq(channel_t channel, channel_ring_t ring, sync_mode_t mode, bool dosync, uint64_t nslots, bool verbose); void sktc_pump_ring_nslots_select(channel_t channel, channel_ring_t ring, sync_mode_t mode, bool dosync, uint64_t nslots, bool verbose); void sktc_pump_ring_nslots_poll(channel_t channel, channel_ring_t ring, sync_mode_t mode, bool dosync, uint64_t nslots, bool verbose); void sktc_raise_file_limit(int new); int sktu_create_interface(sktu_if_type_t type, sktu_if_flag_t flags); channel_t sktu_create_interface_channel(sktu_if_type_t type, int tunsock); void sktu_get_interface_name(sktu_if_type_t type, int s, char name[IFNAMSIZ]); void sktu_dump_buffer(FILE *f, const char *title, const void *p, size_t len); int sysctl_buf(char *oid_name, void **buffer, size_t *len, void *newp, size_t newlen); uint32_t sktu_set_inject_error_rmask(uint32_t *); boolean_t sktu_check_interface_ipv4_address(char *ifname, uint32_t ipaddr); int sktu_create_pfkeysock(void); void sktu_create_sa(int keysock, const char ifname[IFXNAMSIZ], uint32_t spi, struct in_addr *src, struct in_addr *dst); extern unsigned short in_cksum(void * pkt, int len, int sum0); extern uint16_t in_pseudo(uint32_t a, uint32_t b, uint32_t c); extern uint16_t in6_pseudo(const struct in6_addr *src, const struct in6_addr *dst, uint32_t x); extern void sktu_channel_port_init(channel_port_t ch_port, uuid_t instance, nexus_port_t nx_port, bool enable_upp, bool enable_event_ring, bool low_latency); extern void skt_channel_port_send(channel_port_t port, uuid_t flow_id, int protocol, uint16_t src_port, struct in_addr dst_ip, uint16_t dst_port, my_payload_t payload, int payload_length, uint32_t limit, boolean_t must_complete_batch, boolean_t connect, packet_svc_class_t svc_class, boolean_t csum_offload, void (^packet_prehook)(packet_t p)); extern void skt_channel_port_receive(int child, channel_port_t port, uint16_t our_port, struct in_addr peer_ip, uint32_t limit, uint32_t *receive_count, uint32_t *receive_index, boolean_t errors_ok, uint32_t * pkts_dropped); extern void sktu_channel_port_tx_bulk(channel_port_t port, struct sktu_frame **frames, uint32_t n); extern packet_t sktu_channel_port_frame_to_pkt(channel_port_t port, struct sktu_frame *frame); extern uint32_t sktu_channel_port_tx_burst_pkt(channel_port_t port, packet_t *frames, uint32_t n); extern uint32_t sktu_channel_port_rx_burst(channel_port_t port, struct sktu_frame **frames, uint32_t n); extern uint32_t sktu_channel_port_tx_burst(channel_port_t port, struct sktu_frame **frames, uint32_t n); extern uint32_t sktu_utun_fd_rx_burst(int utun_fd, struct sktu_frame **frames, uint32_t n); extern void sktu_utun_fd_tx_burst(int utun_fd, struct sktu_frame **frames, uint32_t n); extern struct sktu_frame * sktu_frame_alloc(); #define sktu_frame_free(frame) \ do { \ free(frame); \ frame = NULL; \ } while (0) extern void sktu_frames_free(struct sktu_frame **frames, size_t n); extern size_t sktu_create_ip_frames(struct sktu_frame **frames, size_t n, void *src_ip, void *dst_ip, uint8_t proto, const void *sdu, size_t sdu_len, size_t mtu, uint16_t csum_flags, uint16_t csum_start, uint16_t csum_stuff); extern size_t sktu_create_ip6_frames(struct sktu_frame **frames, size_t n, void *src_ip, void *dst_ip, uint8_t proto, const void *sdu, size_t sdu_len, size_t mtu, uint16_t csum_flags, uint16_t csum_start, uint16_t csum_stuff); extern size_t sktu_create_tcp_frames(struct sktu_frame **frames, size_t n, uint8_t ipver, void *src_ip, void *dst_ip, uint16_t sport, uint16_t dport, const void *data, size_t data_len, size_t mtu, bool csum_offload); extern size_t sktu_create_udp_frames(struct sktu_frame **frames, size_t n, uint8_t ipver, void *src_ip, void *dst_ip, uint16_t sport, uint16_t dport, const void *data, size_t data_len, size_t mtu, bool csum_offload); extern int sktu_parse_ipv4_frame(struct sktu_frame *frame, void *ip_payload, uint32_t *ip_payload_len); extern int sktu_parse_tcp4_frame(struct sktu_frame *frame, void *tcp_payload, uint32_t *tcp_payload_len); extern int sktu_parse_udp4_frame(struct sktu_frame *frame, void *udp_payload, uint32_t *udp_payload_len); #endif /* _SKYWALK_TEST_UTILS_H_ */