/* -*- P4_16 -*- */ #include #include #include "headers.p4" #include "settings.p4" #define USE_NICO_DELTA_CHECKSUM 1 /************************************************************************* * Parser */ parser MyParser(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { state start { meta.chk_icmp = 0; meta.chk_icmp6 = 0; meta.chk_icmp6_na_ns = 0; meta.chk_ipv4 = 0; meta.chk_udp_v6 = 0; meta.chk_udp_v4 = 0; meta.chk_tcp_v6 = 0; meta.chk_tcp_v4 = 0; meta.v4sum = 0; meta.v6sum = 0; packet.extract(hdr.ethernet); transition select(hdr.ethernet.ethertype){ TYPE_IPV4: ipv4; TYPE_IPV6: ipv6; TYPE_ARP: arp; default: accept; } } state ipv4 { packet.extract(hdr.ipv4); meta.length_without_ip_header = hdr.ipv4.totalLen - 16w20; transition select(hdr.ipv4.protocol){ PROTO_TCP: tcp; PROTO_UDP: udp; PROTO_ICMP: icmp; default: accept; } } state ipv6 { packet.extract(hdr.ipv6); meta.length_without_ip_header = hdr.ipv6.payload_length; transition select(hdr.ipv6.next_header){ PROTO_TCP: tcp; PROTO_UDP: udp; PROTO_ICMP6: icmp6; default: accept; } } state icmp6 { packet.extract(hdr.icmp6); transition select(hdr.icmp6.type) { ICMP6_NS: icmp6_neighbor_solicitation; default: accept; } } state icmp6_neighbor_solicitation { packet.extract(hdr.icmp6_na_ns); /* BUG: This MIGHT fail */ packet.extract(hdr.icmp6_option_link_layer_addr); transition accept; } /* Leaf */ state tcp { packet.extract(hdr.tcp); transition accept; } state udp { packet.extract(hdr.udp); transition accept; } state icmp { packet.extract(hdr.icmp); transition accept; } state arp { packet.extract(hdr.arp); transition accept; } } /************************************************************************* ************************ D E P A R S E R ******************************* *************************************************************************/ control MyDeparser(packet_out packet, in headers hdr) { apply { /* always */ packet.emit(hdr.ethernet); /* only if information is sent to the controller */ packet.emit(hdr.cpu); /* either */ packet.emit(hdr.ipv4); packet.emit(hdr.ipv6); packet.emit(hdr.arp); /* either */ packet.emit(hdr.tcp); packet.emit(hdr.udp); packet.emit(hdr.icmp); /* might be more than one subtype */ packet.emit(hdr.icmp6); packet.emit(hdr.icmp6_na_ns); packet.emit(hdr.icmp6_option_link_layer_addr); } } // OK-UNTIL-HERE /************************************************************************* ************** I N G R E S S P R O C E S S I N G ******************* *************************************************************************/ control MyIngress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { #include "actions_nat64_generic.p4" #include "actions_egress.p4" #include "actions_icmp6_ndp_icmp.p4" #include "actions_arp.p4" #include "actions_delta_checksum.p4" /* only used if enabled at compile time */ /********************** APPLYING TABLES / MAIN LOGIC **************************/ apply { if(hdr.ipv6.isValid()) { if(nat64.apply().hit) { /* generic / static nat64 done */ if(hdr.icmp6.isValid()) { nat64_icmp6_generic(); if(hdr.icmp6.type == ICMP6_ECHO_REPLY) { hdr.icmp.type = ICMP_ECHO_REPLY; hdr.icmp.code = 0; } if(hdr.icmp6.type == ICMP6_ECHO_REQUEST) { hdr.icmp.type = ICMP_ECHO_REQUEST; hdr.icmp.code = 0; } } if(hdr.udp.isValid()) { meta.chk_udp_v4 = 1; } if(hdr.tcp.isValid()) { meta.chk_tcp_v4 = 1; } v4_networks.apply(); /* apply egress for IPv4 */ exit; /* no further v6 processing */ } icmp6.apply(); /* icmp6 echo, icmp6 ndp */ v6_networks.apply(); /* regular egress / routing */ } else if(hdr.ipv4.isValid()) { if(icmp.apply().hit) { v4_networks.apply(); exit; } else if(nat46.apply().hit) { if(hdr.icmp.isValid()) { nat46_icmp_generic(); if(hdr.icmp.type == ICMP_ECHO_REPLY) { hdr.icmp6.type = ICMP6_ECHO_REPLY; } if(hdr.icmp.type == ICMP_ECHO_REQUEST) { hdr.icmp6.type = ICMP6_ECHO_REQUEST; } } if(hdr.udp.isValid()) { #ifdef USE_NICO_DELTA_CHECKSUM v4sum(); v6sum(); bit<16> diff = meta.v6sum - meta.v4sum; hdr.udp.checksum = hdr.udp.checksum + ~diff +1; // hdr.udp.checksum = ~diff; #else meta.chk_udp_v6 = 1; #endif } if(hdr.tcp.isValid()) { #ifdef USE_NICO_DELTA_CHECKSUM v4sum(); v6sum(); bit<16> diff = meta.v6sum - meta.v4sum; hdr.tcp.checksum = hdr.tcp.checksum + ~diff +1; #else meta.chk_tcp_v6 = 1; #endif } v6_networks.apply(); exit; } v4_networks.apply(); /* regular routing, egress */ } else if(hdr.arp.isValid()) { if(v4_arp.apply().hit) { v4_arp_egress.apply(); } } } } /************************************************************************* **************** E G R E S S P R O C E S S I N G ******************* *************************************************************************/ control MyEgress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { apply { // ingress clone if (standard_metadata.instance_type == 1){ hdr.cpu.setValid(); hdr.cpu.task = meta.task; hdr.cpu.ethertype = hdr.ethernet.ethertype; hdr.cpu.ingress_port = (bit<16>) meta.ingress_port; hdr.cpu.table_id = meta.table_id; hdr.ethernet.ethertype = TYPE_CPU; } } } /************************************************************************* * Checksums */ control MyVerifyChecksum(inout headers hdr, inout metadata meta) { apply {} } control MyComputeChecksum(inout headers hdr, inout metadata meta) { apply { update_checksum(meta.chk_icmp6 == 1, { hdr.ipv6.src_addr, /* 128 */ hdr.ipv6.dst_addr, /* 128 */ meta.cast_length, /* 32 */ 24w0, /* 24 0's */ PROTO_ICMP6, /* 8 */ hdr.icmp6.type, /* 8 */ hdr.icmp6.code /* 8 */ }, hdr.icmp6.checksum, HashAlgorithm.csum16 ); } } /************************************************************************* *********************** S W I T C H ******************************* *************************************************************************/ V1Switch( MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser() ) main;