diff --git a/doc/plan.org b/doc/plan.org index 665d520..6edf710 100644 --- a/doc/plan.org +++ b/doc/plan.org @@ -111,8 +111,16 @@ | | - Create p4lang/p4-spec bug | | | | https://github.com/p4lang/p4-spec/issues/745 | | | | | | -| 2019-03-21 | Meet Laurent #4 | | -| | - My dog ate my homework | | +| 2019-03-21 | Meet Laurent #4 - post poned - sick | | +| | https://github.com/p4lang/p4-spec/issues/660 sizeof() missing | | +| | | | +| | - Need to introduce new headers | | +| | - Might need deeper parsing for icmp6_ns | | +| | - Need hwaddr in icmp6_na | | +| | - Need to find out how to handle imcp6 options after target address | | +| | | | +| | | | +| 2019-03-28 | Meet Laurent #4 | | | | - Router solicitation for finding router on startup! | | | | - test.py for TDD | | | | - Parsing icmp6 is not enough - one layer deeper | | @@ -164,6 +172,212 @@ *** DONE Setup P4 base / structure *** DONE Create minimal controller for populating tables *** DONE Checkout / review egress settings +*** TODO Implement ICMP <-> ICMP6 translation +**** DONE Parse icmp +**** DONE Parse icmpv6 +**** DONE Add (static) egress configuration +**** DONE Calculate ICMP6 checksums in controller +***** Need to include the payload!?!! +**** DONE Implement minimal neighbor discovery in controller +***** DONE For the switch +****** DONE Register IPv6 address in table +****** DONE Parse ICMPv6 up to neighbor solicitation -> no: checksum problem +****** DONE Use NDP (Neighbor Solicitation (NDP) , Neighbor Advertisement (NDP)) -> no: controller +****** Approach 2: use cpu header, forward information to controller +****** DONE Fix the ip address match/mapping: 42 -> 2a -> use hex originally +****** DONE Find out why wrong type is used -> overlapping with NDP +DEBUG:main:INCOMING: > +p=> +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Debug purpose only +DEBUG:main:INCOMING: > +p=> +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Debug purpose only +DEBUG:main:INCOMING: > +p=> +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Debug purpose only +****** Disable debug by default -> gives correct packets + +DEBUG:main:INCOMING: > +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Doing neighbor solicitation +DEBUG:main:INCOMING: > +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Doing neighbor solicitation +DEBUG:main:INCOMING: > +DEBUG:main:cpu = > +DEBUG:main:o=>>> +DEBUG:main:Doing neighbor solicitation + +***** DONE For other nodes -> multicast +***** TODO Maybe implement link local addresses (missing at the moment) +****** ff02::/?? +****** rfc4861 +"Neighbor Solicitation messages are multicast to the solicited-node +multicast address of the target address." +****** DONE multicasting / groups +******* create a group ("node") that contains "all other" ports +******* create a multicast group with an ID +******* associate the "node" with the multicast group ID +***** If destination is within ff02::1:ff00:0/104, multicast + +**** DONE Make switch answer icmp6 echo request for +**** DONE Introduce mixed mode: switch: icmp6 echo reply, controller: NDP +***** DONE try 1: reply seen, but checksum is incorrect +***** DONE try 2: analysing tagya checksumming code +static uint16_t ip6_checksum(struct ip6 *ip6, uint32_t data_len, uint8_t proto) +{ + uint32_t sum = 0; + uint16_t *p; + int i; + + for (i = 0, p = ip6->src.s6_addr16; i < 16; ++i) + sum += *p++; + sum += htonl(data_len) >> 16; + sum += htonl(data_len) & 0xffff; + sum += htons(proto); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +static uint16_t convert_cksum(struct ip6 *ip6, struct ip4 *ip4) +{ + uint32_t sum = 0; + uint16_t *p; + int i; + + sum += ~ip4->src.s_addr >> 16; + sum += ~ip4->src.s_addr & 0xffff; + sum += ~ip4->dest.s_addr >> 16; + sum += ~ip4->dest.s_addr & 0xffff; + + for (i = 0, p = ip6->src.s6_addr16; i < 16; ++i) + sum += *p++; + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + + return sum; +} +... +static int xlate_payload_4to6(struct pkt *p, struct ip6 *ip6) +{ + uint16_t *tck; + uint16_t cksum; + + if (p->ip4->flags_offset & htons(IP4_F_MASK)) + return 0; + + switch (p->data_proto) { + case 1: + cksum = ip6_checksum(ip6, htons(p->ip4->length) - + p->header_len, 58); + cksum = ones_add(p->icmp->cksum, cksum); + if (p->icmp->type == 8) { + p->icmp->type = 128; + p->icmp->cksum = ones_add(cksum, ~(128 - 8)); + } else { + p->icmp->type = 129; + p->icmp->cksum = ones_add(cksum, ~(129 - 0)); + } + return 0; +**** DONE Add default route for v6 hosts +p4@ubuntu:~/master-thesis$ mx h1 ip -6 r +sudo: unable to resolve host ubuntu +2001:db8::/64 dev h1-eth0 proto kernel metric 256 pref medium +fe80::/64 dev h1-eth0 proto kernel metric 256 pref medium +default via 2001:db8::42 dev h1-eth0 metric 1024 pref medium +p4@ubuntu:~/master-thesis$ +**** Implement IPv4 side handling +***** TODO Make switch answer icmp echo request for +***** TODO Add default route for v4 hosts +**** TODO Translate ipv6 --> ipv4 with a (freely programmable) prefix +***** DONE Insert prefix into switch: v6_networks +***** TODO Support multiple ipv6 source networks: need new table w/ 2 keys! -> later +***** DONE Write test.py to generate correct destination packets +>>> a = ipaddress.ip_network("2001:db8::/32") +>>> b = ipaddress.ip_address("10.0.0.1") +>>> a[int(b)] +IPv6Address('2001:db8::a00:1') +***** Using test.py, new NDP packets been seen, bur zero icmp on the outgoing side +p4@ubuntu:~/master-thesis/p4app$ python test.py --method v6_static_mapping --debug +INFO:main:Trying to reach 10.0.0.1 (64:ff9b::a00:1) from h1 +sudo: unable to resolve host ubuntu +PING 64:ff9b::a00:1(64:ff9b::a00:1) 56 data bytes + +--- 64:ff9b::a00:1 ping statistics --- +1 packets transmitted, 0 received, 100% packet loss, time 0ms + +p4@ubuntu:~/master-thesis/p4app$ +\x00\x00\x00 :\xff\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x00\n\xff\xfe\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x87\x00\x08+\x00\x00\x00\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x01\x01\x00\x00\n\x00\x00\x01' |>> +DEBUG:main:cpu = > +DEBUG:main:reassambled=>>> +DEBUG:main:INCOMING: > +DEBUG:main:cpu = > +DEBUG:main:reassambled=>>> +DEBUG:main:INCOMING: > +DEBUG:main:cpu = > +DEBUG:main:reassambled=>>> + +***** DONE Debug why neighbor discover does not work anymore +****** log + p4@ubuntu:~$ mx h1 tcpdump -lni any + sudo: unable to resolve host ubuntu + tcpdump: verbose output suppressed, use -v or -vv for full protocol decode + listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes + + 19:57:53.258805 IP6 fe80::200:aff:fe00:1 > ff02::1:ff00:42: ICMP6, neighbor solicitation, who has 2001:db8::42, length 32 + 19:57:54.256924 IP6 2001:db8::1 > 2001:db8::1: ICMP6, destination unreachable, unreachable address 64:ff9b::a00:1, length 112 + + EBUG:main:INCOMING: > + DEBUG:main:cpu = > + DEBUG:main:reassambled=>>> + INFO:main:Doing neighbor solicitation + DEBUG:main:OUTGOING: >>> + DEBUG:main:INCOMING: >>> + + + After removing noise: + + DEBUG:main:reassambled=>>> + DEBUG:main:reassambled=>>> + DEBUG:main:reassambled=>>> + DEBUG:main:reassambled=>>> + DEBUG:main:reassambled=>>> + +****** Do we have routing for fe80::/10? Probably not. Shouldn't we see it in the controller then? +****** NDP is controller only! +***** TODO Finish NDP in switch +****** TODO Need to set R/S/O bits +****** TODO Need to parse R/S/O bits +***** TODO Maybe merge v6_address and v6_networks - /128 is the same +***** TODO Implement address learning? +***** TODO Not sure whether we should react on router solicitation + - Using static routes -> should do the job +***** TODO Implement the calculation +***** TODO Sketch the flow for session handling for icmp6 w/o packet loss + - switch receives icmp6 packet for known prefix + - controller needs to create session entry (?) + +**** TODO Translate icmp <-> icmp6 +**** TODO Create table entry for mapping v4->v6 [net] +**** TODO Create table entry for mapping v6->v4 [net] *** TODO Get p4 VM / vagrant running **** DONE install libvirtd-daemon **** DONE install ebtables @@ -598,212 +812,6 @@ strace: Process 20620 detached Please make sure that it is installed and available in your $PATH: (/home/nico/vcs/master-thesis/support/virtualenv-with-site/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/nico/vcs/master-thesis/support/p4c/build/) (virtualenv-with-site) root@line:/home/nico/vcs/master-thesis/p4app# -*** TODO Implement ICMP <-> ICMP6 translation -**** DONE Parse icmp -**** DONE Parse icmpv6 -**** DONE Add (static) egress configuration -**** DONE Calculate ICMP6 checksums in controller -***** Need to include the payload!?!! -**** DONE Implement minimal neighbor discovery in controller -***** DONE For the switch -****** DONE Register IPv6 address in table -****** DONE Parse ICMPv6 up to neighbor solicitation -> no: checksum problem -****** DONE Use NDP (Neighbor Solicitation (NDP) , Neighbor Advertisement (NDP)) -> no: controller -****** Approach 2: use cpu header, forward information to controller -****** DONE Fix the ip address match/mapping: 42 -> 2a -> use hex originally -****** DONE Find out why wrong type is used -> overlapping with NDP -DEBUG:main:INCOMING: > -p=> -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Debug purpose only -DEBUG:main:INCOMING: > -p=> -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Debug purpose only -DEBUG:main:INCOMING: > -p=> -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Debug purpose only -****** Disable debug by default -> gives correct packets - -DEBUG:main:INCOMING: > -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Doing neighbor solicitation -DEBUG:main:INCOMING: > -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Doing neighbor solicitation -DEBUG:main:INCOMING: > -DEBUG:main:cpu = > -DEBUG:main:o=>>> -DEBUG:main:Doing neighbor solicitation - -***** DONE For other nodes -> multicast -***** TODO Maybe implement link local addresses (missing at the moment) -****** ff02::/?? -****** rfc4861 -"Neighbor Solicitation messages are multicast to the solicited-node -multicast address of the target address." -****** DONE multicasting / groups -******* create a group ("node") that contains "all other" ports -******* create a multicast group with an ID -******* associate the "node" with the multicast group ID -***** If destination is within ff02::1:ff00:0/104, multicast - -**** DONE Make switch answer icmp6 echo request for -**** DONE Introduce mixed mode: switch: icmp6 echo reply, controller: NDP -***** DONE try 1: reply seen, but checksum is incorrect -***** DONE try 2: analysing tagya checksumming code -static uint16_t ip6_checksum(struct ip6 *ip6, uint32_t data_len, uint8_t proto) -{ - uint32_t sum = 0; - uint16_t *p; - int i; - - for (i = 0, p = ip6->src.s6_addr16; i < 16; ++i) - sum += *p++; - sum += htonl(data_len) >> 16; - sum += htonl(data_len) & 0xffff; - sum += htons(proto); - - while (sum > 0xffff) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - -static uint16_t convert_cksum(struct ip6 *ip6, struct ip4 *ip4) -{ - uint32_t sum = 0; - uint16_t *p; - int i; - - sum += ~ip4->src.s_addr >> 16; - sum += ~ip4->src.s_addr & 0xffff; - sum += ~ip4->dest.s_addr >> 16; - sum += ~ip4->dest.s_addr & 0xffff; - - for (i = 0, p = ip6->src.s6_addr16; i < 16; ++i) - sum += *p++; - - while (sum > 0xffff) - sum = (sum & 0xffff) + (sum >> 16); - - return sum; -} -... -static int xlate_payload_4to6(struct pkt *p, struct ip6 *ip6) -{ - uint16_t *tck; - uint16_t cksum; - - if (p->ip4->flags_offset & htons(IP4_F_MASK)) - return 0; - - switch (p->data_proto) { - case 1: - cksum = ip6_checksum(ip6, htons(p->ip4->length) - - p->header_len, 58); - cksum = ones_add(p->icmp->cksum, cksum); - if (p->icmp->type == 8) { - p->icmp->type = 128; - p->icmp->cksum = ones_add(cksum, ~(128 - 8)); - } else { - p->icmp->type = 129; - p->icmp->cksum = ones_add(cksum, ~(129 - 0)); - } - return 0; -**** DONE Add default route for v6 hosts -p4@ubuntu:~/master-thesis$ mx h1 ip -6 r -sudo: unable to resolve host ubuntu -2001:db8::/64 dev h1-eth0 proto kernel metric 256 pref medium -fe80::/64 dev h1-eth0 proto kernel metric 256 pref medium -default via 2001:db8::42 dev h1-eth0 metric 1024 pref medium -p4@ubuntu:~/master-thesis$ -**** Implement IPv4 side handling -***** TODO Make switch answer icmp echo request for -***** TODO Add default route for v4 hosts -**** TODO Translate ipv6 --> ipv4 with a (freely programmable) prefix -***** DONE Insert prefix into switch: v6_networks -***** TODO Support multiple ipv6 source networks: need new table w/ 2 keys! -> later -***** DONE Write test.py to generate correct destination packets ->>> a = ipaddress.ip_network("2001:db8::/32") ->>> b = ipaddress.ip_address("10.0.0.1") ->>> a[int(b)] -IPv6Address('2001:db8::a00:1') -***** Using test.py, new NDP packets been seen, bur zero icmp on the outgoing side -p4@ubuntu:~/master-thesis/p4app$ python test.py --method v6_static_mapping --debug -INFO:main:Trying to reach 10.0.0.1 (64:ff9b::a00:1) from h1 -sudo: unable to resolve host ubuntu -PING 64:ff9b::a00:1(64:ff9b::a00:1) 56 data bytes - ---- 64:ff9b::a00:1 ping statistics --- -1 packets transmitted, 0 received, 100% packet loss, time 0ms - -p4@ubuntu:~/master-thesis/p4app$ -\x00\x00\x00 :\xff\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x00\n\xff\xfe\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x87\x00\x08+\x00\x00\x00\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x01\x01\x00\x00\n\x00\x00\x01' |>> -DEBUG:main:cpu = > -DEBUG:main:reassambled=>>> -DEBUG:main:INCOMING: > -DEBUG:main:cpu = > -DEBUG:main:reassambled=>>> -DEBUG:main:INCOMING: > -DEBUG:main:cpu = > -DEBUG:main:reassambled=>>> - -***** DONE Debug why neighbor discover does not work anymore -****** log - p4@ubuntu:~$ mx h1 tcpdump -lni any - sudo: unable to resolve host ubuntu - tcpdump: verbose output suppressed, use -v or -vv for full protocol decode - listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes - - 19:57:53.258805 IP6 fe80::200:aff:fe00:1 > ff02::1:ff00:42: ICMP6, neighbor solicitation, who has 2001:db8::42, length 32 - 19:57:54.256924 IP6 2001:db8::1 > 2001:db8::1: ICMP6, destination unreachable, unreachable address 64:ff9b::a00:1, length 112 - - EBUG:main:INCOMING: > - DEBUG:main:cpu = > - DEBUG:main:reassambled=>>> - INFO:main:Doing neighbor solicitation - DEBUG:main:OUTGOING: >>> - DEBUG:main:INCOMING: >>> - - - After removing noise: - - DEBUG:main:reassambled=>>> - DEBUG:main:reassambled=>>> - DEBUG:main:reassambled=>>> - DEBUG:main:reassambled=>>> - DEBUG:main:reassambled=>>> - -****** Do we have routing for fe80::/10? Probably not. Shouldn't we see it in the controller then? -****** NDP is controller only! -***** TODO Finish NDP in switch -****** TODO Need to set R/S/O bits -****** TODO Need to parse R/S/O bits -***** TODO Maybe merge v6_address and v6_networks - /128 is the same -***** TODO Implement address learning? -***** TODO Not sure whether we should react on router solicitation - - Using static routes -> should do the job -***** TODO Implement the calculation -***** TODO Sketch the flow for session handling for icmp6 w/o packet loss - - switch receives icmp6 packet for known prefix - - controller needs to create session entry (?) - -**** TODO Translate icmp <-> icmp6 -**** TODO Create table entry for mapping v4->v6 [net] -**** TODO Create table entry for mapping v6->v4 [net] *** TODO Setup test VM [dual stack] for Jool: *** TODO Setup test VM [dual stack] for tayga: *** NAT64/NAT46 Features in jool and tayga @@ -1204,7 +1212,18 @@ Currently offset based - probably not following the RFC! ***** No DNS64 has already been solved in a different domain - could even do transparent / in network modification - +***** Incomplete NDP + Very limited option support +*** Setting up a system for working on P4 on devuan +**** Scripts in the wild + https://github.com/nsg-ethz/p4-learning/blob/master/vm/bin/update-p4c.sh + https://github.com/jafingerhut/p4-guide/blob/master/bin/install-p4dev-p4runtime.sh + https://github.com/nsg-ethz/p4-learning/tree/master/vm/bin +**** mininet +**** bmv2 +[21:24] line:~% sudo apt install libthrift-dev +[21:26] line:~% sudo apt install thrift-compiler +libnanomsg-dev libjudy-dev *** References / Follow up **** RFC 2460 IPv6 (Checksum https://tools.ietf.org/html/rfc2460#section-8.1) **** RFC 3810 MLD2 https://tools.ietf.org/html/rfc3810 diff --git a/p4src/headers.p4 b/p4src/headers.p4 index 81a0e43..8a93b72 100644 --- a/p4src/headers.p4 +++ b/p4src/headers.p4 @@ -37,7 +37,7 @@ const task_t TASK_ICMP6_GENERAL = 2; const task_t TASK_DEBUG = 3; const task_t TASK_ICMP6_REPLY = 4; - +/* 48+48+16 = 112 */ header ethernet_t { mac_addr_t dst_addr; mac_addr_t src_addr; @@ -60,7 +60,10 @@ header ipv4_t { ipv4_addr_t dst_addr; } -/* https://en.wikipedia.org/wiki/IPv6_packet */ +/* +https://en.wikipedia.org/wiki/IPv6_packet +64 + 256 = 320 +*/ header ipv6_t { bit<4> version; bit<8> traffic_class; @@ -105,12 +108,25 @@ header icmp6_t { bit<16> checksum; } +/* + https://tools.ietf.org/html/rfc4861#section-4.4 +*/ +header icmp6_na_ns_t { + bit<1> router; + bit<1> solicitated; + bit<1> override; + bit<29> reserved; + ipv6_addr_t target_addr; +} + header icmp_t { bit<8> type; bit<8> code; bit<16> checksum; + bit<32> rest; } + header cpu_t { task_t task; bit<16> ingress_port; @@ -123,9 +139,10 @@ struct headers { ipv6_t ipv6; tcp_t tcp; udp_t udp; - icmp6_t icmp6; icmp_t icmp; cpu_t cpu; + icmp6_t icmp6; + icmp6_na_ns_t icmp6_na_ns; } struct metadata { diff --git a/p4src/parsers.p4 b/p4src/parsers.p4 index 66f99bd..44a11ae 100644 --- a/p4src/parsers.p4 +++ b/p4src/parsers.p4 @@ -46,17 +46,20 @@ parser MyParser(packet_in packet, } } - /* state icmp6 { packet.extract(hdr.icmp6); transition select(hdr.ipv6.next_header){ - ICMP6_NS: + ICMP6_NS: icmp6_neighbor_solicitation; default: accept; } } - state icmp6_neighbor_solicitation { - } */ + state icmp6_neighbor_solicitation { + packet.extract(hdr.icmp6_na_ns); + transition accept; + + } + /* Leaf */ state tcp { @@ -69,10 +72,10 @@ parser MyParser(packet_in packet, transition accept; } - state icmp6 { - packet.extract(hdr.icmp6); - transition accept; - } + // state icmp6 { + // packet.extract(hdr.icmp6); + // transition accept; + // } state icmp { packet.extract(hdr.icmp); @@ -101,7 +104,10 @@ control MyDeparser(packet_out packet, in headers hdr) { 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); } } diff --git a/p4src/static-mapping.p4 b/p4src/static-mapping.p4 index 2cd7cf1..2189c5a 100644 --- a/p4src/static-mapping.p4 +++ b/p4src/static-mapping.p4 @@ -42,7 +42,7 @@ control MyIngress(inout headers hdr, standard_metadata.mcast_grp = mcast_grp; } - action icmp6_neighbor_solicitation(ipv6_addr_t addr) { + action icmp6_neighbor_solicitation(ipv6_addr_t addr, mac_addr_t hwaddr) { /* egress = ingress */ standard_metadata.egress_spec = standard_metadata.ingress_port; @@ -50,6 +50,16 @@ control MyIngress(inout headers hdr, hdr.ipv6.src_addr = addr; hdr.icmp6.type = ICMP6_NA; + /* ether + ipv6 + icmp6 */ + ipv6_addr_t tgt_addr = + + truncate((bit<32>)(112 + 320 + 32)/8); + hdr.icmp6_na.setValid(); + + hdr.icmp6_na.solicitated = 1; + hdr.icmp6_na.override = 1; + + /* checksum trigger / content */ meta.do_cksum = 1; meta.cast_length = (bit<32>) hdr.ipv6.payload_length;