From a69c4060e2b917fd649cef883dc6de0bd0d40dd3 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 6 Jul 2019 20:57:11 +0200 Subject: [PATCH] begin implementing diff based checksum in p4 --- bin/checksum_delta_diff_test.py | 36 +- doc/plan.org | 29 +- netpfga/minip4/src/minip4_solution-nat64.p4 | 266 +++---- p4src/checksum_diff.p4 | 783 ++++++++++++++++++++ p4src/checksums.p4 | 1 - 5 files changed, 977 insertions(+), 138 deletions(-) create mode 100644 p4src/checksum_diff.p4 diff --git a/bin/checksum_delta_diff_test.py b/bin/checksum_delta_diff_test.py index 79a0c01..2ffb666 100644 --- a/bin/checksum_delta_diff_test.py +++ b/bin/checksum_delta_diff_test.py @@ -8,14 +8,44 @@ import struct # stolen from scapy (little endian system) def checksum_scapy(pkt): + + # Even the length if len(pkt) % 2 == 1: pkt += b"\0" + + # array: create an array of 16 bit values from the input + # and then sum it up -> this might be sligthly/much higher + # than 16 bit (additions!) s = sum(array.array("H", pkt)) + + # add the (right shift 16) and the 16 right bits + # basically: assuming 32 bit (?): add the two 16 bit "words" + # together + # This might still exceed 16 bit! s = (s >> 16) + (s & 0xffff) + + # right shift 16 -> zero least significant bits, + # and add the upper bits to it + # So now we add anything that was left over from before s += s >> 16 + + # 2 complement -- this is the only important part here ??? s = ~s + + # right shift 8 bit -> maximum 8 bit are set (above code) + # then we and it with 1's -- ??? WTF??? -> 8 bit filter! + # -> first part is extracting 8 highest bits + # + # then we left shift the original value by 8 (???) + # and then we OR all of that + # -> second part is unclear + # + # Then we mask it again with 16 bit 1's -> cut off stuff + return (((s>>8)&0xff)|s<<8) & 0xffff + + # a) Compare for TCP, UDP -> IPv6 does not have checksum! # 1. convert to array of "bytes" # 2. import into an array @@ -32,9 +62,9 @@ def checksum_scapy(pkt): def sum_for_udp(packet): sums = "" - sums += struct.pack("H", packet[UDP].sport) - sums += struct.pack("H", packet[UDP].dport) - sums += struct.pack("H", packet[UDP].len) + sums += struct.pack("H", packet[UDP].sport) # 16 bit + sums += struct.pack("H", packet[UDP].dport) # 16 bit + sums += struct.pack("H", packet[UDP].len) # 16 bit return sums diff --git a/doc/plan.org b/doc/plan.org index b2f1cbb..188ee5b 100644 --- a/doc/plan.org +++ b/doc/plan.org @@ -399,10 +399,27 @@ | | - Diff'ing in P4 | | | | * IPv4 checksum is w/o payload | | | | | | +| | - Different generated output | | | | | | | | Next steps: | | | | - Implement in BMV2 diff | | -| | - | | +| | - Checksum assignment / calc phase not clear | | +| | - Check if action has to be used | | +| | - Check if ifdef makes a difference | | +| | - Defense: list of dates | | +| | | | +| | - iperf (alternative: hping) -> test on production setup | | +| | | | +| | Late tests: | | +| | - Performance tests | | +| | - Extra things | | +| | - Maybe compile to openvswitch | | +| | | | +| 2019-07-06 | | | +| | Test case for delta in P4/BMV2: | | +| | | | +| | | | +| | | | | | | | | 2019-07-11 | | | | | Integrated org-documentation into latex / export working | | @@ -4944,6 +4961,16 @@ else: - .packed of ipaddress works *** 2019-07-01: finish sum, use scapy checksum *** 2019-07-01: meeting Laurent +*** 2019-07-06: test bmv2 / delta + Story: + - Static mapping / no controller + - IPv4 packet goes in + - Translated to IPv6 + - IPv6 packet goes in + - Translated to IPv4 + - Checksums match, but we only update it using + HashAlgorithm.csum16 + ** References / Follow up *** RFC 791 IPv4 https://tools.ietf.org/html/rfc791 *** RFC 792 ICMP https://tools.ietf.org/html/rfc792 diff --git a/netpfga/minip4/src/minip4_solution-nat64.p4 b/netpfga/minip4/src/minip4_solution-nat64.p4 index 8a7502f..7cd5fdb 100644 --- a/netpfga/minip4/src/minip4_solution-nat64.p4 +++ b/netpfga/minip4/src/minip4_solution-nat64.p4 @@ -414,166 +414,166 @@ control TopPipe(inout Parsed_packet hdr, /********************** ICMP6 + NDP + ICMP ***********************************/ - /* old/unused action -- is it??*/ - action icmp6_answer() { - if(hdr.icmp6.isValid()) { - if(hdr.icmp6.code == ICMP6_ECHO_REQUEST) { - ipv6_addr_t tmp = hdr.ipv6.src_addr; - hdr.ipv6.src_addr = hdr.ipv6.dst_addr; - hdr.ipv6.dst_addr = tmp; - hdr.icmp6.code = ICMP6_ECHO_REPLY; - } - } - } +// /* old/unused action -- is it??*/ +// action icmp6_answer() { +// if(hdr.icmp6.isValid()) { +// if(hdr.icmp6.code == ICMP6_ECHO_REQUEST) { +// ipv6_addr_t tmp = hdr.ipv6.src_addr; +// hdr.ipv6.src_addr = hdr.ipv6.dst_addr; +// hdr.ipv6.dst_addr = tmp; +// hdr.icmp6.code = ICMP6_ECHO_REPLY; +// } +// } +// } - action icmp6_neighbor_solicitation(ipv6_addr_t addr, mac_addr_t mac_addr) { - /* egress = ingress */ - standard_metadata.egress_spec = standard_metadata.ingress_port; +// action icmp6_neighbor_solicitation(ipv6_addr_t addr, mac_addr_t mac_addr) { +// /* egress = ingress */ +// standard_metadata.egress_spec = standard_metadata.ingress_port; - /* 1. IPv6 changes */ - hdr.ipv6.dst_addr = hdr.ipv6.src_addr; - hdr.ipv6.src_addr = addr; +// /* 1. IPv6 changes */ +// hdr.ipv6.dst_addr = hdr.ipv6.src_addr; +// hdr.ipv6.src_addr = addr; - /* 2. ICMP6 changes */ - hdr.icmp6.type = ICMP6_NA; - hdr.icmp6.code = 0; - hdr.icmp6.checksum = 42; // checksum is calculated in deparser - marking with 42 to see whether it is calculated +// /* 2. ICMP6 changes */ +// hdr.icmp6.type = ICMP6_NA; +// hdr.icmp6.code = 0; +// hdr.icmp6.checksum = 42; // checksum is calculated in deparser - marking with 42 to see whether it is calculated - /* 3. icmp6/neighbor advertisement: values taken from real world answers */ - hdr.icmp6_na_ns.router = 0; - hdr.icmp6_na_ns.solicitated = 1; - hdr.icmp6_na_ns.override = 1; - hdr.icmp6_na_ns.reserved = 0; - hdr.icmp6_na_ns.target_addr = addr; +// /* 3. icmp6/neighbor advertisement: values taken from real world answers */ +// hdr.icmp6_na_ns.router = 0; +// hdr.icmp6_na_ns.solicitated = 1; +// hdr.icmp6_na_ns.override = 1; +// hdr.icmp6_na_ns.reserved = 0; +// hdr.icmp6_na_ns.target_addr = addr; - /* 4. Link layer options */ - hdr.icmp6_option_link_layer_addr.type = ICMP6_NDP_OPT_TARGET_LL; - hdr.icmp6_option_link_layer_addr.ll_length = 1; /* 1* 64 bit */ - hdr.icmp6_option_link_layer_addr.mac_addr = mac_addr; +// /* 4. Link layer options */ +// hdr.icmp6_option_link_layer_addr.type = ICMP6_NDP_OPT_TARGET_LL; +// hdr.icmp6_option_link_layer_addr.ll_length = 1; /* 1* 64 bit */ +// hdr.icmp6_option_link_layer_addr.mac_addr = mac_addr; - /* 5. Checksum trigger/info */ - meta.chk_icmp6_na_ns = 1; - meta.cast_length = (bit<32>) hdr.ipv6.payload_length; - } +// /* 5. Checksum trigger/info */ +// meta.chk_icmp6_na_ns = 1; +// meta.cast_length = (bit<32>) hdr.ipv6.payload_length; +// } - action icmp6_echo_reply() { - mac_addr_t mac_tmp = hdr.ethernet.dst_addr; - hdr.ethernet.dst_addr = hdr.ethernet.src_addr; - hdr.ethernet.src_addr = mac_tmp; +// action icmp6_echo_reply() { +// mac_addr_t mac_tmp = hdr.ethernet.dst_addr; +// hdr.ethernet.dst_addr = hdr.ethernet.src_addr; +// hdr.ethernet.src_addr = mac_tmp; - ipv6_addr_t addr_tmp = hdr.ipv6.dst_addr; - hdr.ipv6.dst_addr = hdr.ipv6.src_addr; - hdr.ipv6.src_addr = addr_tmp; +// ipv6_addr_t addr_tmp = hdr.ipv6.dst_addr; +// hdr.ipv6.dst_addr = hdr.ipv6.src_addr; +// hdr.ipv6.src_addr = addr_tmp; - hdr.icmp6.type = ICMP6_ECHO_REPLY; +// hdr.icmp6.type = ICMP6_ECHO_REPLY; - meta.chk_icmp6 = 1; +// meta.chk_icmp6 = 1; - meta.cast_length = (bit<32>) hdr.ipv6.payload_length; - } +// meta.cast_length = (bit<32>) hdr.ipv6.payload_length; +// } - table icmp6 { - key = { - hdr.ipv6.dst_addr: lpm; - hdr.icmp6.type: exact; - } - actions = { - controller_debug; - icmp6_neighbor_solicitation; - icmp6_echo_reply; - controller_debug_table_id; - NoAction; - } - size = ICMP6_TABLE_SIZE; - default_action = controller_debug_table_id(TABLE_ICMP6); - } +// table icmp6 { +// key = { +// hdr.ipv6.dst_addr: lpm; +// hdr.icmp6.type: exact; +// } +// actions = { +// controller_debug; +// icmp6_neighbor_solicitation; +// icmp6_echo_reply; +// controller_debug_table_id; +// NoAction; +// } +// size = ICMP6_TABLE_SIZE; +// default_action = controller_debug_table_id(TABLE_ICMP6); +// } - action icmp_echo_reply() { - mac_addr_t mac_tmp = hdr.ethernet.dst_addr; - ipv4_addr_t ipv4_tmp = hdr.ipv4.src_addr; +// action icmp_echo_reply() { +// mac_addr_t mac_tmp = hdr.ethernet.dst_addr; +// ipv4_addr_t ipv4_tmp = hdr.ipv4.src_addr; - /* swap ethernet addresses */ - hdr.ethernet.dst_addr = hdr.ethernet.src_addr; - hdr.ethernet.src_addr = mac_tmp; +// /* swap ethernet addresses */ +// hdr.ethernet.dst_addr = hdr.ethernet.src_addr; +// hdr.ethernet.src_addr = mac_tmp; - /* swap ipv4 addresses */ - hdr.ipv4.src_addr = hdr.ipv4.dst_addr; - hdr.ipv4.dst_addr = ipv4_tmp; +// /* swap ipv4 addresses */ +// hdr.ipv4.src_addr = hdr.ipv4.dst_addr; +// hdr.ipv4.dst_addr = ipv4_tmp; - /* set correct type */ - hdr.icmp.type = ICMP_ECHO_REPLY; +// /* set correct type */ +// hdr.icmp.type = ICMP_ECHO_REPLY; - meta.chk_icmp = 1; - } +// meta.chk_icmp = 1; +// } - table icmp { - key = { - hdr.ipv4.dst_addr: lpm; - hdr.icmp.type: exact; - } - actions = { - icmp_echo_reply; - controller_debug_table_id; - NoAction; - } - size = ICMP_TABLE_SIZE; -// default_action = controller_debug_table_id(TABLE_ICMP); - default_action = NoAction; /* do not clone on miss */ - } +// table icmp { +// key = { +// hdr.ipv4.dst_addr: lpm; +// hdr.icmp.type: exact; +// } +// actions = { +// icmp_echo_reply; +// controller_debug_table_id; +// NoAction; +// } +// size = ICMP_TABLE_SIZE; +// // default_action = controller_debug_table_id(TABLE_ICMP); +// default_action = NoAction; /* do not clone on miss */ +// } -// /********************** ARP ***********************************/ +// // /********************** ARP ***********************************/ - action arp_reply(mac_addr_t mac_addr) { - /* swap */ - ipv4_addr_t ipv4_src = hdr.arp.dst_ipv4_addr; - ipv4_addr_t ipv4_dst = hdr.arp.src_ipv4_addr; +// action arp_reply(mac_addr_t mac_addr) { +// /* swap */ +// ipv4_addr_t ipv4_src = hdr.arp.dst_ipv4_addr; +// ipv4_addr_t ipv4_dst = hdr.arp.src_ipv4_addr; - /* swap/add */ - mac_addr_t mac_src = mac_addr; - mac_addr_t mac_dst = hdr.arp.src_mac_addr; +// /* swap/add */ +// mac_addr_t mac_src = mac_addr; +// mac_addr_t mac_dst = hdr.arp.src_mac_addr; - /* fill the ethernet header */ - hdr.ethernet.dst_addr = mac_dst; - hdr.ethernet.src_addr = mac_src; +// /* fill the ethernet header */ +// hdr.ethernet.dst_addr = mac_dst; +// hdr.ethernet.src_addr = mac_src; - /* fill the arp header */ - hdr.arp.dst_mac_addr = mac_dst; - hdr.arp.src_mac_addr = mac_src; +// /* fill the arp header */ +// hdr.arp.dst_mac_addr = mac_dst; +// hdr.arp.src_mac_addr = mac_src; - /* swapping */ - hdr.arp.dst_ipv4_addr = ipv4_dst; - hdr.arp.src_ipv4_addr = ipv4_src; +// /* swapping */ +// hdr.arp.dst_ipv4_addr = ipv4_dst; +// hdr.arp.src_ipv4_addr = ipv4_src; - hdr.arp.opcode = ARP_REPLY; - } +// hdr.arp.opcode = ARP_REPLY; +// } - table v4_arp { - key = { - hdr.ethernet.dst_addr: exact; - hdr.arp.opcode: exact; - hdr.arp.dst_ipv4_addr: lpm; - } - actions = { - controller_debug_table_id; - arp_reply; - NoAction; - } - size = ICMP6_TABLE_SIZE; - default_action = controller_debug_table_id(TABLE_ARP); - } +// table v4_arp { +// key = { +// hdr.ethernet.dst_addr: exact; +// hdr.arp.opcode: exact; +// hdr.arp.dst_ipv4_addr: lpm; +// } +// actions = { +// controller_debug_table_id; +// arp_reply; +// NoAction; +// } +// size = ICMP6_TABLE_SIZE; +// default_action = controller_debug_table_id(TABLE_ARP); +// } - table v4_arp_egress { - key = { - hdr.arp.dst_ipv4_addr: lpm; - } - actions = { - controller_debug_table_id; - set_egress_port; - NoAction; - } - size = ICMP6_TABLE_SIZE; - default_action = controller_debug_table_id(TABLE_ARP_EGRESS); - } +// table v4_arp_egress { +// key = { +// hdr.arp.dst_ipv4_addr: lpm; +// } +// actions = { +// controller_debug_table_id; +// set_egress_port; +// NoAction; +// } +// size = ICMP6_TABLE_SIZE; +// default_action = controller_debug_table_id(TABLE_ARP_EGRESS); +// } // /********************** ROUTING (egress definiton) TABLES ***********************************/ diff --git a/p4src/checksum_diff.p4 b/p4src/checksum_diff.p4 new file mode 100644 index 0000000..75ec6cb --- /dev/null +++ b/p4src/checksum_diff.p4 @@ -0,0 +1,783 @@ +/* -*- P4_16 -*- */ +#include +#include + +#include "headers.p4" +#include "settings.p4" + +/************************************************************************* + * 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; + + 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); + } +} + + +/************************************************************************* +************** 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) { + + /********************** GENERAL ACTIONS ***********************************/ + + action set_egress_port (port_t out_port) { + standard_metadata.egress_spec = out_port; + } + + action controller_debug_table_id(table_t table_id) { + meta.table_id = table_id; + controller_reply(TASK_DEBUG); + } + + action controller_debug() { + controller_reply(TASK_DEBUG); + } + + /********************** 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; + + 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(); + meta.chk_ipv4 = 1; /* need to calculate the hdrchecksum */ + + /* Stuff that might need to be fixed */ + hdr.ipv4.version = (bit<4>)4; + hdr.ipv4.diff_serv = (bit<6>)0; // no ToS + hdr.ipv4.ecn = (bit<2>)0; // unsupported + + /* 5 is ok as long as we don't use options / padding / + anything after the destination address */ + hdr.ipv4.ihl = (bit<4>) 5; // internet header length: 4*5 = 20 + 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 + + /* Stuff that should be fine */ + hdr.ethernet.ethertype = TYPE_IPV4; + + hdr.ipv4.dst_addr = dst; + hdr.ipv4.src_addr = src; + + hdr.ipv4.ttl = hdr.ipv6.hop_limit; + + hdr.ipv4.protocol = hdr.ipv6.next_header; + + 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 = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + controller_debug; + nat64_static; + controller_debug_table_id; + NoAction; + } + size = NAT64_TABLE_SIZE; +// default_action = controller_debug_table_id(TABLE_NAT64); + default_action = NoAction; + } + + table nat46 { + key = { + hdr.ipv4.dst_addr: lpm; + } + actions = { + controller_debug; + nat46_static; + controller_debug_table_id; + NoAction; + } + size = NAT64_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_NAT46); + } + + /********************** NAT64 sessions ***********************************/ + + /* automatic translations */ + action nat64_tcp_session_translate( + ipv4_addr_t src_addr, + bit<16> src_port, + ipv4_addr_t dst_addr, + bit<16> dst_port) + { + hdr.ipv4.setValid(); + + hdr.tcp.src_port = src_port; + hdr.tcp.dst_port = dst_port; + + nat64_generic(src_addr, dst_addr); + } + + action nat46_tcp_session_translate( + ipv6_addr_t src_addr, + bit<16> src_port, + ipv6_addr_t dst_addr, + bit<16> dst_port) + { + hdr.ipv6.setValid(); + + hdr.tcp.src_port = src_port; + hdr.tcp.dst_port = dst_port; + + nat46_generic(src_addr, dst_addr); + } + + /* We are in the right range, need to create a session entry */ + action nat64_tcp_session_create() + { + controller_reply(TASK_NAT64_TCP_SESSION); + } + + + /* Used for detecting traffic that should have a session */ + table nat64_session { + key = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + controller_debug_table_id; + NoAction; + } + size = NAT64_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_NAT64_SESSION); + } + + + table nat64_tcp_session { + key = { + hdr.ipv6.src_addr: exact; + hdr.ipv6.dst_addr: exact; + hdr.tcp.src_port: exact; + hdr.tcp.dst_port: exact; + } + actions = { + controller_debug_table_id; + nat64_tcp_session_create; + nat64_tcp_session_translate; + NoAction; + } + size = NAT64_TABLE_SIZE; + default_action = nat64_tcp_session_create; + } + + table nat46_tcp_session { + key = { + hdr.ipv6.src_addr: exact; + hdr.ipv6.dst_addr: exact; + hdr.tcp.src_port: exact; + hdr.tcp.dst_port: exact; + } + actions = { + controller_debug_table_id; + nat46_tcp_session_translate; + NoAction; + } + size = NAT64_TABLE_SIZE; + //default_action = controller_debug_table_id(TABLE_NAT64_TCP); + default_action = NoAction; + } + + + + /********************** ICMP6 + NDP + ICMP ***********************************/ + + /* old/unused action -- is it??*/ + action icmp6_answer() { + if(hdr.icmp6.isValid()) { + if(hdr.icmp6.code == ICMP6_ECHO_REQUEST) { + ipv6_addr_t tmp = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = hdr.ipv6.dst_addr; + hdr.ipv6.dst_addr = tmp; + hdr.icmp6.code = ICMP6_ECHO_REPLY; + } + } + } + + action icmp6_neighbor_solicitation(ipv6_addr_t addr, mac_addr_t mac_addr) { + /* egress = ingress */ + standard_metadata.egress_spec = standard_metadata.ingress_port; + + /* 1. IPv6 changes */ + hdr.ipv6.dst_addr = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = addr; + + /* 2. ICMP6 changes */ + hdr.icmp6.type = ICMP6_NA; + hdr.icmp6.code = 0; + hdr.icmp6.checksum = 42; // checksum is calculated in deparser - marking with 42 to see whether it is calculated + + /* 3. icmp6/neighbor advertisement: values taken from real world answers */ + hdr.icmp6_na_ns.router = 0; + hdr.icmp6_na_ns.solicitated = 1; + hdr.icmp6_na_ns.override = 1; + hdr.icmp6_na_ns.reserved = 0; + hdr.icmp6_na_ns.target_addr = addr; + + /* 4. Link layer options */ + hdr.icmp6_option_link_layer_addr.type = ICMP6_NDP_OPT_TARGET_LL; + hdr.icmp6_option_link_layer_addr.ll_length = 1; /* 1* 64 bit */ + hdr.icmp6_option_link_layer_addr.mac_addr = mac_addr; + + /* 5. Checksum trigger/info */ + meta.chk_icmp6_na_ns = 1; + meta.cast_length = (bit<32>) hdr.ipv6.payload_length; + } + + action icmp6_echo_reply() { + mac_addr_t mac_tmp = hdr.ethernet.dst_addr; + hdr.ethernet.dst_addr = hdr.ethernet.src_addr; + hdr.ethernet.src_addr = mac_tmp; + + ipv6_addr_t addr_tmp = hdr.ipv6.dst_addr; + hdr.ipv6.dst_addr = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = addr_tmp; + + hdr.icmp6.type = ICMP6_ECHO_REPLY; + + meta.chk_icmp6 = 1; + + meta.cast_length = (bit<32>) hdr.ipv6.payload_length; + } + + table icmp6 { + key = { + hdr.ipv6.dst_addr: lpm; + hdr.icmp6.type: exact; + } + actions = { + controller_debug; + icmp6_neighbor_solicitation; + icmp6_echo_reply; + controller_debug_table_id; + NoAction; + } + size = ICMP6_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_ICMP6); + } + + action icmp_echo_reply() { + mac_addr_t mac_tmp = hdr.ethernet.dst_addr; + ipv4_addr_t ipv4_tmp = hdr.ipv4.src_addr; + + /* swap ethernet addresses */ + hdr.ethernet.dst_addr = hdr.ethernet.src_addr; + hdr.ethernet.src_addr = mac_tmp; + + /* swap ipv4 addresses */ + hdr.ipv4.src_addr = hdr.ipv4.dst_addr; + hdr.ipv4.dst_addr = ipv4_tmp; + + /* set correct type */ + hdr.icmp.type = ICMP_ECHO_REPLY; + + meta.chk_icmp = 1; + } + + table icmp { + key = { + hdr.ipv4.dst_addr: lpm; + hdr.icmp.type: exact; + } + actions = { + icmp_echo_reply; + controller_debug_table_id; + NoAction; + } + size = ICMP_TABLE_SIZE; +// default_action = controller_debug_table_id(TABLE_ICMP); + default_action = NoAction; /* do not clone on miss */ + } + + /********************** ARP ***********************************/ + + action arp_reply(mac_addr_t mac_addr) { + /* swap */ + ipv4_addr_t ipv4_src = hdr.arp.dst_ipv4_addr; + ipv4_addr_t ipv4_dst = hdr.arp.src_ipv4_addr; + + /* swap/add */ + mac_addr_t mac_src = mac_addr; + mac_addr_t mac_dst = hdr.arp.src_mac_addr; + + /* fill the ethernet header */ + hdr.ethernet.dst_addr = mac_dst; + hdr.ethernet.src_addr = mac_src; + + /* fill the arp header */ + hdr.arp.dst_mac_addr = mac_dst; + hdr.arp.src_mac_addr = mac_src; + + /* swapping */ + hdr.arp.dst_ipv4_addr = ipv4_dst; + hdr.arp.src_ipv4_addr = ipv4_src; + + hdr.arp.opcode = ARP_REPLY; + } + + table v4_arp { + key = { + hdr.ethernet.dst_addr: exact; + hdr.arp.opcode: exact; + hdr.arp.dst_ipv4_addr: lpm; + } + actions = { + controller_debug_table_id; + arp_reply; + NoAction; + } + size = ICMP6_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_ARP); + } + + table v4_arp_egress { + key = { + hdr.arp.dst_ipv4_addr: lpm; + } + actions = { + controller_debug_table_id; + set_egress_port; + NoAction; + } + size = ICMP6_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_ARP_EGRESS); + } + + + /********************** ROUTING (egress definiton) TABLES ***********************************/ + + table v6_networks { + key = { + hdr.ipv6.dst_addr: lpm; + } + actions = { + set_egress_port; + set_egress_port_and_mac; + controller_debug; + controller_reply; + controller_debug_table_id; + NoAction; + } + size = ROUTING_TABLE_SIZE; + + default_action = controller_debug_table_id(TABLE_V6_NETWORKS); + } + + table v4_networks { + key = { + hdr.ipv4.dst_addr: lpm; + } + actions = { + set_egress_port; + set_egress_port_and_mac; + controller_debug; + controller_debug_table_id; + NoAction; + } + size = ROUTING_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_V4_NETWORKS); + } + + action v4sum() { + bit<16> localsum = 0; + + localsum += hdr.ipv4.src[15:0]; // 16 bit + localsum += hdr.ipv4.src[31:16]; // 16 bit + localsum += hdr.ipv4.dst[15:0]; // 16 bit + localsum += hdr.ipv4.dst[31:16]; // 16 bit + + localsum += hdr.ipv4.totalLen -20; // 16 bit + localsum += (bit<16>) hdr.ipv4.protocol; // 8 bit + } + + action v6sum() { + bit<16> localsum = 0; + + localsum += hdr.ipv6.src[15:0]; // 16 bit + localsum += hdr.ipv6.src[31:16]; // 16 bit + localsum += hdr.ipv6.src[47:32]; // 16 bit + localsum += hdr.ipv6.src[63:48]; // 16 bit + localsum += hdr.ipv6.src[79:64]; // 16 bit + localsum += hdr.ipv6.src[95:80]; // 16 bit + localsum += hdr.ipv6.src[111:96]; // 16 bit + localsum += hdr.ipv6.src[127:112]; // 16 bit + + localsum += hdr.ipv6.dst[15:0]; // 16 bit + localsum += hdr.ipv6.dst[31:16]; // 16 bit + localsum += hdr.ipv6.dst[47:32]; // 16 bit + localsum += hdr.ipv6.dst[63:48]; // 16 bit + localsum += hdr.ipv6.dst[79:64]; // 16 bit + localsum += hdr.ipv6.dst[95:80]; // 16 bit + localsum += hdr.ipv6.dst[111:96]; // 16 bit + localsum += hdr.ipv6.dst[127:112]; // 16 bit + + localsum += hdr.ipv6.payload_length; // 16 bit + localsum += (bit<16>) hdr.ipv6.next_header; // 8 bit + } + + /********************** APPLYING TABLES ***********************************/ + 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()) { + meta.chk_udp_v6 = 1; + } + if(hdr.tcp.isValid()) { + meta.chk_tcp_v6 = 1; + } + + 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; \ No newline at end of file diff --git a/p4src/checksums.p4 b/p4src/checksums.p4 index 4537dda..e22da18 100644 --- a/p4src/checksums.p4 +++ b/p4src/checksums.p4 @@ -21,7 +21,6 @@ control MyVerifyChecksum(inout headers hdr, inout metadata meta) { control MyComputeChecksum(inout headers hdr, inout metadata meta) { apply { - update_checksum_with_payload(meta.chk_icmp6 == 1, { hdr.ipv6.src_addr, /* 128 */