xf#ifndef NICO_NAT64_GENERIC #define NICO_NAT64_GENERIC #include "actions_egress.p4" #include "actions_delta_checksum.p4" /********************** NAT64 / NAT46 ACTIONS GENERIC ***********************************/ /* changes for icmp6 -> icmp */ action nat64_icmp6_generic() { hdr.icmp.setValid(); hdr.ipv4.protocol = PROTO_ICMP; // overwrite generic same protocol assumption /* trigger checksumming */ meta.switch_task = TASK_CHECKSUM_ICMP; /* FIXME: for delta */ meta.chk_icmp = 1; hdr.icmp6.setInvalid(); /* not needed, as we don't translate them (yet/ever) */ hdr.icmp6_na_ns.setInvalid(); hdr.icmp6_option_link_layer_addr.setInvalid(); } /* NAT64 protocol unspecific changes */ action nat64_generic(ipv4_addr_t src, ipv4_addr_t dst) { hdr.ipv4.setValid(); /* Stuff that might need to be fixed */ hdr.ipv4.version = (bit<4>)4; hdr.ipv4.ihl = (bit<4>)5; // internet header length: 4*5 = 20 /* 5 is ok as long as we don't use options / padding / anything after the destination address */ hdr.ipv4.diff_serv = (bit<6>)0; // no ToS hdr.ipv4.ecn = (bit<2>)0; // unsupported hdr.ipv4.totalLen = (bit<16>) hdr.ipv6.payload_length + 20; // ok under above constraints hdr.ipv4.identification = (bit<16>) 0; // no support for fragments hdr.ipv4.flags = (bit<3>) 0; // DF bit and more fragments hdr.ipv4.fragOffset = (bit<13>) 0; // 0 as there are no fragments hdr.ipv4.ttl = hdr.ipv6.hop_limit; hdr.ipv4.protocol = hdr.ipv6.next_header; hdr.ipv4.src_addr = src; hdr.ipv4.dst_addr = dst; /* Stuff that should be fine */ hdr.ethernet.ethertype = TYPE_IPV4; #ifdef _SUME_SWITCH_P4_ delta_ipv4_from_v6_to_v4(); #else meta.chk_ipv4 = 1; /* need to calculate the hdrchecksum */ #endif hdr.ipv6.setInvalid(); } /* nat64_prefix is the same as the matching key, but without the mask */ action nat64_static(ipv6_addr_t v6_src, ipv4_addr_t v4_dst, ipv6_addr_t nat64_prefix) { ipv6_addr_t src_offset = hdr.ipv6.src_addr - v6_src; ipv4_addr_t src = v4_dst + (ipv4_addr_t) src_offset; ipv4_addr_t dst = (ipv4_addr_t) (hdr.ipv6.dst_addr - nat64_prefix); nat64_generic(src, dst); } /* From https://tools.ietf.org/html/rfc792 (IPv4) Echo or Echo Reply Message 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data ... +-+-+-+-+- From https://tools.ietf.org/html/rfc4443#section-4.1 4.1. Echo Request Message 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data ... +-+-+-+-+- 4.2. Echo Reply Message 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data ... +-+-+-+-+- Type / code are different in ICMP4 and ICMP6! */ /* changes for icmp6 -> icmp */ action nat46_icmp_generic() { hdr.icmp6.setValid(); hdr.ipv6.next_header = PROTO_ICMP6; meta.chk_icmp6 = 1; meta.cast_length = (bit<32>) hdr.ipv6.payload_length; hdr.icmp.setInvalid(); } /* NAT46: protocol unspecific changes */ action nat46_generic(ipv6_addr_t src, ipv6_addr_t dst) { hdr.ipv6.setValid(); hdr.ipv4.setInvalid(); hdr.ethernet.ethertype = TYPE_IPV6; hdr.ipv6.dst_addr = dst; hdr.ipv6.src_addr = src; hdr.ipv6.version = (bit<4>) 6; hdr.ipv6.traffic_class = (bit<8>) hdr.ipv4.diff_serv; hdr.ipv6.flow_label = (bit<20>) 0; hdr.ipv6.payload_length = (bit<16>) hdr.ipv4.totalLen - 20; hdr.ipv6.next_header = hdr.ipv4.protocol; hdr.ipv6.hop_limit = hdr.ipv4.ttl; } /* matching key: v4_network specified again */ action nat46_static(ipv6_addr_t v6_src, ipv4_addr_t v4_dst, ipv6_addr_t nat64_prefix) { ipv6_addr_t src = nat64_prefix + (ipv6_addr_t) hdr.ipv4.src_addr; ipv4_addr_t dst_offset = hdr.ipv4.dst_addr - v4_dst; ipv6_addr_t dst = v6_src + (ipv6_addr_t) dst_offset; nat46_generic(src, dst); } table nat64 { key = { #ifndef _SUME_SWITCH_P4_ hdr.ipv6.dst_addr: lpm; #else hdr.ipv6.dst_addr: exact; #endif } actions = { controller_debug; nat64_static; controller_debug_table_id; NoAction; } size = NAT64_TABLE_SIZE; default_action = NoAction; } table nat46 { key = { #ifndef _SUME_SWITCH_P4_ hdr.ipv4.dst_addr: lpm; #else hdr.ipv4.dst_addr: exact; #endif } actions = { controller_debug; nat46_static; controller_debug_table_id; NoAction; } size = NAT64_TABLE_SIZE; #ifndef _SUME_SWITCH_P4_ default_action = controller_debug_table_id(TABLE_NAT46); #else default_action = controller_debug; #endif } #endif