-/*-
- * 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.
- *
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2013 6WIND S.A.
*/
#include <stdarg.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_ip.h>
#include <rte_icmp.h>
#include <rte_string_fns.h>
+#include <rte_flow.h>
#include "testpmd.h"
static const char *
arp_op_name(uint16_t arp_op)
{
- switch (arp_op ) {
- case ARP_OP_REQUEST:
+ switch (arp_op) {
+ case RTE_ARP_OP_REQUEST:
return "ARP Request";
- case ARP_OP_REPLY:
+ case RTE_ARP_OP_REPLY:
return "ARP Reply";
- case ARP_OP_REVREQUEST:
+ case RTE_ARP_OP_REVREQUEST:
return "Reverse ARP Request";
- case ARP_OP_REVREPLY:
+ case RTE_ARP_OP_REVREPLY:
return "Reverse ARP Reply";
- case ARP_OP_INVREQUEST:
+ case RTE_ARP_OP_INVREQUEST:
return "Peer Identify Request";
- case ARP_OP_INVREPLY:
+ case RTE_ARP_OP_INVREPLY:
return "Peer Identify Reply";
default:
break;
}
static const char *
-ip_proto_name(uint8_t ip_proto)
+ip_proto_name(uint16_t ip_proto)
{
static const char * ip_proto_names[] = {
"IP6HOPOPTS", /**< IP6 hop-by-hop options */
"OSPFIGP", /**< OSPFIGP */
"SRPC", /**< Strite RPC protocol */
- "LARP", /**< Locus Address Resoloution */
+ "LARP", /**< Locus Address Resolution */
"MTP", /**< Multicast Transport */
"AX25", /**< AX.25 Frames */
"4IN4", /**< IP encapsulated in IP */
"PIM", /**< Protocol Independent Mcast */
};
- if (ip_proto < sizeof(ip_proto_names) / sizeof(ip_proto_names[0]))
+ if (ip_proto < RTE_DIM(ip_proto_names))
return ip_proto_names[ip_proto];
switch (ip_proto) {
+#ifdef IPPROTO_PGM
case IPPROTO_PGM: /**< PGM */
return "PGM";
+#endif
case IPPROTO_SCTP: /**< Stream Control Transport Protocol */
return "SCTP";
+#ifdef IPPROTO_DIVERT
case IPPROTO_DIVERT: /**< divert pseudo-protocol */
return "DIVERT";
+#endif
case IPPROTO_RAW: /**< raw IP packet */
return "RAW";
default:
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)
{
}
static void
-ether_addr_dump(const char *what, const struct ether_addr *ea)
+ether_addr_dump(const char *what, const struct rte_ether_addr *ea)
{
- char buf[18];
+ char buf[RTE_ETHER_ADDR_FMT_SIZE];
- ether_addr_to_hexa(ea, buf);
+ rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, ea);
if (what)
printf("%s", what);
printf("%s", buf);
printf("%s", buf);
}
+static uint16_t
+ipv4_hdr_cksum(struct rte_ipv4_hdr *ip_h)
+{
+ uint16_t *v16_h;
+ uint32_t ip_cksum;
+
+ /*
+ * Compute the sum of successive 16-bit words of the IPv4 header,
+ * skipping the checksum field of the header.
+ */
+ v16_h = (unaligned_uint16_t *) ip_h;
+ ip_cksum = v16_h[0] + v16_h[1] + v16_h[2] + v16_h[3] +
+ v16_h[4] + v16_h[6] + v16_h[7] + v16_h[8] + v16_h[9];
+
+ /* reduce 32 bit checksum to 16 bits and complement it */
+ ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+ ip_cksum = (ip_cksum & 0xffff) + (ip_cksum >> 16);
+ ip_cksum = (~ip_cksum) & 0x0000FFFF;
+ return (ip_cksum == 0) ? 0xFFFF : (uint16_t) ip_cksum;
+}
+
+#define is_multicast_ipv4_addr(ipv4_addr) \
+ (((rte_be_to_cpu_32((ipv4_addr)) >> 24) & 0x000000FF) == 0xE0)
+
/*
- * Receive a burst of packets, lookup for ICMP echo requets, and, if any,
+ * Receive a burst of packets, lookup for ICMP echo requests, and, if any,
* send back ICMP echo replies.
*/
static void
{
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;
+ struct rte_ether_hdr *eth_h;
+ struct rte_vlan_hdr *vlan_h;
+ struct rte_arp_hdr *arp_h;
+ struct rte_ipv4_hdr *ip_h;
+ struct rte_icmp_hdr *icmp_h;
+ struct rte_ether_addr eth_addr;
+ uint32_t retry;
uint32_t ip_addr;
uint16_t nb_rx;
uint16_t nb_tx;
uint16_t vlan_id;
uint16_t arp_op;
uint16_t arp_pro;
+ uint32_t cksum;
uint8_t i;
int l2_len;
#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
*/
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
+ if (unlikely(nb_rx == 0))
+ return;
+
fs->rx_packets += nb_rx;
nb_replies = 0;
for (i = 0; i < nb_rx; i++) {
+ if (likely(i < nb_rx - 1))
+ rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[i + 1],
+ void *));
pkt = pkts_burst[i];
- eth_h = (struct ether_hdr *) pkt->pkt.data;
+ eth_h = rte_pktmbuf_mtod(pkt, struct rte_ether_hdr *);
eth_type = RTE_BE_TO_CPU_16(eth_h->ether_type);
- l2_len = sizeof(struct ether_hdr);
+ l2_len = sizeof(struct rte_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);
+ fs->rx_port, pkt->pkt_len, pkt->nb_segs);
ether_addr_dump(" ETH: src=", ð_h->s_addr);
ether_addr_dump(" dst=", ð_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);
+ if (eth_type == RTE_ETHER_TYPE_VLAN) {
+ vlan_h = (struct rte_vlan_hdr *)
+ ((char *)eth_h + sizeof(struct rte_ether_hdr));
+ l2_len += sizeof(struct rte_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)
}
/* 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 (eth_type == RTE_ETHER_TYPE_ARP) {
+ arp_h = (struct rte_arp_hdr *) ((char *)eth_h + l2_len);
+ arp_op = RTE_BE_TO_CPU_16(arp_h->arp_opcode);
+ arp_pro = RTE_BE_TO_CPU_16(arp_h->arp_protocol);
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,
+ RTE_BE_TO_CPU_16(arp_h->arp_hardware),
+ arp_pro, arp_h->arp_hlen,
+ arp_h->arp_plen, 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)
+ if ((RTE_BE_TO_CPU_16(arp_h->arp_hardware) !=
+ RTE_ARP_HRD_ETHER) ||
+ (arp_pro != RTE_ETHER_TYPE_IPV4) ||
+ (arp_h->arp_hlen != 6) ||
+ (arp_h->arp_plen != 4)
) {
rte_pktmbuf_free(pkt);
if (verbose_level > 0)
continue;
}
if (verbose_level > 0) {
- memcpy(ð_addr,
- arp_h->arp_data.arp_ip.arp_sha, 6);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+ ð_addr);
ether_addr_dump(" sha=", ð_addr);
- memcpy(&ip_addr,
- arp_h->arp_data.arp_ip.arp_sip, 4);
+ ip_addr = arp_h->arp_data.arp_sip;
ipv4_addr_dump(" sip=", ip_addr);
printf("\n");
- memcpy(ð_addr,
- arp_h->arp_data.arp_ip.arp_tha, 6);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+ ð_addr);
ether_addr_dump(" tha=", ð_addr);
- memcpy(&ip_addr,
- arp_h->arp_data.arp_ip.arp_tip, 4);
+ ip_addr = arp_h->arp_data.arp_tip;
ipv4_addr_dump(" tip=", ip_addr);
printf("\n");
}
- if (arp_op != ARP_OP_REQUEST) {
+ if (arp_op != RTE_ARP_OP_REQUEST) {
rte_pktmbuf_free(pkt);
continue;
}
*/
/* Use source MAC address as destination MAC address. */
- ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
+ rte_ether_addr_copy(ð_h->s_addr, ð_h->d_addr);
/* Set source MAC address with MAC address of TX port */
- ether_addr_copy(&ports[fs->tx_port].eth_addr,
+ rte_ether_addr_copy(&ports[fs->tx_port].eth_addr,
ð_h->s_addr);
- arp_h->arp_op = rte_cpu_to_be_16(ARP_OP_REPLY);
- memcpy(ð_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,
- ð_h->s_addr, 6);
+ arp_h->arp_opcode = rte_cpu_to_be_16(RTE_ARP_OP_REPLY);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_tha,
+ ð_addr);
+ rte_ether_addr_copy(&arp_h->arp_data.arp_sha,
+ &arp_h->arp_data.arp_tha);
+ rte_ether_addr_copy(ð_h->s_addr,
+ &arp_h->arp_data.arp_sha);
/* 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);
+ ip_addr = arp_h->arp_data.arp_sip;
+ arp_h->arp_data.arp_sip = arp_h->arp_data.arp_tip;
+ arp_h->arp_data.arp_tip = ip_addr;
pkts_burst[nb_replies++] = pkt;
continue;
}
- if (eth_type != ETHER_TYPE_IPv4) {
+ if (eth_type != RTE_ETHER_TYPE_IPV4) {
rte_pktmbuf_free(pkt);
continue;
}
- ip_h = (struct ipv4_hdr *) ((char *)eth_h + l2_len);
+ ip_h = (struct rte_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);
/*
* Check if packet is a ICMP echo request.
*/
- icmp_h = (struct icmp_hdr *) ((char *)ip_h +
- sizeof(struct ipv4_hdr));
+ icmp_h = (struct rte_icmp_hdr *) ((char *)ip_h +
+ sizeof(struct rte_ipv4_hdr));
if (! ((ip_h->next_proto_id == IPPROTO_ICMP) &&
- (icmp_h->icmp_type == IP_ICMP_ECHO_REQUEST) &&
+ (icmp_h->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) &&
(icmp_h->icmp_code == 0))) {
rte_pktmbuf_free(pkt);
continue;
/*
* 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.
+ * - use the request IP source address as the reply IP
+ * destination address,
+ * - if the request IP destination address is a multicast
+ * address:
+ * - choose a reply IP source address different from the
+ * request IP source address,
+ * - re-compute the IP header checksum.
+ * Otherwise:
+ * - switch the request IP source and destination
+ * addresses in the reply IP header,
+ * - keep the IP header checksum unchanged.
+ * - set RTE_IP_ICMP_ECHO_REPLY in ICMP header.
+ * ICMP checksum is computed by assuming it is valid in the
+ * echo request and not verified.
*/
- ether_addr_copy(ð_h->s_addr, ð_addr);
- ether_addr_copy(ð_h->d_addr, ð_h->s_addr);
- ether_addr_copy(ð_addr, ð_h->d_addr);
+ rte_ether_addr_copy(ð_h->s_addr, ð_addr);
+ rte_ether_addr_copy(ð_h->d_addr, ð_h->s_addr);
+ rte_ether_addr_copy(ð_addr, ð_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;
+ if (is_multicast_ipv4_addr(ip_h->dst_addr)) {
+ uint32_t ip_src;
+
+ ip_src = rte_be_to_cpu_32(ip_addr);
+ if ((ip_src & 0x00000003) == 1)
+ ip_src = (ip_src & 0xFFFFFFFC) | 0x00000002;
+ else
+ ip_src = (ip_src & 0xFFFFFFFC) | 0x00000001;
+ ip_h->src_addr = rte_cpu_to_be_32(ip_src);
+ ip_h->dst_addr = ip_addr;
+ ip_h->hdr_checksum = ipv4_hdr_cksum(ip_h);
+ } else {
+ ip_h->src_addr = ip_h->dst_addr;
+ ip_h->dst_addr = ip_addr;
+ }
+ icmp_h->icmp_type = RTE_IP_ICMP_ECHO_REPLY;
+ cksum = ~icmp_h->icmp_cksum & 0xffff;
+ cksum += ~htons(RTE_IP_ICMP_ECHO_REQUEST << 8) & 0xffff;
+ cksum += htons(RTE_IP_ICMP_ECHO_REPLY << 8);
+ cksum = (cksum & 0xffff) + (cksum >> 16);
+ cksum = (cksum & 0xffff) + (cksum >> 16);
+ icmp_h->icmp_cksum = ~cksum;
pkts_burst[nb_replies++] = pkt;
}
if (nb_replies > 0) {
nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst,
nb_replies);
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_replies) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_replies &&
+ retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port,
+ fs->tx_queue,
+ &pkts_burst[nb_tx],
+ nb_replies - nb_tx);
+ }
+ }
fs->tx_packets += nb_tx;
#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;