diff --git a/doc/plan.org b/doc/plan.org index c0f1282..96cd285 100644 --- a/doc/plan.org +++ b/doc/plan.org @@ -9,9 +9,9 @@ | | | | | 2019-02-23 | python2 / ipaddress is buggy | x | | | p4utils is python2 only support | | -| | bmpy_utils is not installable with pip | | +| | bmpy_utils is not installable with pip | | | | python2 / latest ipaddress==1.0.22 still has the bug | | -| | ipaddress.ip_network("2001:db8:61::/64") | | +| | ipaddress.ip_network("2001:db8:61::/64") | | | | IPv6Network(u'3230:3031:3a64:6238:3a36:313a:3a2f:3634/128') | | | | | | | | egress routing | x | @@ -20,7 +20,21 @@ | | | | | | | | | 2019-02-28 | Meet Laurent #2 | | +| | - Setup base code | | | | - Parser for all protocols (udp,tcp,icmp,icmp6) | | +| | - Started with icmp translation | | +| | - Investigating into IPv6 based checksums | | +| | - Some issues with python2 (ipaddr) - slowing down | | +| | - Reading into various RFCs, NDP, MLD | | +| | - Reading about multicast / trying to figure out dynamic membership | | +| | | | +| | - Questions | | +| | * Re-using code (lee howard) | | +| | * Multicast | | +| | * A lot of redundant code / different tables / repeating | | +| | | | +| | - Next steps: | | +| | * Supporting MLD | | | | | | | | | | | 2019-02-22 | Have rough definition of tasks | | @@ -63,7 +77,7 @@ *** DONE Get feature list of tayga *** DONE Setup P4 base / structure *** DONE Create minimal controller for populating tables -*** TODO Checkout / review egress settings +*** DONE Checkout / review egress settings *** TODO Implement ICMP <-> ICMP6 translation **** DONE Parse icmp **** DONE Parse icmpv6 @@ -71,6 +85,9 @@ **** DONE Calculate ICMP6 checksums **** TODO Implement minimal neighbor discovery ***** TODO For the switch +****** DONE Register IPv6 address in table +****** TODO Parse ICMPv6 up to neighbor solicitation +****** TODO Use NDP (Neighbor Solicitation (NDP) , Neighbor Advertisement (NDP)) ***** TODO For other nodes -> multicast ***** TODO Maybe implement link local addresses (missing at the moment) ****** ff02::/?? @@ -231,6 +248,106 @@ root@ubuntu:~/master-thesis/p4app# ls -1 /proc/sys/net/ipv6/conf/*/disable_ipv6 /proc/sys/net/ipv6/conf/lo/disable_ipv6 root@ubuntu:~/master-thesis/p4app# +Works on mininet + +mininet> h2 bash +root@line:~# ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: h2-eth0@if93: mtu 1500 qdisc noqueue state UP group default qlen 1000 + link/ether 32:0e:1e:bf:3c:4b brd ff:ff:ff:ff:ff:ff link-netnsid 0 + inet 10.0.0.2/8 brd 10.255.255.255 scope global h2-eth0 + valid_lft forever preferred_lft forever + inet6 fe80::300e:1eff:febf:3c4b/64 scope link + valid_lft forever preferred_lft forever +root@line:~# ip addr add 2001:db8:61::42/64 dev h2-eth0 +root@line:~# ^Dexit +mininet> h1 bash +root@line:~# ip addr add 2001:db8:61::42/64^[[D^[[D^?^?^?^?^?^?^?^?^?^?^?^C^C +root@line:~# ^Dexit +mininet> h1 ip addr add 2001:db8:61::2/64 dev h1-eth0 +mininet> h2 ping6 -c2 2001:db8:61::2 +PING 2001:db8:61::2(2001:db8:61::2) 56 data bytes +64 bytes from 2001:db8:61::2: icmp_seq=1 ttl=64 time=0.230 ms +64 bytes from 2001:db8:61::2: icmp_seq=2 ttl=64 time=0.138 ms + +--- 2001:db8:61::2 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1018ms +rtt min/avg/max/mdev = 0.138/0.184/0.230/0.046 ms +mininet> + + +mininet on VM also works + +mininet> h1 ip addr add 2001:db8:61::1/64 dev h1-eth0 +mininet> h2 ip addr add 2001:db8:61::2/64 dev h2-eth0 +mininet> h2 ping6 -c2 2001:db8:61::2 +PING 2001:db8:61::2(2001:db8:61::2) 56 data bytes +64 bytes from 2001:db8:61::2: icmp_seq=1 ttl=64 time=0.053 ms +64 bytes from 2001:db8:61::2: icmp_seq=2 ttl=64 time=0.082 ms + +--- 2001:db8:61::2 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 999ms +rtt min/avg/max/mdev = 0.053/0.067/0.082/0.016 ms +mininet> + +WORKING trace on mininet on the VM + +19:38:49.852088 IP6 2001:db8:61::2 > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2001:db8:61::1, length 32 +19:38:49.852144 IP6 2001:db8:61::1 > 2001:db8:61::2: ICMP6, neighbor advertisement, tgt is 2001:db8:61::1, length 32 +19:38:49.852163 IP6 2001:db8:61::2 > 2001:db8:61::1: ICMP6, echo request, seq 1, length 64 +19:38:49.852176 IP6 2001:db8:61::1 > 2001:db8:61::2: ICMP6, echo reply, seq 1, length 64 + + +checking ipv6 in p4-utils + +p4@ubuntu:~/p4-utils$ grep -ri ipv6 . +./p4utils/mininetlib/p4_mininet.py: # disable IPv6 +./p4utils/mininetlib/p4_mininet.py: self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1") +./p4utils/mininetlib/p4_mininet.py: self.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1") +./p4utils/mininetlib/p4_mininet.py: self.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1") +./p4utils/mininetlib/p4net.py: #remove Ipv6 for all the interfaces +./p4utils/mininetlib/p4net.py: cmd2 = "sysctl net.ipv6.conf.{0}.disable_ipv6=1" +./p4utils/mininetlib/p4net.py: #remove ipv6 +Binary file ./p4utils/mininetlib/p4_mininet.pyc matches +Binary file ./p4utils/mininetlib/p4net.pyc matches +Binary file ./p4utils/utils/runtime_API.pyc matches +./p4utils/utils/runtime_API.py:class UIn_BadIPv6Error(UIn_Error): +./p4utils/utils/runtime_API.py:def ipv6Addr_to_bytes(addr): +./p4utils/utils/runtime_API.py: from ipaddr import IPv6Address +./p4utils/utils/runtime_API.py: ip = IPv6Address(addr) +./p4utils/utils/runtime_API.py: raise UIn_BadIPv6Error() +./p4utils/utils/runtime_API.py: raise UIn_BadIPv6Error() +./p4utils/utils/runtime_API.py: return ipv6Addr_to_bytes(input_str) +./p4utils/utils/runtime_API.py: except UIn_BadIPv6Error: +./p4utils/utils/runtime_API.py: raise UIn_BadParamError("Invalid IPv6 address") +p4@ubuntu:~/p4-utils$ + + +Messages we see in the controller on startup + +DEBUG:main:INCOMING: , ] |>] |>>>> +DEBUG:main:INCOMING: , ] |] |>>>> +DEBUG:main:INCOMING: , ] |] |>>>> +DEBUG:main:INCOMING: >>> +DEBUG:main:INCOMING: , ] |>] |>>>> +DEBUG:main:INCOMING: , ] |] |>>>> +DEBUG:main:INCOMING: , ] |>] |>>>> +DEBUG:main:INCOMING: >>> +DEBUG:main:INCOMING: , ] |>] |>>>> +DEBUG:main:INCOMING: >>> +DEBUG:main:INCOMING: >>> +DEBUG:main:INCOMING: >>> +DEBUG:main:INCOMING: >>> + +***** Ignored ICMPv6 packets +We are not using router advertisements, so we ignore RS packets +DEBUG:main:INCOMING: >>> + **** Static mappings - likely need table(s) @@ -276,6 +393,10 @@ listening on h1-eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 4 packets received by filter 0 packets dropped by kernel root@ubuntu:~/master-thesis# + + + + ***** When pinging we see DEBUG:main:INCOMING: >>> DEBUG:main:INCOMING: >>> @@ -292,12 +413,13 @@ DEBUG:main:INCOMING: "ok" + +root@ubuntu:~/master-thesis/p4app# ping6 -c1 2001:db8:61::42 +PING 2001:db8:61::42(2001:db8:61::42) 56 data bytes +From 2001:db8:61::1 icmp_seq=1 Destination unreachable: Address unreachable + +--- 2001:db8:61::42 ping statistics --- +1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms + +root@ubuntu:~/master-thesis/p4app# + + +sudo: unable to resolve host ubuntu +tcpdump: verbose output suppressed, use -v or -vv for full protocol decode +listening on h1-eth0, link-type EN10MB (Ethernet), capture size 262144 bytes +09:47:07.191569 IP6 2001:db8:61::1 > ff02::1:ff00:42: ICMP6, neighbor solicitation, who has 2001:db8:61::42, length 32 +09:47:08.190331 IP6 2001:db8:61::1 > ff02::1:ff00:42: ICMP6, neighbor solicitation, who has 2001:db8:61::42, length 32 +09:47:09.190279 IP6 2001:db8:61::1 > ff02::1:ff00:42: ICMP6, neighbor solicitation, who has 2001:db8:61::42, length 32 +*** TODO special rule for ff02::1:ff00:42 diff --git a/p4app/controller.py b/p4app/controller.py index 3cd944d..1bc1321 100644 --- a/p4app/controller.py +++ b/p4app/controller.py @@ -110,6 +110,9 @@ class L2Controller(object): self.controller.table_add("ndp", "multicast_pkg", [ndp_prefix, str(port)], [str(port)]) + # Special rule for switch entries + self.controller.table_add("ndp_answer", "icmp6_neighbor_solicitation", ["ff02::1:ff00:42", "135"], ["2001:db8:61::42"]) + def init_boilerplate(self, sw_name): self.topo = Topology(db="topology.db") self.sw_name = sw_name diff --git a/p4src/checksums.p4 b/p4src/checksums.p4 index ca4575e..842eedd 100644 --- a/p4src/checksums.p4 +++ b/p4src/checksums.p4 @@ -26,12 +26,13 @@ control MyComputeChecksum(inout headers hdr, inout metadata meta) { { hdr.ipv6.src_addr, /* 128 */ hdr.ipv6.dst_addr, /* 128 */ - hdr.ipv6.payload_length, /* 16 -> should be 32 according to RFC2460 - also static number? */ + hdr.ipv6.payload_length, /* 16 bit -> should be 32 according to RFC2460 - also static number? */ 24w0, /* 24 0's */ PROTO_ICMP6 /* 8 */ }, hdr.icmp6.checksum, - HashAlgorithm.csum16); + HashAlgorithm.csum16 + ); } } diff --git a/p4src/headers.p4 b/p4src/headers.p4 index c8f232b..aff2d62 100644 --- a/p4src/headers.p4 +++ b/p4src/headers.p4 @@ -24,6 +24,9 @@ const bit<8> TCP_SEQ_LEN = 4; const bit<8> ICMP6_ECHO_REQUEST = 128; const bit<8> ICMP6_ECHO_REPLY = 129; +const bit<8> ICMP6_NS = 135; +const bit<8> ICMP6_NA = 136; + header ethernet_t { diff --git a/p4src/static-mapping.p4 b/p4src/static-mapping.p4 index a236675..43bf7f6 100644 --- a/p4src/static-mapping.p4 +++ b/p4src/static-mapping.p4 @@ -16,18 +16,81 @@ control MyIngress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - /* use for debugging and controlling flows */ + /********************** ACTIONS ***********************************/ + + /* As the name says */ + action drop() { + mark_to_drop(); + } + + /* As the name says */ action send_to_controller() { clone3(CloneType.I2E, 100, meta); } - /********************** NDP support ***********************************/ - - /* map port to group */ + /* Output PKG on correct ports (plural) */ action multicast_pkg(mcast_t mcast_grp) { standard_metadata.mcast_grp = mcast_grp; } + action icmp6_neighbor_solicitation(ipv6_addr_t addr) { + /* egress = ingress */ + standard_metadata.egress_spec = standard_metadata.ingress_port; + + hdr.ipv6.dst_addr = hdr.ipv6.src_addr; + hdr.ipv6.src_addr = addr; + hdr.icmp6.type = ICMP6_NA; + } + + /********************** Reply to NDP for US ***********************************/ + table ndp_answer { + key = { + hdr.ipv6.dst_addr: exact; /* our multicast embedded mac address */ + hdr.icmp6.type: exact; + } + actions = { + send_to_controller; + reply_icmp6_neighbor_solicitation; + NoAction; + } + size = NDP_TABLE_SIZE; + default_action = NoAction; + } + + /********************** debugging / general support ***********************************/ + + table port2mcast { + key = { + standard_metadata.ingress_port : exact; + } + actions = { + multicast_pkg; + send_to_controller; + NoAction; + } + size = NDP_TABLE_SIZE; + default_action = NoAction; +// default_action = send_to_controller; + } + + /* Handle multicast registration of NDP */ + table addr2mcast { + key = { + hdr.ipv6.dst_addr: exact; + } + actions = { + multicast_pkg; + send_to_controller; + NoAction; + } + size = NDP_TABLE_SIZE; + default_action = NoAction; +// default_action = send_to_controller; + } + + /********************** NDP support ***********************************/ + + table ndp { key = { hdr.ipv6.dst_addr: lpm; @@ -106,9 +169,13 @@ control MyIngress(inout headers hdr, default_action = NoAction; } + /********************** APPLYING TABLES ***********************************/ apply { if(hdr.ipv6.isValid()) { + /* FIXME: structure / use .hit to do logic */ + ndp_answer.apply(); + ndp.apply(); /* flood or if it is us - answer */ v6_addresses.apply(); v6_routing.apply();