Added test for reproducing pw bug.
Test flows._MplsFwdInterfaceProblem_PW reproduces the bug we discussed
where the dst mac address was set wrongly, even though the client reported the
correct rules.
Change-Id: Iedfd640e3805c40e129317b3cfd31ed3e4a71038
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 479957c..2c1be4a 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -1293,7 +1293,6 @@
],
buffer_id=ofp.OFP_NO_BUFFER,
priority=1)
- logging.info("Inserting MPLS flow , label %ld", label)
ctrl.message_send(request)
if send_barrier:
@@ -1380,6 +1379,7 @@
# 0x0002nnnn is for UNI interfaces
apply_actions.append(ofp.action.set_field(ofp.oxm.exp4ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_L2_PORT, value=0x00020000 + of_port)))
apply_actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=ofp.oxm.OFDPA_EXP_TYPE_MPLS_TYPE, value=ofp.oxm.VPWS)))
+
write_actions.append(ofp.action.group(action_group_id))
request = ofp.message.flow_add(
@@ -1845,7 +1845,7 @@
return index + (10 << OFDPA_GROUP_TYPE_SHIFT)+(subtype<<OFDPA_MPLS_SUBTYPE_SHIFT)
-def add_mpls_intf_group(ctrl, ref_gid, dst_mac, src_mac, vid, index, subtype=0, send_barrier=False):
+def add_mpls_intf_group(ctrl, ref_gid, dst_mac, src_mac, vid, index, subtype=0, send_barrier=False, add=True):
action=[]
action.append(ofp.action.set_field(ofp.oxm.eth_src(src_mac)))
action.append(ofp.action.set_field(ofp.oxm.eth_dst(dst_mac)))
@@ -1855,10 +1855,17 @@
buckets = [ofp.bucket(actions=action)]
mpls_group_id =encode_mpls_interface_group_id(subtype, index)
- request = ofp.message.group_add(group_type=ofp.OFPGT_INDIRECT,
- group_id=mpls_group_id,
- buckets=buckets
- )
+ if add:
+ request = ofp.message.group_add(group_type=ofp.OFPGT_INDIRECT,
+ group_id=mpls_group_id,
+ buckets=buckets
+ )
+ else:
+ request = ofp.message.group_modify(group_type=ofp.OFPGT_INDIRECT,
+ group_id=mpls_group_id,
+ buckets=buckets
+ )
+
logging.debug("Adding MPLS interface group %02x, src_mac %s , dst_mac %s , vid %d", mpls_group_id, src_mac, dst_mac, vid)
ctrl.message_send(request)
diff --git a/ofdpa/flows.py b/ofdpa/flows.py
index 9f02081..199b429 100755
--- a/ofdpa/flows.py
+++ b/ofdpa/flows.py
@@ -2651,6 +2651,7 @@
eth_dst=input_dst_mac_str,
)
pkt = str( parsed_pkt )
+
self.dataplane.send( src_port, pkt )
label = (mpls_label, 0, 1, 62)
@@ -3121,9 +3122,10 @@
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" )
+ logging.info( "port count less than 2, can't run this case" )
return
input_src_mac = [ 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc ]
@@ -3211,4 +3213,143 @@
finally:
delete_all_flows( self.controller )
delete_groups( self.controller, Groups )
- delete_all_groups( self.controller )
\ No newline at end of file
+ delete_all_groups( self.controller )
+
+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 )
+
+
diff --git a/ofdpa/pw_flows.py b/ofdpa/pw_flows.py
index 5713a94..37a2ad6 100644
--- a/ofdpa/pw_flows.py
+++ b/ofdpa/pw_flows.py
@@ -1894,7 +1894,6 @@
verify_no_other_packets( self )
finally:
-
delete_all_flows( self.controller )
delete_groups( self.controller, Groups )
delete_all_groups( self.controller )
@@ -2180,6 +2179,179 @@
delete_all_flows( self.controller )
delete_all_groups( self.controller )
+class IntermediateTransportBug( base_tests.SimpleDataPlane ):
+ """
+ This test is meant to verify that the alternative approach for handling
+ pseudowires in spine switches. Specifically, in the mpls table we install
+ 2 rules , the match(SR1, BoS=1) and match(SR2, BoS=0). The match(SR2, BoS=0)
+ should match and the packet should be forwarded through the port and the label
+ for SR2 should be removed.
+ """
+ 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
+ ports = config[ "port_map" ].keys( )
+ in_port = ports[0]
+ out_port = ports[1]
+ out_vlan = 4094
+ src_mac = [ 0x00, 0x00, 0x00, 0x00, 0x11, 0x01 ]
+ src_mac_str = ':'.join( [ '%02X' % x for x in src_mac ] )
+ dst_mac = [ 0x00, 0x00, 0x00, 0x11, 0x11, 0x01 ]
+ dst_mac_str = ':'.join( [ '%02X' % x for x in dst_mac ] )
+ mpls_label = 100
+ mpls_label_SR1 = 100 + 5
+ mpls_label_SR2 = 100 + 10
+ mpls_label_PW = 100 + 15
+
+ # Add l2 interface group, we have to pop the VLAN;
+ l2_intf_gid, l2_intf_msg = add_one_l2_interface_group(
+ ctrl=self.controller,
+ port=out_port,
+ vlan_id=out_vlan,
+ is_tagged=False,
+ send_barrier=False
+ )
+ Groups._put( l2_intf_gid )
+
+ # add MPLS interface group
+ mpls_intf_gid, mpls_intf_msg = add_mpls_intf_group(
+ ctrl=self.controller,
+ ref_gid=l2_intf_gid,
+ dst_mac=dst_mac,
+ src_mac=src_mac,
+ vid=out_vlan,
+ index=in_port
+ )
+ Groups._put( mpls_intf_gid )
+
+ # Add L3 Unicast group
+ l3_msg = add_l3_unicast_group(
+ ctrl=self.controller,
+ port=out_port,
+ vlanid=out_vlan,
+ id=in_port,
+ src_mac=src_mac,
+ dst_mac=dst_mac
+ )
+ Groups._put( l3_msg.group_id )
+
+ # Add L3 ecmp group
+ ecmp_msg = add_l3_ecmp_group(
+ ctrl=self.controller,
+ id=in_port,
+ l3_ucast_groups=[ l3_msg.group_id ]
+ )
+ Groups._put( ecmp_msg.group_id )
+
+ # Add MPLS flow with BoS=1
+ add_mpls_flow(
+ ctrl=self.controller,
+ action_group_id=ecmp_msg.group_id,
+ label=mpls_label_SR1
+ )
+
+ # 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=src_mac,
+ vlanid=out_vlan,
+ goto_table=23
+ )
+ # add VLAN flows
+ add_one_vlan_table_flow(
+ ctrl=self.controller,
+ of_port=in_port,
+ vlan_id=out_vlan,
+ flag=VLAN_TABLE_FLAG_ONLY_TAG,
+ )
+ add_one_vlan_table_flow(
+ ctrl=self.controller,
+ of_port=in_port,
+ vlan_id=out_vlan,
+ flag=VLAN_TABLE_FLAG_ONLY_UNTAG
+ )
+ # Packet generation with sleep
+ time.sleep(2)
+ label_SR1 = (mpls_label_SR1, 0, 1, 32)
+ 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
+
+ pw = True
+ if pw:
+ parsed_pkt = mpls_packet(
+ pktlen=104,
+ ip_ttl=63,
+ eth_dst=src_mac_str,
+ label=[label_SR2, label_2],
+ encapsulated_ethernet = True
+ )
+
+ pkt = str( parsed_pkt )
+
+ self.dataplane.send( in_port, pkt )
+
+ expected_label = (mpls_label_PW, 0, 1, 31)
+ # we geneate the expected pw packet
+ parsed_pkt = mpls_packet(
+ pktlen=100,
+ ip_ttl=63,
+ eth_dst=dst_mac_str,
+ eth_src=src_mac_str,
+ label=[ expected_label ],
+ encapsulated_ethernet = True
+ )
+
+ pkt = str( parsed_pkt )
+ verify_packet( self, pkt, out_port )
+ verify_no_packet( self, pkt, in_port )
+ else:
+ # packet for routing traffic
+ parsed_pkt_2 = mpls_packet(
+ pktlen=104,
+ ip_ttl=63,
+ eth_dst=src_mac_str,
+ label=[ label_SR1 ]
+ )
+ pkt_2 = str(parsed_pkt_2)
+ self.dataplane.send( in_port, pkt_2 )
+
+ # we geneate the expected routed packet
+ parsed_pkt_2 = simple_tcp_packet(
+ pktlen=100,
+ ip_ttl=31,
+ eth_dst=dst_mac_str,
+ eth_src=src_mac_str,
+ )
+ pkt_2 = str(parsed_pkt_2)
+
+ verify_packet( self, pkt_2, out_port)
+ verify_no_packet( self, pkt_2, in_port )
+
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+