[CORD-381] Implement L3McastToL2 tests
- Be careful with 224.1.1.1
Change-Id: I3f233315520be19ce062363898a4bb829531e3b1
diff --git a/README.md b/README.md
index c90c160..74ef3b6 100755
--- a/README.md
+++ b/README.md
@@ -90,30 +90,40 @@
The following tests are implemented and these are their results.
-Test Results | i12_1.7 | 2.0 GA | 3.0 EA0
-------- | ------- | ------ | -------
-/0Ucast | X | ok | ok
-/24UnicastTagged | ok | ok | ok
-/32UnicastTagged | ok | ok | ok
-/24ECMPL3 | ok | ok | ok
-/32ECMPL3 | ok | ok | ok
-/24ECMPVPN | ok | ok | ok
-/32ECMPVPN | ok | ok | ok
-/32VPN | ok | ok | ok
-/24VPN | ok | ok | ok
-EcmpGroupMod | X | X | ok
-PacketInArp | ok | ok | ok
-MTU1500 | ok | ok | ok
-MplsTermination | ok | ok | ok
-MplsFwd | X | ok | ok
-L2FloodQinQ | ok | ok | ok
-L2UnicastTagged | ok | ok | ok
-L3McastToL3 | ok | X | ok
-L3McastToL2 | ok | X | X
-FloodGroupMod | X | X | ok
-PacketInUDP | ok | ok | ok
-Unfiltered | X | ok | X
-Untagged | n/a | n/a | ok
+Test Results | i12_1.7 | 2.0 GA | 3.0 EA0
+------- | ------- | ------ | -------
+/0Ucast | X | ok | ok
+/24UnicastTagged | ok | ok | ok
+/32UnicastTagged | ok | ok | ok
+/24ECMPL3 | ok | ok | ok
+/32ECMPL3 | ok | ok | ok
+/24ECMPVPN | ok | ok | ok
+/32ECMPVPN | ok | ok | ok
+/32VPN | ok | ok | ok
+/24VPN | ok | ok | ok
+EcmpGroupMod | X | X | ok
+PacketInArp | ok | ok | ok
+MTU1500 | ok | ok | ok
+MplsTermination | ok | ok | ok
+MplsFwd | X | ok | ok
+L2FloodQinQ | ok | ok | ok
+L2UnicastTagged | ok | ok | ok
+L3McastToL3 | ok | X | ok
+L3McastToL2_1* | ? | ? | ok
+L3McastToL2_2** | ? | ? | ok
+L3McastToL2_3*** | ? | ? | ok
+L3McastToL2_4**** | ok | ? | ok
+L3McastToL2_5***** | ? | ? | ok
+FloodGroupMod | X | X | ok
+PacketInUDP | ok | ok | ok
+Unfiltered | X | ok | X
+Untagged | ok | n/a | ok
+
+* Untag -> Untag (4094 as internal vlan)
+** Untag -> Tag
+*** Tag -> Untag
+**** Tag -> Tag
+***** Tag -> Tag (Translated)
n/a means test is not available for that version of the pipeline.
diff --git a/accton/accton_util.py b/accton/accton_util.py
index 46e04c5..cf1634c 100755
--- a/accton/accton_util.py
+++ b/accton/accton_util.py
@@ -626,6 +626,36 @@
logging.info("Add allow all vlan on port %d " %(in_port))
ctrl.message_send(request)
+def add_one_vlan_table_flow_translation(ctrl, of_port, vlan_id=1, new_vlan_id=-1, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_BOTH, send_barrier=False):
+ # Install a flow for VLAN translation
+ # in VLAN table.
+ # table 10: vlan
+ # goto to table 20
+ if (flag == VLAN_TABLE_FLAG_ONLY_TAG) or (flag == VLAN_TABLE_FLAG_ONLY_BOTH) or (flag == 4):
+ match = ofp.match()
+ match.oxm_list.append(ofp.oxm.in_port(of_port))
+ match.oxm_list.append(ofp.oxm.vlan_vid_masked(0x1000+vlan_id,0x1fff))
+
+ actions=[]
+ if vrf!=0:
+ actions.append(ofp.action.set_field(ofp.oxm.exp2ByteValue(exp_type=1, value=vrf)))
+ if new_vlan_id != -1:
+ actions.append(ofp.action.set_field(ofp.oxm.vlan_vid(0x1000+new_vlan_id)))
+
+ request = ofp.message.flow_add(
+ table_id=10,
+ cookie=42,
+ match=match,
+ instructions=[
+ ofp.instruction.apply_actions(
+ actions=actions
+ ),
+ ofp.instruction.goto_table(20)
+ ],
+ priority=0)
+ logging.info("Add vlan %d tagged packets on port %d and go to table 20" %( vlan_id, of_port))
+ ctrl.message_send(request)
+
def add_one_vlan_table_flow(ctrl, of_port, vlan_id=1, vrf=0, flag=VLAN_TABLE_FLAG_ONLY_BOTH, send_barrier=False):
# table 10: vlan
# goto to table 20
diff --git a/ofdpa/flows.py b/ofdpa/flows.py
index dc5d2e9..675b284 100755
--- a/ofdpa/flows.py
+++ b/ofdpa/flows.py
@@ -943,6 +943,9 @@
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
@@ -1001,6 +1004,354 @@
verify_no_other_packets( self )
+ parsed_pkt = simple_udp_packet( pktlen=100, dl_vlan_enable=True, vlan_vid=vlan_id,
+ 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 )
+ for port in config[ "port_map" ].keys( ):
+ if port == port2 or port == port1:
+ verify_no_packet( self, pkt, port )
+ continue
+ verify_packet( self, pkt, port )
+ verify_no_other_packets( self )
+ finally:
+ delete_all_flows( self.controller )
+ delete_groups( self.controller, Groups )
+ delete_all_groups( self.controller )
+
+class L3McastToL2UntagToUntag( base_tests.SimpleDataPlane ):
+ """
+ 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_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_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_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_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_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 )
diff --git a/ofdpa/utils.py b/ofdpa/utils.py
index 5bbce7f..7fd78a0 100644
--- a/ofdpa/utils.py
+++ b/ofdpa/utils.py
@@ -3,6 +3,126 @@
from oftest.testutils import *
from accton_util import *
+def fill_mcast_pipeline_L3toL2(
+ controller,
+ logging,
+ ports,
+ is_ingress_tagged,
+ is_egress_tagged,
+ is_vlan_translated,
+ is_max_vlan
+ ):
+ """
+ This method, according to the scenario, fills properly
+ the pipeline. The method generates using ports data the
+ necessary information to fill the multicast pipeline and
+ fills properly the pipeline which consists in this scenario:
+
+ i) to create l2 interface groups;
+ ii) to create l3 multicast groups;
+ iii) to add multicast flows;
+ iv) to add termination; flows;
+ v) to add vlan flows
+
+ Scenarios:
+ 1) ingress untagged, egress untagged
+ 2) ingress untagged, egress tagged
+ 3) ingress tagged, egress untagged
+ 4) ingress tagged, egress tagged, no translation
+ 5) ingress tagged, egress tagged, translation
+ """
+
+ MAX_INTERNAL_VLAN = 4094
+ # Used for no translation
+ FIXED_VLAN = 300
+ Groups = Queue.LifoQueue( )
+ L2_Groups = []
+ port_to_in_vlan = {}
+ port_to_out_vlan = {}
+ port_to_src_mac = {}
+ port_to_src_mac_str = {}
+ port_to_dst_mac = {}
+ port_to_dst_mac_str = {}
+ port_to_src_ip = {}
+ port_to_src_ip_str = {}
+ src_ip_0 = 0xc0a80100
+ src_ip_0_str = "192.168.1.%s"
+ dst_ip = 0xe0000001
+ switch_mac = [ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 ]
+
+ for port in ports:
+ in_vlan_id = port + 1
+ out_vlan_id = MAX_INTERNAL_VLAN - port
+ if is_max_vlan and not is_vlan_translated:
+ in_vlan_id = MAX_INTERNAL_VLAN
+ out_vlan_id = MAX_INTERNAL_VLAN
+ elif not is_max_vlan and not is_vlan_translated:
+ in_vlan_id = FIXED_VLAN
+ out_vlan_id = FIXED_VLAN
+ src_mac = [ 0x00, 0x11, 0x11, 0x11, 0x11, port ]
+ src_mac_str = ':'.join( [ '%02X' % x for x in src_mac ] )
+ dst_mac = [ 0x01, 0x00, 0x5e, 0x01, 0x01, port ]
+ dst_mac_str = ':'.join( [ '%02X' % x for x in dst_mac ] )
+ src_ip = src_ip_0 + port
+ src_ip_str = src_ip_0_str % port
+ port_to_in_vlan[port] = in_vlan_id
+ port_to_out_vlan[port] = out_vlan_id
+ port_to_src_mac[port] = src_mac
+ port_to_src_mac_str[port] = src_mac_str
+ port_to_dst_mac[port] = dst_mac
+ port_to_dst_mac_str[port] = dst_mac_str
+ port_to_src_ip[port] = src_ip
+ port_to_src_ip_str[port] = src_ip_str
+
+ for in_port in ports:
+
+ L2_Groups = []
+ # add vlan flows table
+ add_one_vlan_table_flow( controller, in_port, port_to_in_vlan[in_port], flag=VLAN_TABLE_FLAG_ONLY_TAG )
+ if not is_ingress_tagged:
+ add_one_vlan_table_flow( controller, in_port, port_to_in_vlan[in_port], flag=VLAN_TABLE_FLAG_ONLY_UNTAG )
+ elif is_vlan_translated:
+ add_one_vlan_table_flow_translation( controller, in_port, port_to_in_vlan[in_port], port_to_out_vlan[in_port], flag=VLAN_TABLE_FLAG_ONLY_TAG)
+ # add termination flow
+ if not is_vlan_translated:
+ add_termination_flow( controller, in_port, 0x0800, switch_mac, port_to_in_vlan[in_port] )
+ else:
+ add_termination_flow( controller, in_port, 0x0800, switch_mac, port_to_out_vlan[in_port] )
+
+ for out_port in ports:
+ if out_port == in_port:
+ continue
+ # add l2 interface group, vlan_id equals for each port and must coincide with mcast_group vlan_id
+ if not is_vlan_translated:
+ l2gid, msg = add_one_l2_interface_group( controller, out_port, vlan_id=port_to_in_vlan[in_port],
+ is_tagged=is_egress_tagged, send_barrier=True )
+ else:
+ l2gid, msg = add_one_l2_interface_group( controller, out_port, vlan_id=port_to_out_vlan[in_port],
+ is_tagged=is_egress_tagged, send_barrier=True )
+ Groups._put( l2gid )
+ L2_Groups.append( l2gid )
+
+ # add l3 mcast group
+ if not is_vlan_translated:
+ mcat_group_msg = add_l3_mcast_group( controller, port_to_in_vlan[in_port], in_port, L2_Groups )
+ else:
+ mcat_group_msg = add_l3_mcast_group( controller, port_to_out_vlan[in_port], in_port, L2_Groups )
+ Groups._put( mcat_group_msg.group_id )
+ # add mcast routing flow
+ if not is_vlan_translated:
+ add_mcast4_routing_flow( controller, port_to_in_vlan[in_port], port_to_src_ip[in_port], 0, dst_ip, mcat_group_msg.group_id )
+ else:
+ add_mcast4_routing_flow( controller, port_to_out_vlan[in_port], port_to_src_ip[in_port], 0, dst_ip, mcat_group_msg.group_id )
+
+ return (
+ port_to_in_vlan,
+ port_to_out_vlan,
+ port_to_src_mac_str,
+ port_to_dst_mac_str,
+ port_to_src_ip_str,
+ Groups
+ )
+
def fill_mcast_pipeline_L3toL3(
controller,
logging,