Merge branch 'tyabe'

Conflicts:
	tests/pktact.py
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 85cfc63..322d859 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -621,7 +621,7 @@
 # to standard output.  If FILTER_PATTERNS is specified, this tag will be 
 # ignored.
 
-INPUT_FILTER           = "python /usr/bin/doxypy.py"
+INPUT_FILTER           = "python /usr/local/bin/doxypy.py"
 
 # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
 # basis.  Doxygen will compare the file name with each pattern and apply the 
diff --git a/src/python/oftest/parse.py b/src/python/oftest/parse.py
index 13dac43..ed05aa1 100644
--- a/src/python/oftest/parse.py
+++ b/src/python/oftest/parse.py
@@ -240,8 +240,13 @@
     except:
         udp = None
 
-    # @todo arp and icmp are not yet supported
-    icmp = arp = None
+    try:
+        icmp = ether[scapy.ICMP]
+    except:
+        icmp = None
+
+    # @todo arp is not yet supported
+    arp = None
     return (dot1q, ip, tcp, udp, icmp, arp)
 
 def packet_to_flow_match(packet, pkt_format="L2"):
@@ -289,9 +294,12 @@
 
     if dot1q:
         match.dl_vlan = dot1q.vlan
-        match.wildcards &= ~OFPFW_DL_VLAN
         match.dl_vlan_pcp = dot1q.prio
-        match.wildcards &= ~OFPFW_DL_VLAN_PCP
+    else:
+        match.dl_vlan = OFP_VLAN_NONE
+        match.dl_vlan_pcp = 0
+    match.wildcards &= ~OFPFW_DL_VLAN
+    match.wildcards &= ~OFPFW_DL_VLAN_PCP
 
     if ip:
         match.nw_src = parse_ip(ip.src)
@@ -315,6 +323,11 @@
         match.tp_dst = tcp.dport
         match.wildcards &= ~OFPFW_TP_DST
 
-    #@todo Implement ICMP and ARP fields
+    if icmp:
+        match.nw_proto = 1
+        match.tp_src = icmp.type
+        match.tp_dst = icmp.code
+
+    #@todo Implement ARP fields
 
     return match
diff --git a/tests/pktact.py b/tests/pktact.py
index 535eea1..8d886b9 100644
--- a/tests/pktact.py
+++ b/tests/pktact.py
@@ -66,12 +66,19 @@
     Verify the packet is received at the egress port only
     """
     def runTest(self):
+        self.handleFlow()
+
+    def handleFlow(self, pkttype='TCP'):
+
         global pa_port_map
         of_ports = pa_port_map.keys()
         of_ports.sort()
         self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
 
-        pkt = simple_tcp_packet()
+        if (pkttype == 'ICMP'):
+            pkt = simple_icmp_packet()
+        else:
+            pkt = simple_tcp_packet()
         match = parse.packet_to_flow_match(pkt)
         match.wildcards &= ~ofp.OFPFW_IN_PORT
         self.assertTrue(match is not None, 
@@ -110,8 +117,20 @@
             self.assertEqual(rcv_port, egress_port, "Unexpected receive port")
             self.assertEqual(str(pkt), str(rcv_pkt),
                              'Response packet does not match send packet')
-            
-        
+
+class DirectPacketICMP(DirectPacket):
+    """
+    Send ICMP packet to single egress port
+
+    Generate a ICMP packet
+    Generate and install a matching flow
+    Add action to direct the packet to an egress port
+    Send the packet to ingress dataplane port
+    Verify the packet is received at the egress port only
+    Difference from DirectPacket test is that sent packet is ICMP
+    """
+    def runTest(self):
+        self.handleFlow(pkttype='ICMP')
 
 class DirectTwoPorts(basic.SimpleDataPlane):
     """
@@ -331,7 +350,6 @@
             receive_pkt_check(self.dataplane, pkt, yes_ports, [ingress_port],
                               self, pa_logger)
 
-
 class FloodPlusIngress(basic.SimpleDataPlane):
     """
     Flood to all ports plus send to ingress port
@@ -485,7 +503,6 @@
             receive_pkt_check(self.dataplane, pkt, of_ports, [], self,
                               pa_logger)
             
-
 class FloodMinusPort(basic.SimpleDataPlane):
     """
     Config port with No_Flood and test Flood action
@@ -553,5 +570,416 @@
 
             #@todo Should check no other packets received
 
+class SimpleExactMatch(basic.SimpleDataPlane):
+    """
+    Exercise exact matching for all ports
+
+    Generate a packet
+    Generate and install a matching flow without wildcard mask
+    Add action to forward to a port
+    Send the packet to the port
+    Verify the packet is received at all other ports (one port at a time)
+    Verify flow_expiration message is correct when command option is set
+    """
+    IP_ETHTYPE = 0x800
+    TCP_PROTOCOL = 0x6
+    UDP_PROTOCOL = 0x11
+
+    def runTest(self):
+        self.flowMatchTest()
+
+    def flowMatchTest(self, wildcards=0, check_expire=False):
+        global pa_port_map
+        of_ports = pa_port_map.keys()
+        of_ports.sort()
+        self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
+
+        pkt = simple_tcp_packet()
+        match = parse.packet_to_flow_match(pkt)
+        self.assertTrue(match is not None,
+                        "Could not generate flow match from pkt")
+        match.dl_vlan = ofp.OFP_VLAN_NONE
+        match.nw_proto = self.TCP_PROTOCOL
+        match.wildcards = wildcards
+
+        for idx in range(len(of_ports)):
+            ingress_port = of_ports[idx]
+            pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
+            match.in_port = ingress_port
+
+            for egr_idx in range(len(of_ports)):
+                if egr_idx == idx:
+                    continue
+
+                rc = delete_all_flows(self.controller, pa_logger)
+                self.assertEqual(rc, 0, "Failed to delete all flows")
+                do_barrier(self.controller)
+
+                request = message.flow_mod()
+                request.match = match
+                request.buffer_id = 0xffffffff
+                #@todo Need UI to setup FLAGS parameter for flow_mod
+                if(check_expire):
+                    request.flags |= ofp.OFPFF_SEND_FLOW_REM
+                    request.hard_timeout = 1
+
+                act = action.action_output()
+                act.port = of_ports[egr_idx]
+                self.assertTrue(request.actions.add(act),
+                                "Could not add output action")
+                pa_logger.info(request.show())
+
+                pa_logger.info("Inserting flow")
+                rv = self.controller.message_send(request)
+                self.assertTrue(rv != -1, "Error installing flow mod")
+                do_barrier(self.controller)
+
+                pa_logger.info("Sending packet to dp port " +str(ingress_port))
+                self.dataplane.send(ingress_port, str(pkt))
+
+                ofport = of_ports[egr_idx]
+                self.verifPkt(ofport, pkt)
+
+                #@todo Need UI for enabling response-verification
+                if(check_expire):
+                    self.verifFlowRemoved(request)
+
+    def verifPkt(self, ofport, exp_pkt):
+        (rcv_port, rcv_pkt, pkt_time) = self.dataplane.poll(
+                    port_number=ofport, timeout=1)
+        self.assertTrue(rcv_pkt is not None,
+                    "Did not receive packet port " + str(ofport))
+        pa_logger.debug("Packet len " + str(len(rcv_pkt)) + " in on "
+                    + str(rcv_port))
+
+        self.assertEqual(str(exp_pkt), str(rcv_pkt),
+            'Response packet does not match send packet ' +
+            "on port " + str(ofport))
+
+    def verifFlowRemoved(self, request):
+        (response, raw) = self.controller.poll(ofp.OFPT_FLOW_REMOVED, 2)
+        self.assertTrue(response is not None,
+            'Flow removed message not received')
+
+        req_match = request.match
+        res_match = response.match
+        if(req_match != res_match):
+            self.verifMatchField(req_match, res_match)
+
+        self.assertEqual(request.cookie, response.cookie,
+            self.matchErrStr('cookie'))
+        if (req_match.wildcards != 0):
+            self.assertEqual(request.priority, response.priority,
+                self.matchErrStr('priority'))
+            self.assertEqual(response.reason, ofp.OFPRR_HARD_TIMEOUT,
+                'Reason is not HARD TIMEOUT')
+            self.assertEqual(response.packet_count, 1,
+                'Packet count is not correct')
+            self.assertEqual(response.byte_count, len(pkt),
+                'Packet length is not correct')
+
+    def verifMatchField(self, req_match, res_match):
+        self.assertEqual(str(req_match.wildcards), str(res_match.wildcards),
+            self.matchErrStr('wildcards'))
+        self.assertEqual(str(req_match.in_port), str(res_match.in_port),
+            self.matchErrStr('in_port'))
+        self.assertEqual(str(req_match.dl_src), str(res_match.dl_src),
+            self.matchErrStr('dl_src'))
+        self.assertEqual(str(req_match.dl_dst), str(res_match.dl_dst),
+            self.matchErrStr('dl_dst'))
+        self.assertEqual(str(req_match.dl_vlan), str(res_match.dl_vlan),
+            self.matchErrStr('dl_vlan'))
+        self.assertEqual(str(req_match.dl_vlan_pcp), str(res_match.dl_vlan_pcp),
+            self.matchErrStr('dl_vlan_pcp'))
+        self.assertEqual(str(req_match.dl_type), str(res_match.dl_type),
+            self.matchErrStr('dl_type'))
+        if(not(req_match.wildcards & ofp.OFPFW_DL_TYPE)
+           and (req_match.dl_type == self.IP_ETHERTYPE)):
+            self.assertEqual(str(req_match.nw_tos), str(res_match.nw_tos),
+                self.matchErrStr('nw_tos'))
+            self.assertEqual(str(req_match.nw_proto), str(res_match.nw_proto),
+                self.matchErrStr('nw_proto'))
+            self.assertEqual(str(req_match.nw_src), str(res_match.nw_src),
+                self.matchErrStr('nw_src'))
+            self.assertEqual(str(req_match.nw_dst), str(res_match.nw_dst),
+                self.matchErrStr('nw_dst'))
+            if(not(req_match.wildcards & ofp.OFPFW_NW_PROTO)
+               and ((req_match.nw_proto == self.TCP_PROTOCOL)
+                    or (req_match.nw_proto == self.UDP_PROTOCOL))):
+                self.assertEqual(str(req_match.tp_src), str(res_match.tp_src),
+                    self.matchErrStr('tp_src'))
+                self.assertEqual(str(req_match.tp_dst), str(res_match.tp_dst),
+                    self.matchErrStr('tp_dst'))
+
+    def matchErrStr(self, field):
+        return ('Response Match_' + field + ' does not match send message')
+
+class SingleWildcardMatch(SimpleExactMatch):
+    """
+    Exercise wildcard matching for all ports
+
+    Generate a packet
+    Generate and install a matching flow with wildcard mask
+    Add action to forward to a port
+    Send the packet to the port
+    Verify the packet is received at all other ports (one port at a time)
+    Verify flow_expiration message is correct when command option is set
+    """
+    def __init__(self):
+        SimpleExactMatch.__init__(self)
+        self.wildcards = [ofp.OFPFW_IN_PORT,
+                          ofp.OFPFW_DL_VLAN,
+                          ofp.OFPFW_DL_SRC,
+                          ofp.OFPFW_DL_DST,
+                          ofp.OFPFW_DL_TYPE,
+                          ofp.OFPFW_NW_PROTO,
+                          ofp.OFPFW_TP_SRC,
+                          ofp.OFPFW_TP_DST,
+                          0x3F << ofp.OFPFW_NW_SRC_SHIFT,
+                          0x3F << ofp.OFPFW_NW_DST_SHIFT,
+                          ofp.OFPFW_DL_VLAN_PCP,
+                          ofp.OFPFW_NW_TOS]
+
+    def runTest(self):
+        for exec_wildcard in range(len(self.wildcards)):
+            self.flowMatchTest(exec_wildcard)
+
+class AllExceptOneWildcardMatch(SingleWildcardMatch):
+    """
+    Create All-execpt-one-field wildcard and exercise for all ports
+
+    Generate a packet
+    Generate and install a matching flow with wildcard all except one filed
+    Add action to forward to a port
+    Send the packet to the port
+    Verify the packet is received at all other ports (one port at a time)
+    Verify flow_expiration message is correct when command option is set
+    """
+    def runTest(self):
+        for exec_wildcard in range(len(self.wildcards)):
+            all_exp_one_wildcard = ofp.OFPFW_ALL ^ self.wildcards[exec_wildcard]
+            self.flowMatchTest(all_exp_one_wildcard)
+
+class AllWildcardMatch(SingleWildcardMatch):
+    """
+    Create Wildcard-all flow and exercise for all ports
+
+    Generate a packet
+    Generate and install a matching flow with wildcard-all
+    Add action to forward to a port
+    Send the packet to the port
+    Verify the packet is received at all other ports (one port at a time)
+    Verify flow_expiration message is correct when command option is set
+    """
+    def runTest(self):
+        self.flowMatchTest(ofp.OFPFW_ALL)
+
+class ExactModifyAction(SimpleExactMatch):
+    """
+    Perform Modify action with exact matching for all ports
+
+    Generate a packet for transmit
+    Generate the expected packet
+    Generate and install a matching flow with a modify action and
+    an output action without wildcard mask
+    Send the packet to the port
+    Verify the expected packet is received at all other ports
+    (one port at a time)
+    Verify flow_expiration message is correct when command option is set
+    """
+    def __init__(self):
+        SimpleExactMatch.__init__(self)
+        self.modify_act = [ofp.OFPAT_SET_VLAN_VID,
+                           ofp.OFPAT_SET_VLAN_PCP,
+                           ofp.OFPAT_STRIP_VLAN,
+                           ofp.OFPAT_SET_DL_SRC,
+                           ofp.OFPAT_SET_DL_DST,
+                           ofp.OFPAT_SET_NW_SRC,
+                           ofp.OFPAT_SET_NW_DST,
+                           ofp.OFPAT_SET_NW_TOS,
+                           ofp.OFPAT_SET_TP_SRC,
+                           ofp.OFPAT_SET_TP_DST]
+
+    def runTest(self):
+        self.flowMatchModTest()
+
+    def flowMatchModTest(self, wildcards=0, check_expire=False):
+        global pa_port_map
+        of_ports = pa_port_map.keys()
+        of_ports.sort()
+        self.assertTrue(len(of_ports) > 1, "Not enough ports for test")
+
+        mod_dl_dst = '43:21:0F:ED:CB:A9'
+        mod_dl_src = '7F:ED:CB:A9:87:65'
+        mod_dl_vlan = 4094
+        mod_dl_vlan_pcp = 7
+        mod_ip_src = '10.20.30.40'
+        mod_ip_dst = '50.60.70.80'
+        mod_ip_tos = 0xf0
+        mod_tcp_sport = 4321
+        mod_tcp_dport = 8765
+
+        request = message.features_request()
+        (reply, pkt) = self.controller.transact(request, timeout=2)
+        self.assertTrue(reply is not None, "Did not get response to ftr req")
+        supported_act = reply.actions
+
+        for idx in range(len(of_ports)):
+            ingress_port = of_ports[idx]
+            pa_logger.info("Ingress " + str(ingress_port) + " to all the other ports")
+
+            for egr_idx in range(len(of_ports)):
+                if egr_idx == idx:
+                    continue
+
+                for exec_mod in range(len(self.modify_act)):
+                    pkt_len = 100
+                    dl_dst = '0C:DE:F0:12:34:56'
+                    dl_src = '01:23:45:67:89:AB'
+                    dl_vlan_enable = False
+                    dl_vlan = 0
+                    dl_vlan_pcp = 0
+                    ip_src = '192.168.0.1'
+                    ip_dst = '192.168.0.2'
+                    ip_tos = 0
+                    tcp_sport = 1234
+                    tcp_dport = 80
+
+                    rc = delete_all_flows(self.controller, pa_logger)
+                    self.assertEqual(rc, 0, "Failed to delete all flows")
+                    do_barrier(self.controller)
+
+                    pkt = simple_tcp_packet(pktlen=pkt_len,
+                        dl_dst=dl_dst,
+                        dl_src=dl_src,
+                        dl_vlan_enable=dl_vlan_enable,
+                        dl_vlan=dl_vlan,
+                        dl_vlan_pcp=dl_vlan_pcp,
+                        ip_src=ip_src,
+                        ip_dst=ip_dst,
+                        ip_tos=ip_tos,
+                        tcp_sport=tcp_sport,
+                        tcp_dport=tcp_dport)
+
+                    match = parse.packet_to_flow_match(pkt)
+                    self.assertTrue(match is not None,
+                        "Could not generate flow match from pkt")
+                    match.in_port = ingress_port
+                    match.dl_vlan = ofp.OFP_VLAN_NONE
+                    match.nw_proto = self.TCP_PROTOCOL
+                    match.wildcards = wildcards
+
+                    request = message.flow_mod()
+                    request.match = match
+                    request.buffer_id = 0xffffffff
+                    #@todo Need UI to setup FLAGS parameter for flow_mod
+                    if(check_expire):
+                        request.flags |= ofp.OFPFF_SEND_FLOW_REM
+                        request.hard_timeout = 1
+
+                    exec_act = self.modify_act[exec_mod]
+                    if exec_act == ofp.OFPAT_SET_VLAN_VID:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_VID):
+                            continue
+                        pkt_len = pkt_len + 4
+                        dl_vlan_enable = True
+                        dl_vlan = mod_dl_vlan
+                        mod_act = action.action_set_vlan_vid()
+                        mod_act.vlan_vid = mod_dl_vlan
+                    elif exec_act == ofp.OFPAT_SET_VLAN_PCP:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_VLAN_PCP):
+                            continue
+                        pkt_len = pkt_len + 4
+                        dl_vlan_enable = True
+                        dl_vlan_pcp = mod_dl_vlan_pcp
+                        mod_act = action.action_set_vlan_pcp()
+                        mod_act.vlan_pcp = mod_dl_vlan_pcp
+                    elif exec_act == ofp.OFPAT_STRIP_VLAN:
+                        if not(supported_act & 1<<ofp.OFPAT_STRIP_VLAN):
+                            continue
+                        dl_vlan_enable = False
+                        mod_act = action.action_strip_vlan()
+                    elif exec_act == ofp.OFPAT_SET_DL_SRC:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_DL_SRC):
+                            continue
+                        dl_src = mod_dl_src
+                        mod_act = action.action_set_dl_src()
+                        mod_act.dl_addr = parse.parse_mac(mod_dl_src)
+                    elif exec_act == ofp.OFPAT_SET_DL_DST:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_DL_DST):
+                            continue
+                        dl_dst = mod_dl_dst
+                        mod_act = action.action_set_dl_dst()
+                        mod_act.dl_addr = parse.parse_mac(mod_dl_dst)
+                    elif exec_act == ofp.OFPAT_SET_NW_SRC:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_NW_SRC):
+                            continue
+                        ip_src = mod_ip_src
+                        mod_act = action.action_set_nw_src()
+                        mod_act.nw_addr = parse.parse_ip(mod_ip_src)
+                    elif exec_act == ofp.OFPAT_SET_NW_DST:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_NW_DST):
+                            continue
+                        ip_dst = mod_ip_dst
+                        mod_act = action.action_set_nw_dst()
+                        mod_act.nw_addr = parse.parse_ip(mod_ip_dst)
+                    elif exec_act == ofp.OFPAT_SET_NW_TOS:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_NW_TOS):
+                            continue
+                        ip_tos = mod_ip_tos
+                        mod_act = action.action_set_nw_tos()
+                        mod_act.nw_tos = mod_ip_tos
+                    elif exec_act == ofp.OFPAT_SET_TP_SRC:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_TP_SRC):
+                            continue
+                        tcp_sport = mod_tcp_sport
+                        mod_act = action.action_set_tp_src()
+                        mod_act.tp_port = mod_tcp_sport
+                    elif exec_act == ofp.OFPAT_SET_TP_DST:
+                        if not(supported_act & 1<<ofp.OFPAT_SET_TP_DST):
+                            continue
+                        tcp_dport = mod_tcp_dport
+                        mod_act = action.action_set_tp_dst()
+                        mod_act.tp_port = mod_tcp_dport
+                    else:
+                        continue
+
+                    self.assertTrue(request.actions.add(mod_act),
+                            "Could not add output action")
+                    pa_logger.info(request.show())
+
+                    exp_pkt = simple_tcp_packet(pktlen=pkt_len,
+                        dl_dst=dl_dst,
+                        dl_src=dl_src,
+                        dl_vlan_enable=dl_vlan_enable,
+                        dl_vlan=dl_vlan,
+                        dl_vlan_pcp=dl_vlan_pcp,
+                        ip_src=ip_src,
+                        ip_dst=ip_dst,
+                        ip_tos=ip_tos,
+                        tcp_sport=tcp_sport,
+                        tcp_dport=tcp_dport)
+
+                    act = action.action_output()
+                    act.port = of_ports[egr_idx]
+                    self.assertTrue(request.actions.add(act),
+                                    "Could not add output action")
+                    pa_logger.info(request.show())
+
+                    pa_logger.info("Inserting flow")
+                    rv = self.controller.message_send(request)
+                    self.assertTrue(rv != -1, "Error installing flow mod")
+                    do_barrier(self.controller)
+
+                    pa_logger.info("Sending packet to dp port " +str(ingress_port))
+                    self.dataplane.send(ingress_port, str(pkt))
+
+                    ofport = of_ports[egr_idx]
+                    self.verifPkt(ofport, exp_pkt)
+
+                    #@todo Need UI for enabling response-verification
+                    if(check_expire):
+                        self.verifFlowRemoved(request)
+
 if __name__ == "__main__":
     print "Please run through oft script:  ./oft --test_spec=basic"
diff --git a/tests/testutils.py b/tests/testutils.py
index a66e575..ea82ecc 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -36,8 +36,12 @@
 def simple_tcp_packet(pktlen=100, 
                       dl_dst='00:01:02:03:04:05',
                       dl_src='00:06:07:08:09:0a',
+                      dl_vlan_enable=False,
+                      dl_vlan=0,
+                      dl_vlan_pcp=0,
                       ip_src='192.168.0.1',
                       ip_dst='192.168.0.2',
+                      ip_tos=0,
                       tcp_sport=1234,
                       tcp_dport=80
                       ):
@@ -48,8 +52,12 @@
     @param len Length of packet in bytes w/o CRC
     @param dl_dst Destinatino MAC
     @param dl_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param dl_vlan VLAN ID
+    @param dl_vlan_pcp VLAN priority
     @param ip_src IP source
     @param ip_dst IP destination
+    @param ip_tos IP ToS
     @param tcp_dport TCP destination port
     @param ip_sport TCP source port
 
@@ -57,13 +65,66 @@
     shouldn't assume anything about this packet other than that
     it is a valid ethernet/IP/TCP frame.
     """
-    pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
-        scapy.IP(src=ip_src, dst=ip_dst)/ \
-        scapy.TCP(sport=tcp_sport, dport=tcp_dport)
+    if (dl_vlan_enable):
+        pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
+            scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
+            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
+            scapy.TCP(sport=tcp_sport, dport=tcp_dport)
+    else:
+        pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
+            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
+            scapy.TCP(sport=tcp_sport, dport=tcp_dport)
+
     pkt = pkt/("D" * (pktlen - len(pkt)))
 
     return pkt
 
+def simple_icmp_packet(pktlen=60, 
+                      dl_dst='00:01:02:03:04:05',
+                      dl_src='00:06:07:08:09:0a',
+                      dl_vlan_enable=False,
+                      dl_vlan=0,
+                      dl_vlan_pcp=0,
+                      ip_src='192.168.0.1',
+                      ip_dst='192.168.0.2',
+                      ip_tos=0,
+                      icmp_type=8,
+                      icmp_code=0
+                      ):
+    """
+    Return a simple ICMP packet
+
+    Supports a few parameters:
+    @param len Length of packet in bytes w/o CRC
+    @param dl_dst Destinatino MAC
+    @param dl_src Source MAC
+    @param dl_vlan_enable True if the packet is with vlan, False otherwise
+    @param dl_vlan VLAN ID
+    @param dl_vlan_pcp VLAN priority
+    @param ip_src IP source
+    @param ip_dst IP destination
+    @param ip_tos IP ToS
+    @param icmp_type ICMP type
+    @param icmp_code ICMP code
+
+    Generates a simple ICMP ECHO REQUEST.  Users
+    shouldn't assume anything about this packet other than that
+    it is a valid ethernet/ICMP frame.
+    """
+    if (dl_vlan_enable):
+        pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
+            scapy.Dot1Q(prio=dl_vlan_pcp, id=0, vlan=dl_vlan)/ \
+            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
+            scapy.ICMP(type=icmp_type, code=icmp_code)
+    else:
+        pkt = scapy.Ether(dst=dl_dst, src=dl_src)/ \
+            scapy.IP(src=ip_src, dst=ip_dst, tos=ip_tos)/ \
+            scapy.ICMP(type=icmp_type, code=icmp_code)
+
+    pkt = pkt/("0" * (pktlen - len(pkt)))
+
+    return pkt
+
 def do_barrier(ctrl):
     b = message.barrier_request()
     ctrl.transact(b)