[dpdk-dev] [PATCH] app/testpmd: add engine that replies to ARP and ICMP echo requests

David Marchand david.marchand at 6wind.com
Wed Apr 30 15:30:11 CEST 2014


From: Ivan Boule <ivan.boule at 6wind.com>

Add a new specific packet processing engine in the "testpmd" application that
only replies to ARP requests and to ICMP echo requests.
For this purpose, a new "icmpecho" forwarding mode is provided that can be
dynamically selected with the following testpmd command:

    set fwd icmpecho

before starting the receipt of packets on the selected ports.

Then, the "icmpecho" engine performs the following actions on all received
packets:

- replies to a received ARP request by sending back on the RX port a ARP
  reply with a "sender hardware address" field containing the MAC address
  of the RX port,

- replies to a ICMP echo request by sending back on the RX port a ICMP echo
  reply, swapping the IP source and the IP destination address in the IP
  header,

- otherwise, simply drops the received packet.

When replying to a received packet that was encapsulated into a VLAN tunnel,
the reply is sent back with the same VLAN identifier.
By default, the testpmd configures VLAN header stripping RX option on each
port.
This option is not managed by the icmpecho engine which won't detect
packets that were encapsulated into a VLAN.
To address this issue, the VLAN header stripping option must be previously
switched off with the following testpmd command:

    vlan set strip off

When the "verbose" mode has been set with the testpmd command
"set verbose 1", the "icmpecho" engine displays informations about each
received packet.

The "icmpecho" forwarding engine can also be used to simply check port
connectivity at the hardware level (check that cables are well-plugged)
and at the software level (receipt of VLAN packets, for instance).

Signed-off-by: Ivan Boule <ivan.boule at 6wind.com>
---
 app/test-pmd/Makefile     |    1 +
 app/test-pmd/cmdline.c    |   67 ++++--
 app/test-pmd/config.c     |   59 ++++++
 app/test-pmd/icmpecho.c   |  504 +++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c    |    1 +
 app/test-pmd/testpmd.h    |    1 +
 lib/librte_net/Makefile   |    2 +-
 lib/librte_net/rte_arp.h  |   84 ++++++++
 lib/librte_net/rte_icmp.h |  101 +++++++++
 9 files changed, 803 insertions(+), 17 deletions(-)
 create mode 100644 app/test-pmd/icmpecho.c
 create mode 100644 lib/librte_net/rte_arp.h
 create mode 100644 lib/librte_net/rte_icmp.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index bec83eb..ae41f4f 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -58,6 +58,7 @@ SRCS-$(CONFIG_RTE_TEST_PMD) += macfwd-retry.c
 SRCS-$(CONFIG_RTE_TEST_PMD) += rxonly.c
 SRCS-$(CONFIG_RTE_TEST_PMD) += txonly.c
 SRCS-$(CONFIG_RTE_TEST_PMD) += csumonly.c
+SRCS-$(CONFIG_RTE_TEST_PMD) += icmpecho.c
 ifeq ($(CONFIG_RTE_LIBRTE_IEEE1588),y)
 SRCS-$(CONFIG_RTE_TEST_PMD) += ieee1588fwd.c
 endif
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 9d3c823..9cc680f 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -294,17 +294,31 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"        bit 3 - insert sctp checksum offload if set\n"
 			"    Please check the NIC datasheet for HW limits.\n\n"
 
+			"set fwd ("
+			  "io"
+			  "|mac"
+			  "|mac_retry"
+			  "|rxonly"
+			  "|csum"
+			  "|icmpecho"
 #ifdef RTE_LIBRTE_IEEE1588
-			"set fwd (io|mac|mac_retry|rxonly|txonly|csum|ieee1588)\n"
-			"    Set IO, MAC, MAC_RETRY, RXONLY, CSUM or TXONLY or ieee1588"
+			  "|ieee1588"
+#endif
+			  "|txonly"
+			")\n"
+			"    Set "
+			  "IO"
+			  ", MAC"
+			  ", MAC_RETRY"
+			  ", RXONLY"
+			  ", CSUM"
+			  ", ICMPECHO"
+#ifdef RTE_LIBRTE_IEEE1588
+			  ", IEEE1588"
+#endif
+			  " or TXONLY"
 			" packet forwarding mode.\n\n"
 
-#else
-			"set fwd (io|mac|mac_retry|rxonly|txonly|csum)\n"
-			"    Set IO, MAC, MAC_RETRY, RXONLY, CSUM or TXONLY packet"
-			" forwarding mode.\n\n"
-
-#endif
 			"mac_addr add (port_id) (XX:XX:XX:XX:XX:XX)\n"
 			"    Add a MAC address on port_id.\n\n"
 
@@ -2728,22 +2742,43 @@ cmdline_parse_token_string_t cmd_setfwd_fwd =
 	TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, fwd, "fwd");
 cmdline_parse_token_string_t cmd_setfwd_mode =
 	TOKEN_STRING_INITIALIZER(struct cmd_set_fwd_mode_result, mode,
+				 "io"
+				 "#mac"
+				 "#mac_retry"
+				 "#rxonly"
+				 "#csum"
+				 "#icmpecho"
 #ifdef RTE_LIBRTE_IEEE1588
-				 "io#mac#mac_retry#rxonly#txonly#csum#ieee1588");
-#else
-				 "io#mac#mac_retry#rxonly#txonly#csum");
+				 "#ieee1588"
 #endif
+				 "#txonly");
 
 cmdline_parse_inst_t cmd_set_fwd_mode = {
 	.f = cmd_set_fwd_mode_parsed,
 	.data = NULL,
+	.help_str = "set fwd "
+			"io"
+			"|mac"
+			"|mac_retry"
+			"|rxonly"
+			"|csum"
+			"|icmpecho"
 #ifdef RTE_LIBRTE_IEEE1588
-	.help_str = "set fwd io|mac|mac_retry|rxonly|txonly|csum|ieee1588 - set IO, MAC,"
-	" MAC_RETRY, RXONLY, TXONLY, CSUM or IEEE1588 packet forwarding mode",
-#else
-	.help_str = "set fwd io|mac|mac_retry|rxonly|txonly|csum - set IO, MAC,"
-	" MAC_RETRY, RXONLY, CSUM or TXONLY packet forwarding mode",
+			"|ieee1588"
+#endif
+			"|txonly"
+		    " - set "
+			"IO"
+			", MAC"
+			", MAC_RETRY"
+			", RXONLY"
+			", CSUM"
+			", ICMPECHO"
+#ifdef RTE_LIBRTE_IEEE1588
+			", IEEE1588"
 #endif
+			" or TXONLY"
+		    " packet forwarding mode",
 	.tokens = {
 		(void *)&cmd_setfwd_set,
 		(void *)&cmd_setfwd_fwd,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 1feb133..5905fea 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -958,10 +958,69 @@ dcb_fwd_config_setup(void)
 	}
 }
 
+static void
+icmp_echo_config_setup(void)
+{
+	portid_t  rxp;
+	queueid_t rxq;
+	lcoreid_t lc_id;
+	uint16_t  sm_id;
+
+	if ((nb_txq * nb_fwd_ports) < nb_fwd_lcores)
+		cur_fwd_config.nb_fwd_lcores = (lcoreid_t)
+			(nb_txq * nb_fwd_ports);
+	else
+		cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores;
+	cur_fwd_config.nb_fwd_ports = nb_fwd_ports;
+	cur_fwd_config.nb_fwd_streams =
+		(streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports);
+	if (cur_fwd_config.nb_fwd_streams < cur_fwd_config.nb_fwd_lcores)
+		cur_fwd_config.nb_fwd_lcores =
+			(lcoreid_t)cur_fwd_config.nb_fwd_streams;
+	if (verbose_level > 0) {
+		printf("%s fwd_cores=%d fwd_ports=%d fwd_streams=%d\n",
+		       __FUNCTION__,
+		       cur_fwd_config.nb_fwd_lcores,
+		       cur_fwd_config.nb_fwd_ports,
+		       cur_fwd_config.nb_fwd_streams);
+	}
+
+	/* reinitialize forwarding streams */
+	init_fwd_streams();
+	setup_fwd_config_of_each_lcore(&cur_fwd_config);
+	rxp = 0; rxq = 0;
+	for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) {
+		if (verbose_level > 0)
+			printf("  core=%d: \n", lc_id);
+		for (sm_id = 0; sm_id < fwd_lcores[lc_id]->stream_nb; sm_id++) {
+			struct fwd_stream *fs;
+			fs = fwd_streams[fwd_lcores[lc_id]->stream_idx + sm_id];
+			fs->rx_port = fwd_ports_ids[rxp];
+			fs->rx_queue = rxq;
+			fs->tx_port = fs->rx_port;
+			fs->tx_queue = lc_id;
+			fs->peer_addr = fs->tx_port;
+			if (verbose_level > 0)
+				printf("  stream=%d port=%d rxq=%d txq=%d\n",
+				       sm_id, fs->rx_port, fs->rx_queue,
+				       fs->tx_queue);
+			rxq = (queueid_t) (rxq + 1);
+			if (rxq == nb_rxq) {
+				rxq = 0;
+				rxp = (portid_t) (rxp + 1);
+			}
+		}
+	}
+}
+
 void
 fwd_config_setup(void)
 {
 	cur_fwd_config.fwd_eng = cur_fwd_eng;
+	if (strcmp(cur_fwd_eng->fwd_mode_name, "icmpecho") == 0) {
+		icmp_echo_config_setup();
+		return;
+	}
 	if ((nb_rxq > 1) && (nb_txq > 1)){
 		if (dcb_config)
 			dcb_fwd_config_setup();
diff --git a/app/test-pmd/icmpecho.c b/app/test-pmd/icmpecho.c
new file mode 100644
index 0000000..c28ff5a
--- /dev/null
+++ b/app/test-pmd/icmpecho.c
@@ -0,0 +1,504 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2013 6WIND
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <sys/queue.h>
+#include <sys/stat.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_cycles.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_ring.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_arp.h>
+#include <rte_ip.h>
+#include <rte_icmp.h>
+#include <rte_string_fns.h>
+
+#include "testpmd.h"
+
+static const char *
+arp_op_name(uint16_t arp_op)
+{
+	switch (arp_op ) {
+	case ARP_OP_REQUEST:
+		return "ARP Request";
+	case ARP_OP_REPLY:
+		return "ARP Reply";
+	case ARP_OP_REVREQUEST:
+		return "Reverse ARP Request";
+	case ARP_OP_REVREPLY:
+		return "Reverse ARP Reply";
+	case ARP_OP_INVREQUEST:
+		return "Peer Identify Request";
+	case ARP_OP_INVREPLY:
+		return "Peer Identify Reply";
+	default:
+		break;
+	}
+	return "Unkwown ARP op";
+}
+
+static const char *
+ip_proto_name(uint8_t ip_proto)
+{
+	static const char * ip_proto_names[] = {
+		"IP6HOPOPTS", /**< IP6 hop-by-hop options */
+		"ICMP",       /**< control message protocol */
+		"IGMP",       /**< group mgmt protocol */
+		"GGP",        /**< gateway^2 (deprecated) */
+		"IPv4",       /**< IPv4 encapsulation */
+
+		"UNASSIGNED",
+		"TCP",        /**< transport control protocol */
+		"ST",         /**< Stream protocol II */
+		"EGP",        /**< exterior gateway protocol */
+		"PIGP",       /**< private interior gateway */
+
+		"RCC_MON",    /**< BBN RCC Monitoring */
+		"NVPII",      /**< network voice protocol*/
+		"PUP",        /**< pup */
+		"ARGUS",      /**< Argus */
+		"EMCON",      /**< EMCON */
+
+		"XNET",       /**< Cross Net Debugger */
+		"CHAOS",      /**< Chaos*/
+		"UDP",        /**< user datagram protocol */
+		"MUX",        /**< Multiplexing */
+		"DCN_MEAS",   /**< DCN Measurement Subsystems */
+
+		"HMP",        /**< Host Monitoring */
+		"PRM",        /**< Packet Radio Measurement */
+		"XNS_IDP",    /**< xns idp */
+		"TRUNK1",     /**< Trunk-1 */
+		"TRUNK2",     /**< Trunk-2 */
+
+		"LEAF1",      /**< Leaf-1 */
+		"LEAF2",      /**< Leaf-2 */
+		"RDP",        /**< Reliable Data */
+		"IRTP",       /**< Reliable Transaction */
+		"TP4",        /**< tp-4 w/ class negotiation */
+
+		"BLT",        /**< Bulk Data Transfer */
+		"NSP",        /**< Network Services */
+		"INP",        /**< Merit Internodal */
+		"SEP",        /**< Sequential Exchange */
+		"3PC",        /**< Third Party Connect */
+
+		"IDPR",       /**< InterDomain Policy Routing */
+		"XTP",        /**< XTP */
+		"DDP",        /**< Datagram Delivery */
+		"CMTP",       /**< Control Message Transport */
+		"TPXX",       /**< TP++ Transport */
+
+		"ILTP",       /**< IL transport protocol */
+		"IPv6_HDR",   /**< IP6 header */
+		"SDRP",       /**< Source Demand Routing */
+		"IPv6_RTG",   /**< IP6 routing header */
+		"IPv6_FRAG",  /**< IP6 fragmentation header */
+
+		"IDRP",       /**< InterDomain Routing*/
+		"RSVP",       /**< resource reservation */
+		"GRE",        /**< General Routing Encap. */
+		"MHRP",       /**< Mobile Host Routing */
+		"BHA",        /**< BHA */
+
+		"ESP",        /**< IP6 Encap Sec. Payload */
+		"AH",         /**< IP6 Auth Header */
+		"INLSP",      /**< Integ. Net Layer Security */
+		"SWIPE",      /**< IP with encryption */
+		"NHRP",       /**< Next Hop Resolution */
+
+		"UNASSIGNED",
+		"UNASSIGNED",
+		"UNASSIGNED",
+		"ICMPv6",     /**< ICMP6 */
+		"IPv6NONEXT", /**< IP6 no next header */
+
+		"Ipv6DSTOPTS",/**< IP6 destination option */
+		"AHIP",       /**< any host internal protocol */
+		"CFTP",       /**< CFTP */
+		"HELLO",      /**< "hello" routing protocol */
+		"SATEXPAK",   /**< SATNET/Backroom EXPAK */
+
+		"KRYPTOLAN",  /**< Kryptolan */
+		"RVD",        /**< Remote Virtual Disk */
+		"IPPC",       /**< Pluribus Packet Core */
+		"ADFS",       /**< Any distributed FS */
+		"SATMON",     /**< Satnet Monitoring */
+
+		"VISA",       /**< VISA Protocol */
+		"IPCV",       /**< Packet Core Utility */
+		"CPNX",       /**< Comp. Prot. Net. Executive */
+		"CPHB",       /**< Comp. Prot. HeartBeat */
+		"WSN",        /**< Wang Span Network */
+
+		"PVP",        /**< Packet Video Protocol */
+		"BRSATMON",   /**< BackRoom SATNET Monitoring */
+		"ND",         /**< Sun net disk proto (temp.) */
+		"WBMON",      /**< WIDEBAND Monitoring */
+		"WBEXPAK",    /**< WIDEBAND EXPAK */
+
+		"EON",        /**< ISO cnlp */
+		"VMTP",       /**< VMTP */
+		"SVMTP",      /**< Secure VMTP */
+		"VINES",      /**< Banyon VINES */
+		"TTP",        /**< TTP */
+
+		"IGP",        /**< NSFNET-IGP */
+		"DGP",        /**< dissimilar gateway prot. */
+		"TCF",        /**< TCF */
+		"IGRP",       /**< Cisco/GXS IGRP */
+		"OSPFIGP",    /**< OSPFIGP */
+
+		"SRPC",       /**< Strite RPC protocol */
+		"LARP",       /**< Locus Address Resoloution */
+		"MTP",        /**< Multicast Transport */
+		"AX25",       /**< AX.25 Frames */
+		"4IN4",       /**< IP encapsulated in IP */
+
+		"MICP",       /**< Mobile Int.ing control */
+		"SCCSP",      /**< Semaphore Comm. security */
+		"ETHERIP",    /**< Ethernet IP encapsulation */
+		"ENCAP",      /**< encapsulation header */
+		"AES",        /**< any private encr. scheme */
+
+		"GMTP",       /**< GMTP */
+		"IPCOMP",     /**< payload compression (IPComp) */
+		"UNASSIGNED",
+		"UNASSIGNED",
+		"PIM",        /**< Protocol Independent Mcast */
+	};
+
+	if (ip_proto < sizeof(ip_proto_names) / sizeof(ip_proto_names[0]))
+		return ip_proto_names[ip_proto];
+	switch (ip_proto) {
+	case IPPROTO_PGM:  /**< PGM */
+		return "PGM";
+	case IPPROTO_SCTP:  /**< Stream Control Transport Protocol */
+		return "SCTP";
+	case IPPROTO_DIVERT: /**< divert pseudo-protocol */
+		return "DIVERT";
+	case IPPROTO_RAW: /**< raw IP packet */
+		return "RAW";
+	default:
+		break;
+	}
+	return "UNASSIGNED";
+}
+
+static void
+ether_addr_to_hexa(const struct ether_addr *ea, char *buf)
+{
+	sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+		ea->addr_bytes[0],
+		ea->addr_bytes[1],
+		ea->addr_bytes[2],
+		ea->addr_bytes[3],
+		ea->addr_bytes[4],
+		ea->addr_bytes[5]);
+}
+
+static void
+ipv4_addr_to_dot(uint32_t be_ipv4_addr, char *buf)
+{
+	uint32_t ipv4_addr;
+
+	ipv4_addr = rte_be_to_cpu_32(be_ipv4_addr);
+	sprintf(buf, "%d.%d.%d.%d", (ipv4_addr >> 24) & 0xFF,
+		(ipv4_addr >> 16) & 0xFF, (ipv4_addr >> 8) & 0xFF,
+		ipv4_addr & 0xFF);
+}
+
+static void
+ether_addr_dump(const char *what, const struct ether_addr *ea)
+{
+	char buf[18];
+
+	ether_addr_to_hexa(ea, buf);
+	if (what)
+		printf("%s", what);
+	printf("%s", buf);
+}
+
+static void
+ipv4_addr_dump(const char *what, uint32_t be_ipv4_addr)
+{
+	char buf[16];
+
+	ipv4_addr_to_dot(be_ipv4_addr, buf);
+	if (what)
+		printf("%s", what);
+	printf("%s", buf);
+}
+
+/*
+ * Receive a burst of packets, lookup for ICMP echo requets, and, if any,
+ * send back ICMP echo replies.
+ */
+static void
+reply_to_icmp_echo_rqsts(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_mbuf *pkt;
+	struct ether_hdr *eth_h;
+	struct vlan_hdr *vlan_h;
+	struct arp_hdr  *arp_h;
+	struct ipv4_hdr *ip_h;
+	struct icmp_hdr *icmp_h;
+	struct ether_addr eth_addr;
+	uint32_t ip_addr;
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+	uint16_t nb_replies;
+	uint16_t eth_type;
+	uint16_t vlan_id;
+	uint16_t arp_op;
+	uint16_t arp_pro;
+	uint8_t  i;
+	int l2_len;
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	uint64_t start_tsc;
+	uint64_t end_tsc;
+	uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	start_tsc = rte_rdtsc();
+#endif
+
+	/*
+	 * First, receive a burst of packets.
+	 */
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue, pkts_burst,
+				 nb_pkt_per_burst);
+	if (unlikely(nb_rx == 0))
+		return;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+	fs->rx_packets += nb_rx;
+	nb_replies = 0;
+	for (i = 0; i < nb_rx; i++) {
+		pkt = pkts_burst[i];
+		eth_h = (struct ether_hdr *) pkt->pkt.data;
+		eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
+		l2_len = sizeof(struct ether_hdr);
+		if (verbose_level > 0) {
+			printf("\nPort %d pkt-len=%u nb-segs=%u\n",
+			       fs->rx_port, pkt->pkt.pkt_len, pkt->pkt.nb_segs);
+			ether_addr_dump("  ETH:  src=", &eth_h->s_addr);
+			ether_addr_dump(" dst=", &eth_h->d_addr);
+		}
+		if (eth_type == ETHER_TYPE_VLAN) {
+			vlan_h = (struct vlan_hdr *)
+				((char *)eth_h + sizeof(struct ether_hdr));
+			l2_len  += sizeof(struct vlan_hdr);
+			eth_type = rte_be_to_cpu_16(vlan_h->eth_proto);
+			if (verbose_level > 0) {
+				vlan_id = rte_be_to_cpu_16(vlan_h->vlan_tci)
+					& 0xFFF;
+				printf(" [vlan id=%u]", vlan_id);
+			}
+		}
+		if (verbose_level > 0) {
+			printf(" type=0x%04x\n", eth_type);
+		}
+
+		/* Reply to ARP requests */
+		if (eth_type == ETHER_TYPE_ARP) {
+			arp_h = (struct arp_hdr *) ((char *)eth_h + l2_len);
+			arp_op = RTE_BE_TO_CPU_16(arp_h->arp_op);
+			arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_pro);
+			if (verbose_level > 0) {
+				printf("  ARP:  hrd=%d proto=0x%04x hln=%d "
+				       "pln=%d op=%u (%s)\n",
+				       RTE_BE_TO_CPU_16(arp_h->arp_hrd),
+				       arp_pro, arp_h->arp_hln,
+				       arp_h->arp_pln, arp_op,
+				       arp_op_name(arp_op));
+			}
+			if ((RTE_BE_TO_CPU_16(arp_h->arp_hrd) !=
+			     ARP_HRD_ETHER) ||
+			    (arp_pro != ETHER_TYPE_IPv4) ||
+			    (arp_h->arp_hln != 6) ||
+			    (arp_h->arp_pln != 4)
+			    ) {
+				rte_pktmbuf_free(pkt);
+				if (verbose_level > 0)
+					printf("\n");
+				continue;
+			}
+			if (verbose_level > 0) {
+				memcpy(&eth_addr,
+				       arp_h->arp_data.arp_ip.arp_sha, 6);
+				ether_addr_dump("        sha=", &eth_addr);
+				memcpy(&ip_addr,
+				       arp_h->arp_data.arp_ip.arp_sip, 4);
+				ipv4_addr_dump(" sip=", ip_addr);
+				printf("\n");
+				memcpy(&eth_addr,
+				       arp_h->arp_data.arp_ip.arp_tha, 6);
+				ether_addr_dump("        tha=", &eth_addr);
+				memcpy(&ip_addr,
+				       arp_h->arp_data.arp_ip.arp_tip, 4);
+				ipv4_addr_dump(" tip=", ip_addr);
+				printf("\n");
+			}
+			if (arp_op != ARP_OP_REQUEST) {
+				rte_pktmbuf_free(pkt);
+				continue;
+			}
+
+			/*
+			 * Build ARP reply.
+			 */
+
+			/* Use source MAC address as destination MAC address. */
+			ether_addr_copy(&eth_h->s_addr, &eth_h->d_addr);
+			/* Set source MAC address with MAC address of TX port */
+			ether_addr_copy(&ports[fs->tx_port].eth_addr,
+					&eth_h->s_addr);
+
+			arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
+			memcpy(&eth_addr, arp_h->arp_data.arp_ip.arp_tha, 6);
+			memcpy(arp_h->arp_data.arp_ip.arp_tha,
+			       arp_h->arp_data.arp_ip.arp_sha, 6);
+			memcpy(arp_h->arp_data.arp_ip.arp_sha,
+			       &eth_h->s_addr, 6);
+
+			/* Swap IP addresses in ARP payload */
+			memcpy(&ip_addr, arp_h->arp_data.arp_ip.arp_sip, 4);
+			memcpy(arp_h->arp_data.arp_ip.arp_sip,
+			       arp_h->arp_data.arp_ip.arp_tip, 4);
+			memcpy(arp_h->arp_data.arp_ip.arp_tip, &ip_addr, 4);
+			pkts_burst[nb_replies++] = pkt;
+			continue;
+		}
+
+		if (eth_type != ETHER_TYPE_IPv4) {
+			rte_pktmbuf_free(pkt);
+			continue;
+		}
+		ip_h = (struct ipv4_hdr *) ((char *)eth_h + l2_len);
+		if (verbose_level > 0) {
+			ipv4_addr_dump("  IPV4: src=", ip_h->src_addr);
+			ipv4_addr_dump(" dst=", ip_h->dst_addr);
+			printf(" proto=%d (%s)\n",
+			       ip_h->next_proto_id,
+			       ip_proto_name(ip_h->next_proto_id));
+		}
+
+		/*
+		 * Check if packet is a ICMP echo request.
+		 */
+		icmp_h = (struct icmp_hdr *) ((char *)ip_h +
+					      sizeof(struct ipv4_hdr));
+		if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
+		       (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST) &&
+		       (icmp_h->icmp_code == 0))) {
+			rte_pktmbuf_free(pkt);
+			continue;
+		}
+
+		if (verbose_level > 0)
+			printf("  ICMP: echo request seq id=%d\n",
+			       rte_be_to_cpu_16(icmp_h->icmp_seq_nb));
+
+		/*
+		 * Prepare ICMP echo reply to be sent back.
+		 * - switch ethernet source and destinations addresses,
+		 * - switch IPv4 source and destinations addresses,
+		 * - set IP_ICMP_ECHO_REPLY in ICMP header.
+		 * No need to re-compute the IP header checksum.
+		 * Reset ICMP checksum.
+		 */
+		ether_addr_copy(&eth_h->s_addr, &eth_addr);
+		ether_addr_copy(&eth_h->d_addr, &eth_h->s_addr);
+		ether_addr_copy(&eth_addr, &eth_h->d_addr);
+		ip_addr = ip_h->src_addr;
+		ip_h->src_addr = ip_h->dst_addr;
+		ip_h->dst_addr = ip_addr;
+		icmp_h->icmp_type = IP_ICMP_ECHO_REPLY;
+		icmp_h->icmp_cksum = 0;
+		pkts_burst[nb_replies++] = pkt;
+	}
+
+	/* Send back ICMP echo replies, if any. */
+	if (nb_replies > 0) {
+		nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,
+					 nb_replies);
+		fs->tx_packets += nb_tx;
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+		fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+		if (unlikely(nb_tx < nb_replies)) {
+			fs->fwd_dropped += (nb_replies - nb_tx);
+			do {
+				rte_pktmbuf_free(pkts_burst[nb_tx]);
+			} while (++nb_tx < nb_replies);
+		}
+	}
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	end_tsc = rte_rdtsc();
+	core_cycles = (end_tsc - start_tsc);
+	fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+struct fwd_engine icmp_echo_engine = {
+	.fwd_mode_name  = "icmpecho",
+	.port_fwd_begin = NULL,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = reply_to_icmp_echo_rqsts,
+};
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index b9447f2..621df88 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -147,6 +147,7 @@ struct fwd_engine * fwd_engines[] = {
 	&rx_only_engine,
 	&tx_only_engine,
 	&csum_fwd_engine,
+	&icmp_echo_engine,
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index e1664fa..ffd3495 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -202,6 +202,7 @@ extern struct fwd_engine mac_retry_fwd_engine;
 extern struct fwd_engine rx_only_engine;
 extern struct fwd_engine tx_only_engine;
 extern struct fwd_engine csum_fwd_engine;
+extern struct fwd_engine icmp_echo_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
diff --git a/lib/librte_net/Makefile b/lib/librte_net/Makefile
index 0585d94..a59a4fb 100644
--- a/lib/librte_net/Makefile
+++ b/lib/librte_net/Makefile
@@ -34,7 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 
 # install includes
-SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_NET)-include := rte_ip.h rte_tcp.h rte_udp.h rte_sctp.h rte_icmp.h rte_arp.h
 
 
 include $(RTE_SDK)/mk/rte.install.mk
diff --git a/lib/librte_net/rte_arp.h b/lib/librte_net/rte_arp.h
new file mode 100644
index 0000000..c7b0e51
--- /dev/null
+++ b/lib/librte_net/rte_arp.h
@@ -0,0 +1,84 @@
+/*   BSD LICENSE
+ *
+ *   Copyright(c) 2013 6WIND.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ARP_H_
+#define _RTE_ARP_H_
+
+/**
+ * @file
+ *
+ * ARP-related defines
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ARP header IPv4 payload.
+ */
+struct arp_ipv4 {
+	uint8_t  arp_sha[6]; /* sender hardware address */
+	uint8_t  arp_sip[4]; /* sender IP address */
+	uint8_t  arp_tha[6]; /* target hardware address */
+	uint8_t  arp_tip[4]; /* target IP address */
+} __attribute__((__packed__));
+
+/**
+ * ARP header.
+ */
+struct arp_hdr {
+	uint16_t arp_hrd;    /* format of hardware address */
+#define ARP_HRD_ETHER     1  /* ARP Ethernet address format */
+
+	uint16_t arp_pro;    /* format of protocol address */
+	uint8_t  arp_hln;    /* length of hardware address */
+	uint8_t  arp_pln;    /* length of protocol address */
+	uint16_t arp_op;     /* ARP opcode (command) */
+#define	ARP_OP_REQUEST    1 /* request to resolve address */
+#define	ARP_OP_REPLY      2 /* response to previous request */
+#define	ARP_OP_REVREQUEST 3 /* request proto addr given hardware */
+#define	ARP_OP_REVREPLY   4 /* response giving protocol address */
+#define	ARP_OP_INVREQUEST 8 /* request to identify peer */
+#define	ARP_OP_INVREPLY   9 /* response identifying peer */
+
+	union {
+		struct arp_ipv4 arp_ip;
+	} arp_data;
+} __attribute__((__packed__));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ARP_H_ */
diff --git a/lib/librte_net/rte_icmp.h b/lib/librte_net/rte_icmp.h
new file mode 100644
index 0000000..8b287f6
--- /dev/null
+++ b/lib/librte_net/rte_icmp.h
@@ -0,0 +1,101 @@
+/*   BSD LICENSE
+ *
+ *   Copyright(c) 2013 6WIND.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)in.h        8.3 (Berkeley) 1/3/94
+ * $FreeBSD: src/sys/netinet/in.h,v 1.82 2003/10/25 09:37:10 ume Exp $
+ */
+
+#ifndef _RTE_ICMP_H_
+#define _RTE_ICMP_H_
+
+/**
+ * @file
+ *
+ * ICMP-related defines
+ */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ICMP Header
+ */
+struct icmp_hdr {
+	uint8_t  icmp_type;   /* ICMP packet type. */
+	uint8_t  icmp_code;   /* ICMP packet code. */
+	uint16_t icmp_cksum;  /* ICMP packet checksum. */
+	uint16_t icmp_ident;  /* ICMP packet identifier. */
+	uint16_t icmp_seq_nb; /* ICMP packet sequence number. */
+} __attribute__((__packed__));
+
+/* ICMP packet types */
+#define IP_ICMP_ECHO_REPLY   0
+#define IP_ICMP_ECHO_REQUEST 8
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* RTE_ICMP_H_ */
-- 
1.7.10.4



More information about the dev mailing list