From c7d2ee96cf33f304424f39761e67d1ee5b70033e Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Mon, 10 Mar 2014 17:49:47 -0700 Subject: [PATCH 1/8] Changed simple_eth_pkt minsize from 60 to 68 Minimum legal frame size is 68 not 60 ... grr. --- src/python/oftest/testutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/oftest/testutils.py b/src/python/oftest/testutils.py index 5b2e36518..ceee12588 100644 --- a/src/python/oftest/testutils.py +++ b/src/python/oftest/testutils.py @@ -425,7 +425,7 @@ def simple_arp_packet(pktlen=60, return pkt -def simple_eth_packet(pktlen=60, +def simple_eth_packet(pktlen=68, eth_dst='00:01:02:03:04:05', eth_src='00:06:07:08:09:0a', eth_type=0x88cc): From d1a383e2e2f94ef3bed8564d678805df00f9b314 Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Fri, 2 Oct 2015 15:15:33 -0700 Subject: [PATCH 2/8] Initial code to test an L3 Legacy Router Yes, it's not OpenFlow, but OFTest provides a lot of useful packet processing capabilities for dataplane and control plane merged testing (the "C-Clamp" architecture). First test is "do all of the interfaces ping?" --- tests-legacy-l3/README.md | 12 +++ tests-legacy-l3/l3.py | 152 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tests-legacy-l3/README.md create mode 100644 tests-legacy-l3/l3.py diff --git a/tests-legacy-l3/README.md b/tests-legacy-l3/README.md new file mode 100644 index 000000000..c5a1799fa --- /dev/null +++ b/tests-legacy-l3/README.md @@ -0,0 +1,12 @@ +These tests are for testing a traditional routing box, e.g., running +FaceBook's FBOSS or a netlink listenner like Open Route Cache (ORC). + +While OFTest is meant to test openflow switches, a lot of the same +infrastructure gets reused, so we've decided to keep these +tests in OFTest even though they are not strictly speaking *OpenFlow* +tests. + +To run, do something like: + +sudo ./oft --test-dir=tests-legacy-l3/ --verbose + diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py new file mode 100644 index 000000000..976b63dd4 --- /dev/null +++ b/tests-legacy-l3/l3.py @@ -0,0 +1,152 @@ +""" +Test cases to verify a black box L3 router, e.g. ORC, FBOSS, etc. + +Simple dataplane things like +* "can you ping the interfaces" +* "does the router arp correctly for end points" +* "does the router correctly change MACs and dec TTL" + + +""" + +import copy +import logging +import time +import unittest +import random +import pdb + +import scapy.all as scapy + +import ofp +from oftest import config +import oftest.controller as controller +import oftest.base_tests as base_tests +import oftest.testutils as testutils + + + +class BasicL3Test(base_tests.DataPlaneOnly): + """ + Bottom of inheritance stack + """ + + # port # --> L3 interface mapping +# Interfaces = { +# 1 : "172.31.1.1", +# 2 : "172.31.2.1", +# 3 : "172.31.3.1", +# 4 : "172.31.4.1" +# } + Interfaces = { + 1 : "169.254.0.10", + 2 : "169.254.0.10", + 3 : "169.254.0.10", + 4 : "169.254.0.10" + } + + def pkt_smart_cmp(self, expected=None, recv=None): + """ + @param expected an Ether() object from scapy + @param recv an Ether() object from scapy + @return boolean true iff the relevant fields of + the packet match, e.g., ignoring IP.ID + IP.chksum, and if there are weird trailers + (including checksum) match between the two packets + """ + if expected is None or recv is None: + self.fail("Error: pkt_cmp_no_id() called with None parameters") + p1 = scapy.Ether(str(expected)) # make duplicate copies of pkts + p2 = scapy.Ether(str(recv)) + if p1.type != p2.type: + return False # not same ethertype + #pdb.set_trace() + if p1.type == 0x0800: # if IP, remove ID, chksum + ip1 = p1.payload + ip2 = p2.payload + del ip1.id + del ip2.id + del ip1.chksum + del ip2.chksum + return str(p1)[:ip1.len] == str(p2)[:ip2.len] + + + def same_slash24_subnet(self, ip): + """ + @param ip is a string of the form 'w.x.y.z', e.g. "192.168.1.1" + @return the ip 'w.x.y.z+1' , e.g., "192.168.1.2" + """ + quad = ip.split('.') + return "%s.%s.%s.%d" % ( quad[0], quad[1], quad[2], int(quad[3])+1) + + +class PingInterfacesL3(BasicL3Test): + + def runTest(self): + ports = config["port_map"].keys() + ports.sort() + for port in ports : + if port not in self.Interfaces: + logging.info("Skipping port %d -- not IP interface defined" % port) + continue + dst_ip = self.Interfaces[port] + src_ip = self.same_slash24_subnet(dst_ip) + src_mac = "00:11:22:33:44:%2d" % port + # first arp for the interface + arp = testutils.simple_arp_packet( + eth_src = src_mac, + hw_snd = src_mac, + ip_snd = src_ip, + ip_tgt = dst_ip) + + logging.info("ARP request packet for %s out port %d " % + ( dst_ip, port)) + logging.debug("Data: " + str(arp).encode('hex')) + self.dataplane.send(port, str(arp)) + arp_found = False + start_time = time.time() + dst_mac = None + while not arp_found: + timeout = (start_time + 3) - time.time() # timeout after 3 seconds total + if timeout <= 0: + logging.error("Timeout on ARP reply for port %d" % port) + self.fail("Timeout on ARP for port %d" % port) + (rcv_port, pkt, t) = self.dataplane.poll(port_number = port, timeout = timeout) + if pkt is not None: # if is none, then we will loop and immediately timeout + parsed_pkt = scapy.Ether(pkt) + if (parsed_pkt is not None and + type(parsed_pkt.payload) == scapy.ARP and + parsed_pkt.payload.op == 2): # 2 == reply + arp_found = True + dst_mac = parsed_pkt.payload.hwsrc + logging.info("Learned via ARP: MAC %s neighbor to port %d" % + ( dst_mac, port)) + ping = testutils.simple_icmp_packet(ip_dst = dst_ip, # request + ip_src = src_ip, + eth_dst = dst_mac, + eth_src = src_mac + ) + pong = testutils.simple_icmp_packet(ip_dst = src_ip, # reply + ip_src = dst_ip, + eth_dst = src_mac, + eth_src = dst_mac, + ip_ttl = 63, + icmp_type = 0, # type = echo reply + icmp_code = 0 # echo reply + ) + logging.info("Sending ping to %s out port %d" % (dst_ip, port)) + logging.debug("Data: " + str(ping).encode('hex')) + logging.debug("Expecting: " + str(ping).encode('hex')) + #scapy.hexdump(pong) + self.dataplane.send(port, str(ping)) + start_time = time.time() + pong_found = False + while not pong_found: + timeout = (start_time + 3) - time.time() + if timeout <= 0: + logging.error("Timeout on PING reply for port %d" % port) + self.fail("Timeout on PING for port %d" % port) + (rcv_port, rcv_pkt, t) = self.dataplane.poll(port_number = port, timeout=timeout) + if rcv_pkt is not None: + pong_found = self.pkt_smart_cmp(expected=pong, recv=scapy.Ether(rcv_pkt)) + From d547bbd1e970d8702552493f0513e541a178945f Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Thu, 12 Nov 2015 15:45:51 -0800 Subject: [PATCH 3/8] Fixed the 'ping the interfaces' test --- tests-legacy-l3/l3.py | 36 +- tests-legacy-l3/ocp-demo.json | 1017 +++++++++++++++++++++++++++++++++ 2 files changed, 1040 insertions(+), 13 deletions(-) create mode 100644 tests-legacy-l3/ocp-demo.json diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index 976b63dd4..42427f84a 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -32,26 +32,30 @@ class BasicL3Test(base_tests.DataPlaneOnly): """ # port # --> L3 interface mapping -# Interfaces = { -# 1 : "172.31.1.1", -# 2 : "172.31.2.1", -# 3 : "172.31.3.1", -# 4 : "172.31.4.1" -# } Interfaces = { - 1 : "169.254.0.10", - 2 : "169.254.0.10", - 3 : "169.254.0.10", - 4 : "169.254.0.10" +# 1 : "169.254.0.10", +# 2 : "169.254.0.10", +# 3 : "169.254.0.10", +# 4 : "169.254.0.10", + 1 : "172.31.1.1", + 2 : "172.31.2.1", + 3 : "172.31.3.1", + 4 : "172.31.4.1", + 5 : "172.31.5.1", + 6 : "172.31.6.1", } - def pkt_smart_cmp(self, expected=None, recv=None): + + def pkt_smart_cmp(self, expected=None, recv=None, ttl=True): """ @param expected an Ether() object from scapy @param recv an Ether() object from scapy @return boolean true iff the relevant fields of the packet match, e.g., ignoring IP.ID - IP.chksum, and if there are weird trailers + IP.chksum, IP.ttl and if there are weird trailers + NOTE: ignoring IP.ttl seems weird, but routers are + non-standard for whether they decrement ttl for + ICMP echo packets to the ingress interface (including checksum) match between the two packets """ if expected is None or recv is None: @@ -68,6 +72,9 @@ def pkt_smart_cmp(self, expected=None, recv=None): del ip2.id del ip1.chksum del ip2.chksum + if not ttl: + del ip1.ttl + del ip2.ttl return str(p1)[:ip1.len] == str(p2)[:ip2.len] @@ -83,6 +90,9 @@ def same_slash24_subnet(self, ip): class PingInterfacesL3(BasicL3Test): def runTest(self): + self.pingAllInterfaces() + + def pingAllInterfaces(self): ports = config["port_map"].keys() ports.sort() for port in ports : @@ -130,7 +140,7 @@ def runTest(self): ip_src = dst_ip, eth_dst = src_mac, eth_src = dst_mac, - ip_ttl = 63, + ip_ttl = 64, icmp_type = 0, # type = echo reply icmp_code = 0 # echo reply ) diff --git a/tests-legacy-l3/ocp-demo.json b/tests-legacy-l3/ocp-demo.json new file mode 100644 index 000000000..b6ae13183 --- /dev/null +++ b/tests-legacy-l3/ocp-demo.json @@ -0,0 +1,1017 @@ +{ + "version": 0, + "ports": [ + { + "logicalID": 1, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1001, + "speed": 0 + }, + { + "logicalID": 2, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1002, + "speed": 0 + }, + { + "logicalID": 3, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1003, + "speed": 0 + }, + { + "logicalID": 4, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1004, + "speed": 0 + }, + { + "logicalID": 5, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1005, + "speed": 0 + }, + { + "logicalID": 6, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1006, + "speed": 0 + }, + { + "logicalID": 7, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 8, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 9, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 10, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 11, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 12, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 13, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 14, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 15, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 16, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 17, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 18, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 19, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 20, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 21, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 22, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 23, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 24, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 25, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 26, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 27, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 28, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 29, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 30, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 31, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 32, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 33, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 34, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 35, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 36, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 37, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 38, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 39, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 40, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 41, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 42, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 43, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 44, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 1500, + "parserType": 1, + "routable": true, + "ingressVlan": 1000, + "speed": 0 + }, + { + "logicalID": 45, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 9000, + "parserType": 1, + "routable": true, + "ingressVlan": 3001, + "speed": 0 + }, + { + "logicalID": 46, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 9000, + "parserType": 1, + "routable": true, + "ingressVlan": 3002, + "speed": 0 + }, + { + "logicalID": 47, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 9000, + "parserType": 1, + "routable": true, + "ingressVlan": 3003, + "speed": 0 + }, + { + "logicalID": 48, + "state": 2, + "minFrameSize": 64, + "maxFrameSize": 9000, + "parserType": 1, + "routable": true, + "ingressVlan": 3004, + "speed": 0 + } + ], + "vlans": [ + { + "name": "downlinks", + "id": 1000, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "169.254.0.10", + "2001:db:1111:1150::a/64" + ], + "dhcpRelayAddressV4": "10.1.2.6", + "dhcpRelayAddressV6": "2001:db:ea10:a67::" + }, + { + "name": "vlan1001", + "id": 1001, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.1.1" + ] + }, + { + "name": "vlan1002", + "id": 1002, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.2.1" + ] + }, + { + "name": "vlan1003", + "id": 1003, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.3.1" + ] + }, + { + "name": "vlan1004", + "id": 1004, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.4.1" + ] + }, + { + "name": "vlan1005", + "id": 1005, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.5.1" + ] + }, + { + "name": "vlan1006", + "id": 1006, + "recordStats": true, + "mtuIndex": 0, + "routable": true, + "ipAddresses": [ + "172.31.6.1" + ] + }, + { + "name": "default", + "id": 4095, + "recordStats": true, + "mtuIndex": 0, + "routable": false, + "ipAddresses": [ + + ] + }, + { + "name": "uplink_1", + "id": 3001, + "recordStats": true, + "mtuIndex": 1, + "routable": true, + "ipAddresses": [ + "10.11.0.111", + "2001:db:3333:e01:1000::aa" + ] + }, + { + "name": "uplink_2", + "id": 3002, + "recordStats": true, + "mtuIndex": 1, + "routable": true, + "ipAddresses": [ + "10.11.8.111", + "2001:db:3334:e01:1000::aa" + ] + }, + { + "name": "uplink_3", + "id": 3003, + "recordStats": true, + "mtuIndex": 1, + "routable": true, + "ipAddresses": [ + "10.11.16.111", + "2001:db:3335:e01:1000::aa" + ] + }, + { + "name": "uplink_4", + "id": 3004, + "recordStats": true, + "mtuIndex": 1, + "routable": true, + "ipAddresses": [ + "10.11.24.111", + "2001:db:3336:e01:1000::aa" + ] + } + ], + "vlanPorts": [ + { + "vlanID": 1001, + "logicalPort": 1, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1002, + "logicalPort": 2, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1003, + "logicalPort": 3, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1004, + "logicalPort": 4, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1005, + "logicalPort": 5, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1006, + "logicalPort": 6, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 7, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 8, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 9, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 10, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 11, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 12, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 13, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 14, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 15, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 16, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 17, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 18, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 19, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 20, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 21, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 22, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 23, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 24, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 25, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 26, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 27, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 28, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 29, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 30, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 31, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 32, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 33, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 34, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 35, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 36, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 37, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 38, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 39, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 40, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 41, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 42, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 43, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 1000, + "logicalPort": 44, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 3001, + "logicalPort": 45, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 3002, + "logicalPort": 46, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 3003, + "logicalPort": 47, + "spanningTreeState": 2, + "emitTags": false + }, + { + "vlanID": 3004, + "logicalPort": 48, + "spanningTreeState": 2, + "emitTags": false + } + ], + "defaultVlan": 4095, + "interfaces": [ + { + "intfID": 1000, + "routerID": 0, + "vlanID": 1000, + "ipAddresses": [ + "169.254.0.10/16", + "2001:db:1111:1150::a/64" + ], + "ndp": { + "routerAdvertisementSeconds": 4, + "curHopLimit": 255, + "routerLifetime": 1800, + "prefixValidLifetimeSeconds": 2592000, + "prefixPreferredLifetimeSeconds": 604800, + "routerAdvertisementManagedBit": true, + "routerAdvertisementOtherBit": true + } + }, + { + "intfID": 1001, + "routerID": 0, + "vlanID": 1001, + "ipAddresses": [ + "172.31.1.1/24" + ] + }, + { + "intfID": 1002, + "routerID": 0, + "vlanID": 1002, + "ipAddresses": [ + "172.31.2.1/24" + ] + }, + { + "intfID": 1003, + "routerID": 0, + "vlanID": 1003, + "ipAddresses": [ + "172.31.3.1/24" + ] + }, + { + "intfID": 1004, + "routerID": 0, + "vlanID": 1004, + "ipAddresses": [ + "172.31.4.1/24" + ] + }, + { + "intfID": 1005, + "routerID": 0, + "vlanID": 1005, + "ipAddresses": [ + "172.31.5.1/24" + ] + }, + { + "intfID": 1006, + "routerID": 0, + "vlanID": 1006, + "ipAddresses": [ + "172.31.6.1/24" + ] + }, + { + "intfID": 3001, + "routerID": 0, + "vlanID": 3001, + "ipAddresses": [ + "10.11.0.111/31", + "2001:db:3333:e01:1000::aa/127" + ] + }, + { + "intfID": 3002, + "routerID": 0, + "vlanID": 3002, + "ipAddresses": [ + "10.11.8.111/31", + "2001:db:3334:e01:1000::aa/127" + ] + }, + { + "intfID": 3003, + "routerID": 0, + "vlanID": 3003, + "ipAddresses": [ + "10.11.16.111/31", + "2001:db:3335:e01:1000::aa/127" + ] + }, + { + "intfID": 3004, + "routerID": 0, + "vlanID": 3004, + "ipAddresses": [ + "10.11.24.111/31", + "2001:db:3336:e01:1000::aa/127" + ] + } + ], + "arpTimeoutSeconds": 60, + "arpRefreshSeconds": 20, + "arpAgerInterval": 5, + "proactiveArp": false, + "supportedMTUs": [ + 1500, + 9000 + ] +} From 49ac32a194d5db307b8d7892f59e22fa1f2791c5 Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Thu, 12 Nov 2015 16:20:40 -0800 Subject: [PATCH 4/8] l3: refactor ping test --- tests-legacy-l3/l3.py | 82 ++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 33 deletions(-) diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index 42427f84a..2c8ab6be8 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -88,11 +88,48 @@ def same_slash24_subnet(self, ip): class PingInterfacesL3(BasicL3Test): + def arpForMac(self, + src_mac = None, + src_ip = None, + dst_ip = None, + port = None, + maxtimeout=3): + """ + Send out ARP requests for the given dst_ip + """ + if src_mac == None or src_ip == None or \ + dst_ip == None or port == None: + raise "Missing args for arpForMac()" + arp = testutils.simple_arp_packet( + eth_src = src_mac, + hw_snd = src_mac, + ip_snd = src_ip, + ip_tgt = dst_ip) + + logging.info("ARP request packet for %s out port %d " % + ( dst_ip, port)) + logging.debug("Data: " + str(arp).encode('hex')) + self.dataplane.send(port, str(arp)) + arp_found = False + start_time = time.time() + while not arp_found: + timeout = (start_time + maxtimeout) - time.time() # timeout after 3ish seconds total + if timeout <= 0: + logging.error("Timeout on ARP reply for port %d" % port) + self.fail("Timeout on ARP for port %d" % port) + (rcv_port, pkt, t) = self.dataplane.poll(port_number = port, timeout = timeout) + if pkt is not None: # if is none, then we will loop and immediately timeout + parsed_pkt = scapy.Ether(pkt) + if (parsed_pkt is not None and + type(parsed_pkt.payload) == scapy.ARP and + parsed_pkt.payload.op == 2): # 2 == reply + arp_found = True + dst_mac = parsed_pkt.payload.hwsrc + logging.info("Learned via ARP: MAC %s neighbor to port %d" % + ( dst_mac, port)) + return dst_mac def runTest(self): - self.pingAllInterfaces() - - def pingAllInterfaces(self): ports = config["port_map"].keys() ports.sort() for port in ports : @@ -103,40 +140,19 @@ def pingAllInterfaces(self): src_ip = self.same_slash24_subnet(dst_ip) src_mac = "00:11:22:33:44:%2d" % port # first arp for the interface - arp = testutils.simple_arp_packet( - eth_src = src_mac, - hw_snd = src_mac, - ip_snd = src_ip, - ip_tgt = dst_ip) - - logging.info("ARP request packet for %s out port %d " % - ( dst_ip, port)) - logging.debug("Data: " + str(arp).encode('hex')) - self.dataplane.send(port, str(arp)) - arp_found = False - start_time = time.time() - dst_mac = None - while not arp_found: - timeout = (start_time + 3) - time.time() # timeout after 3 seconds total - if timeout <= 0: - logging.error("Timeout on ARP reply for port %d" % port) - self.fail("Timeout on ARP for port %d" % port) - (rcv_port, pkt, t) = self.dataplane.poll(port_number = port, timeout = timeout) - if pkt is not None: # if is none, then we will loop and immediately timeout - parsed_pkt = scapy.Ether(pkt) - if (parsed_pkt is not None and - type(parsed_pkt.payload) == scapy.ARP and - parsed_pkt.payload.op == 2): # 2 == reply - arp_found = True - dst_mac = parsed_pkt.payload.hwsrc - logging.info("Learned via ARP: MAC %s neighbor to port %d" % - ( dst_mac, port)) - ping = testutils.simple_icmp_packet(ip_dst = dst_ip, # request + dst_mac = self.arpForMac( + src_mac=src_mac, + src_ip=src_ip, + dst_ip=dst_ip, + port=port) + ping = testutils.simple_icmp_packet( # request + ip_dst = dst_ip, ip_src = src_ip, eth_dst = dst_mac, eth_src = src_mac ) - pong = testutils.simple_icmp_packet(ip_dst = src_ip, # reply + pong = testutils.simple_icmp_packet( # reply + ip_dst = src_ip, ip_src = dst_ip, eth_dst = src_mac, eth_src = dst_mac, From ad439222641b119e28ce36fe532a9a34482cc544 Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Thu, 12 Nov 2015 17:21:13 -0800 Subject: [PATCH 5/8] L3: Added ping egress/cross interface test --- tests-legacy-l3/l3.py | 80 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index 2c8ab6be8..6bea61d67 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -33,10 +33,6 @@ class BasicL3Test(base_tests.DataPlaneOnly): # port # --> L3 interface mapping Interfaces = { -# 1 : "169.254.0.10", -# 2 : "169.254.0.10", -# 3 : "169.254.0.10", -# 4 : "169.254.0.10", 1 : "172.31.1.1", 2 : "172.31.2.1", 3 : "172.31.3.1", @@ -86,8 +82,6 @@ def same_slash24_subnet(self, ip): quad = ip.split('.') return "%s.%s.%s.%d" % ( quad[0], quad[1], quad[2], int(quad[3])+1) - -class PingInterfacesL3(BasicL3Test): def arpForMac(self, src_mac = None, src_ip = None, @@ -128,14 +122,76 @@ def arpForMac(self, logging.info("Learned via ARP: MAC %s neighbor to port %d" % ( dst_mac, port)) return dst_mac - - def runTest(self): - ports = config["port_map"].keys() - ports.sort() - for port in ports : + def getPrunedPorts(self): + all_ports = config["port_map"].keys() + all_ports.sort() + ports = [] + for port in all_ports : if port not in self.Interfaces: logging.info("Skipping port %d -- not IP interface defined" % port) - continue + else: + ports.append(port) + return ports + +class PingCrossInterfacesL3(BasicL3Test): + """ For each interface i + verify we can ping each interface j""" + def runTest(self): + ports = self.getPrunedPorts() + if len(ports) < 2 : + self.fail("Need at least two ports to run this test") + for src_port in ports: + for dst_port in ports: + if src_port == dst_port: + continue + gateway_ip = self.Interfaces[src_port] + dst_ip = self.Interfaces[dst_port] + src_ip = self.same_slash24_subnet(self.Interfaces[src_port]) + src_mac = "00:11:22:33:44:%2d" % src_port + # first arp for the gateway interface + gateway_mac = self.arpForMac( + src_mac=src_mac, + src_ip=src_ip, + dst_ip=gateway_ip, + port=src_port) + ping = testutils.simple_icmp_packet( # request + ip_dst = dst_ip, + ip_src = src_ip, + eth_dst = gateway_mac, + eth_src = src_mac + ) + pong = testutils.simple_icmp_packet( # reply + ip_dst = src_ip, + ip_src = dst_ip, + eth_dst = src_mac, + eth_src = gateway_mac, + ip_ttl = 64, + icmp_type = 0, # type = echo reply + icmp_code = 0 # echo reply + ) + logging.info("Sending ping to %s out port %d" % (dst_ip, src_port)) + logging.debug("Data: " + str(ping).encode('hex')) + logging.debug("Expecting: " + str(ping).encode('hex')) + #scapy.hexdump(pong) + self.dataplane.send(src_port, str(ping)) + start_time = time.time() + pong_found = False + while not pong_found: + timeout = (start_time + 3) - time.time() + if timeout <= 0: + logging.error("Timeout on PING reply from port %d to port %d" % (src_port,dst_port)) + self.fail("Timeout on PING from port %d to port %d" % (src_port, dst_port)) + (rcv_port, rcv_pkt, t) = self.dataplane.poll(port_number = src_port, timeout=timeout) + if rcv_pkt is not None: + pong_found = self.pkt_smart_cmp(expected=pong, recv=scapy.Ether(rcv_pkt)) + + + + +class PingInterfacesL3(BasicL3Test): + """ For each interface, try to ping it """ + def runTest(self): + for port in self.getPrunedPorts() : dst_ip = self.Interfaces[port] src_ip = self.same_slash24_subnet(dst_ip) src_mac = "00:11:22:33:44:%2d" % port From e1837066e3cd4fa5c45c2b8783d5730c0ad4992c Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Thu, 12 Nov 2015 18:04:29 -0800 Subject: [PATCH 6/8] Added PingAllHosts test Test seems to work, but exposed a bug in orc. --- tests-legacy-l3/l3.py | 68 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index 6bea61d67..e1bbb0948 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -60,7 +60,7 @@ def pkt_smart_cmp(self, expected=None, recv=None, ttl=True): p2 = scapy.Ether(str(recv)) if p1.type != p2.type: return False # not same ethertype - #pdb.set_trace() + pdb.set_trace() if p1.type == 0x0800: # if IP, remove ID, chksum ip1 = p1.payload ip2 = p2.payload @@ -133,7 +133,7 @@ def getPrunedPorts(self): ports.append(port) return ports -class PingCrossInterfacesL3(BasicL3Test): +class PingEgressInterfacesL3(BasicL3Test): """ For each interface i verify we can ping each interface j""" def runTest(self): @@ -185,10 +185,72 @@ def runTest(self): if rcv_pkt is not None: pong_found = self.pkt_smart_cmp(expected=pong, recv=scapy.Ether(rcv_pkt)) +class PingAllHosts(BasicL3Test): + """ For each interface i + for each interface j + fake a host A off of interface i + fake a host B off of interface j + send a ping from A to B + verify that B receives the ping + don't reply + """ + def runTest(self): + ports = self.getPrunedPorts() + if len(ports) < 2 : + self.fail("Need at least two ports to run this test") + for src_port in ports: + for dst_port in ports: + if src_port == dst_port: + continue + ingress_gateway_ip = self.Interfaces[src_port] + egress_gateway_ip = self.Interfaces[dst_port] + dst_ip = self.same_slash24_subnet(self.Interfaces[dst_port]) + src_ip = self.same_slash24_subnet(self.Interfaces[src_port]) + src_mac = "00:11:22:33:44:%2d" % src_port + dst_mac = "00:11:22:33:44:%2d" % dst_port + # first arp for the gateway interface + ingress_gateway_mac = self.arpForMac( + src_mac=src_mac, + src_ip=src_ip, + dst_ip=ingress_gateway_ip, + port=src_port) + egress_gateway_mac = self.arpForMac( + src_mac=dst_mac, + src_ip=dst_ip, + dst_ip=egress_gateway_ip, + port=dst_port) + ping = testutils.simple_icmp_packet( # request + ip_dst = dst_ip, + ip_src = src_ip, + eth_dst = ingress_gateway_mac, + eth_src = src_mac + ) + recv_ping = testutils.simple_icmp_packet( # reply + ip_dst = src_ip, + ip_src = dst_ip, + eth_dst = dst_mac, + eth_src = egress_gateway_mac, + ip_ttl = 63 + ) + logging.info("Sending ping to %s out port %d" % (dst_ip, src_port)) + logging.debug("Data: " + str(ping).encode('hex')) + logging.debug("Expecting: " + str(ping).encode('hex')) + #scapy.hexdump(pong) + self.dataplane.send(src_port, str(ping)) + start_time = time.time() + pong_found = False + while not pong_found: + timeout = (start_time + 3) - time.time() + if timeout <= 0: + logging.error("Timeout on PING reply from port %d to port %d" % (src_port,dst_port)) + self.fail("Timeout on PING from port %d to port %d" % (src_port, dst_port)) + (rcv_port, rcv_pkt, t) = self.dataplane.poll(port_number = dst_port, timeout=timeout) + if rcv_pkt is not None: + pong_found = self.pkt_smart_cmp(expected=recv_ping, recv=scapy.Ether(rcv_pkt)) -class PingInterfacesL3(BasicL3Test): +class PingIngressInterfacesL3(BasicL3Test): """ For each interface, try to ping it """ def runTest(self): for port in self.getPrunedPorts() : From a39d8e45c7cd03991489b66a58aa058142687046 Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Thu, 12 Nov 2015 18:11:08 -0800 Subject: [PATCH 7/8] legacy l3: all three tests working --- tests-legacy-l3/l3.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index e1bbb0948..f04de6215 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -60,7 +60,7 @@ def pkt_smart_cmp(self, expected=None, recv=None, ttl=True): p2 = scapy.Ether(str(recv)) if p1.type != p2.type: return False # not same ethertype - pdb.set_trace() + #pdb.set_trace() if p1.type == 0x0800: # if IP, remove ID, chksum ip1 = p1.payload ip2 = p2.payload @@ -226,8 +226,8 @@ def runTest(self): eth_src = src_mac ) recv_ping = testutils.simple_icmp_packet( # reply - ip_dst = src_ip, - ip_src = dst_ip, + ip_dst = dst_ip, + ip_src = src_ip, eth_dst = dst_mac, eth_src = egress_gateway_mac, ip_ttl = 63 From ac59da533625ebc70ed52b4feceb744750868b9e Mon Sep 17 00:00:00 2001 From: Rob Sherwood Date: Mon, 30 Nov 2015 21:28:45 -0800 Subject: [PATCH 8/8] legacy l3: test src/dst ethernet addrs --- tests-legacy-l3/l3.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests-legacy-l3/l3.py b/tests-legacy-l3/l3.py index f04de6215..1386aa2dd 100644 --- a/tests-legacy-l3/l3.py +++ b/tests-legacy-l3/l3.py @@ -60,6 +60,10 @@ def pkt_smart_cmp(self, expected=None, recv=None, ttl=True): p2 = scapy.Ether(str(recv)) if p1.type != p2.type: return False # not same ethertype + if p1.src != p2.src: + return False + if p1.dst != p2.dst: + return False #pdb.set_trace() if p1.type == 0x0800: # if IP, remove ID, chksum ip1 = p1.payload