Initial set of Fabric switch test cases
Change-Id: I86fd2b67d3b773aa496f5ef61f1e1fdf51fd9925
diff --git a/Fabric/Tests/README b/Fabric/Tests/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Fabric/Tests/README
diff --git a/Fabric/Tests/cleanup_flows.py b/Fabric/Tests/cleanup_flows.py
new file mode 100755
index 0000000..dc45d0f
--- /dev/null
+++ b/Fabric/Tests/cleanup_flows.py
@@ -0,0 +1,43 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Check README file
+"""
+import Queue
+
+from oftest import config
+import inspect
+import logging
+import oftest.base_tests as base_tests
+import ofp
+import time
+from oftest.oft12.testutils import delete_all_flows_one_table
+from oftest.testutils import *
+from accton_util import *
+from oftest.utils import *
+
+class CleanupAllFlows( base_tests.SimpleDataPlane ):
+ """
+ Clean-up all flows in the switch
+ """
+
+ def runTest( self ):
+ logging.info( "Cleanup Start" )
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+ logging.info( "Cleanup Completed" )
+
diff --git a/Fabric/Tests/functional.py b/Fabric/Tests/functional.py
new file mode 100755
index 0000000..aa3a5bb
--- /dev/null
+++ b/Fabric/Tests/functional.py
@@ -0,0 +1,4796 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Check README file
+"""
+import Queue
+
+from oftest import config
+import inspect
+import logging
+import oftest.base_tests as base_tests
+import ofp
+import time
+from oftest.oft12.testutils import delete_all_flows_one_table
+from oftest.testutils import *
+from accton_util import *
+from oftest.utils import *
+
+
+class FabricSW_OF_PacketInUDP_TC_0010( base_tests.SimpleDataPlane ):
+ """
+ Verify ACL rule for IP_PROTO=2 wont match a UDP packet and a rule for IP_PROTO=17 WILL match a UDP packet.
+ """
+
+ def runTest( self ):
+ try:
+ parsed_vlan_pkt = simple_udp_packet( pktlen=104, vlan_vid=0x1001, dl_vlan_enable=True )
+ vlan_pkt = str( parsed_vlan_pkt )
+ # create match
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0800 ) )
+ match.oxm_list.append( ofp.oxm.ip_proto( 2 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ), ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=1 )
+ logging.info( "Inserting packet in flow to controller" )
+ self.controller.message_send( request )
+
+ for of_port in config[ "port_map" ].keys( ):
+ logging.info( "PacketInMiss test, port %d", of_port )
+ self.dataplane.send( of_port, vlan_pkt )
+
+ verify_no_packet_in( self, vlan_pkt, of_port )
+ delete_all_flows( self.controller )
+ do_barrier( self.controller )
+
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0800 ) )
+ match.oxm_list.append( ofp.oxm.ip_proto( 17 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ), ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=1 )
+ logging.info( "Inserting packet in flow to controller" )
+ self.controller.message_send( request )
+ do_barrier( self.controller )
+
+ for of_port in config[ "port_map" ].keys( ):
+ logging.info( "PacketInMiss test, port %d", of_port )
+ self.dataplane.send( of_port, vlan_pkt )
+
+ verify_packet_in( self, vlan_pkt, of_port, ofp.OFPR_ACTION )
+
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+@disabled
+class ArpNL2( base_tests.SimpleDataPlane ):
+ """
+ Needs a description, disabled for now. Also needs try/finally
+ """
+ def runTest( self ):
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+ ports = sorted( config[ "port_map" ].keys( ) )
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0806 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ), ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=40000 )
+ self.controller.message_send( request )
+ for port in ports:
+ add_one_l2_interface_group( self.controller, port, 1, False, False )
+ add_one_vlan_table_flow( self.controller, port, 1, flag=VLAN_TABLE_FLAG_ONLY_BOTH )
+ group_id = encode_l2_interface_group_id( 1, port )
+ add_bridge_flow( self.controller, [ 0x00, 0x12, 0x34, 0x56, 0x78, port ], 1, group_id, True )
+ do_barrier( self.controller )
+ parsed_arp_pkt = simple_arp_packet( )
+ arp_pkt = str( parsed_arp_pkt )
+
+ for out_port in ports:
+ self.dataplane.send( out_port, arp_pkt )
+ verify_packet_in( self, arp_pkt, out_port, ofp.OFPR_ACTION )
+ # change dest based on port number
+ mac_dst = '00:12:34:56:78:%02X' % out_port
+ for in_port in ports:
+ if in_port == out_port:
+ continue
+ # change source based on port number to avoid packet-ins from learning
+ mac_src = '00:12:34:56:78:%02X' % in_port
+ parsed_pkt = simple_tcp_packet( eth_dst=mac_dst, eth_src=mac_src )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for ofport in ports:
+ if ofport in [ out_port ]:
+ verify_packet( self, pkt, ofport )
+ else:
+ verify_no_packet( self, pkt, ofport )
+
+ verify_no_other_packets( self )
+
+class FabricSW_OF_PacketInArp_TC_0005( base_tests.SimpleDataPlane ):
+ """
+ Verify Packet-in message from eth_type 0x806 on ACL table
+ """
+
+ def runTest( self ):
+ try:
+ parsed_arp_pkt = simple_arp_packet( )
+ arp_pkt = str( parsed_arp_pkt )
+ # create match
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0806 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ), ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=1 )
+
+ logging.info( "Inserting arp flow " )
+ self.controller.message_send( request )
+ do_barrier( self.controller )
+
+ for of_port in config[ "port_map" ].keys( ):
+ logging.info( "PacketInArp test, sending arp packet to port %d", of_port )
+ self.dataplane.send( of_port, arp_pkt )
+
+ verify_packet_in( self, arp_pkt, of_port, ofp.OFPR_ACTION )
+
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+@disabled
+class PacketInIPTable( base_tests.SimpleDataPlane ):
+ """
+ Verify Packet-in message from IP table when controller action is used
+ Send a packet to each dataplane port and verify that a packet
+ in message is received from the controller for each
+ #todo verify you stop receiving after adding rule
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = sorted( config[ "port_map" ].keys( ) )
+
+ for port in ports:
+ # add l2 interface group
+ vlan_id = port
+ add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id, is_tagged=True,
+ send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, vlan_id=vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, l3_msg.group_id,
+ send_ctrl=True )
+ Groups.put( l3_msg.group_id )
+
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % in_port
+ ip_src = '192.168.%02d.1' % in_port
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % out_port
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=in_port,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ verify_packet_in( self, pkt, in_port, ofp.OFPR_ACTION )
+ # verify_no_other_packets(self)
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF_L2FloodQinQ_TC_0015( base_tests.SimpleDataPlane ):
+ """
+ Verify Vlan based flooding of QinQ based on its outer vlan
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+ vlan_id = 100
+
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ add_one_vlan_table_flow( self.controller, port, vlan_id=vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ Groups.put( L2gid )
+
+ msg = add_l2_flood_group( self.controller, ports, vlan_id, vlan_id )
+ Groups.put( msg.group_id )
+ add_bridge_flow( self.controller, None, vlan_id, msg.group_id, True )
+ do_barrier( self.controller )
+
+ # verify flood
+ for ofport in ports:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan( pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id, in_dl_vlan_enable=True, in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ofport, pkt )
+ # self won't rx packet
+ verify_no_packet( self, pkt, ofport )
+ # others will rx packet
+ tmp_ports = list( ports )
+ tmp_ports.remove( ofport )
+ verify_packets( self, pkt, tmp_ports )
+
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+
+@disabled
+class L2FloodTagged( base_tests.SimpleDataPlane ):
+ """
+ currently disabled; fix with try/finally
+ Test L2 flood to a vlan
+ Send a packet with unknown dst_mac and check if the packet is flooded to all ports except inport
+ """
+
+ def runTest( self ):
+ # Hashes Test Name and uses it as id for installing unique groups
+ vlan_id = abs( hash( inspect.stack( )[ 0 ][ 3 ] ) ) % (256)
+ print vlan_id
+
+ ports = sorted( config[ "port_map" ].keys( ) )
+
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+ # Installing flows to avoid packet-in
+ for port in ports:
+ add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ add_one_vlan_table_flow( self.controller, port, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ msg = add_l2_flood_group( self.controller, ports, vlan_id, vlan_id )
+ add_bridge_flow( self.controller, None, vlan_id, msg.group_id, True )
+ do_barrier( self.controller )
+
+ # verify flood
+ for ofport in ports:
+ # change dest based on port number
+ pkt = str(
+ simple_tcp_packet( dl_vlan_enable=True, vlan_vid=vlan_id, eth_dst='00:12:34:56:78:9a' ) )
+ self.dataplane.send( ofport, pkt )
+ # self won't rx packet
+ verify_no_packet( self, pkt, ofport )
+ # others will rx packet
+ tmp_ports = list( ports )
+ tmp_ports.remove( ofport )
+ verify_packets( self, pkt, tmp_ports )
+ verify_no_other_packets( self )
+
+
+class FabricSW_OF_L2UnicastTagged_TC_0020( base_tests.SimpleDataPlane ):
+ """ Verify Bridging works: match(VID, DST_MAC)> fwd(port) """
+
+ def runTest( self ):
+
+ Groups = Queue.LifoQueue( )
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+ vlan_id = 1;
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ add_one_vlan_table_flow( self.controller, port, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ Groups.put( L2gid )
+ add_bridge_flow( self.controller, [ 0x00, 0x12, 0x34, 0x56, 0x78, port ], vlan_id, L2gid,
+ True )
+ do_barrier( self.controller )
+
+ for out_port in ports:
+ # change dest based on port number
+ mac_dst = '00:12:34:56:78:%02X' % out_port
+ for in_port in ports:
+ if in_port == out_port:
+ continue
+ pkt = str( simple_tcp_packet( dl_vlan_enable=True, vlan_vid=vlan_id, eth_dst=mac_dst ) )
+ self.dataplane.send( in_port, pkt )
+ for ofport in ports:
+ if ofport in [ out_port ]:
+ verify_packet( self, pkt, ofport )
+ else:
+ verify_no_packet( self, pkt, ofport )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF_Bridging_TC_0001( base_tests.SimpleDataPlane ):
+ """
+ Verify bridging works including flooding with different vlans
+ ports[0] has vlan 31 untagged
+ ports[1] has vlan 31 untagged (native) and vlan 41 tagged
+ ARP request should be flooded
+ ARP reply should be forwarded by bridging rule
+ Both arp messages should also be copied to controller
+ """
+
+ def runTest( self ):
+ Groupd = Queue.LifoQueue()
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ ports = sorted( config[ "port_map" ].keys() )
+ vlan_p0_untagged = 31
+ vlan_p1_tagged = 31
+ vlan_p1_native = 41
+
+ #l2 interface groups and table 10 flows
+ L2p0gid, l2msg0 = add_one_l2_interface_group( self.controller, ports[0], vlan_p0_untagged,
+ is_tagged=False, send_barrier=False )
+ add_one_vlan_table_flow( self.controller, ports[0], vlan_id=vlan_p0_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+ L2p1gid, l2msg1 = add_one_l2_interface_group( self.controller, ports[1], vlan_p1_tagged,
+ is_tagged=True, send_barrier=False )
+ add_one_vlan_table_flow( self.controller, ports[1], vlan_id=vlan_p1_tagged, flag=VLAN_TABLE_FLAG_ONLY_TAG,
+ send_barrier=True)
+ L2p1gid2, l2msg3 = add_one_l2_interface_group( self.controller, ports[1], vlan_p1_native,
+ is_tagged=False, send_barrier=False )
+ add_one_vlan_table_flow( self.controller, ports[1], vlan_id=vlan_p1_native, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+ #flooding groups
+ Floodmsg31 = add_l2_flood_group( self.controller, ports, vlan_p0_untagged, id=0 )
+ Floodmsg41 = add_l2_flood_group( self.controller, [ ports[1] ], vlan_p1_native, id=0 )
+
+ #add bridging flows for flooding groups
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_p0_untagged, group_id=Floodmsg31.group_id )
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_p1_native, group_id=Floodmsg41.group_id )
+ do_barrier( self.controller )
+
+ # add bridging flows for dstMac+vlan
+ add_bridge_flow( self.controller, [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 ], vlan_p0_untagged, L2p0gid, True )
+ add_bridge_flow( self.controller, [ 0x00, 0x66, 0x77, 0x88, 0x99, 0xaa ], vlan_p1_tagged, L2p1gid, True )
+ add_bridge_flow( self.controller, [ 0x00, 0x66, 0x77, 0x88, 0x99, 0xaa ], vlan_p1_native, L2p1gid2, True )
+
+ # add terminationMac flow
+ router_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, router_mac, vlan_p0_untagged )
+ add_termination_flow( self.controller, 0, 0x0800, router_mac, vlan_p1_native )
+ else:
+ add_termination_flow( self.controller, ports[0], 0x0800, router_mac, vlan_p0_untagged )
+ add_termination_flow( self.controller, ports[1], 0x0800, router_mac, vlan_p1_tagged )
+ add_termination_flow( self.controller, ports[1], 0x0800, router_mac, vlan_p1_native )
+
+ # add acl rule for arp
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0806 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ), ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=1 )
+ self.controller.message_send( request )
+ do_barrier( self.controller )
+
+ #acl rule for gateway ip
+ match = ofp.match( )
+ match.oxm_list.append( ofp.oxm.eth_type( 0x0800 ) )
+ match.oxm_list.append( ofp.oxm.ipv4_dst( 0xc0a80003 ) )
+ request = ofp.message.flow_add( table_id=60, cookie=42, match=match, instructions=[
+ ofp.instruction.apply_actions( actions=[
+ ofp.action.output( port=ofp.OFPP_CONTROLLER, max_len=ofp.OFPCML_NO_BUFFER ) ] ),
+ ofp.instruction.clear_actions() ],
+ buffer_id=ofp.OFP_NO_BUFFER, priority=1 )
+ self.controller.message_send( request )
+ do_barrier( self.controller )
+
+ # send ARP request
+ parsed_arp_pkt = simple_arp_packet(pktlen=80,
+ eth_dst='ff:ff:ff:ff:ff:ff',
+ eth_src='00:66:77:88:99:aa',
+ vlan_vid=vlan_p1_tagged,
+ vlan_pcp=0,
+ arp_op=1,
+ ip_snd='192.168.0.2',
+ ip_tgt='192.168.0.1',
+ hw_snd='00:66:77:88:99:aa',
+ hw_tgt='00:00:00:00:00:00')
+ arp_pkt_to_send = str( parsed_arp_pkt )
+ logging.info( "sending arp request to port %d", ports[1] )
+ self.dataplane.send( ports[1], arp_pkt_to_send )
+ verify_packet_in( self, arp_pkt_to_send, ports[1], ofp.OFPR_ACTION )
+ parsed_arp_pkt_untagged = simple_arp_packet(pktlen=76,
+ eth_dst='ff:ff:ff:ff:ff:ff',
+ eth_src='00:66:77:88:99:aa',
+ vlan_vid=0,
+ vlan_pcp=0,
+ arp_op=1,
+ ip_snd='192.168.0.2',
+ ip_tgt='192.168.0.1',
+ hw_snd='00:66:77:88:99:aa',
+ hw_tgt='00:00:00:00:00:00')
+ arp_pkt_dest = str( parsed_arp_pkt_untagged )
+ verify_packet( self, arp_pkt_dest, ports[0] )
+ #verify_no_other_packets( self )
+
+ # send ARP reply
+ parsed_arp_pkt = simple_arp_packet(pktlen=76,
+ eth_dst='00:66:77:88:99:aa',
+ eth_src='00:11:22:33:44:55',
+ vlan_vid=0,
+ vlan_pcp=0,
+ arp_op=2,
+ ip_snd='192.168.0.1',
+ ip_tgt='192.168.0.2',
+ hw_snd='00:11:22:33:44:55',
+ hw_tgt='00:66:77:88:99:aa')
+ arp_pkt_to_send = str( parsed_arp_pkt )
+ logging.info( "sending arp reply to port %d", ports[0] )
+ self.dataplane.send( ports[0], arp_pkt_to_send )
+ verify_packet_in( self, arp_pkt_to_send, ports[0], ofp.OFPR_ACTION )
+ parsed_arp_pkt_tagged = simple_arp_packet(pktlen=80,
+ eth_dst='00:66:77:88:99:aa',
+ eth_src='00:11:22:33:44:55',
+ vlan_vid=vlan_p1_tagged,
+ vlan_pcp=0,
+ arp_op=2,
+ ip_snd='192.168.0.1',
+ ip_tgt='192.168.0.2',
+ hw_snd='00:11:22:33:44:55',
+ hw_tgt='00:66:77:88:99:aa')
+ arp_pkt_dest = str( parsed_arp_pkt_tagged )
+ verify_packet( self, arp_pkt_dest, ports[1] )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+ #print("done")
+
+
+
+class FabricSW_OF_Mtu1500_TC_0035( base_tests.SimpleDataPlane ):
+ """
+ Verifies basic mtu limits
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+ vlan_id = 18
+ for port in ports:
+ L2gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ Groups.put( L2gid )
+ add_bridge_flow( self.controller, [ 0x00, 0x12, 0x34, 0x56, 0x78, port ], vlan_id, L2gid,
+ True )
+ do_barrier( self.controller )
+
+ for out_port in ports:
+ # change dest based on port number
+ mac_dst = '00:12:34:56:78:%02X' % out_port
+ for in_port in ports:
+ if in_port == out_port:
+ continue
+ pkt = str( simple_tcp_packet( pktlen=1500, dl_vlan_enable=True, vlan_vid=vlan_id,
+ eth_dst=mac_dst ) )
+ self.dataplane.send( in_port, pkt )
+ for ofport in ports:
+ if ofport in [ out_port ]:
+ verify_packet( self, pkt, ofport )
+ else:
+ verify_no_packet( self, pkt, ofport )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF__32UcastTagged_TC_0055( base_tests.SimpleDataPlane ):
+ """ Verify /32 IP forwarding to L3 Unicast-> L2Interface"""
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ test_id = 26
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ vlan_id = port + test_id
+ # add l2 interface group and l3 unicast group
+ l2gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, l3_msg.group_id )
+ Groups.put( l2gid )
+ Groups.put( l3_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:32:%02X' % (test_id + in_port)
+ ip_src = '192.168.%02d.1' % (test_id + in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (test_id + out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + in_port), eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % (test_id + out_port)
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + out_port), eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _32VPN( base_tests.SimpleDataPlane ):
+ """
+ Verify /32 routing rule -> MPLS_VPN_Label -> MPLSInterface -> L2Interface
+ No ECMP group used
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ id = port
+ vlan_id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, True )
+ dst_mac[ 5 ] = vlan_id
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=port, set_bos=1, set_ttl=32 )
+ do_barrier( self.controller )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, vrf=2,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, mpls_label_gid, vrf=2 )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port),
+ eth_dst=switch_mac, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ label = (out_port, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_port), ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _32EcmpVpn( base_tests.SimpleDataPlane ):
+ """
+ Verify /32 routing rule -> L3 ECMP -> MPLS_VPN_Label -> MPLSInterface -> L2Interface
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ id = port
+ vlan_id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, True )
+ dst_mac[ 5 ] = vlan_id
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=port, set_bos=1, set_ttl=32 )
+ ecmp_msg = add_l3_ecmp_group( self.controller, vlan_id, [ mpls_label_gid ] )
+ do_barrier( self.controller )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, ecmp_msg.group_id )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ Groups._put( ecmp_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port),
+ eth_dst=switch_mac, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ label = (out_port, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_port), ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class One_32EcmpVpn( base_tests.SimpleDataPlane ):
+ """
+ Verify /32 routing rule -> L3 ECMP -> MPLS_VPN_Label -> MPLSInterface -> L2Interface
+ in only one direction
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ # add l2 interface group
+ id = ports[1]
+ in_offset = 19
+ out_offset = 20
+ vlan_id = ports[1] + out_offset
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, ports[1], vlan_id, True, True )
+ dst_mac[ 5 ] = ports[1]
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=ports[1] + out_offset, set_bos=1, set_ttl=32 )
+ # add ECMP group
+ ecmp_msg = add_l3_ecmp_group( self.controller, vlan_id, [ mpls_label_gid ] )
+ do_barrier( self.controller )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, ports[0], 1, vlan_id=ports[0] + in_offset, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlanid=ports[0] + in_offset )
+ else:
+ add_termination_flow( self.controller, ports[0], 0x0800, intf_src_mac, vlanid=ports[0] + in_offset )
+ # add routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, ecmp_msg.group_id, send_barrier=True )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ Groups._put( ecmp_msg.group_id )
+
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ in_port = ports[0]
+ out_port = ports[1]
+ ip_src = '192.168.%02d.1' % (in_port)
+ ip_dst = '192.168.%02d.1' % (out_port+out_offset)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port + in_offset),
+ eth_dst=switch_mac, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ label = (out_port+out_offset, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_port + out_offset), ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ #verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_group(self.controller, ecmp_msg.group_id)
+ delete_group(self.controller, mpls_label_gid)
+ delete_group(self.controller, mpls_gid)
+ delete_group(self.controller, l2_gid)
+
+
+class FabricSW_OF__32ECMPL3_TC_0050( base_tests.SimpleDataPlane ):
+ """
+ Verifies /32 IP routing and ECMP with no label push
+ IP -> L3ECMP -> L3Unicast -> L2Interface
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ # Hashes Test Name and uses it as id for installing unique groups
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ vlan_id = port
+ id = port
+ # add l2 interface group
+ l2_gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, ecmp_msg.group_id )
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ Groups._put( ecmp_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % in_port
+ ip_src = '192.168.%02d.1' % in_port
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % out_port
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=in_port,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class One_32ECMPL3( base_tests.SimpleDataPlane ):
+ """
+ Verifies /32 IP routing and ECMP with no label push
+ IP -> L3ECMP -> L3Unicast -> L2Interface
+ in only one direction
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ # Hashes Test Name and uses it as id for installing unique groups
+ ports = config[ "port_map" ].keys( )
+ inport = ports[0]
+ outport = ports[1]
+ in_offset = 19
+ out_offset = 20
+ vlan_id = outport + out_offset
+ id = outport
+ # add l2 interface group, l3 unicast and ecmp group for outport
+ l2_gid, msg = add_one_l2_interface_group( self.controller, outport, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = outport
+ l3_msg = add_l3_unicast_group( self.controller, outport, vlanid=vlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, of_port=inport, vlan_id=inport+in_offset, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlanid=inport+in_offset )
+ else:
+ add_termination_flow( self.controller, in_port=inport, eth_type=0x0800, dst_mac=intf_src_mac, vlanid=inport+in_offset )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, ecmp_msg.group_id, send_barrier=True )
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ Groups._put( ecmp_msg.group_id )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ mac_src = '00:00:00:22:22:%02X' % inport
+ ip_src = '192.168.%02d.1' % inport
+ ip_dst = '192.168.%02d.1' % (outport+out_offset)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=inport+in_offset,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( inport, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % outport
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=outport+out_offset,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, outport )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+
+
+@disabled
+class _24VPN( base_tests.SimpleDataPlane ):
+ """ Verify MPLS IP VPN Initiation from /32 rule without using ECMP """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ id = port
+ vlan_id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, True )
+ dst_mac[ 5 ] = vlan_id
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=port, set_bos=1, set_ttl=32 )
+ # ecmp_msg=add_l3_ecmp_group(self.controller, vlan_id, [mpls_label_gid])
+ do_barrier( self.controller )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, mpls_label_gid )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port),
+ eth_dst=switch_mac, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ label = (out_port, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_port), ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _24EcmpVpn( base_tests.SimpleDataPlane ):
+ """ Verify MPLS IP VPN Initiation from /24 rule using ECMP """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ id = port
+ vlan_id = id
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, True )
+ dst_mac[ 5 ] = vlan_id
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=port, set_bos=1, set_ttl=32 )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ mpls_label_gid ] )
+ do_barrier( self.controller )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add routing flow
+ dst_ip = dip + (vlan_id << 8)
+ # add_unicast_routing_flow(self.controller, 0x0800, dst_ip, 0, mpls_label_gid, vrf=2)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, ecmp_msg.group_id,
+ vrf=0 )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ Groups._put( ecmp_msg.group_id )
+
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % (in_port)
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port),
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ label = (out_port, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_port), ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF_FloodGroupMod_TC_0030( base_tests.SimpleDataPlane ):
+ """ Modify a referenced flood group """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+ vlan_id = 1
+
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ add_one_vlan_table_flow( self.controller, port, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ Groups.put( L2gid )
+
+ msg = add_l2_flood_group( self.controller, ports, vlan_id, vlan_id )
+ Groups.put( msg.group_id )
+ add_bridge_flow( self.controller, None, vlan_id, msg.group_id, True )
+ do_barrier( self.controller )
+ # verify flood
+ for ofport in ports:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan( pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id, in_dl_vlan_enable=True, in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ofport, pkt )
+ # self won't rx packet
+ verify_no_packet( self, pkt, ofport )
+ # others will rx packet
+ tmp_ports = list( ports )
+ tmp_ports.remove( ofport )
+ verify_packets( self, pkt, tmp_ports )
+ verify_no_other_packets( self )
+ msg = mod_l2_flood_group( self.controller, [ ports[ 0 ] ], vlan_id, vlan_id )
+ mac_src = '00:12:34:56:78:%02X' % ports[ 1 ]
+ parsed_pkt = simple_tcp_packet_two_vlan( pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id, in_dl_vlan_enable=True, in_vlan_vid=10, eth_dst='00:12:34:56:78:9a',
+ eth_src=mac_src )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ports[ 1 ], pkt )
+ verify_packets( self, pkt, [ ports[ 0 ] ] )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF__24ECMPL3_TC_0040( base_tests.SimpleDataPlane ):
+ """ Verifies /24 IP routing using ECMP -> L3U -> L2I """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ # Hashes Test Name and uses it as id for installing unique groups
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ vlan_id = port
+ id = port
+ # add l2 interface group
+ l2_gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, ecmp_msg.group_id )
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ Groups._put( ecmp_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % in_port
+ ip_src = '192.168.%02d.1' % in_port
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % out_port
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=in_port,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class MPLSBUG( base_tests.SimpleDataPlane ):
+ """
+ Needs a description or needs to be removed
+ """
+ def runTest( self ):
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ Groups = Queue.LifoQueue( )
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ vlan_id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ dst_mac[ 5 ] = vlan_id
+ # add L3 Unicast group
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_BOTH )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x08847, intf_src_mac, vlan_id, goto_table=24 )
+ else:
+ add_termination_flow( self.controller, port, 0x8847, intf_src_mac, vlan_id, goto_table=24 )
+ # add mpls flow
+ add_mpls_flow( self.controller, l3_msg.group_id, port )
+ # add termination flow
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, l3_msg.group_id )
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % in_port
+ ip_src = '192.168.%02d.1' % in_port
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % out_port
+ switch_mac = "00:00:00:cc:cc:cc"
+ label = (out_port, 0, 1, 32)
+ parsed_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=in_port, ip_src=ip_src,
+ ip_dst=ip_dst, eth_dst=switch_mac, eth_src=mac_src, label=[ label ] )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=31, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=in_port,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+
+class L3McastToL3( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing, in this test case the traffic comes in tagged.
+ port+1 is used as ingress vlan_id. The packet goes out tagged on
+ different ports. 4094-port is used as egress vlan_id.
+ """
+ def runTest( self ):
+ """
+ port1 (vlan 300)-> All Ports (vlan 300)
+ """
+ Groups = Queue.LifoQueue( )
+ try:
+ # We can forward on the in_port but egress_vlan has to be different from ingress_vlan
+ if len( config[ "port_map" ] ) < 1:
+ logging.info( "Port count less than 1, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ port_to_intf_src_mac_str,
+ Groups) = fill_mcast_pipeline_L3toL3(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = True,
+ is_egress_tagged = True,
+ is_vlan_translated = True,
+ is_max_vlan = False
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_in_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_out_vlan[out_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_intf_src_mac_str[out_port],
+ ip_ttl = 63,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ verify_packet( self, pkt, out_port )
+
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class L3McastToL2UntagToUntag( base_tests.SimpleDataPlane ):
+ """
+ Fails on alternate runs
+ Mcast routing, in this test case the traffic is untagged.
+ 4094 is used as internal vlan_id. The packet goes out
+ untagged.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = False,
+ is_egress_tagged = False,
+ is_vlan_translated = False,
+ is_max_vlan = True
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class L3McastToL2UntagToTag( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing, in this test case the traffic is untagged.
+ 300 is used as vlan_id. The packet goes out
+ tagged.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = False,
+ is_egress_tagged = True,
+ is_vlan_translated = False,
+ is_max_vlan = False
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_out_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class L3McastToL2TagToUntag( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing, in this test case the traffic is tagged.
+ 300 is used as vlan_id. The packet goes out
+ untagged.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = True,
+ is_egress_tagged = False,
+ is_vlan_translated = False,
+ is_max_vlan = False
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_in_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class L3McastToL2TagToTag( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing, in this test case the traffic is tagged.
+ 300 is used as vlan_id. The packet goes out tagged.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = True,
+ is_egress_tagged = True,
+ is_vlan_translated = False,
+ is_max_vlan = False
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_in_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_in_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class L3McastToL2TagToTagTranslated( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing, in this test case the traffic is tagged.
+ port+1 is used as ingress vlan_id. The packet goes out
+ tagged. 4094-port is used as egress vlan_id
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = True,
+ is_egress_tagged = True,
+ is_vlan_translated = True,
+ is_max_vlan = False
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_in_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 100,
+ dl_vlan_enable = True,
+ vlan_vid = port_to_out_vlan[in_port],
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class L3McastTrafficThenDrop( base_tests.SimpleDataPlane ):
+ # fails on alternate repeated runs
+ """
+ Mcast routing, in this test case the traffic is untagged.
+ 4094 is used as internal vlan_id. We first install aa full pipeline,
+ test that it forwards properly then remove all rules on table 40 and
+ mcast groups and ensure traffic is dropped. Blackhole of mcast traffic
+ if no tree is programmed on the switch.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ assert (False)
+ return
+ ports = config[ "port_map" ].keys( )
+ dst_ip_str = "224.0.0.1"
+ (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip,
+ port_to_src_ip_str,
+ Groups) = fill_mcast_pipeline_L3toL2(
+ self.controller,
+ logging,
+ ports,
+ is_ingress_tagged = False,
+ is_egress_tagged = False,
+ is_vlan_translated = False,
+ is_max_vlan = True
+ )
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ delete_all_flows_one_table(ctrl=self.controller, logger=logging, table_id=40);
+ delete_all_groups(self.controller)
+
+ for in_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ for out_port in ports:
+
+ parsed_pkt = simple_udp_packet(
+ pktlen = 96,
+ eth_dst = port_to_dst_mac_str[in_port],
+ eth_src = port_to_src_mac_str[in_port],
+ ip_ttl = 64,
+ ip_src = port_to_src_ip_str[in_port],
+ ip_dst = dst_ip_str
+ )
+ pkt = str( parsed_pkt )
+ if out_port == in_port:
+ verify_no_packet( self, pkt, in_port )
+ continue
+ verify_no_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _MplsFwd( base_tests.SimpleDataPlane ):
+ """ Verify basic MPLS forwarding: Label switch router """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ dip = 0xc0a80001
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ # Assigns unique hardcoded test_id to make sure tests don't overlap when writing rules
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ vlan_id = port + 16
+ mpls_label = port + 16
+
+ # add l2 interface group
+ id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ dst_mac[ 5 ] = port
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ vlan_id, id )
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_SWAP_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=False, set_mpls_label=mpls_label, set_bos=1 )
+ #ecmp_gid, ecmp_msg = add_mpls_forwarding_group( self.controller,
+ # subtype=OFDPA_MPLS_GROUP_SUBTYPE_ECMP, index=id, ref_gids=[mpls_label_gid] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x8847, intf_src_mac, vlan_id, goto_table=24 )
+ else:
+ add_termination_flow( self.controller, port, 0x8847, intf_src_mac, vlan_id, goto_table=24 )
+ #add_mpls_flow( self.controller, ecmp_gid, port, goto_table=29 )
+ if config["switch_type"] != 'xpliant':
+ add_mpls_flow( self.controller, mpls_label_gid, mpls_label, goto_table=29 )
+ else:
+ xpliant_add_mpls_flow( self.controller, mpls_label_gid, mpls_label, goto_table=29 )
+ dst_ip = dip + (vlan_id << 8)
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ #Groups._put( ecmp_gid )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ out_mpls_label = out_port + 16
+ in_vlan_vid = in_port + 16
+ out_vlan_vid = out_port + 16
+
+ ip_dst = '192.168.%02d.1' % (out_port)
+ label = (out_mpls_label, 0, 1, 32)
+ parsed_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(in_vlan_vid),
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=switch_mac, label=[ label ] )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ label = (out_mpls_label, 0, 1, 31)
+ exp_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(out_vlan_vid),
+ ip_src=ip_src, ip_dst=ip_dst, eth_src=switch_mac, eth_dst=mac_dst,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _MplsTermination( base_tests.SimpleDataPlane ):
+ """ Verify MPLS VPN Termination at penultimate hop """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ dip = 0xc0a80001
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ # Assigns unique hardcoded test_id to make sure tests don't overlap when writing rules
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ vlan_id = port + 16
+ mpls_label = port + 16
+
+ # add l2 interface group
+ id, dst_mac[ 5 ] = port, port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, port, vlan_id, True, False )
+ # add L3 Unicast group
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add L3 ecmp group
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x8847, intf_src_mac, vlan_id, goto_table=24 )
+ else:
+ add_termination_flow( self.controller, port, 0x8847, intf_src_mac, vlan_id, goto_table=24 )
+
+ if config["switch_type"] != 'xpliant':
+ add_mpls_flow( self.controller, ecmp_msg.group_id, mpls_label )
+ else:
+ xpliant_add_mpls_flow( self.controller, ecmp_msg.group_id, mpls_label )
+
+ # add_mpls_flow(self.controller, label=port)
+ dst_ip = dip + (vlan_id << 8)
+ # add_unicast_routing_flow(self.controller, 0x0800, dst_ip, 0xffffff00,
+ # ecmp_msg.group_id, 1)
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ Groups._put( ecmp_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ out_mpls_label = out_port + 16
+ in_vlan_vid = in_port + 16
+ out_vlan_vid = out_port + 16
+
+ ip_dst = '192.168.%02d.1' % (out_port)
+ label = (out_mpls_label, 0, 1, 32)
+ parsed_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(in_vlan_vid),
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=switch_mac, label=[ label ] )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ if config["switch_type"] != 'xpliant':
+ ip_ttl=31
+ else:
+ ip_ttl=64
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(out_vlan_vid),
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=ip_ttl, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class One_MplsTermination( base_tests.SimpleDataPlane ):
+ """
+ Verify MPLS VPN Termination at penultimate hop in only one direction
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ dip = 0xc0a80001
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ # Assigns unique hardcoded test_id to make sure tests don't overlap when writing rules
+ ports = config[ "port_map" ].keys( )
+ inport = ports[0]
+ outport = ports[1]
+
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ invlan_id = inport + 16
+ outvlan_id = outport + 16
+ mpls_label = outport + 16
+
+ # add l2 interface group
+ id, dst_mac[ 5 ] = inport, outport
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, outport, outvlan_id, True, False )
+ # add L3 Unicast group
+ l3_msg = add_l3_unicast_group( self.controller, outport, vlanid=outvlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add L3 ecmp group
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, inport, 1, invlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add tmac flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x8847, intf_src_mac, invlan_id, goto_table=24 )
+ else:
+ add_termination_flow( self.controller, inport, 0x8847, intf_src_mac, invlan_id, goto_table=24 )
+ # add mpls termination flow
+ add_mpls_flow( self.controller, ecmp_msg.group_id, mpls_label, send_barrier=True )
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ Groups._put( ecmp_msg.group_id )
+
+ time.sleep(0.1)
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ ip_src = '192.168.%02d.1' % (inport)
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ out_mpls_label = outport + 16
+ in_vlan_vid = inport + 16
+ out_vlan_vid = outport + 16
+
+ ip_dst = '192.168.%02d.1' % (outport)
+ label = (out_mpls_label, 0, 1, 32)
+ parsed_pkt = mpls_packet( pktlen=104, dl_vlan_enable=True, vlan_vid=(in_vlan_vid),
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=switch_mac, label=[ label ] )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( inport, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % (outport)
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(out_vlan_vid),
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=31, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, outport )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF__24UcastTagged_TC_0045( base_tests.SimpleDataPlane ):
+ """ Verify /24 IP forwarding to L3 Interface """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ test_id = 26
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ vlan_id = port + test_id
+ l2gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ # def add_unicast_routing_flow(ctrl, eth_type, dst_ip, mask, action_group_id, vrf=0, send_ctrl=False, send_barrier=False, priority = 1):
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, l3_msg.group_id )
+ Groups.put( l2gid )
+ Groups.put( l3_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % (test_id + in_port)
+ ip_src = '192.168.%02d.1' % (test_id + in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (test_id + out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + in_port), eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % (test_id + out_port)
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + out_port), eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class _24UcastRouteBlackHole( base_tests.SimpleDataPlane ):
+ """ Verify black-holing of unicast routes, feature present only from OFDPA Premium 1.1.3.0"""
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ test_id = 27
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ vlan_id = port + test_id
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ #dst ip = 10.0.0.0/8
+ dst_ip = 0x0a000000
+ add_unicast_blackhole_flow(self.controller, 0x0800, dst_ip, 0xffffff00 )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % (test_id + in_port)
+ ip_src = '192.168.%02d.1' % (test_id + in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (test_id + out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + in_port), eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % (test_id + out_port)
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=(test_id + out_port), eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_no_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class _0Ucast( base_tests.SimpleDataPlane ):
+ """ Verify default gateway IP forwarding to L3 Interface ( /0 rule ) """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+ for port in ports:
+ # add l2 interface group
+ vlan_id = port
+ l2gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id + 1,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id + 1, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffffff, l3_msg.group_id, priority=2 )
+ Groups.put( l2gid )
+ Groups.put( l3_msg.group_id )
+ l3_gid = encode_l3_unicast_group_id( ports[ 0 ] )
+ dst_ip = 0x0
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0x0, l3_gid )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ for in_port in ports:
+ mac_src = '00:00:00:22:22:%02X' % (in_port)
+ ip_src = '192.168.%02d.1' % (in_port)
+ for out_port in ports:
+ if in_port == out_port:
+ continue
+ ip_dst = '192.168.%02d.1' % (out_port)
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(in_port),
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % (out_port)
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=(out_port + 1),
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ ip_dst = '1.168.%02d.1' % ports[ 0 ]
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=in_port,
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expect packet
+ mac_dst = '00:00:00:22:22:%02X' % ports[ 0 ]
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ] + 1,
+ ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst, eth_dst=mac_dst, eth_src=switch_mac )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, ports[ 0 ] )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class Unfiltered( base_tests.SimpleDataPlane ):
+ """
+ Attempt to add an unfiltered group: [ATTENTION] this doesn't verify addition
+ """
+
+ def runTest( self ):
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+ vlan_id = 1;
+ for port in ports:
+ add_l2_unfiltered_group( self.controller, [ port ], False )
+ do_barrier( self.controller )
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+@disabled
+class L3McastToVPN( base_tests.SimpleDataPlane ):
+ """
+ Mcast routing and VPN initiation
+ """
+
+ def runTest( self ):
+ """
+ port1 (vlan 1)-> port 2 (vlan 2)
+ """
+ try:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+ if len( config[ "port_map" ] ) < 3:
+ logging.info( "Port count less than 3, can't run this case" )
+ assert (False)
+ return
+
+ vlan_id = 1
+ port2_out_vlan = 2
+ port3_out_vlan = 3
+ in_vlan = 1 # macast group vid shall use input vlan diffe from l3 interface use output vlan
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ intf_src_mac_str = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ dst_mac = [ 0x01, 0x00, 0x5e, 0x01, 0x01, 0x01 ]
+ dst_mac_str = ':'.join( [ '%02X' % x for x in dst_mac ] )
+ port1_mac = [ 0x00, 0x11, 0x11, 0x11, 0x11, 0x11 ]
+ port1_mac_str = ':'.join( [ '%02X' % x for x in port1_mac ] )
+ src_ip = 0xc0a80101
+ src_ip_str = "192.168.1.1"
+ dst_ip = 0xe0010101
+ dst_ip_str = "224.1.1.1"
+
+ port1 = config[ "port_map" ].keys( )[ 0 ]
+ port2 = config[ "port_map" ].keys( )[ 1 ]
+ # port3=config["port_map"].keys()[2]
+
+ # add l2 interface group
+ for port in config[ "port_map" ].keys( ):
+ add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id, is_tagged=False,
+ send_barrier=False )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ vlan_id += 1
+
+ # add termination flow
+ add_termination_flow( self.controller, port1, 0x0800, [ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 ],
+ vlan_id )
+
+ # add MPLS interface group
+ l2_gid = encode_l2_interface_group_id( port2_out_vlan, port2 )
+ mpls_gid2, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dst_mac, intf_src_mac,
+ port2_out_vlan, port2 )
+ # l2_gid3 = encode_l2_interface_group_id(port3_out_vlan, port3)
+ # mpls_gid3, mpls_msg = add_mpls_intf_group(self.controller, l2_gid3, dst_mac, intf_src_mac, port3_out_vlan, port3)
+ # add L3VPN groups
+ mpls_label_gid2, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=(0x20000 + port2), ref_gid=mpls_gid2,
+ push_mpls_header=True, set_mpls_label=port2, set_bos=1, cpy_ttl_outward=True )
+ # mpls_label_gid3, mpls_label_msg = add_mpls_label_group(self.controller, subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL,
+ # index=(0x10000+port3), ref_gid= mpls_gid3, push_mpls_header=True, set_mpls_label=port3, set_bos=1, cpy_ttl_outward=True)
+
+ mcat_group_msg = add_l3_mcast_group( self.controller, in_vlan, 2, [ mpls_label_gid2 ] )
+ add_mcast4_routing_flow( self.controller, in_vlan, src_ip, 0, dst_ip, mcat_group_msg.group_id )
+
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=1, eth_dst=dst_mac_str,
+ eth_src=port1_mac_str, ip_ttl=64, ip_src=src_ip_str, ip_dst=dst_ip_str )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( port1, pkt )
+ label = (12, 0, 1, 63)
+ exp_pkt = mpls_packet( pktlen=100, eth_dst=dst_mac_str, eth_src=intf_src_mac_str, ip_ttl=64,
+ ip_src=src_ip_str, label=[ label ], ip_dst=dst_ip_str )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, port2 )
+ # verify_packet(self, pkt, port3)
+ verify_no_other_packets( self )
+ delete_all_groups( self.controller )
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+@disabled
+class PacketInSrcMacMiss( base_tests.SimpleDataPlane ):
+ """
+ Test packet in function on a src-mac miss
+ Send a packet to each dataplane port and verify that a packet
+ in message is received from the controller for each
+ #todo verify you stop receiving after adding rule
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ ports = sorted( config[ "port_map" ].keys( ) )
+
+ Groups = Queue.LifoQueue( )
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group( self.controller, port, 1, True, False )
+ add_one_vlan_table_flow( self.controller, port, 1, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ Groups.put( L2gid )
+ parsed_vlan_pkt = simple_tcp_packet( pktlen=104, vlan_vid=0x1001, dl_vlan_enable=True )
+ vlan_pkt = str( parsed_vlan_pkt )
+ for of_port in config[ "port_map" ].keys( ):
+ logging.info( "PacketInMiss test, port %d", of_port )
+ self.dataplane.send( of_port, vlan_pkt )
+ verify_packet_in( self, vlan_pkt, of_port, ofp.OFPR_NO_MATCH )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+
+class FabricSW_OF_EcmpGroupMod_TC_0025( base_tests.SimpleDataPlane ):
+ """
+ Verify referenced group can be modified by adding or removing buckets
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ # Hashes Test Name and uses it as id for installing unique groups
+ ports = config[ "port_map" ].keys( )
+ ecmp = [ ]
+ dst_ips = []
+ # add flows for all ports but include only the egress switchport (connected to ports[1])
+ # in the ecmp group
+ for port in ports:
+ vlan_id = port
+ id = port
+ # add l2 interface group
+ l2_gid, msg = add_one_l2_interface_group( self.controller, port, vlan_id=vlan_id,
+ is_tagged=True, send_barrier=False )
+ dst_mac[ 5 ] = vlan_id
+ l3_msg = add_l3_unicast_group( self.controller, port, vlanid=vlan_id, id=id,
+ src_mac=intf_src_mac, dst_mac=dst_mac )
+ if port == ports[1]:
+ ecmp += [ l3_msg.group_id ]
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ ecmp_msg = add_l3_ecmp_group( self.controller, ports[ 0 ], [ l3_msg.group_id ] )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ dst_ip = dip + (vlan_id << 8)
+ dst_ips += [dst_ip]
+ Groups._put( ecmp_msg.group_id )
+ mod_l3_ecmp_group( self.controller, ports[ 0 ], ecmp )
+ for dst_ip in dst_ips:
+ add_unicast_routing_flow( self.controller, 0x0800, dst_ip, 0xffffff00, ecmp_msg.group_id )
+ do_barrier(self.controller)
+ time.sleep(0.1)
+ # first part of the test: send packet from ingress switchport and expect it at egress switchport
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ parsed_pkt = exp_pkt = 0
+ in_port = ports[0]
+ out_port = ports[1]
+ logging.info("\nSending packet to port: " + str(in_port) + ", expected egress on port: " + str(out_port))
+ mac_src = '00:00:00:22:22:%02X' % ports[ 0 ]
+ ip_src = '192.168.%02d.%02d' % (ports[ 0 ], 1)
+ ip_dst = '192.168.%02d.%02d' % (ports[ 1 ], 1)
+ tcp = out_port if out_port == 24 else 25
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ],
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src,
+ ip_dst=ip_dst, tcp_dport=tcp )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ports[ 0 ], pkt )
+ # build expected packet at egress switchport
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src,
+ ip_dst=ip_dst, tcp_dport=tcp )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ # second part of the test - edit the ecmp group to remove the orginal egress switchport
+ # and instead add the ingress switchport. Send packet from ingress switchport, and expect
+ # it back on the ingress switchport
+ l3_gid = encode_l3_unicast_group_id( ports[ 0 ] )
+ mod_l3_ecmp_group( self.controller, ports[ 0 ], [ l3_gid ] )
+ time.sleep(0.1)
+ logging.info("Sending packet to port: " + str(ports[0]) + ", expected egress on port: " + str(ports[0]))
+ mac_src = '00:00:00:22:22:%02X' % ports[ 0 ]
+ ip_src = '192.168.%02d.%02d' % (ports[ 0 ], 1)
+ ip_dst = '192.168.%02d.%02d' % (ports[ 1 ], 1)
+ tcp = port if port == 24 else 25
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ],
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src,
+ ip_dst=ip_dst,tcp_dport=tcp )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ports[ 0 ], pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:%02X' % ports[ 0 ]
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ],
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src,
+ ip_dst=ip_dst,tcp_dport=tcp )
+ # Expects packet on the input port
+ if config["switch_type"] != 'xpliant':
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, ports[ 0 ] )
+ verify_no_other_packets( self )
+
+ # third part of the test - edit the group to completely remove bucket. Packet sent
+ # should be dropped by the switch
+ mod_l3_ecmp_group( self.controller, ports[ 0 ], [ ] )
+ time.sleep(0.1)
+ logging.info("Sending packet to port: " + str(ports[0]) + ", expected drop")
+ mac_src = '00:00:00:22:22:%02X' % ports[ 0 ]
+ ip_src = '192.168.%02d.%02d' % (ports[ 0 ], 1)
+ ip_dst = '192.168.%02d.%02d' % (ports[ 1 ], 1)
+ tcp = port if port == 24 else 25
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ],
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src,
+ ip_dst=ip_dst,tcp_dport=tcp )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ports[ 0 ], pkt )
+ verify_no_other_packets( self )
+
+ # final part of the test - edit the empty group to add back the bucket for the
+ # original egress port, and verify packet is received on egress switch port
+ l3_gid = encode_l3_unicast_group_id( ports[ 1 ] )
+ mod_l3_ecmp_group( self.controller, ports[ 0 ], [ l3_gid ] )
+ do_barrier(self.controller)
+ in_port = ports[0]
+ out_port = ports[1]
+ logging.info("Sending packet to port: " + str(in_port) + ", expected egress on port: " + str(out_port))
+ mac_src = '00:00:00:22:22:%02X' % ports[ 0 ]
+ ip_src = '192.168.%02d.%02d' % (ports[ 0 ], 1)
+ ip_dst = '192.168.%02d.%02d' % (ports[ 1 ], 1)
+ tcp = out_port if out_port == 24 else 25
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=ports[ 0 ],
+ eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64, ip_src=ip_src,
+ ip_dst=ip_dst, tcp_dport=tcp )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( ports[ 0 ], pkt )
+ # build expected packet at egress switchport
+ mac_dst = '00:00:00:22:22:%02X' % out_port
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=out_port,
+ eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63, ip_src=ip_src,
+ ip_dst=ip_dst, tcp_dport=tcp )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class Untagged( base_tests.SimpleDataPlane ):
+ """
+ Verify VLAN filtering table does not require OFPVID_PRESENT bit to be 0.
+ This should be fixed in OFDPA 2.0 GA and above, the test fails with
+ previous versions of the OFDPA.
+
+ Two rules are necessary in VLAN table (10):
+ 1) Assignment: match 0x0000/(no mask), set_vlan_vid 0x100A, goto 20
+ 2) Filtering: match 0x100A/0x1FFF, goto 20
+
+ In this test case vlan_id = (MAX_INTERNAL_VLAN - port_no).
+ The remaining part of the test is based on the use of the bridging table
+ """
+
+ MAX_INTERNAL_VLAN = 4094
+
+ def runTest( self ):
+ groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted( config[ "port_map" ].keys( ) )
+ for port in ports:
+ vlan_id = Untagged.MAX_INTERNAL_VLAN - port
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ add_one_vlan_table_flow( self.controller, port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+ for other_port in ports:
+ if other_port == port:
+ continue
+ L2gid, l2msg = add_one_l2_interface_group( self.controller, other_port, vlan_id, False, False )
+ groups.put( L2gid )
+ add_bridge_flow( self.controller, [ 0x00, 0x12, 0x34, 0x56, 0x78, other_port ], vlan_id, L2gid, True )
+
+ do_barrier( self.controller )
+
+ for out_port in ports:
+ # change dest based on port number
+ mac_dst = '00:12:34:56:78:%02X' % out_port
+ for in_port in ports:
+ if in_port == out_port:
+ continue
+ pkt = str( simple_tcp_packet( eth_dst=mac_dst ) )
+ self.dataplane.send( in_port, pkt )
+ for ofport in ports:
+ if ofport in [ out_port ]:
+ verify_packet( self, pkt, ofport )
+ else:
+ verify_no_packet( self, pkt, ofport )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, groups )
+ delete_all_groups( self.controller )
+
+class MPLSSwapTest( base_tests.SimpleDataPlane ):
+ """
+ MPLS switching with the same label used.
+ Used for interconnecting spines between different fabrics where
+ the label should not be popped, but swapepd with the same label.
+ """
+
+ def runTest( self ):
+ try:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 3, can't run this case" )
+ assert (False)
+ return
+
+ input_src_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x01 ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x02 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x5e, 0x01, 0x01, 0x03 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ mpls_label = 1000
+
+ src_ip = 0xc0a80101
+ src_ip_str = "192.168.1.1"
+ dst_ip = 0xe0010101
+ dst_ip_str = "224.1.1.1"
+
+ src_port = config[ "port_map" ].keys( )[ 0 ]
+ dst_port = config[ "port_map" ].keys( )[ 1 ]
+
+ out_vlan = 4094
+
+ add_one_l2_interface_group( self.controller, dst_port, vlan_id=out_vlan, is_tagged=False,
+ send_barrier=True )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, src_port, out_vlan_id=out_vlan, vlan_id=out_vlan, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ add_one_vlan_table_flow( self.controller, src_port, out_vlan_id=out_vlan, vlan_id=out_vlan, flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+
+ # add termination flow
+
+ if config["switch_type"] == "qmx":
+ logging.debug("MPLSSwitching : Adding flow for qmx, without input port")
+ add_termination_flow( self.controller, 0, eth_type=0x08847, dst_mac=input_dst_mac, vlanid=out_vlan, goto_table=23)
+ else:
+ add_termination_flow( self.controller, in_port=src_port,
+ eth_type=0x8847, dst_mac=input_dst_mac, vlanid=out_vlan, goto_table=23)
+
+ # add groups that will be used now
+ l2_gid = encode_l2_interface_group_id( out_vlan, dst_port)
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid,
+ output_dst_mac, input_dst_mac,
+ out_vlan, dst_port, send_barrier=True)
+ index = 60
+ mpls_swap_gid, mpls_swap_msg = add_mpls_swap_label_group( self.controller, mpls_gid,
+ 5, index, mpls_label)
+
+ # add flow to mpls table
+ add_mpls_flow_swap( self.controller, mpls_swap_gid, mpls_label, 0x8847, 1, send_barrier=True)
+
+ # we generate the packet which carries a single label
+ label = (mpls_label, 0, 1, 63)
+ parsed_pkt = mpls_packet(
+ pktlen=104,
+ label=[label],
+ eth_src=input_src_mac_str,
+ eth_dst=input_dst_mac_str,
+ )
+ pkt = str( parsed_pkt )
+
+ self.dataplane.send( src_port, pkt )
+
+ label = (mpls_label, 0, 1, 62)
+ parsed_pkt = mpls_packet(
+ pktlen=104,
+ label=[label],
+ eth_src=input_dst_mac_str,
+ eth_dst=output_dst_mac_str,
+ )
+ pkt = str( parsed_pkt )
+
+ verify_packet( self, pkt, dst_port )
+ verify_no_packet( self, pkt, src_port )
+ verify_no_other_packets( self )
+
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+
+@disabled
+class DoubleToUntagged( base_tests.SimpleDataPlane ):
+ """
+ Verify MPLS IP VPN Initiation from /24 rule using ECMP
+ where we receive double tagged packets and output untagged
+ packets.
+
+ Each double tagged packet represents a subscriber where Outer tag is pon
+ and inner tag is the subrscriber tag.
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = 66
+ outer_vlan = 77
+ id = 10
+ mpls_label = 152
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface group
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, out_port, inner_vlan, False, True )
+
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, output_dst_mac, input_dst_mac,
+ inner_vlan, id )
+
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=mpls_label, set_bos=1, set_ttl=32 )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ mpls_label_gid ] )
+
+ do_barrier( self.controller )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, outer_vlan, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_STACKED )
+
+ add_one_vlan_1_table_flow( self.controller, port, outer_vlan_id=outer_vlan, inner_vlan_id=inner_vlan,
+ flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, input_dst_mac, inner_vlan )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, input_dst_mac, inner_vlan )
+
+ # add_unicast_routing_flow(self.controller, 0x0800, dst_ip, 0, mpls_label_gid, vrf=2)
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffff00, ecmp_msg.group_id,
+ vrf=0 )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ Groups._put( ecmp_msg.group_id )
+
+ do_barrier( self.controller )
+
+ ip_src = '192.168.5.5'
+ ip_dst = '192.168.0.5'
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=inner_vlan, outer_vlan=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+
+ # print("Expected %s" % format_packet(pkt))
+
+ self.dataplane.send( port, pkt )
+
+ # build expect packet
+ label = (mpls_label, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=96, dl_vlan_enable=False, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=output_dst_mac_str, eth_src=input_dst_mac_str,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class DoubleToUntaggedMultipleSubscribers( base_tests.SimpleDataPlane ):
+ """
+ Verify MPLS IP VPN Initiation from /24 rule using ECMP
+ where we receive double tagged packets and output untagged
+ packets.
+
+ Each double tagged packet represents a subscriber where Outer tag is pon
+ and inner tag is the subrscriber tag.
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ # each entry represents a subscriber [id, ip in hex, inner_vlan, outer_vlan, ip in dot form]
+ subscriber_info = [ [10, 0xc0a80001, 10, 100, "192.168.0.1"],
+ [20, 0xc0a80002, 10, 101, "192.168.0.2"],
+ [30, 0xc0a80003, 11, 100, "192.168.0.3"],
+ [40, 0xc0a80004, 11, 101, "192.168.0.4"]]
+
+ print("")
+
+ for sub_info in subscriber_info:
+
+ print("Initializing rules for subscriber with id {0}".format(sub_info[0]))
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+ id = 10
+ mpls_label = 152
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface group
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, out_port, inner_vlan, False, True )
+
+ # add MPLS interface group
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, output_dst_mac, input_dst_mac,
+ inner_vlan, id )
+
+ # add MPLS L3 VPN group
+ mpls_label_gid, mpls_label_msg = add_mpls_label_group( self.controller,
+ subtype=OFDPA_MPLS_GROUP_SUBTYPE_L3_VPN_LABEL, index=id, ref_gid=mpls_gid,
+ push_mpls_header=True, set_mpls_label=mpls_label, set_bos=1, set_ttl=32 )
+ ecmp_msg = add_l3_ecmp_group( self.controller, id, [ mpls_label_gid ] )
+
+ do_barrier( self.controller )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, outer_vlan, vrf=0,
+ flag=VLAN_TABLE_FLAG_ONLY_STACKED )
+
+ add_one_vlan_1_table_flow( self.controller, port, outer_vlan_id=outer_vlan, inner_vlan_id=inner_vlan,
+ flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, input_dst_mac, inner_vlan )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, input_dst_mac, inner_vlan )
+
+ # add_unicast_routing_flow(self.controller, 0x0800, dst_ip, 0, mpls_label_gid, vrf=2)
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffff00, ecmp_msg.group_id,
+ vrf=0 )
+ Groups._put( l2_gid )
+ Groups._put( mpls_gid )
+ Groups._put( mpls_label_gid )
+ Groups._put( ecmp_msg.group_id )
+
+ do_barrier( self.controller )
+
+ for sub_info in subscriber_info:
+
+ print("Sending packet for subscriber with id {0}".format(sub_info[0]))
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+ id = 10
+ mpls_label = 152
+
+ port = ports[0]
+ out_port = ports[1]
+
+ ip_src = sub_info[4]
+ ip_dst = '192.168.0.{}'.format(sub_info[0])
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=inner_vlan, outer_vlan=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+
+ # print("Sent %s" % format_packet(pkt))
+
+ self.dataplane.send( port, pkt )
+
+ # build expect packet
+ label = (mpls_label, 0, 1, 32)
+ exp_pkt = mpls_packet( pktlen=96, dl_vlan_enable=False, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst, eth_dst=output_dst_mac_str, eth_src=input_dst_mac_str,
+ label=[ label ] )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class UntaggedToDouble ( base_tests.SimpleDataPlane ):
+ """
+ Verify google senario where we need to go from
+ an untagged packet to a double tagged packet.
+
+ This is used for a single subscriber.
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = 66
+ outer_vlan = 77
+ id = 10
+ mpls_label = 152
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 unfiltered interface group
+ l2_gid, l2_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ l3_msg = add_l3_unicast_group( self.controller, out_port, vlanid=4094, id=id,
+ src_mac=input_dst_mac, dst_mac=output_dst_mac, gid=l2_gid)
+
+ do_barrier( self.controller )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, 4094,
+ flag=VLAN_TABLE_FLAG_ONLY_BOTH )
+
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, input_dst_mac, 4094 )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, input_dst_mac, 4094 )
+
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffffff, l3_msg.group_id,
+ vrf=0 )
+
+ add_one_egress_vlan_table_flow( self.controller, out_port, 4094 , inner_vlan, outer_vlan)
+
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+
+ do_barrier( self.controller )
+
+ ip_src = '192.168.5.5'
+ ip_dst = '192.168.0.1'
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=False,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+
+ # print("Input Packet %s" % format_packet(pkt))
+
+ self.dataplane.send( port, pkt )
+
+ # build expect packet
+ exp_pkt = simple_tcp_packet( pktlen=108, dl_vlan_enable=True, vlan_vid=inner_vlan, outer_vlan=outer_vlan,
+ eth_dst=output_dst_mac_str, eth_src=input_dst_mac_str, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+
+ # print("Expected Packet %s" % format_packet(pkt))
+
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class UntaggedToDoubleMultipleSubscribers ( base_tests.SimpleDataPlane ):
+ """
+ Verify google senario where we need to go from
+ an untagged packet to a double tagged packet.
+
+ This is used for multiple subscribers.
+
+ However, this solution does not scale, since we assign an internal vlan to each subscriber
+ used in L3 Unicast Group in order to differentiate between them in the Egress Vlan Table.
+ """
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ # each entry represents a subscriber [id, ip in hex, inner_vlan, outer_vlan, ip in dot form, internal vlan]
+ subscriber_info = [[1, 0xc0a80001, 10, 100, "192.168.0.1", 4000],
+ [2, 0xc0a80002, 10, 101, "192.168.0.2", 4001],
+ [3, 0xc0a80003, 11, 100, "192.168.0.3", 4002],
+ [4, 0xc0a80004, 11, 101, "192.168.0.4", 4003]]
+
+ print("")
+
+ for sub_info in subscriber_info:
+
+ print("Initializing rules for subscriber with id {0}".format(sub_info[0]))
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+ internal_vlan = sub_info[5]
+ id = sub_info[0] + 10
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 unfiltered interface group
+ l2_gid, l2_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ l3_msg = add_l3_unicast_group( self.controller, out_port, vlanid=internal_vlan, id=id,
+ src_mac=input_dst_mac, dst_mac=output_dst_mac, gid=l2_gid)
+
+ do_barrier( self.controller )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, 4094,
+ flag=VLAN_TABLE_FLAG_ONLY_BOTH )
+
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, input_dst_mac, 4094 )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, input_dst_mac, 4094 )
+
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffffff, l3_msg.group_id,
+ vrf=0 )
+
+ add_one_egress_vlan_table_flow( self.controller, out_port, internal_vlan, inner_vlan, outer_vlan)
+
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+ do_barrier( self.controller )
+
+ for sub_info in subscriber_info:
+
+ print("Sending packet for subscriber with id {0}".format(sub_info[0]))
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+ internal_vlan = sub_info[5]
+
+ id = sub_info[0] + 10
+ ip_src = '192.168.5.5'
+ ip_dst = '192.168.0.{}'.format(sub_info[0])
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=False,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+
+ # print("Input Packet %s" % format_packet(pkt))
+
+ self.dataplane.send( port, pkt )
+
+ # build expect packet
+ exp_pkt = simple_tcp_packet( pktlen=108, dl_vlan_enable=True, vlan_vid=inner_vlan, outer_vlan=outer_vlan,
+ eth_dst=output_dst_mac_str, eth_src=input_dst_mac_str, ip_ttl=63, ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+
+ # print("Expected Packet %s" % format_packet(pkt))
+
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class UntaggedToDoubleChangeEthertype ( base_tests.SimpleDataPlane ):
+
+ def runTest( self ):
+ Groups = Queue.LifoQueue()
+
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "port count less than 2, can't run this case" )
+ return
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = 0xc0a80001
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = 66
+ outer_vlan = 77
+ id = 10
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 unfiltered interface group
+ l2_gid, l2_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ l3_msg = add_l3_unicast_group( self.controller, out_port, vlanid=4094, id=id,
+ src_mac=input_dst_mac, dst_mac=output_dst_mac, gid=l2_gid)
+
+ do_barrier( self.controller )
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, 1, 4094,
+ flag=VLAN_TABLE_FLAG_ONLY_BOTH )
+
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, input_dst_mac, 4094 )
+ else:
+ add_termination_flow( self.controller, port, 0x0800, input_dst_mac, 4094 )
+
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffffff, l3_msg.group_id,
+ vrf=0 )
+
+ add_one_egress_vlan_table_flow( self.controller, out_port, 4094 , inner_vlan, outer_vlan)
+
+ Groups._put( l2_gid )
+ Groups._put( l3_msg.group_id )
+
+ # add vlan flow table
+ add_one_egress_vlan_tpid_table_flow( self.controller, out_port, outer_vlan+0x1000 )
+ do_barrier( self.controller )
+
+ ip_src = '192.168.5.5'
+ ip_dst = '192.168.0.1'
+ parsed_pkt = simple_tcp_packet( pktlen=100,
+ dl_vlan_enable=False,
+ eth_dst=input_dst_mac_str,
+ eth_src=input_src_mac_str,
+ ip_ttl=64,
+ ip_src=ip_src,
+ ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+
+ print("Input Packet %s" % format_packet(pkt))
+
+ self.dataplane.send( port, pkt )
+
+ # build expect packet
+ exp_pkt = simple_tcp_packet_two_vlan( pktlen=108,
+ out_dl_vlan_enable=True,
+ out_vlan_vid=outer_vlan,
+ out_vlan_tpid=0x88a8,
+ in_dl_vlan_enable=True,
+ in_vlan_vid=inner_vlan,
+ eth_dst=output_dst_mac_str,
+ eth_src=input_dst_mac_str,
+ ip_ttl=63,
+ ip_src=ip_src,
+ ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+
+ print("Expected Packet %s" % format_packet(pkt))
+
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class _MplsFwdInterfaceProblem_PW( base_tests.SimpleDataPlane ):
+ """
+ Reproduces the pseudowire bug with the wrongly set destination mac address.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 1:
+ logging.info( "Port count less than 1, can't run this case" )
+ assert (False)
+ return
+
+ macs_to_test = [( [ 0x00, 0x00, 0x00, 0x11, 0x11, 0x00 ], [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ], '00:00:00:11:11:00', '00:00:00:22:22:00'),
+ ( [ 0x00, 0x00, 0x00, 0x11, 0x22, 0x00 ], [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ], '00:00:00:11:22:00', '00:00:00:33:33:00'),
+ ( [ 0x00, 0x00, 0x00, 0x11, 0x33, 0x00 ], [ 0x00, 0x00, 0x00, 0x44, 0x44, 0x00 ], '00:00:00:11:33:00', '00:00:00:44:44:00'),
+ ( [ 0x00, 0x00, 0x00, 0x11, 0x44, 0x00 ], [ 0x00, 0x00, 0x00, 0x55, 0x55, 0x00 ], '00:00:00:11:44:00', '00:00:00:55:55:00'),
+ ( [ 0x00, 0x00, 0x00, 0x11, 0x55, 0x00 ], [ 0x00, 0x00, 0x00, 0x66, 0x66, 0x00 ], '00:00:00:11:55:00', '00:00:00:66:66:00')]
+
+ for dummy_dst_mac, dst_mac, mac_dst_dummy, mac_dst in macs_to_test:
+
+ dip = 0xc0a80001
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+
+ out_port = 12
+ port = 24
+ # Shift MPLS label and VLAN ID by 16 to avoid reserved values
+ vlan_id = port + 16
+ mpls_label = port + 16
+
+ in_port = 24
+ ip_src = '192.168.%02d.1' % (in_port)
+
+ # create dummy groups
+ id = port
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, out_port, vlan_id, False, False)
+ mpls_gid, mpls_msg = add_mpls_intf_group( self.controller, l2_gid, dummy_dst_mac, intf_src_mac,
+ vlan_id, id, send_barrier=True)
+ do_barrier( self.controller )
+
+ # PW Case.
+ raw_input("Press anything to move on with pseudowire rules, after that you should see the updated groups in the switch.")
+ logging.info("Installing entries for pseudowire!")
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ mpls_label = 100
+ mpls_label_SR2 = 100 + 10
+ mpls_label_PW = 100 + 15
+
+ print("Install MPLS intf group for dst mac {0}", dst_mac)
+ # add MPLS interface group
+ mpls_intf_gid, mpls_intf_msg = add_mpls_intf_group(
+ ctrl=self.controller,
+ ref_gid=l2_gid,
+ dst_mac=dst_mac,
+ src_mac=intf_src_mac,
+ vid=vlan_id,
+ index=id,
+ add=False,
+ send_barrier=True
+ )
+
+ # add MPLS flow with BoS=0
+ add_mpls_flow_pw(
+ ctrl=self.controller,
+ action_group_id=mpls_intf_gid,
+ label=mpls_label_SR2,
+ ethertype=0x8847,
+ tunnel_index=1,
+ bos=0
+ )
+
+ # add Termination flow
+ add_termination_flow(
+ ctrl=self.controller,
+ in_port=in_port,
+ eth_type=0x8847,
+ dst_mac=intf_src_mac,
+ vlanid=vlan_id,
+ goto_table=23
+ )
+
+ # add VLAN flows
+ add_one_vlan_table_flow(
+ ctrl=self.controller,
+ of_port=in_port,
+ vlan_id=vlan_id,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG,
+ )
+ add_one_vlan_table_flow(
+ ctrl=self.controller,
+ of_port=in_port,
+ vlan_id=vlan_id,
+ flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+ )
+ # Packet generation with sleep
+ time.sleep(2)
+ label_SR2 = (mpls_label_SR2, 0, 0, 32)
+ label_2 = (mpls_label_PW, 0, 1, 32)
+
+ # set to false to test if routing traffic
+ # comes through
+ raw_input("Press enter to send the packet, inspect the groups in the switch!")
+ print("Sending packet with dst mac {0} and labels {1}".format(switch_mac, [label_SR2, label_2]))
+ parsed_pkt = mpls_packet(
+ pktlen=104,
+ ip_ttl=63,
+ label=[label_SR2, label_2],
+ encapsulated_ethernet = True,
+ eth_dst=switch_mac
+ )
+
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+
+ expected_label = (mpls_label_PW, 0, 1, 31)
+ print("Expecting packet with dst mac {0} and labels {1}".format(mac_dst, [label_2]))
+ parsed_pkt = mpls_packet(
+ pktlen=100,
+ ip_ttl=63,
+ eth_dst=mac_dst,
+ eth_src=switch_mac,
+ label=[ expected_label ],
+ encapsulated_ethernet = True
+ )
+
+ pkt = str( parsed_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_packet( self, pkt, in_port )
+
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+class VlanCrossConnect ( base_tests.SimpleDataPlane ):
+ """
+ Tries the cross connect functionality of the ofdpa switches.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ # each entry represents a subscriber [id, ip in hex, inner_vlan, outer_vlan, ip in dot form]
+ subscriber_info = [ [10, 0xc0a80001, 12, 11, "192.168.0.1"] ]
+
+ index = 5
+ for sub_info in subscriber_info:
+
+ #print("Initializing rules for subscriber with id {0}".format(sub_info[0]))
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+
+ index = inner_vlan
+
+ port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface group, uncomment for unfiltered
+ l2_gid, l2_msg = add_one_l2_interface_group( self.controller, out_port, outer_vlan, True, True)
+ #i l2_gid, l2_msg = add_one_l2_unfiltered_group( self.controller, out_port, 1, True)
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, inner_vlan, outer_vlan, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_STACKED )
+ add_one_vlan_1_table_flow_pw( self.controller, port, index, new_outer_vlan_id=outer_vlan ,outer_vlan_id=outer_vlan, inner_vlan_id=inner_vlan, cross_connect=True, send_barrier=True)
+ add_mpls_l2_port_flow(ctrl=self.controller, of_port=port, mpls_l2_port=port, tunnel_index=index, ref_gid=l2_gid, qos_index=0, goto=ACL_FLOW_TABLE)
+ index += 1
+
+ Groups._put( l2_gid )
+ do_barrier( self.controller )
+
+ for sub_info in subscriber_info:
+ #print("Sending packet for subscriber with id {0}".format(sub_info[0]))
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+
+ port = ports[0]
+ out_port = ports[1]
+
+ ip_src = sub_info[4]
+ ip_dst = '192.168.0.{}'.format(sub_info[0])
+ parsed_pkt = qinq_tcp_packet( pktlen=120, vlan_vid=inner_vlan, dl_vlan_outer=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ parsed_pkt = simple_tcp_packet_two_vlan( pktlen=120, out_dl_vlan_enable=True, in_dl_vlan_enable=True, in_vlan_vid=inner_vlan, out_vlan_vid=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+
+ pkt = str( parsed_pkt )
+
+ self.dataplane.send( port, pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class Lag( base_tests.SimpleDataPlane ):
+ """
+ Checks the L2 load balancing (LAG) functionality of the ofdpa switches.
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface unfiltered group
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+ Groups.put(l2_o_gid, lag_gid)
+
+ # --- TEST 1: bridging with load-bal----
+ vlan_in_port_untagged = 31
+ # table 10 flows and bridging flows for dstMac+vlan -> l2-load-bal group
+ add_one_vlan_table_flow( self.controller, in_port, vlan_id=vlan_in_port_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+ mac_dst = [ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 ]
+ mac_dst_str = '00:11:22:33:44:55'
+ add_bridge_flow( self.controller, mac_dst, vlan_in_port_untagged, lag_gid, True )
+ # untagged packet input becomes tagged packet at output
+ time.sleep(0.1)
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=mac_dst_str ) )
+ exp_pkt = str( simple_tcp_packet( pktlen=84, dl_vlan_enable=True, vlan_vid=vlan_in_port_untagged, eth_dst=mac_dst_str ) )
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+ verify_no_other_packets( self )
+
+ # --- TEST 2: flooding with load-bal ----
+ # flooding group --> load-bal group --> l2 unfiltered interface
+ floodmsg = add_l2_flood_group_with_gids( self.controller, [lag_gid] , vlan_in_port_untagged, id=0 )
+ Groups.put( floodmsg.group_id )
+ # add bridging flows for flooding groups
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_in_port_untagged, group_id=floodmsg.group_id )
+ # unknown dstmac packet input to hit flood group
+ un_mac_dst_str = '00:11:22:ff:ff:ff'
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=un_mac_dst_str ) )
+ exp_pkt = str( simple_tcp_packet( pktlen=84, dl_vlan_enable=True, vlan_vid=vlan_in_port_untagged, eth_dst=un_mac_dst_str ) )
+ time.sleep(0.1)
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+ verify_no_other_packets( self )
+
+ # --- TEST 3: editing load-bal ----
+ # create and add another l2 unfiltered interface group to the load-balancing group
+ l2_i_gid, l2_i_msg = add_one_l2_unfiltered_group( self.controller, in_port, True)
+ msg = mod_l2_loadbal_group(self.controller, 1, [l2_o_gid, l2_i_gid], True)
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+
+ # delete all buckets in loadbal group
+ msg = mod_l2_loadbal_group(self.controller, 1, [], True)
+ time.sleep(0.1)
+ self.dataplane.send( in_port, pkt )
+ verify_no_other_packets( self ) # no buckets
+
+ # only input port in load balancing group
+ msg = mod_l2_loadbal_group(self.controller, 1, [l2_i_gid], True)
+ self.dataplane.send( in_port, pkt )
+ verify_no_other_packets( self ) # packet should not be sent out of in port
+
+ # remove input port and add output port in lag group
+ msg = mod_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+ time.sleep(0.1)
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ #print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class FloodLb( base_tests.SimpleDataPlane ):
+ """
+ Checks L2 flood group pointing to L2 load balance group with 2 buckets (unfiltered).
+ The packet from in_port should not be seen on the out_port
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+ vlan_in_port_untagged = 31
+
+ # add l2 unfiltered interface group for outport
+ l2_i_gid, l2_i_msg = add_one_l2_unfiltered_group( self.controller, in_port, True)
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_i_gid, l2_o_gid], True)
+
+ # create l2 flood group with mix of l2i and l2-loadbal
+ floodmsg = add_l2_flood_group_with_gids( self.controller, [lag_gid] , vlan_in_port_untagged, id=0, send_barrier=True )
+ Groups.put( l2_i_gid )
+ Groups.put( l2_o_gid )
+ Groups.put( lag_gid )
+ Groups.put( floodmsg.group_id )
+
+ # table 10 flows for untagged input
+ add_one_vlan_table_flow( self.controller, in_port, vlan_id=vlan_in_port_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+ add_one_vlan_table_flow( self.controller, out_port, vlan_id=vlan_in_port_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+
+ # add bridging flows for flooding groups
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_in_port_untagged, group_id=floodmsg.group_id )
+ # unknown dstmac packet will hit flood group
+ un_mac_dst_str = '00:11:22:ff:ff:ff'
+
+ # check one direction -> packet enters through inport should not be seen on the outport
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=un_mac_dst_str ) )
+ self.dataplane.send( in_port, pkt )
+ verify_no_other_packets( self )
+
+ # check other direction -> packet enters through outport should not be seen on the inport
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=un_mac_dst_str ) )
+ self.dataplane.send( out_port, pkt )
+ verify_no_other_packets( self )
+
+ finally:
+ #print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class FloodMixUntagged( base_tests.SimpleDataPlane ):
+ """
+ Checks the combination of L2 filtered and L2 load balancing (LAG) groups
+ in a flooding group
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+ vlan_in_port_untagged = 31
+
+ # add l2 unfiltered interface group for outport
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+
+ # create l2 interface (filtered) group for inport
+ l2_i_gid, l2_i_msg = add_one_l2_interface_group( self.controller, in_port, vlan_in_port_untagged,
+ is_tagged=False, send_barrier=True)
+
+ # create l2 flood group with mix of l2i and l2-loadbal
+ floodmsg = add_l2_flood_group_with_gids( self.controller, [lag_gid, l2_i_gid] , vlan_in_port_untagged, id=0 )
+ Groups.put( l2_o_gid )
+ Groups.put( lag_gid )
+ Groups.put( l2_i_gid )
+ Groups.put( floodmsg.group_id )
+
+ # table 10 flows for untagged input
+ add_one_vlan_table_flow( self.controller, in_port, vlan_id=vlan_in_port_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+
+ # add bridging flows for flooding groups
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_in_port_untagged, group_id=floodmsg.group_id )
+ # unknown dstmac packet will hit flood group
+ un_mac_dst_str = '00:11:22:ff:ff:ff'
+
+ # check one direction -> packet enters through filtered port (inport) and exits through
+ # unfiltered port (outport) via the flood and lag groups
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=un_mac_dst_str ) )
+ exp_pkt = str( simple_tcp_packet( pktlen=84, dl_vlan_enable=True, vlan_vid=vlan_in_port_untagged, eth_dst=un_mac_dst_str ) )
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+ verify_no_other_packets( self )
+
+ # check other direction -> packet enters through unfiltered port (outport) and exits through
+ # filtered port (inport) via the flood group
+ add_one_vlan_table_flow( self.controller, out_port, vlan_id=vlan_in_port_untagged, flag=VLAN_TABLE_FLAG_ONLY_BOTH,
+ send_barrier=True)
+ pkt = str( simple_tcp_packet( pktlen=80, eth_dst=un_mac_dst_str ) )
+ exp_pkt = pkt # ingress packet gets internal vlan 31 which gets popped at l2 interface group before egress
+ self.dataplane.send( out_port, pkt )
+ verify_packet( self, exp_pkt, in_port )
+ verify_no_other_packets( self )
+
+ finally:
+ print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class FloodMixTagged( base_tests.SimpleDataPlane ):
+ """
+ Checks the combination of L2 filtered and L2 load balancing (LAG) groups
+ in a flooding group
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+ vlan_in_port_untagged = 31
+
+ # add l2 unfiltered interface group for outport
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+
+ # create l2 interface (filtered) group for inport
+ l2_i_gid, l2_i_msg = add_one_l2_interface_group( self.controller, in_port, vlan_in_port_untagged,
+ is_tagged=True, send_barrier=True)
+
+ # create l2 flood group with mix of l2i and l2-loadbal
+ floodmsg = add_l2_flood_group_with_gids( self.controller, [lag_gid, l2_i_gid] , vlan_in_port_untagged, id=0 )
+ Groups.put( l2_o_gid )
+ Groups.put( lag_gid )
+ Groups.put( l2_i_gid )
+ Groups.put( floodmsg.group_id )
+
+ # table 10 flows for tagged in_port. Note: VLAN in table 10 must be wildcarded for an unfiltered port
+ add_vlan_table_flow_allow_all_vlan(self.controller, in_port, send_barrier=True)
+
+ # add bridging flows for flooding groups
+ add_bridge_flow( self.controller, dst_mac=None, vlanid=vlan_in_port_untagged, group_id=floodmsg.group_id )
+ # unknown dstmac packet will hit flood group
+ un_mac_dst_str = '00:11:22:ff:ff:ff'
+
+ # check one direction -> packet enters through unfiltered port (inport) and exits through
+ # unfiltered port (outport) via the flood and lag groups
+ pkt = str( simple_tcp_packet( pktlen=80, dl_vlan_enable=True, vlan_vid=vlan_in_port_untagged, eth_dst=un_mac_dst_str ) )
+ exp_pkt = pkt
+ self.dataplane.send( in_port, pkt )
+ verify_packet( self, exp_pkt, out_port )
+ verify_no_other_packets( self )
+
+ # check other direction -> packet enters through unfiltered port (outport) and exits through
+ # unfiltered port (inport) via the flood group
+
+ # table 10 flows for tagged out_port. Note: VLAN must be wildcarded for an unfiltered port
+ add_vlan_table_flow_allow_all_vlan(self.controller, out_port, send_barrier=True)
+ pkt = str( simple_tcp_packet( pktlen=80, dl_vlan_enable=True, vlan_vid=vlan_in_port_untagged, eth_dst=un_mac_dst_str ) )
+ exp_pkt = pkt
+ self.dataplane.send( out_port, pkt )
+ verify_packet( self, exp_pkt, in_port )
+ verify_no_other_packets( self )
+
+ finally:
+ print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class LagMix( base_tests.SimpleDataPlane ):
+ """
+ Checks the combination of L2 filtered and unfiltered interface groups
+ in a L2 load balancing (LAG) group - this should not work according to spec
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+ vlan_in_port_untagged = 31
+
+ # add l2 unfiltered interface group
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 interface (filtered) group
+ l2_i_gid, l2_i_msg = add_one_l2_interface_group( self.controller, in_port, vlan_in_port_untagged,
+ is_tagged=False, send_barrier=True)
+
+ # create l2 load-balance group with a mix of filtered and unfiltered groups
+ """
+ XXX the following does not work - the group does not get created but curiously we don't get an openflow
+ error message. The ofdpa logs show
+ ofdbGroupBucketValidate: Referenced Group Id 0x1f000c not of type L2 Unfiltered Interface.
+ We do get an openflow error message for the flood group that follows because it cannot
+ find the lag group it points to (because it did not get created).
+ """
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid, l2_i_gid], True)
+
+ # create l2 flood group to point to lag group
+ floodmsg = add_l2_flood_group_with_gids( self.controller, [lag_gid] , vlan_in_port_untagged, id=0 )
+ Groups.put( floodmsg.group_id, l2_i_gid, lag_gid )
+ Groups.put( l2_o_gid )
+
+ finally:
+ #print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+
+@disabled
+class LagXconn( base_tests.SimpleDataPlane ):
+ """
+ Checks the L2 load balancing (LAG) with vlan crossconnects.
+ Note that for this to work, basic VlanCrossConnect test above (without LAG) should work first
+ Note: this doesn't work on XGS or QMX yet with premium 1.1.7
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface unfiltered group
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+ Groups.put(l2_o_gid, lag_gid)
+
+ # a subscriber [id, ip in hex, inner_vlan, outer_vlan, ip in dot form]
+ sub_info = [10, 0xc0a80001, 12, 11, "192.168.0.1"]
+
+ input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, sub_info[0] ]
+ input_src_mac_str = ':'.join( [ '%02X' % x for x in input_src_mac ] )
+ input_dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ input_dst_mac_str = ':'.join( [ '%02X' % x for x in input_dst_mac ] )
+ output_dst_mac = [ 0x00, 0x00, 0x00, 0x33, 0x33, 0x00 ]
+ output_dst_mac_str = ':'.join( [ '%02X' % x for x in output_dst_mac ] )
+
+ dip = sub_info[1]
+ ports = config[ "port_map" ].keys( )
+ inner_vlan = sub_info[2]
+ outer_vlan = sub_info[3]
+ index = inner_vlan
+ port = ports[0]
+ out_port = ports[1]
+
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, port, inner_vlan, outer_vlan, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_STACKED )
+ add_one_vlan_1_table_flow_pw( self.controller, port, index, new_outer_vlan_id=outer_vlan, outer_vlan_id=outer_vlan,
+ inner_vlan_id=inner_vlan, cross_connect=True, send_barrier=True)
+ """
+ XXX The following flow in table 13 is rejected by the switch (qmx) probably due to the reference to lag group
+ ofdpa logs say: 08-22 00:43:10.344338 [ofstatemanager] Error from Forwarding while inserting flow: Unknown error
+ """
+ add_mpls_l2_port_flow(ctrl=self.controller, of_port=port, mpls_l2_port=port, tunnel_index=index, ref_gid=lag_gid,
+ qos_index=0, goto=ACL_FLOW_TABLE)
+ do_barrier( self.controller )
+
+ ip_src = sub_info[4]
+ ip_dst = '192.168.0.{}'.format(sub_info[0])
+ parsed_pkt = qinq_tcp_packet( pktlen=120, vlan_vid=inner_vlan, dl_vlan_outer=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str, ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+ parsed_pkt = simple_tcp_packet_two_vlan( pktlen=120, out_dl_vlan_enable=True, in_dl_vlan_enable=True,
+ in_vlan_vid=inner_vlan, out_vlan_vid=outer_vlan,
+ eth_dst=input_dst_mac_str, eth_src=input_src_mac_str,
+ ip_ttl=64, ip_src=ip_src, ip_dst=ip_dst )
+
+ pkt = str( parsed_pkt )
+ self.dataplane.send( port, pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ #print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+@disabled
+class LagRouting( base_tests.SimpleDataPlane ):
+ """
+ Checks the L2 load balancing (LAG) with routing flows.
+ Specifically route -> L3Unicast -> Lag -> L2 Unfiltered interface
+ """
+ def runTest( self ):
+ Groups = Queue.LifoQueue( )
+ try:
+ if len( config[ "port_map" ] ) < 2:
+ logging.info( "Port count less than 2, can't run this case" )
+ return
+
+ ports = sorted(config[ "port_map" ].keys( ))
+ in_port = ports[0]
+ out_port = ports[1]
+
+ # add l2 interface unfiltered group
+ l2_o_gid, l2_o_msg = add_one_l2_unfiltered_group( self.controller, out_port, True)
+
+ # create l2 load-balance group
+ lag_gid, lag_msg = add_l2_loadbal_group(self.controller, 1, [l2_o_gid], True)
+ Groups.put(l2_o_gid, lag_gid)
+
+ intf_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
+ dst_mac = [ 0x00, 0x00, 0x00, 0x22, 0x22, 0x00 ]
+ dip = 0xc0a80001
+ vlan_id = 31
+
+ # create L3 Unicast group to point to Lag group
+ l3_msg = add_l3_unicast_group( self.controller, out_port, vlanid=vlan_id, id=vlan_id,
+ src_mac=intf_src_mac, dst_mac=dst_mac, gid=lag_gid )
+ # add vlan flow table
+ add_one_vlan_table_flow( self.controller, in_port, 1, vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ # add termination flow
+ if config["switch_type"] == "qmx":
+ add_termination_flow( self.controller, 0, 0x0800, intf_src_mac, vlan_id )
+ else:
+ add_termination_flow( self.controller, in_port, 0x0800, intf_src_mac, vlan_id )
+ # add unicast routing flow
+ add_unicast_routing_flow( self.controller, 0x0800, dip, 0xffffffff, l3_msg.group_id )
+
+ Groups.put( l3_msg.group_id )
+ do_barrier( self.controller )
+
+ switch_mac = ':'.join( [ '%02X' % x for x in intf_src_mac ] )
+ mac_src = '00:00:00:22:22:%02X' % (in_port)
+ ip_src = '192.168.0.2'
+ ip_dst = '192.168.0.1'
+ parsed_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=vlan_id, eth_dst=switch_mac, eth_src=mac_src, ip_ttl=64,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( parsed_pkt )
+ self.dataplane.send( in_port, pkt )
+ # build expected packet
+ mac_dst = '00:00:00:22:22:00'
+ exp_pkt = simple_tcp_packet( pktlen=100, dl_vlan_enable=True,
+ vlan_vid=vlan_id, eth_dst=mac_dst, eth_src=switch_mac, ip_ttl=63,
+ ip_src=ip_src, ip_dst=ip_dst )
+ pkt = str( exp_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_other_packets( self )
+
+ finally:
+ #print("done")
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class FabricSW_OF_EAPOL_TC_0060(base_tests.SimpleDataPlane):
+ """
+ To verify double VLAN tagged EAPOL packets can be matched and sent to controller.
+ """
+
+ def runTest(self):
+ try:
+ eth_type_eapol = 0x888e
+ eth_type_non_eapol = 0x88ee
+ eth_type = 0x8100
+ vlan_id100 = 100
+ vlanid200 = 200
+
+ logging.info("Step 1")
+ logging.info("Add a flow to TABLE-10 to match VLAN ID '100' for packets received at Data Port 1 and action transition to TABLE-20.")
+
+ ports = sorted(config["port_map"].keys())
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_eapol)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_eapol))
+
+ logging.info("Step 2")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_eapol)))
+ parsed_pkt = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_eapol,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt = str(parsed_pkt)
+
+ logging.info("Step 3")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_non_eapol)))
+ parsed_pkt_non_eapol = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_non_eapol,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt_non_eapol = str(parsed_pkt_non_eapol)
+
+ logging.info("Step 4")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_eapol), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+ logging.info("Step 5")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_non_eapol), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt_non_eapol)
+ verify_no_packet_in(self, vlan_pkt_non_eapol, ports[0])
+
+ logging.info("Step 6 Cleanup flows")
+ delete_all_flows(self.controller)
+ time.sleep(1)
+
+ logging.info("Step 7")
+ logging.info("Add flows again ID=10 and ID=60")
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_eapol)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_eapol))
+ time.sleep(1)
+
+ logging.info("Step 8")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_eapol), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+ logging.info("End of Test")
+
+
+
+class FabricSW_OF_ARP_TC_0065(base_tests.SimpleDataPlane):
+ """
+ To verify double VLAN tagged ARP packets can be matched and sent to controller.
+ """
+
+ def runTest(self):
+ try:
+ eth_type_arp = 0x806
+ eth_type_non_arp = 0x888e
+ eth_type = 0x8100
+ vlan_id100 = 100
+ vlanid200 = 200
+
+ logging.info("Step 1")
+ logging.info("Add a flow to TABLE-10 to match VLAN ID '100' for packets received at Data Port 1 and action transition to TABLE-20.")
+
+ ports = sorted(config["port_map"].keys())
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_arp)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_arp))
+
+ logging.info("Step 2")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_arp)))
+ parsed_pkt = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_arp,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt = str(parsed_pkt)
+
+ logging.info("Step 3")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_non_arp)))
+ parsed_pkt_non_arp = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_non_arp,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt_non_arp = str(parsed_pkt_non_arp)
+
+ logging.info("Step 4")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_arp), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+ logging.info("Step 5")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_non_arp), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt_non_arp)
+ verify_no_packet_in(self, vlan_pkt_non_arp, ports[0])
+
+ logging.info("Step 6 Cleanup flows")
+ delete_all_flows(self.controller)
+ time.sleep(1)
+
+ logging.info("Step 7")
+ logging.info("Add flows again ID=10 and ID=60")
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_arp)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_arp))
+ time.sleep(1)
+
+ logging.info("Step 8")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_arp), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+@disabled
+class FabricSW_OF_ARP_LAG_TC(base_tests.SimpleDataPlane):
+ """
+ To verify double VLAN tagged ARP packets received over a LAG interface can be matched and sent to controller.
+
+ TODO: Need to add step: Create a logical port (LAG) and bind data ports 1 and 2 to the logical port.
+ """
+
+ def runTest(self):
+ try:
+ eth_type_arp = 0x806
+ eth_type_non_arp = 0x888e
+ eth_type = 0x8100
+ vlan_id100 = 100
+ vlanid200 = 200
+
+ logging.info("Step 1")
+ logging.info(
+ "Create a logical port (LAG) and bind data ports 1 and 2 to the logical port.")
+
+ # TODO: add LAG here:
+
+ logging.info("Step 2")
+ logging.info("Add a flow to TABLE-10 to match VLAN ID '100' for packets received at Data Port 1 and action transition to TABLE-20.")
+
+ ports = sorted(config["port_map"].keys())
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_arp)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_arp))
+
+ logging.info("Step 3")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_arp)))
+ parsed_pkt = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_arp,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt = str(parsed_pkt)
+
+ logging.info("Step 4")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_non_arp)))
+ parsed_pkt_non_eapol = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_non_arp,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt_non_eapol = str(parsed_pkt_non_eapol)
+
+ logging.info("Step 5")
+ for port in ports:
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_arp), port))
+ self.dataplane.send(port, vlan_pkt)
+ verify_packet_in(self, vlan_pkt, port, ofp.OFPR_ACTION)
+
+ logging.info("Step 7")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_non_arp), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt_non_eapol)
+ verify_no_packet_in(self, vlan_pkt_non_eapol, ports[0])
+
+ logging.info("Step 8 Cleanup flows")
+ delete_all_flows(self.controller)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_arp))
+
+ logging.info("Step 9")
+ logging.info(
+ "Send double tagged vlan packet with ethernet type {} to port {}".format(hex(eth_type_arp), ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_no_packet_in(self, vlan_pkt, ports[0])
+
+
+ finally:
+ delete_all_flows( self.controller )
+ delete_all_groups( self.controller )
+ logging.info("End of Test")
+
+
+class FabricSW_OF_VLANPUSH_TC_0070(base_tests.SimpleDataPlane):
+ """
+ To verify a VLAN tag can be pushed into an untagged packet received on a physical interface.
+ """
+
+ def runTest(self):
+ try:
+ vlan_id100 = 100
+ ports = sorted(config["port_map"].keys())
+
+ logging.info("Step 1")
+ logging.info("Add a flow to TABLE-10 to match untagged packets received in Data Port 1 and immediate "
+ "action to insert VLAN tag {} and transition to TABLE-20.".format(vlan_id100))
+ add_one_vlan_table_flow(ctrl=self.controller, of_port=ports[0], vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ add_one_vlan_table_flow(ctrl=self.controller, of_port=ports[0], vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_UNTAG)
+
+ logging.info("Step 2")
+ logging.info("Add a flow to TABLE-60 to match VLAN tag {} and action Send to Controller".format(vlan_id100))
+ add_acl_rule(ctrl=self.controller, vlan_id=vlan_id100)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id100))
+
+ logging.info("Step 3")
+ logging.info("Creating an untagged vlan packet")
+ parsed_pkt = simple_ether_packet_two_vlan(out_dl_vlan_enable=False,
+ in_dl_vlan_enable=False)
+ vlan_pkt = str(parsed_pkt)
+
+ logging.info("Step 4")
+ logging.info("Send untagged packet to port {}".format(ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+ logging.info("Step 6 Cleanup flows")
+ delete_all_flows(self.controller)
+
+ logging.info("Step 5")
+ logging.info("Send untagged packet to port {}".format(ports[0]))
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_no_packet_in(self, vlan_pkt, ports[0])
+
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+class FabricSW_OF_LLDP_TC_0075(base_tests.SimpleDataPlane):
+ """
+ To verify LLDP packets received on a physical interface can be matched and sent to Controller.
+ """
+
+ def runTest(self):
+ try:
+ eth_type_lldp = 0x88cc
+ eth_type_non_lldp = 0x88ee
+
+ similar_steps(eth_type_lldp, eth_type_non_lldp, self)
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+class FabricSW_OF_BDDP_TC_0080(base_tests.SimpleDataPlane):
+ """
+ To verify BDDP packets received on a physical interface can be matched and sent to Controller.
+ """
+
+ def runTest(self):
+ try:
+ eth_type_bddp = 0x8942
+ eth_type_non_bddp = 0x888e
+
+ similar_steps(eth_type_bddp, eth_type_non_bddp, self)
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+class FabricSW_OF_VLANXConnect_Single_TC_0085(base_tests.SimpleDataPlane):
+ """
+ Verify QnQ traffic flooding between 2 cross (one-to-one) connected physical interfaces.
+ """
+
+ def runTest(self):
+ groups = Queue.LifoQueue()
+ try:
+ ports = sorted(config["port_map"].keys())
+ vlan_id = 100
+ vlan_id101 = 101
+
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group(self.controller, port, vlan_id, True, False)
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ groups.put(L2gid)
+
+ msg = add_l2_flood_group(self.controller, ports, vlan_id, vlan_id)
+ groups.put(msg.group_id)
+ add_bridge_flow(self.controller, None, vlan_id, msg.group_id, True)
+
+ #do_barrier(self.controller)
+
+ logging.info(
+ "Add a flow to TABLE-60 to match vlan {} and action Send to Controller".format(vlan_id))
+ add_acl_rule(self.controller, vlan_id=vlan_id)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id))
+
+ # verify flood
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id))
+ for ofport in ports:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id, in_dl_vlan_enable=True, in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ofport, pkt)
+ # self won't rx packet
+ verify_no_packet(self, pkt, ofport)
+ # others will rx packet
+ tmp_ports = list(ports)
+ tmp_ports.remove(ofport)
+ verify_packets(self, pkt, tmp_ports)
+
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id101))
+ mac_src = '00:12:34:56:78:%02X' % ports[0]
+ parsed_pkt_101 = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id101, in_dl_vlan_enable=True, in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt_101 = str(parsed_pkt_101)
+ logging.info("Send double tugged packet to port {}".format(ports[0]))
+ self.dataplane.send(ports[0], pkt_101)
+
+ logging.info("Verify the packet is not flooded to data port2 with outer vlan id {}".format(vlan_id101))
+ verify_no_packet(self, pkt_101, ports[1])
+
+ logging.info("Cleanup flows")
+ delete_all_flows(self.controller)
+
+ logging.info("Send double tugged packet to port {}".format(ports[1]))
+ self.dataplane.send(ports[1], pkt)
+
+ logging.info("Verify the packet is not flooded to data port1 with outer vlan id {}".format(vlan_id))
+ verify_no_packet(self, pkt, ports[0])
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_groups(self.controller, groups)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+class FabricSW_OF_VLANXConnect_Multi_TC_0090(base_tests.SimpleDataPlane):
+ """
+ Verify QnQ traffic flooding between Many-to-One (multiple S tags to single BNG) and One-Many (Single BNG to
+ multiple S tags) cross connected physical interfaces.
+ """
+
+ def runTest(self):
+ groups = Queue.LifoQueue()
+ try:
+ ports = sorted(config["port_map"].keys())
+ vlan_id100 = 100
+ vlan_id101 = 101
+ vlan_id102 = 102
+
+ # Create VLAN100 flow and tables for port1 and port4
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[1])
+ tmp_ports.remove(ports[2])
+
+ for port in tmp_ports:
+ L2gid, l2msg = add_one_l2_interface_group(self.controller, port, vlan_id100, True, False)
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ groups.put(L2gid)
+
+ msg = add_l2_flood_group(self.controller, tmp_ports, vlan_id100, vlan_id100)
+ groups.put(msg.group_id)
+ add_bridge_flow(self.controller, None, vlan_id100, msg.group_id, True)
+
+ # do_barrier(self.controller)
+
+ logging.info(
+ "Add a flow to TABLE-60 to match vlan {} and action Send to Controller".format(vlan_id100))
+ add_acl_rule(self.controller, vlan_id=vlan_id100)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id100))
+
+ # Create VLAN101 flow and tables for port2 and port4
+ tmp_ports1 = list(ports)
+ tmp_ports1.remove(ports[0])
+ tmp_ports1.remove(ports[2])
+
+ for port in tmp_ports1:
+ L2gid, l2msg = add_one_l2_interface_group(self.controller, port, vlan_id101, True, False)
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id101, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ groups.put(L2gid)
+
+ msg = add_l2_flood_group(self.controller, tmp_ports1, vlan_id101, vlan_id101)
+ groups.put(msg.group_id)
+ add_bridge_flow(self.controller, None, vlan_id101, msg.group_id, True)
+
+ # do_barrier(self.controller)
+
+ logging.info(
+ "Add a flow to TABLE-60 to match vlan {} and action Send to Controller".format(vlan_id101))
+ add_acl_rule(self.controller, vlan_id=vlan_id101)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id101))
+
+ # Create VLAN102 flow and tables for port3 and port4
+ tmp_ports2 = list(ports)
+ tmp_ports2.remove(ports[0])
+ tmp_ports2.remove(ports[1])
+
+ for port in tmp_ports2:
+ L2gid, l2msg = add_one_l2_interface_group(self.controller, port, vlan_id102, True, False)
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id102, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ groups.put(L2gid)
+
+ msg = add_l2_flood_group(self.controller, tmp_ports2, vlan_id102, vlan_id102)
+ groups.put(msg.group_id)
+ add_bridge_flow(self.controller, None, vlan_id102, msg.group_id, True)
+
+ # do_barrier(self.controller)
+
+ logging.info(
+ "Add a flow to TABLE-60 to match vlan {} and action Send to Controller".format(vlan_id102))
+ add_acl_rule(self.controller, vlan_id=vlan_id102)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id102))
+
+
+ # verify flood VLAN100 from port1 to port4
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id100))
+ for ofport in tmp_ports:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id100, in_dl_vlan_enable=True, in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ofport, pkt)
+ # self won't rx packet
+ verify_no_packet(self, pkt, ofport)
+ # others will rx packet
+ tmp_ports.remove(ofport)
+ verify_packets(self, pkt, tmp_ports)
+
+ # verify flood VLAN101 from port2 to port4
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id101))
+ for ofport in tmp_ports1:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id101, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ofport, pkt)
+ # self won't rx packet
+ verify_no_packet(self, pkt, ofport)
+ # others will rx packet
+ tmp_ports1.remove(ofport)
+ verify_packets(self, pkt, tmp_ports1)
+
+ # verify flood VLAN102 from port3 to port4
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id102))
+ for ofport in tmp_ports2:
+ # change dest based on port number
+ mac_src = '00:12:34:56:78:%02X' % ofport
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id102, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ofport, pkt)
+ # self won't rx packet
+ verify_no_packet(self, pkt, ofport)
+ # others will rx packet
+ tmp_ports2.remove(ofport)
+ verify_packets(self, pkt, tmp_ports2)
+
+ # verify flood VLAN101 to port1 - no receive on other ports
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id101))
+ mac_src = '00:12:34:56:78:01'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id101, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[0], pkt)
+ # won't rx packet
+ verify_no_packet(self, pkt, ports[1])
+ verify_no_packet(self, pkt, ports[2])
+ verify_no_packet(self, pkt, ports[3])
+
+ # verify flood VLAN100 to port4 - receive on port1
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id100))
+ mac_src = '00:12:34:56:78:04'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id100, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[3], pkt)
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[1])
+ tmp_ports.remove(ports[2])
+ tmp_ports.remove(ports[3])
+ # rx packet on port1
+ verify_packets(self, pkt, tmp_ports)
+
+ # verify flood VLAN101 to port4 - receive on port2
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id101))
+ mac_src = '00:12:34:56:78:04'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id101, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[3], pkt)
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[0])
+ tmp_ports.remove(ports[2])
+ tmp_ports.remove(ports[3])
+ # rx packet on port1
+ verify_packets(self, pkt, tmp_ports)
+
+ # verify flood VLAN102 to port4 - receive on port3
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id102))
+ mac_src = '00:12:34:56:78:04'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id102, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[3], pkt)
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[0])
+ tmp_ports.remove(ports[1])
+ tmp_ports.remove(ports[3])
+ # rx packet on port1
+ verify_packets(self, pkt, tmp_ports)
+
+ logging.info("Cleanup flows")
+ delete_all_flows(self.controller)
+
+ # verify flood VLAN101 to port1 and port4 - no receive on any ports
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id100))
+ mac_src = '00:12:34:56:78:01'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id100, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[0], pkt)
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[0])
+ # won't rx packet
+ verify_no_packet(self, pkt, ports[1])
+ verify_no_packet(self, pkt, ports[2])
+ verify_no_packet(self, pkt, ports[3])
+
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id100))
+ mac_src = '00:12:34:56:78:04'
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=108, out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id100, in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a', eth_src=mac_src)
+
+ pkt = str(parsed_pkt)
+ self.dataplane.send(ports[3], pkt)
+ tmp_ports = list(ports)
+ tmp_ports.remove(ports[3])
+ # won't rx packet
+ verify_no_packet(self, pkt, ports[0])
+ verify_no_packet(self, pkt, ports[1])
+ verify_no_packet(self, pkt, ports[2])
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_groups(self.controller, groups)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+class FabricSW_OF_Counters_TC_0095(base_tests.SimpleDataPlane):
+ """
+ To verify the following port counters can be retrieved successfully from Open Flow switch:
+ rx_bytes_total, tx_bytes_total, rx_packets_total, tx_packets_total, rx_drop_packets_total, tx_drop_packets_total.
+ """
+
+ def runTest(self):
+ groups = Queue.LifoQueue()
+ try:
+ ports = sorted(config["port_map"].keys())
+ vlan_id = 100
+ vlan_len = 4
+ num_pkts = 5
+ pktlen = 108
+ rx_bytes_expected = (pktlen + vlan_len) * num_pkts
+ rx_dropped_expected = 0
+ tx_pkt_expected = num_pkts
+ tx_bytes_expected = rx_bytes_expected
+ tx_dropped_expected = 0
+
+ for port in ports:
+ L2gid, l2msg = add_one_l2_interface_group(self.controller, port, vlan_id, True, False)
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ groups.put(L2gid)
+
+ msg = add_l2_flood_group(self.controller, ports, vlan_id, vlan_id)
+ groups.put(msg.group_id)
+ add_bridge_flow(self.controller, None, vlan_id, msg.group_id, True)
+
+ # do_barrier(self.controller)
+
+ logging.info("Add a flow to TABLE-60 to match vlan {}".format(vlan_id))
+ add_acl_rule(self.controller, vlan_id=vlan_id)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.vlan_vid(vlan_id))
+
+ # Send Port_Stats request for the ingress port (retrieve old counter state)
+ initial_stats_rx = get_port_stats(self, ports[0])
+ initial_stats_tx = get_port_stats(self, ports[1])
+
+ logging.info("Get required counter values from port".format(ports[0]))
+ rx_bytes_before = get_required_statistic_from_port(self, ports[0], "rx_bytes")
+ rx_pkts_before = get_required_statistic_from_port(self, ports[0], "rx_packets")
+ rx_dropped_before = get_required_statistic_from_port(self, ports[0], "rx_dropped")
+ tx_bytes_before = get_required_statistic_from_port(self, ports[1], "tx_bytes")
+ tx_packets_before = get_required_statistic_from_port(self, ports[1], "tx_packets")
+ tx_dropped_before = get_required_statistic_from_port(self, ports[1], "tx_dropped")
+
+ logging.info("Creating a double tagged vlan packet with outer vlan id {}".format(vlan_id))
+ parsed_pkt = simple_tcp_packet_two_vlan(pktlen=pktlen,
+ out_dl_vlan_enable=True,
+ out_vlan_vid=vlan_id,
+ in_dl_vlan_enable=True,
+ in_vlan_vid=10,
+ eth_dst='00:12:34:56:78:9a')
+ pkt = str(parsed_pkt)
+
+ logging.info("Send double tugged packets to port {}".format(ports[0]))
+ for pkt_cnt in range(num_pkts):
+ self.dataplane.send(ports[0], pkt)
+
+ logging.info("Verify transmitted_packet counters")
+ verify_port_stats(self, ports[0], initial=initial_stats_rx, rx_pkts=num_pkts)
+ verify_port_stats(self, ports[1], initial=initial_stats_tx, tx_pkts=num_pkts)
+
+ logging.info("Get required counter values from port after sending packets".format(ports[0]))
+ rx_bytes_after = get_required_statistic_from_port(self, ports[0], "rx_bytes")
+ rx_pkts_after = get_required_statistic_from_port(self, ports[0], "rx_packets")
+ rx_dropped_after = get_required_statistic_from_port(self, ports[0], "rx_dropped")
+ tx_bytes_after = get_required_statistic_from_port(self, ports[1], "tx_bytes")
+ tx_packets_after = get_required_statistic_from_port(self, ports[1], "tx_packets")
+ tx_dropped_after = get_required_statistic_from_port(self, ports[1], "tx_dropped")
+
+ logging.info("Verify values incremented as expected on port".format(ports[0]))
+ self.assertGreaterEqual(rx_pkts_after - rx_pkts_before, num_pkts,
+ "Port RX packet counter is not updated as expected: {}, current value: {}".format(num_pkts, rx_pkts_after - rx_pkts_before))
+ self.assertGreaterEqual(rx_bytes_after - rx_bytes_before, rx_bytes_expected,
+ "Port RX bytes counter is not updated as expected: {}, current value: {}".format(rx_bytes_expected, rx_bytes_after - rx_bytes_before))
+ self.assertGreaterEqual(rx_dropped_after - rx_dropped_before, rx_dropped_expected,
+ "Port RX dropped counter is not updated as expected: {}, current value: {}".format(rx_dropped_expected, rx_dropped_after - rx_dropped_before))
+
+ self.assertEqual(tx_packets_after - tx_packets_before, tx_pkt_expected,
+ "Port TX packet counter is not updated as expected: {}, current value: {}".format(tx_pkt_expected, tx_packets_after - tx_packets_before))
+ self.assertEqual(tx_bytes_after - tx_bytes_before, tx_bytes_expected,
+ "Port TX bytes counter is not updated as expected: {}, current value: {}".format(tx_bytes_expected, tx_bytes_after - tx_bytes_before))
+ self.assertEqual(tx_dropped_after - tx_dropped_before, tx_dropped_expected,
+ "Port TX dropped counter is not updated as expected: {}, current value: {}".format(tx_dropped_expected, tx_dropped_after - tx_dropped_before))
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_groups(self.controller, groups)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
+
+
+def similar_steps(eth_type, not_expected_eth_type, self):
+ """
+ Similar steps for tests: FabricSW_OF_BDDP_TC_0020 and FabricSW_OF_LLDP_TC_0015
+ parameters:
+ @param eth_type matched ethernet type
+ @param not_expected_eth_type not matched ethernet type
+ @param self class instance
+ """
+
+ ports = sorted(config["port_map"].keys())
+
+ logging.info("Step 1")
+ logging.info(
+ "Add a flow to TABLE-60 to match Ethernet Type to {} and action Send to Controller".format(eth_type))
+ add_acl_rule(self.controller, eth_type=eth_type)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type))
+
+ logging.info("Step 2")
+ logging.info("Creating an untagged packet with ethernet type {}".format(hex(eth_type)))
+ parsed_pkt = simple_eth_packet(eth_type=eth_type)
+ eth_pkt = str(parsed_pkt)
+
+ logging.info("Step 3")
+ logging.info("Creating an untagged packet with ethernet type {}".format(hex(not_expected_eth_type)))
+ parsed_pkt_not_expected = simple_eth_packet(eth_type=not_expected_eth_type)
+ eth_pkt_non_lldp = str(parsed_pkt_not_expected)
+
+ logging.info("Step 4")
+ logging.info(
+ "Send untagged packet with ethernet type {} to port {}".format(hex(eth_type), ports[0]))
+ self.dataplane.send(ports[0], eth_pkt)
+ verify_packet_in(self, eth_pkt, ports[0], ofp.OFPR_ACTION)
+
+ logging.info("Step 5")
+ logging.info(
+ "Send untagged packet with ethernet type {} to port {}".format(hex(not_expected_eth_type), ports[0]))
+ self.dataplane.send(ports[0], eth_pkt_non_lldp)
+ verify_no_packet_in(self, eth_pkt_non_lldp, ports[0])
+
+ logging.info("Step 6 Cleanup flows")
+ delete_all_flows(self.controller)
+ time.sleep(1)
+
+ logging.info("Step 7")
+ logging.info(
+ "Send untagged packet with ethernet type {} to port {}".format(hex(eth_type), ports[0]))
+ self.dataplane.send(ports[0], eth_pkt)
+ verify_no_packet_in(self, eth_pkt, ports[0])
+
+
+@disabled
+class test_interface_flap(base_tests.SimpleDataPlane):
+ """
+ This is pilot test case to verify interface flap
+ """
+
+ def runTest(self):
+ try:
+ eth_type_eapol = 0x888e
+ eth_type = 0x8100
+ vlan_id100 = 100
+ vlanid200 = 200
+
+ logging.info("Step 1")
+ logging.info(
+ "Add a flow to TABLE-10 to match VLAN ID '100' for packets received at Data Port 1 and action transition to TABLE-20.")
+
+ ports = sorted(config["port_map"].keys())
+ for port in ports:
+ add_one_vlan_table_flow(self.controller, port, vlan_id=vlan_id100, flag=VLAN_TABLE_FLAG_ONLY_TAG)
+
+ add_acl_rule(self.controller, eth_type=eth_type_eapol)
+
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.eth_type(eth_type_eapol))
+
+ logging.info("Step 2")
+ logging.info("Creating a double tagged vlan packet with ethernet type {}".format(hex(eth_type_eapol)))
+ parsed_pkt = simple_ether_packet_two_vlan(out_dl_vlan_enable=True,
+ in_dl_vlan_enable=True,
+ out_vlan_tpid=eth_type,
+ in_vlan_tpid=eth_type_eapol,
+ out_vlan_vid=vlan_id100,
+ in_vlan_vid=vlanid200)
+ vlan_pkt = str(parsed_pkt)
+
+ logging.info("Step 4")
+ logging.info("Send untagged packet to port {}".format(ports[0]))
+
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+ print("")
+ print("flapping interface")
+ self.dataplane.port_down(ports[0])
+
+ time.sleep(2)
+
+ print("bring up interface")
+ self.dataplane.port_up(ports[0])
+
+ self.dataplane.send(ports[0], vlan_pkt)
+ verify_packet_in(self, vlan_pkt, ports[0], ofp.OFPR_ACTION)
+
+
+ finally:
+ delete_all_flows(self.controller)
+ delete_all_groups(self.controller)
+ logging.info("End of Test")
diff --git a/Fabric/Tests/oft b/Fabric/Tests/oft
new file mode 100755
index 0000000..cae63b6
--- /dev/null
+++ b/Fabric/Tests/oft
@@ -0,0 +1,619 @@
+#!/usr/bin/env python
+"""
+@package oft
+
+OpenFlow test framework top level script
+
+This script is the entry point for running OpenFlow tests using the OFT
+framework. For usage information, see --help or the README.
+
+To add a new command line option, edit both the CONFIG_DEFAULT dictionary and
+the config_setup function. The option's result will end up in the global
+oftest.config dictionary.
+"""
+
+from __future__ import print_function
+
+import sys
+import optparse
+import logging
+import unittest
+import time
+import os
+import imp
+import random
+import signal
+import fnmatch
+import copy
+
+ROOT_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)
+LOG_DIR = os.path.join(ROOT_DIR, "Log")+time.strftime("/%Y-%m/%d%H%M%S")
+#LOG_FILE = time.strftime("%H%M%S")+"oft.log"
+PY_SRC_DIR = os.path.join(ROOT_DIR, 'Utilities', 'src', 'python')
+if os.path.exists(os.path.join(PY_SRC_DIR, 'oftest')):
+ # Running from source tree
+ sys.path.insert(0, PY_SRC_DIR)
+
+if os.path.exists(os.path.join(ROOT_DIR, 'Utilities', 'accton')):
+ PY_ACCTON_DIR = os.path.join(ROOT_DIR, 'Utilities', 'accton')
+ sys.path.insert(0, PY_ACCTON_DIR)
+
+import oftest
+from oftest import config
+import oftest.ofutils
+import oftest.help_formatter
+import loxi
+
+##@var DEBUG_LEVELS
+# Map from strings to debugging levels
+DEBUG_LEVELS = {
+ 'debug' : logging.DEBUG,
+ 'verbose' : logging.DEBUG,
+ 'info' : logging.INFO,
+ 'warning' : logging.WARNING,
+ 'warn' : logging.WARNING,
+ 'error' : logging.ERROR,
+ 'critical' : logging.CRITICAL
+}
+
+##@var CONFIG_DEFAULT
+# The default configuration dictionary for OFT
+CONFIG_DEFAULT = {
+ # Miscellaneous options
+ "list" : False,
+ "list_test_names" : False,
+ "allow_user" : False,
+
+ # Test selection options
+ "test_spec" : "",
+ "test_file" : None,
+ "test_dir" : os.path.join(ROOT_DIR, "Tests"),
+
+ # Switch connection options
+ "controller_host" : "0.0.0.0", # For passive bind
+ "controller_port" : 6653,
+ "switch_ip" : None, # If not none, actively connect to switch
+ "switch_type" : None, # If not none, adapt flows to pipeline differences for switch type
+ "platform" : "eth",
+ "platform_args" : None,
+ "platform_dir" : os.path.join(ROOT_DIR, "Utilities", "platforms"),
+ "interfaces" : [],
+ "openflow_version" : "1.0",
+
+ # Logging options
+ "log_file" : time.strftime("%H%M%S")+"oft.log",
+ "log_dir" : LOG_DIR,
+ "debug" : "verbose",
+ "profile" : False,
+ "profile_file" : "profile.out",
+ "xunit" : False,
+ "xunit_dir" : "xunit",
+
+ # Test behavior options
+ "relax" : False,
+ "test_params" : "None",
+ "fail_skipped" : False,
+ "default_timeout" : 2.0,
+ "default_negative_timeout" : 0.01,
+ "minsize" : 0,
+ "random_seed" : None,
+ "disable_ipv6" : False,
+ "random_order" : False,
+ "dump_packet" : True,
+ "cicada_poject" : False,
+ "force_ofdpa_restart": False,
+ # Other configuration
+ "port_map" : {},
+}
+
+def config_setup():
+ """
+ Set up the configuration including parsing the arguments
+
+ @return A pair (config, args) where config is an config
+ object and args is any additional arguments from the command line
+ """
+
+ usage = "usage: %prog [options] (test|group)..."
+
+ description = """\
+OFTest is a framework and set of tests for validating OpenFlow switches.
+
+The default configuration assumes that an OpenFlow 1.0 switch is attempting to
+connect to a controller on the machine running OFTest, port 6653. Additionally,
+the interfaces veth1, veth3, veth5, and veth7 should be connected to the switch's
+dataplane.
+
+If no positional arguments are given then OFTest will run all tests that
+depend only on standard OpenFlow 1.0. Otherwise each positional argument
+is interpreted as either a test name or a test group name. The union of
+these will be executed. To see what groups each test belongs to use the
+--list option. Tests and groups can be subtracted from the result by
+prefixing them with the '^' character.
+"""
+
+ # Parse --interface
+ def check_interface(option, opt, value):
+ try:
+ ofport, interface = value.split('@', 1)
+ ofport = int(ofport)
+ except ValueError:
+ raise optparse.OptionValueError("incorrect interface syntax (got %s, expected 'ofport@interface')" % repr(value))
+ return (ofport, interface)
+
+ class Option(optparse.Option):
+ TYPES = optparse.Option.TYPES + ("interface",)
+ TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER)
+ TYPE_CHECKER["interface"] = check_interface
+
+ parser = optparse.OptionParser(version="%prog 0.1",
+ usage=usage,
+ description=description,
+ formatter=oftest.help_formatter.HelpFormatter(),
+ option_class=Option)
+
+ # Set up default values
+ parser.set_defaults(**CONFIG_DEFAULT)
+
+ parser.add_option("--list", action="store_true",
+ help="List all tests and exit")
+ parser.add_option("--list-test-names", action='store_true',
+ help="List test names matching the test spec and exit")
+ parser.add_option("--allow-user", action="store_true",
+ help="Proceed even if oftest is not run as root")
+
+ group = optparse.OptionGroup(parser, "Test selection options")
+ group.add_option("-T", "--test-spec", "--test-list", help="Tests to run, separated by commas")
+ group.add_option("-f", "--test-file", help="File of tests to run, one per line")
+ group.add_option("--test-dir", type="string", help="Directory containing tests")
+ parser.add_option_group(group)
+
+ group = optparse.OptionGroup(parser, "Switch connection options")
+ group.add_option("-H", "--host", dest="controller_host",
+ help="IP address to listen on (default %default)")
+ group.add_option("-p", "--port", dest="controller_port",
+ type="int", help="Port number to listen on (default %default)")
+ group.add_option("-S", "--switch-ip", dest="switch_ip",
+ help="If set, actively connect to this switch by IP")
+ group.add_option("-Y", "--switch-type", dest="switch_type",
+ help="If set to qmx, flows will adapt to pipline differences")
+ group.add_option("-P", "--platform", help="Platform module name (default %default)")
+ group.add_option("-a", "--platform-args", help="Custom arguments for the platform")
+ group.add_option("--platform-dir", type="string", help="Directory containing platform modules")
+ group.add_option("--interface", "-i", type="interface", dest="interfaces", metavar="INTERFACE", action="append",
+ help="Specify a OpenFlow port number and the dataplane interface to use. May be given multiple times. Example: 1@eth1")
+ group.add_option("--of-version", "-V", dest="openflow_version", choices=loxi.version_names.values(),
+ help="OpenFlow version to use")
+ parser.add_option_group(group)
+
+ group = optparse.OptionGroup(parser, "Logging options")
+ group.add_option("--log-file", help="Name of log file (default %default)")
+ group.add_option("--log-dir", help="Name of log directory")
+ dbg_lvl_names = sorted(DEBUG_LEVELS.keys(), key=lambda x: DEBUG_LEVELS[x])
+ group.add_option("--debug", choices=dbg_lvl_names,
+ help="Debug lvl: debug, info, warning, error, critical (default %default)")
+ group.add_option("-v", "--verbose", action="store_const", dest="debug",
+ const="verbose", help="Shortcut for --debug=verbose")
+ group.add_option("-q", "--quiet", action="store_const", dest="debug",
+ const="warning", help="Shortcut for --debug=warning")
+ group.add_option("--profile", action="store_true", help="Enable Python profiling")
+ group.add_option("--profile-file", help="Output file for Python profiler")
+ group.add_option("--xunit", action="store_true", help="Enable xUnit-formatted results")
+ group.add_option("--xunit-dir", help="Output directory for xUnit-formatted results")
+ parser.add_option_group(group)
+
+ group = optparse.OptionGroup(parser, "Test behavior options")
+ group.add_option("--relax", action="store_true",
+ help="Relax packet match checks allowing other packets")
+ test_params_help = """Set test parameters: key=val;... (see --list)
+ """
+ group.add_option("-t", "--test-params", help=test_params_help)
+ group.add_option("--fail-skipped", action="store_true",
+ help="Return failure if any test was skipped")
+ group.add_option("--default-timeout", type=float,
+ help="Timeout in seconds for most operations")
+ group.add_option("--default-negative-timeout", type=float,
+ help="Timeout in seconds for negative checks")
+ group.add_option("--minsize", type="int",
+ help="Minimum allowable packet size on the dataplane.")
+ group.add_option("--random-seed", type="int",
+ help="Random number generator seed")
+ group.add_option("--force-ofdpa-restart",
+ help="If set force ofdpa restart on user@switchIP")
+ group.add_option("--disable-ipv6", action="store_true",
+ help="Disable IPv6 tests")
+ group.add_option("--random-order", action="store_true",
+ help="Randomize order of tests")
+ group.add_option("--dump_packet", action="store_true",
+ help="Dump packet content on log when verify packet fail")
+ group.add_option("--cicada_poject", action="store_true",
+ help="True verify Cicada behavior, False verify AOS behaviro")
+ parser.add_option_group(group)
+
+ # Might need this if other parsers want command line
+ # parser.allow_interspersed_args = False
+ (options, args) = parser.parse_args()
+
+ # If --test-dir wasn't given, pick one based on the OpenFlow version
+# if options.test_dir == None:
+# if options.openflow_version == "1.3":
+# options.test_dir = os.path.join(ROOT_DIR, "Test", "ofdpa")
+
+ # Convert options from a Namespace to a plain dictionary
+ config = CONFIG_DEFAULT.copy()
+ for key in config.keys():
+ config[key] = getattr(options, key)
+
+ return (config, args)
+
+#def logging_directory()
+ """
+ creates a specific log directory based on day of execution
+ """
+# log_dir=os.path.join(ROOT_DIR, "Log")+time.strftime("/%Y/%m/%d")
+# return(log_dir)
+
+def logging_setup(config):
+ """
+ Set up logging based on config
+ """
+
+ logging.getLogger().setLevel(DEBUG_LEVELS[config["debug"]])
+
+ if config["log_dir"] != None:
+ if not os.path.exists(config["log_dir"]):
+ os.makedirs(config["log_dir"])
+ else:
+ if os.path.exists(config["log_file"]):
+ os.remove(config["log_file"])
+
+ oftest.open_logfile('main')
+
+def xunit_setup(config):
+ """
+ Set up xUnit output based on config
+ """
+
+ if not config["xunit"]:
+ return
+
+ if os.path.exists(config["xunit_dir"]):
+ import shutil
+ shutil.rmtree(config["xunit_dir"])
+ os.makedirs(config["xunit_dir"])
+
+def pcap_setup(config):
+ """
+ Set up dataplane packet capturing based on config
+ """
+
+ if config["log_dir"] == None:
+ filename = os.path.splitext(config["log_file"])[0] + '.pcap'
+ oftest.dataplane_instance.start_pcap(filename)
+ else:
+ # start_pcap is called per-test in base_tests
+ pass
+
+def profiler_setup(config):
+ """
+ Set up profiler based on config
+ """
+
+ if not config["profile"]:
+ return
+
+ import cProfile
+ profiler = cProfile.Profile()
+ profiler.enable()
+
+ return profiler
+
+def profiler_teardown(profiler):
+ """
+ Tear down profiler based on config
+ """
+
+ if not config["profile"]:
+ return
+
+ profiler.disable()
+ profiler.dump_stats(config["profile_file"])
+
+
+def load_test_modules(config):
+ """
+ Load tests from the test_dir directory.
+
+ Test cases are subclasses of unittest.TestCase
+
+ Also updates the _groups member to include "standard" and
+ module test groups if appropriate.
+
+ @param config The oft configuration dictionary
+ @returns A dictionary from test module names to tuples of
+ (module, dictionary from test names to test classes).
+ """
+
+ result = {}
+
+ for root, dirs, filenames in os.walk(config["test_dir"]):
+ # Iterate over each python file
+ for filename in fnmatch.filter(filenames, '[!.]*.py'):
+ modname = os.path.splitext(os.path.basename(filename))[0]
+
+ try:
+ if sys.modules.has_key(modname):
+ mod = sys.modules[modname]
+ else:
+ mod = imp.load_module(modname, *imp.find_module(modname, [root]))
+ except:
+ logging.warning("Could not import file " + filename)
+ raise
+
+ # Find all testcases defined in the module
+ tests = dict((k, v) for (k, v) in mod.__dict__.items() if type(v) == type and
+ issubclass(v, unittest.TestCase) and
+ hasattr(v, "runTest"))
+ if tests:
+ for (testname, test) in tests.items():
+ # Set default annotation values
+ if not hasattr(test, "_groups"):
+ test._groups = []
+ if not hasattr(test, "_nonstandard"):
+ test._nonstandard = False
+ if not hasattr(test, "_disabled"):
+ test._disabled = False
+
+ # Put test in its module's test group
+ if not test._disabled:
+ test._groups.append(modname)
+
+ # Put test in the standard test group
+ if not test._disabled and not test._nonstandard:
+ test._groups.append("standard")
+ test._groups.append("all") # backwards compatibility
+
+ result[modname] = (mod, tests)
+
+ return result
+
+def prune_tests(test_specs, test_modules, version):
+ """
+ Return tests matching the given test-specs and OpenFlow version
+ @param test_specs A list of group names or test names.
+ @param version An OpenFlow version (e.g. "1.0")
+ @param test_modules Same format as the output of load_test_modules.
+ @returns Same format as the output of load_test_modules.
+ """
+ result = {}
+ for e in test_specs:
+ matched = False
+
+ if e.startswith('^'):
+ negated = True
+ e = e[1:]
+ else:
+ negated = False
+
+ for (modname, (mod, tests)) in test_modules.items():
+ for (testname, test) in tests.items():
+ if e in test._groups or e == "%s.%s" % (modname, testname):
+ result.setdefault(modname, (mod, {}))
+ if not negated:
+ if not hasattr(test, "_versions") or version in test._versions:
+ result[modname][1][testname] = test
+ else:
+ if modname in result and testname in result[modname][1]:
+ del result[modname][1][testname]
+ if not result[modname][1]:
+ del result[modname]
+ matched = True
+
+ if not matched:
+ die("test-spec element %s did not match any tests" % e)
+
+ return result
+
+def die(msg, exit_val=1):
+ logging.critical(msg)
+ sys.exit(exit_val)
+
+#
+# Main script
+#
+
+# Setup global configuration
+(new_config, args) = config_setup()
+oftest.config.update(new_config)
+
+logging_setup(config)
+xunit_setup(config)
+logging.info("++++++++ " + time.asctime() + " ++++++++")
+
+# Pick an OpenFlow protocol module based on the configured version
+name_to_version = dict((v,k) for k, v in loxi.version_names.iteritems())
+sys.modules["ofp"] = loxi.protocol(name_to_version[config["openflow_version"]])
+
+# HACK: testutils.py imports controller.py, which needs the ofp module
+import oftest.testutils
+
+# Allow tests to import each other
+sys.path.append(config["test_dir"])
+
+test_specs = args
+if config["test_spec"] != "":
+ logging.warning("The '--test-spec' option is deprecated.")
+ test_specs += config["test_spec"].split(',')
+if config["test_file"] != None:
+ with open(config["test_file"], 'r') as f:
+ for line in f:
+ line, _, _ = line.partition('#') # remove comments
+ line = line.strip()
+ if line:
+ test_specs.append(line)
+if test_specs == []:
+ test_specs = ["standard"]
+
+test_modules = load_test_modules(config)
+
+# Check if test list is requested; display and exit if so
+if config["list"]:
+ mod_count = 0
+ test_count = 0
+ all_groups = set()
+
+ print("""
+Tests are shown grouped by module. If a test is in any groups beyond
+"standard" and its module's group then they are shown in parentheses.
+
+Tests marked with '*' are non-standard and may require vendor extensions or
+special switch configuration. These are not part of the "standard" test group.
+
+Tests marked with '!' are disabled because they are experimental,
+special-purpose, or are too long to be run normally. These are not part of
+the "standard" test group or their module's test group.
+
+Tests marked (TP1) after name take --test-params including:
+
+ 'vid=N;strip_vlan=bool;add_vlan=bool'
+
+Test List:
+""")
+ for (modname, (mod, tests)) in test_modules.items():
+ mod_count += 1
+ desc = (mod.__doc__ or "No description").strip().split('\n')[0]
+ print(" Module %13s: %s" % (mod.__name__, desc))
+
+ for (testname, test) in tests.items():
+ desc = (test.__doc__ or "No description").strip().split('\n')[0]
+
+ groups = set(test._groups) - set(["all", "standard", modname])
+ all_groups.update(test._groups)
+ if groups:
+ desc = "(%s) %s" % (",".join(groups), desc)
+ if hasattr(test, "_versions"):
+ desc = "(%s) %s" % (",".join(sorted(test._versions)), desc)
+
+ start_str = " %s%s %s:" % (test._nonstandard and "*" or " ",
+ test._disabled and "!" or " ",
+ testname)
+ print(" %22s : %s" % (start_str, desc))
+ test_count += 1
+ print
+ print("'%d' modules shown with a total of '%d' tests\n" %
+ (mod_count, test_count))
+ print("Test groups: %s" % (', '.join(sorted(all_groups))))
+
+ sys.exit(0)
+
+test_modules = prune_tests(test_specs, test_modules, config["openflow_version"])
+
+# Check if test list is requested; display and exit if so
+if config["list_test_names"]:
+ for (modname, (mod, tests)) in test_modules.items():
+ for (testname, test) in tests.items():
+ print("%s.%s" % (modname, testname))
+
+ sys.exit(0)
+
+# Generate the test suite
+#@todo Decide if multiple suites are ever needed
+suite = unittest.TestSuite()
+
+sorted_tests = []
+for (modname, (mod, tests)) in sorted(test_modules.items()):
+ for (testname, test) in sorted(tests.items()):
+ sorted_tests.append(test)
+
+if config["random_order"]:
+ random.shuffle(sorted_tests)
+
+for test in sorted_tests:
+ suite.addTest(test())
+
+# Allow platforms to import each other
+sys.path.append(config["platform_dir"])
+
+# Load the platform module
+platform_name = config["platform"]
+logging.info("Importing platform: " + platform_name)
+platform_mod = None
+try:
+ platform_mod = imp.load_module(platform_name, *imp.find_module(platform_name, [config["platform_dir"]]))
+except:
+ logging.warn("Failed to import " + platform_name + " platform module")
+ raise
+
+try:
+ platform_mod.platform_config_update(config)
+except:
+ logging.warn("Could not run platform host configuration")
+ raise
+
+if not config["port_map"]:
+ die("Interface port map was not defined by the platform. Exiting.")
+
+logging.debug("Configuration: " + str(config))
+logging.info("OF port map: " + str(config["port_map"]))
+
+oftest.ofutils.default_timeout = config["default_timeout"]
+oftest.ofutils.default_negative_timeout = config["default_negative_timeout"]
+oftest.testutils.MINSIZE = config['minsize']
+
+if os.getuid() != 0 and not config["allow_user"]:
+ die("Super-user privileges required. Please re-run with sudo or as root.")
+ sys.exit(1)
+
+if config["random_seed"] is not None:
+ logging.info("Random seed: %d" % config["random_seed"])
+ random.seed(config["random_seed"])
+else:
+ # Generate random seed and report to log file
+ seed = random.randrange(100000000)
+ logging.info("Autogen random seed: %d" % seed)
+ random.seed(seed)
+
+# Remove python's signal handler which raises KeyboardError. Exiting from an
+# exception waits for all threads to terminate which might not happen.
+signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+if __name__ == "__main__":
+ profiler = profiler_setup(config)
+
+ # Set up the dataplane
+ oftest.dataplane_instance = oftest.dataplane.DataPlane(config)
+ pcap_setup(config)
+ for of_port, ifname in config["port_map"].items():
+ oftest.dataplane_instance.port_add(ifname, of_port)
+
+ logging.info("*** TEST RUN START: " + time.asctime())
+ if config["xunit"]:
+ try:
+ import xmlrunner # fail-fast if module missing
+ except ImportError as ex:
+ oftest.dataplane_instance.kill()
+ profiler_teardown(profiler)
+ raise ex
+ runner = xmlrunner.XMLTestRunner(output=config["xunit_dir"],
+ outsuffix="",
+ verbosity=2)
+ result = runner.run(suite)
+ else:
+ result = unittest.TextTestRunner(verbosity=2).run(suite)
+ oftest.open_logfile('main')
+ if oftest.testutils.skipped_test_count > 0:
+ message = "Skipped %d test(s)" % oftest.testutils.skipped_test_count
+ logging.info(message)
+ logging.info("*** TEST RUN END : %s", time.asctime())
+
+ # Shutdown the dataplane
+ oftest.dataplane_instance.kill()
+ oftest.dataplane_instance = None
+
+ profiler_teardown(profiler)
+
+ if result.failures or result.errors:
+ # exit(1) hangs sometimes
+ os._exit(1)
+ if oftest.testutils.skipped_test_count > 0 and config["fail_skipped"]:
+ os._exit(1)
diff --git a/Fabric/Tests/operational.py b/Fabric/Tests/operational.py
new file mode 100644
index 0000000..9292a08
--- /dev/null
+++ b/Fabric/Tests/operational.py
@@ -0,0 +1,15 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/Fabric/Tests/scalability.py b/Fabric/Tests/scalability.py
new file mode 100755
index 0000000..9292a08
--- /dev/null
+++ b/Fabric/Tests/scalability.py
@@ -0,0 +1,15 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/Fabric/Tests/seba-1.0.0 b/Fabric/Tests/seba-1.0.0
new file mode 100644
index 0000000..b478ec8
--- /dev/null
+++ b/Fabric/Tests/seba-1.0.0
@@ -0,0 +1,67 @@
+
+# Copyright 2017-present Open Networking Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+
+##########################################################################################
+########################### CORD CERTIFICATION PROGRAM (CCP) ##########################
+##########################################################################################
+
+############## This file lists the mandatory test cases to be executed ################
+################## for certifying a Fabric switch against SEBA1.0 ####################
+
+
+
+
+
+### Functional Test cases ###
+## Total #test cases - 19
+
+functional.FabricSW_OF_Bridging_TC_0001
+functional.FabricSW_OF_PacketInArp_TC_0005
+functional.FabricSW_OF_PacketInUDP_TC_0010
+functional.FabricSW_OF_L2FloodQinQ_TC_0015
+functional.FabricSW_OF_L2UnicastTagged_TC_0020
+functional.FabricSW_OF_EcmpGroupMod_TC_0025
+functional.FabricSW_OF_FloodGroupMod_TC_0030
+functional.FabricSW_OF_Mtu1500_TC_0035
+functional.FabricSW_OF__24ECMPL3_TC_0040
+functional.FabricSW_OF__24UcastTagged_TC_0045
+functional.FabricSW_OF__32ECMPL3_TC_0050
+functional.FabricSW_OF__32UcastTagged_TC_0055
+functional.FabricSW_OF_EAPOL_TC_0060
+functional.FabricSW_OF_ARP_TC_0065
+functional.FabricSW_OF_VLANPUSH_TC_0070
+functional.FabricSW_OF_LLDP_TC_0075
+functional.FabricSW_OF_BDDP_TC_0080
+functional.FabricSW_OF_VLANXConnect_Single_TC_0085
+#functional.FabricSW_OF_VLANXConnect_Multi_TC_0090
+#functional.FabricSW_OF_Counters_TC_0095
+
+
+
+### Operational Test cases ###
+## Total #test cases -
+
+
+
+
+
+
+
+
+### Scalability Test cases ###
+## Total #test cases -