// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: CERN-OHL-S-2.0 #include "hls_jfjoch.h" #include "ip_header_checksum.h" void ipv4(AXI_STREAM ð_in, AXI_STREAM &udp_out, AXI_STREAM &icmp_out, ap_uint<32> fpga_ipv4_addr, ap_uint<1> direct) { #pragma HLS INTERFACE ap_ctrl_none port=return #pragma HLS INTERFACE axis register both port=eth_in #pragma HLS INTERFACE axis register both port=udp_out #pragma HLS INTERFACE axis register both port=icmp_out #pragma HLS INTERFACE ap_none register port=fpga_ipv4_addr #pragma HLS INTERFACE ap_none register port=direct #pragma HLS PIPELINE II=1 style=flp enum ipv4_dest {DEST_UDP = 0, DEST_ICMP = 1, DEST_IGNORE=2}; enum ipv4_state {INSPECT_HEADER, FORWARD, DISCARD}; static ipv4_state state = INSPECT_HEADER; static ipv4_dest dest; packet_512_t packet_in; if (eth_in.read_nb(packet_in)) { if (state == INSPECT_HEADER) { dest = DEST_IGNORE; ap_uint<4> ip_version = packet_in.data(eth_payload_pos + 8 - 1, eth_payload_pos + 4); ap_uint<8> ipv4_protocol = packet_in.data(eth_payload_pos + 80 - 1, eth_payload_pos + 72); ap_uint<32> ipv4_dest_ip = packet_in.data(eth_payload_pos + 128 + 31, eth_payload_pos + 128); ap_uint<16> ipv4_header_checksum_check = computeCheckSum20B( packet_in.data(eth_payload_pos + 159, eth_payload_pos)); if ((ip_version == 4) && (ipv4_header_checksum_check == 0)) { // IP is version 4 + IP address is correct + checksum is OK // Possibly the conditions can be relaxed for broadcast ICMP if ((ipv4_protocol == PROTOCOL_UDP) && ((ipv4_dest_ip == fpga_ipv4_addr) || (ipv4_dest_ip == IPV4_BROADCAST) || direct)) { // For UDP packets the following is OK: // * correct IP // * broadcast (e.g. timing) // * direct settings - no address enforced state = FORWARD; dest = DEST_UDP; } else if ((ipv4_protocol == PROTOCOL_ICMP) && (ipv4_dest_ip == fpga_ipv4_addr)) { // IPv4 address is enforced (don't want broadcast pings) // Has to be from 100G network state = FORWARD; dest = DEST_ICMP; } } } switch (dest) { case DEST_UDP: udp_out.write(packet_in); break; case DEST_ICMP: icmp_out.write(packet_in); break; default: break; } if (packet_in.last) state = INSPECT_HEADER; } }