From 07f0867175323b2a1a746522a33731af9906800c Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 31 Mar 2019 15:48:00 +0200 Subject: [PATCH] Begin to introduce arp support --- doc/plan.org | 29 ++++++++++++++++++++++++++--- p4app/controller.py | 21 +++++++++++++++++++-- p4src/headers.p4 | 23 +++++++++++++++++++++++ p4src/static-mapping.p4 | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 100 insertions(+), 7 deletions(-) diff --git a/doc/plan.org b/doc/plan.org index 1d6e8b6..b1ac5c0 100644 --- a/doc/plan.org +++ b/doc/plan.org @@ -603,7 +603,7 @@ root@ubuntu:~# ip r default via 10.0.0.66 dev h3-eth0 10.0.0.0/24 dev h3-eth0 proto kernel scope link src 10.0.0.1 root@ubuntu:~# -***** TODO try6: host sees packet, but does not react on it +***** DONE try6: host sees packet, but does not react on it, manually tring gateway ping p4@ubuntu:~$ mx h3 tcpdump -lni h3-eth0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode @@ -630,9 +630,31 @@ no arp entries: root@ubuntu:~# arp -an root@ubuntu:~# +root@ubuntu:~# ping -c1 10.0.0.66 +PING 10.0.0.66 (10.0.0.66) 56(84) bytes of data. +From 10.0.0.1 icmp_seq=1 Destination Host Unreachable -***** TODO Implement default route handling, maybe implement ARP -****** +--- 10.0.0.66 ping statistics --- +1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms + +root@ubuntu:~# + +***** DONE try7: checkout dump from ping4_gw-2019-03-31-0916-h3.pcap: regular arp +***** TODO Get a real world arp trace +root@line:/home/nico/vcs/master-thesis/pcap# tcpdump -ni wlan0 -w ping4_realworld_p7 icmp or arp or host 192.168.4.1 +tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes +root@line:~# arp -an +? (192.168.4.188) at 00:0d:b9:46:3b:d4 [ether] on wlan0 +root@line:~# ping -c1 192.168.4.1 +PING 192.168.4.1 (192.168.4.1) 56(84) bytes of data. +64 bytes from 192.168.4.1: icmp_seq=1 ttl=64 time=15.5 ms + +--- 192.168.4.1 ping statistics --- +1 packets transmitted, 1 received, 0% packet loss, time 0ms +rtt min/avg/max/mdev = 15.533/15.533/15.533/0.000 ms +root@line:~# + +***** TODO Implement default route handling, maybe implement ARP? ****** Entry in v4_networks? **** DONE Add table name support in debug messages **** DONE Why getting IPv6 packets in @@ -1726,6 +1748,7 @@ used only in one network. *** References / Follow up **** RFC 791 IPv4 https://tools.ietf.org/html/rfc791 **** RFC 792 ICMP https://tools.ietf.org/html/rfc792 +**** RFC 826 ARP https://tools.ietf.org/html/rfc826 **** RFC 1017 ICMP checksum https://tools.ietf.org/html/rfc1071 **** 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/p4app/controller.py b/p4app/controller.py index 6c11104..0c74fd2 100755 --- a/p4app/controller.py +++ b/p4app/controller.py @@ -35,7 +35,8 @@ table_id_fields = { 2: 'TABLE_ICMP6', 3: 'TABLE_V6_NETWORKS', 4: 'TABLE_NAT46', - 5: 'TABLE_V4_NETWORKS' + 5: 'TABLE_V4_NETWORKS', + 6: 'TABLE_ARP' } table_proto = { @@ -47,6 +48,10 @@ table_proto = { 'ICMP_ECHO_REQUEST' : 8 } +table_arp = { + 'ARP_REQUEST': 1, + 'ARP_REPLY': 2 +} class CpuHeader(Packet): @@ -72,6 +77,7 @@ class L2Controller(object): # https://en.wikipedia.org/wiki/Solicited-node_multicast_address self.info['ndp_multicast'] = ipaddress.ip_network("ff02::1:ff00:0/104") self.info['mac_addr'] = "00:00:0a:00:00:42" + self.info['mac_broadcast'] = "ff:ff:ff:ff:ff:ff:ff" self.info['ipv6_link_local'] = ipaddress.ip_address("fe80::200:aff:fe00:42") self.info['v6_mask'] = 64 @@ -234,6 +240,9 @@ class L2Controller(object): [str(icmp6_net), str(icmp6_type)], []) + def ipv4_router(self, net): + return net[self.info['switch_suffix']] + def fill_tables(self): self.controller.table_clear("v6_networks") for v6route in self.v6_routes[self.mode]: @@ -243,6 +252,14 @@ class L2Controller(object): for v4route in self.v4_routes[self.mode]: self.controller.table_add("v4_networks", "set_egress_port", [str(v4route['net'])], [str(v4route['port'])]) + # ARP support + router = "{}/32".format(self.ipv4_router(v4route['net'])) + self.controller.table_add("v4_arp", "arp_reply", + [str(self.info['mac_broadcast']), + str(table_arp['ARP_REQUEST']), + router], + [str(self.info['mac_addr'])] + if self.args.multicast_to_controller: self.listen_to_icmp6_multicast() @@ -304,7 +321,7 @@ class L2Controller(object): dev = "{}-eth0".format(host) net = v4route['net'] ipaddr = "{}/{}".format(net[1],net.prefixlen) - router = str(net[self.info['switch_suffix']]) + router = self.ipv4_router(net) self.config_v4_host(host, str(net), str(ipaddr), dev, router) diff --git a/p4src/headers.p4 b/p4src/headers.p4 index a8271a7..270a4d1 100644 --- a/p4src/headers.p4 +++ b/p4src/headers.p4 @@ -5,6 +5,8 @@ #include #include +/**************************************** types ****************************************/ + typedef bit<48> mac_addr_t; typedef bit<32> ipv4_addr_t; typedef bit<128> ipv6_addr_t; @@ -13,11 +15,14 @@ typedef bit<16> mcast_t; typedef bit<16> task_t; typedef bit<16> table_t; /* to map debug messages - 16 bit to match shortenumfield */ +/**************************************** constants ****************************************/ + const bit<16> TABLE_NAT64 = 1; const bit<16> TABLE_ICMP6 = 2; const bit<16> TABLE_V6_NETWORKS = 3; const bit<16> TABLE_NAT46 = 4; const bit<16> TABLE_V4_NETWORKS = 5; +const bit<16> TABLE_ARP = 6; const bit<16> TYPE_IPV4 = 0x0800; @@ -41,6 +46,8 @@ const bit<8> ICMP6_NA = 136; const bit<8> ICMP_ECHO_REPLY = 0; const bit<8> ICMP_ECHO_REQUEST = 8; +const bit<16> ARP_REQUEST = 1; +const bit<16> ARP_REPLY = 2; /* RFC4861, Section 4.6 */ const bit<8> ICMP6_NDP_OPT_SOURCE_LL = 1; @@ -58,6 +65,8 @@ const task_t TASK_CHECKSUM_ICMP6 = 5; /* data plane */ const task_t TASK_CHECKSUM_ICMP6_NA = 6; /* data plane */ const task_t TASK_CHECKSUM_ICMP = 7; /* data plane */ +/**************************************** header ****************************************/ + /* 48+48+16 = 112 */ header ethernet_t { @@ -154,6 +163,17 @@ header icmp_t { bit<16> checksum; } +header arp_t { + bit<16> hw_type; + bit<16> protocol; + bit<8> hw_size; + bit<8> protocol_size; + bit<16> opcode; + mac_addr_t src_mac_addr; + ipv4_addr_t src_ipv4_addr; + mac_addr_t dst_mac_addr; + ipv4_addr_t dst_ipv4_addr; +} header cpu_t { task_t task; @@ -162,6 +182,8 @@ header cpu_t { table_t table_id; } +/**************************************** struct ****************************************/ + struct headers { ethernet_t ethernet; ipv4_t ipv4; @@ -175,6 +197,7 @@ struct headers { icmp6_option_link_layer_addr_t icmp6_option_link_layer_addr; } + struct metadata { port_t ingress_port; task_t task; diff --git a/p4src/static-mapping.p4 b/p4src/static-mapping.p4 index c0609a7..1aeaf04 100644 --- a/p4src/static-mapping.p4 +++ b/p4src/static-mapping.p4 @@ -225,7 +225,7 @@ Echo or Echo Reply Message } - /********************** ICMP6 ***********************************/ + /********************** ICMP6 + NDP ***********************************/ /* old/unused action */ action icmp6_answer() { @@ -329,7 +329,36 @@ Echo or Echo Reply Message // } // size = NDP_TABLE_SIZE; // default_action = NoAction; - // } + // } + + /********************** ARP ***********************************/ + + action arp_reply(mac_addr_t mac_addr) { + ipv4_addr_t tmp = hdr.arp.src_ipv4_addr; + + hdr.arp.src_mac_addr = mac_addr; + hdr.arp.src_ipv4_addr = hdr.arp.dst_ipv4_addr; + + hdr.arp.dst_mac_addr = hdr.arp.src_mac_addr; + hdr.arp.dst_ipv4_addr = tmp; + + 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; + NoAction; + } + size = ICMP6_TABLE_SIZE; + default_action = controller_debug_table_id(TABLE_ARP); + } + /********************** ROUTING (egress definiton) TABLES ***********************************/ @@ -400,6 +429,7 @@ Echo or Echo Reply Message v6_networks.apply(); exit; } + v4_arp.apply(); v4_networks.apply(); /* regular routing, egress */ } }