* Re: [PATCH v1 0/4] Generalize PCI specific EAL function/structures
From: Shreyansh Jain @ 2016-10-03 5:37 UTC (permalink / raw)
To: David Marchand; +Cc: dev@dpdk.org, Jan Viktorin, Thomas Monjalon
In-Reply-To: <CALwxeUtrswaOEBirUetWO+KWemgzySEBfC0cWPPKcP2VuKbZ8A@mail.gmail.com>
Hi David,
On Friday 30 September 2016 09:01 PM, David Marchand wrote:
> On Tue, Sep 27, 2016 at 4:12 PM, Shreyansh Jain <shreyansh.jain@nxp.com> wrote:
>> (I rebased these over HEAD 7b3c4f3)
>>
>> These patches were initially part of Jan's original series on SoC
>> Framework ([1],[2]). An update to that series, without these patches,
>> was posted here [3].
>>
>> Main motivation for these is aim of introducing a non-PCI centric
>> subsystem in EAL. As of now the first usecase is SoC, but not limited to
>> it.
>>
>> 4 patches in this series are independent of each other, as well as SoC
>> framework. All these focus on generalizing some structure or functions
>> present with the PCI specific code to EAL Common area (or splitting a
>> function to be more userful).
>
> Those patches move linux specifics (binding pci devices using sysfs)
> to common infrastucture.
> We have no proper hotplug support on bsd, but if we had some common
> code we should at least try to make the apis generic.
>
I am not sure if I understood your point well. Just to confirm - you are
stating that the movement done in the patches might not suit BSD.
Probably you are talking about (Patch 3/4 and 4/4).
Is my understanding correct?
So, movement to just Linux area is not enough?
I am not well versed with BSD way of doing something similar so if
someone can point it out, I can integrate that. (I will investigate it
at my end as well).
This patchset makes the PCI->EAL movement *only* for Linux for sysfs
bind/unbind. (I should add this to cover letter, at the least).
-
Shreyansh
^ permalink raw reply
* [PATCH] l2fwd:mac learning
From: Rafat Jahan @ 2016-10-03 5:27 UTC (permalink / raw)
To: dev; +Cc: Rafat Jahan
Added MAC learning to reduce load at l2
Signed-off-by: Rafat Jahan <rafat.jahan@tcs.com>
---
examples/l2fwd-mac/Makefile | 50 ++
examples/l2fwd-mac/main.c | 1325 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1375 insertions(+)
create mode 100644 examples/l2fwd-mac/Makefile
create mode 100644 examples/l2fwd-mac/main.c
diff --git a/examples/l2fwd-mac/Makefile b/examples/l2fwd-mac/Makefile
new file mode 100644
index 0000000..6ab93f4
--- /dev/null
+++ b/examples/l2fwd-mac/Makefile
@@ -0,0 +1,50 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# 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 Intel Corporation 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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-mac
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-mac/main.c b/examples/l2fwd-mac/main.c
new file mode 100644
index 0000000..33d6a6e
--- /dev/null
+++ b/examples/l2fwd-mac/main.c
@@ -0,0 +1,1325 @@
+/*-thread created and in which two seperate threads for updation and checking are created infinately
+
+ final working code
+
+
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_arp.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF 8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define default_aging_time 30
+pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * Work-around of a compilation error with ICC on invocations of the
+ * rte_be_to_cpu_16() function.
+ */
+#ifdef __GCC__
+#define RTE_BE_TO_CPU_16(be_16_v) rte_be_to_cpu_16((be_16_v))
+#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v))
+#else
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v)
+#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
+#else
+#define RTE_BE_TO_CPU_16(be_16_v) \
+ (uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
+#define RTE_CPU_TO_BE_16(cpu_16_v) \
+ (uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
+#endif
+#endif /* __GCC__ */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+static int64_t l2fwd_user_defined_dst_port = 0;
+static int16_t l2fwd_mac_learning_enabled = 0;
+uint64_t total_duplicate_packets_dropped = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port);
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport);
+static void l2fwd_mac_display(void);
+static void l2fwd_show_mac_entry(void);
+void source_mac_table(struct ether_hdr *eth,unsigned port);
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port);
+void update_aging(struct ether_hdr *eth);
+void *thread1(void);
+void *thread2(void);
+void *threadInit(void);
+
+
+struct node
+{
+ unsigned port;
+ struct ether_addr s_addr; /**< Source address. */
+ struct ether_addr d_addr; /**< Destination address. */
+ time_t starttime;
+ struct node *next;
+}*head = NULL;
+
+struct mac_list
+{
+ unsigned port;
+ struct ether_addr s_addr;
+ time_t rx_time;
+ char *buff;
+ int aging_time;
+ struct mac_list *next;
+}*start = NULL;
+
+
+struct mbuf_table {
+ unsigned len;
+ struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+void update_node(struct mac_list *ptr);
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+ unsigned n_rx_port;
+ unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+ struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static const struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload disabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+ uint64_t tx;
+ uint64_t rx;
+ uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+static inline void
+print_ether_addr(const char *what, struct ether_addr *eth_addr)
+{
+ char buf[ETHER_ADDR_FMT_SIZE];
+ ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
+ printf("%s%s", what, buf);
+}
+
+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
+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);
+}
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+ struct node *new = NULL;
+ new = (struct node*)malloc(sizeof(struct node));
+ if(new == NULL)
+ {
+ printf("Memory not allocated for MAC database");
+ }
+
+ source_mac_table(eth,port);
+
+ new->port = port;
+ new->starttime = time(NULL);
+ ether_addr_copy(ð->s_addr, &new->s_addr);
+ ether_addr_copy(ð->d_addr, &new->d_addr);
+ if(head == NULL)
+ {
+ head = new;
+ head->next = NULL;
+
+ }
+ else
+ {
+ new->next = head;
+ head = new;
+
+ }
+}
+
+void source_mac_table(struct ether_hdr *eth,unsigned port)
+{
+
+ struct mac_list *ptr = NULL;
+ ptr = start;
+ if(start == NULL)
+ {
+ printf("Adding entry to the table\n");
+ add_src_mac_entry(eth,port);
+ }
+ else
+ {
+ while(ptr != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+
+ ptr->rx_time=time(NULL);
+ ptr->aging_time=default_aging_time;
+ if(ptr->port != port )
+ {
+ ptr->port = port;
+ break;
+ }
+ else
+ break; // received from same mac
+ }
+ ptr = ptr->next;
+ }
+ if(ptr == NULL)
+ {
+ /*If the mac entry is not found in the table, then add the entry
+ to the mac table */
+ printf("Adding MAC entry to table\n");
+ add_src_mac_entry(eth,port);
+ }
+
+ }
+}
+
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+ struct mac_list *new = NULL;
+ new = (struct mac_list*)malloc(sizeof(struct mac_list));
+ if(new == NULL)
+ {
+ printf("Memory not allocated for MAC database");
+ }
+ new->port = port;
+ ether_addr_copy(ð->s_addr, &new->s_addr);
+ new->rx_time=time(NULL);
+ new->aging_time=default_aging_time;
+ if(start == NULL)
+ {
+ start = new;
+ start->next = NULL;
+ }
+ else
+ {
+ new->next=start;
+ start=new;
+ }
+
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+ uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+ unsigned portid;
+
+ total_packets_dropped = 0;
+ total_packets_tx = 0;
+ total_packets_rx = 0;
+
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ printf("\nPort statistics ====================================");
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ /* skip disabled ports */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+ printf("\nStatistics for port %u ------------------------------"
+ "\nPackets sent: %24"PRIu64
+ "\nPackets received: %20"PRIu64
+ "\nPackets dropped: %21"PRIu64,
+ portid,
+ port_statistics[portid].tx,
+ port_statistics[portid].rx,
+ port_statistics[portid].dropped);
+
+ total_packets_dropped += port_statistics[portid].dropped;
+ total_packets_tx += port_statistics[portid].tx;
+ total_packets_rx += port_statistics[portid].rx;
+ }
+ printf("\nAggregate statistics ==============================="
+ "\nTotal packets sent: %18"PRIu64
+ "\nTotal packets received: %14"PRIu64
+ "\nTotal packets dropped: %15"PRIu64,
+ total_packets_tx,
+ total_packets_rx,
+ total_packets_dropped);
+ printf("\nTotal duplicate packets dropped: %5"PRIu64,
+ total_duplicate_packets_dropped);
+ printf("\n====================================================\n");
+}
+
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+ struct rte_mbuf **m_table;
+ unsigned ret;
+ unsigned queueid =0;
+
+ m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+ ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+ port_statistics[port].tx += ret;
+ if (unlikely(ret < n)) {
+ port_statistics[port].dropped += (n - ret);
+ do {
+ rte_pktmbuf_free(m_table[ret]);
+ } while (++ret < n);
+ }
+
+ return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+ unsigned lcore_id, len;
+ struct lcore_queue_conf *qconf;
+
+ lcore_id = rte_lcore_id();
+
+ qconf = &lcore_queue_conf[lcore_id];
+ len = qconf->tx_mbufs[port].len;
+ qconf->tx_mbufs[port].m_table[len] = m;
+ len++;
+
+ /* enough pkts to be sent */
+ if (unlikely(len == MAX_PKT_BURST)) {
+ l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+ len = 0;
+ }
+
+ qconf->tx_mbufs[port].len = len;
+ return 0;
+}
+static void l2fwd_mac_display(void)
+{
+ struct node *node = NULL;
+ printf("\n==============DEBUGGING MAC TABLE=================\n");
+ printf(" SMAC DMAC PORT \n");
+ node = head;
+ while(node != NULL)
+ {
+ print_ether_addr("", &node->s_addr);
+ print_ether_addr(" ",&node->d_addr);
+ printf(" %d\n",node->port);
+ node = node->next;
+ }
+ printf("========================================\n");
+}
+static void l2fwd_show_mac_entry(void)
+{
+ struct mac_list *node = NULL;
+ printf("\n==============MAC TABLE=================\n");
+ printf(" MAC PORT\taging time\n");
+ node = start;
+ while(node != NULL)
+ {
+ print_ether_addr("", &node->s_addr);
+ printf(" %d\t",node->port);
+ printf("%d\n",node->aging_time);
+
+ node = node->next;
+ }
+ printf("========================================\n");
+}
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport)
+{
+ struct node *ptr = NULL;
+ struct mac_list *ptr1 = NULL;
+
+ ptr = head;
+ while(ptr != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr->port = rxport;
+ }
+ ptr = ptr->next;
+ }
+
+ ptr1 = start;
+ while(ptr1 != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr1->port = rxport;
+ ptr1->rx_time=time(NULL);
+ ptr1->aging_time=default_aging_time;
+ }
+ ptr1 = ptr1->next;
+ }
+
+}
+void update_aging(struct ether_hdr *eth)
+{
+ struct mac_list *ptr1=NULL;
+ ptr1 = start;
+ while(ptr1 != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr1->rx_time=time(NULL);
+ ptr1->aging_time=default_aging_time;
+ }
+ ptr1 = ptr1->next;
+ }
+}
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+ struct ether_hdr *eth;
+ void *tmp;
+ unsigned dst_port;
+ int currenttime,difference,timeout = 8;
+ //int err;
+ //pthread_t t1,t2;
+ dst_port = l2fwd_dst_ports[portid];
+ printf("---------- Forwarding Path ----------\n");
+ printf("Default forwarding dst port : %d\n",dst_port);
+
+ eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+ if(l2fwd_user_defined_dst_port > 0)
+ {
+ dst_port = l2fwd_user_defined_dst_port;
+ printf("User defined dst Port : %d\n",dst_port);
+ printf("----------------------------------------\n");
+ printf("Forwarding path has been modified from default to user defined\n");
+ }
+ else if(l2fwd_mac_learning_enabled)
+ {
+ //l2fwd_mac_display();
+ //l2fwd_show_mac_entry();
+ //pthread_mutex_lock( &mutex1 );
+ struct node *ptr = NULL;
+ struct mac_list *temp = NULL;
+ ptr = head;
+ if(head == NULL)
+ {
+ printf("No MAC address exist in table , adding entry to the table\n");
+ add_mac_entry(eth,portid);
+ }
+ else
+ {
+ /* condition to check and overwrite the 'port' if the same mac address
+ was already received from another 'port' earlier*/
+ while(ptr != NULL)
+ {
+ if ((memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0) &&
+ (memcmp(ð->d_addr, &ptr->d_addr, ETHER_ADDR_LEN) == 0))
+ {
+ // printf("----->same SMAC DMAC\n");
+ if(portid != ptr->port)
+ {
+ printf("port id is different %d\n",portid);
+ currenttime = time(NULL);
+ difference = currenttime - (ptr->starttime);
+ if(difference > timeout)
+ {
+ printf("----->difference %d\n",difference);
+ ptr->port = portid;
+ ptr->starttime = time(NULL);
+ l2fwd_mac_ports_update(eth,portid);
+ // add_mac_entry(eth,portid);
+ break;
+ } else {
+ printf("Detected duplication,packet dropped \n");
+ //duplicate packet
+ total_duplicate_packets_dropped++;
+ //need to check whether break is needed
+ // return;
+ }
+ }
+
+ ptr->starttime = time(NULL);
+ update_aging(eth);
+ // printf("---->received from same mac diff %d\n",difference);
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(ptr == NULL)
+ {
+ /*If the mac entry is not found in the table, then add the entry
+ to the mac table */
+ printf("Adding MAC entry to table\n");
+ add_mac_entry(eth,portid);
+ //l2fwd_mac_ports_update(eth,portid);
+ }
+ }
+
+
+ /* lookup to get the dst port if the mac entry is already present in the table*/
+ temp = start;
+ while(temp != NULL)
+ {
+ if (memcmp(ð->d_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ dst_port = temp->port;
+ printf("\n");
+ printf("dst port from table : %d\n",dst_port);
+ break;
+ }
+ temp = temp->next;
+ }
+ /*If the dst mac is not available,then forward the packet in dumping port*/
+ if(temp == NULL)
+ {
+ dst_port = 9;
+ printf("Dumping port : %d\n",dst_port);
+ }
+
+ }
+ else
+ {
+//========================================================
+ /* 02:00:00:00:00:xx */
+ tmp = ð->d_addr.addr_bytes[0];
+ *((uint64_t *)tmp) = 0xffffffffffff ;
+ //*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+ /* src addr */
+ ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr);
+ }
+
+ printf("========================================\n");
+ l2fwd_mac_display();
+ l2fwd_show_mac_entry();
+ //pthread_mutex_unlock( &mutex1 );
+ l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *m;
+ unsigned lcore_id;
+ uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+ unsigned i, j, portid, nb_rx;
+ struct lcore_queue_conf *qconf;
+ const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+ struct ether_hdr *eth_hdr;
+ uint16_t eth_type;
+ struct ipv4_hdr *ip_h;
+ int l2_len;
+ struct arp_hdr *arp_h;
+ uint32_t sip_addr,tip_addr;
+
+ prev_tsc = 0;
+ timer_tsc = 0;
+
+ lcore_id = rte_lcore_id();
+ qconf = &lcore_queue_conf[lcore_id];
+
+ if (qconf->n_rx_port == 0) {
+ RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+ return;
+ }
+
+ RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+ portid);
+ }
+
+ while (1) {
+
+ cur_tsc = rte_rdtsc();
+
+ /*
+ * TX burst queue drain
+ */
+ diff_tsc = cur_tsc - prev_tsc;
+ if (unlikely(diff_tsc > drain_tsc)) {
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ if (qconf->tx_mbufs[portid].len == 0)
+ continue;
+ l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+ qconf->tx_mbufs[portid].len,
+ (uint8_t) portid);
+ qconf->tx_mbufs[portid].len = 0;
+ }
+
+ /* if timer is enabled */
+ if (timer_period > 0) {
+
+ /* advance the timer */
+ timer_tsc += diff_tsc;
+
+ /* if timer has reached its timeout */
+ if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+ /* do this only on master core */
+ if (lcore_id == rte_get_master_lcore()) {
+ print_stats();
+ /* reset the timer */
+ timer_tsc = 0;
+ }
+ }
+ }
+
+ prev_tsc = cur_tsc;
+ }
+
+ /*
+ * Read packet from RX queues
+ */
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+ pkts_burst, MAX_PKT_BURST);
+
+ if(nb_rx == 0)
+ continue;
+ port_statistics[portid].rx += nb_rx;
+
+ for (j = 0; j < nb_rx; j++) {
+ m = pkts_burst[j];
+ rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+
+ eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+ eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
+ l2_len = sizeof(struct ether_hdr);
+
+ //if (eth_type != ETHER_TYPE_IPv4) {
+ // rte_pktmbuf_free(m);
+ // continue;
+ //}
+
+ printf("========================================\n");
+ printf("Packet received on port :%d\n",portid);
+ printf("------------ L2 Details------------\n");
+ print_ether_addr(" Source MAC : ", ð_hdr->s_addr);
+ print_ether_addr("\n Destination MAC : ", ð_hdr->d_addr);
+ printf("\n Port : %d"
+ "\n Ethernet Type : 0x%04x"
+ "\n Length : %u "
+ "\n Nb_segs : %d",
+ portid,
+ eth_type,
+ (unsigned) m->pkt_len,
+ (int)m->nb_segs);
+ printf("\n");
+
+ if (eth_type == ETHER_TYPE_ARP)
+ {
+ arp_h = (struct arp_hdr *) ((char *)eth_hdr + l2_len);
+ sip_addr = arp_h->arp_data.arp_sip;
+ tip_addr = arp_h->arp_data.arp_tip;
+ } else
+ {
+ if (eth_type != ETHER_TYPE_IPv4) {
+ rte_pktmbuf_free(m);
+ continue;
+ }
+ ip_h = (struct ipv4_hdr *) ((char *)eth_hdr + l2_len);
+ sip_addr = ip_h->src_addr;
+ tip_addr = ip_h->dst_addr;
+ }
+ printf("------------ L3 Details------------\n");
+ ipv4_addr_dump(" Source IP : ", sip_addr);
+ ipv4_addr_dump("\n Destination IP : ", tip_addr);
+ printf("\n");
+
+ l2fwd_simple_forward(m, portid);
+ }
+ }
+ }
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+ l2fwd_main_loop();
+ return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+ printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+ " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+ " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+ " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
+ " -d DST PORT: user input to select the destination port\n"
+ " -l MAC LEARNING: enable l2fwd mac learning 1-enable : 0 - disable(default) \n",
+ prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+ char *end = NULL;
+ unsigned long pm;
+
+ /* parse hexadecimal string */
+ pm = strtoul(portmask, &end, 16);
+ if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ if (pm == 0)
+ return -1;
+
+ return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+ char *end = NULL;
+ unsigned long n;
+
+ /* parse hexadecimal string */
+ n = strtoul(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return 0;
+ if (n == 0)
+ return 0;
+ if (n >= MAX_RX_QUEUE_PER_LCORE)
+ return 0;
+
+ return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+static int
+pktcap_parse_dst_port(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n > RTE_MAX_ETHPORTS)
+ return -1;
+
+ return n;
+}
+
+static int
+l2fwd_parse_mac_learning(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 0);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n > 1)
+ return -1;
+
+ return n;
+}
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+ int opt, ret;
+ char **argvopt;
+ int option_index;
+ char *prgname = argv[0];
+ static struct option lgopts[] = {
+ {NULL, 0, 0, 0}
+ };
+
+ argvopt = argv;
+
+ while ((opt = getopt_long(argc, argvopt, "p:q:T:d:l:",
+ lgopts, &option_index)) != EOF) {
+
+ switch (opt) {
+ /* portmask */
+ case 'p':
+ l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+ if (l2fwd_enabled_port_mask == 0) {
+ printf("invalid portmask\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* nqueue */
+ case 'q':
+ l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+ if (l2fwd_rx_queue_per_lcore == 0) {
+ printf("invalid queue number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* timer period */
+ case 'T':
+ timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+ if (timer_period < 0) {
+ printf("invalid timer period\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* user defined dst port*/
+ case 'd':
+ l2fwd_user_defined_dst_port = pktcap_parse_dst_port(optarg);
+ if (l2fwd_user_defined_dst_port < 0) {
+ printf("invalid port number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* l2 mac learning*/
+ case 'l':
+ l2fwd_mac_learning_enabled = l2fwd_parse_mac_learning(optarg);
+ if (l2fwd_mac_learning_enabled < 0) {
+ printf("invalid option\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+ /* long options */
+ case 0:
+ l2fwd_usage(prgname);
+ return -1;
+
+ default:
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ }
+
+ if (optind >= 0)
+ argv[optind-1] = prgname;
+
+ ret = optind-1;
+ optind = 0; /* reset getopt lib */
+ return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status");
+ fflush(stdout);
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << portid)) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(portid, &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status)
+ printf("Port %d Link Up - speed %u "
+ "Mbps - %s\n", (uint8_t)portid,
+ (unsigned)link.link_speed,
+ (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex\n"));
+ else
+ printf("Port %d Link Down\n",
+ (uint8_t)portid);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == 0) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+void *thread2(void)
+{
+ if(start!=NULL)
+ {
+
+ pthread_mutex_lock( &mutex1 );
+ struct mac_list *temp=start;
+ while(temp!=NULL)
+ {
+ if(temp->aging_time>0)
+ temp->aging_time=default_aging_time-(time(NULL)-temp->rx_time);
+ //strcpy(temp->buff,"check");
+ temp=temp->next;
+ }
+ pthread_mutex_unlock( &mutex1 );
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void update_node(struct mac_list *l_temp)
+{
+ struct node *temp,*temp2,*prev;
+ if(head!=NULL)
+ {
+ while(head!=NULL)
+ {
+ if(memcmp(&l_temp->s_addr, &head->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ temp=head;
+ head=head->next;
+ free(temp);
+ }
+ else
+ break;
+ }
+ // if(head!=NULL)
+ temp=head->next;
+ prev=head;
+ while(temp!=NULL && head!=NULL)
+ {
+ if(memcmp(&l_temp->s_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ prev->next=temp->next;
+ temp2=temp;
+ temp=temp->next;
+ free(temp2);
+ }
+ else
+ {
+ temp=temp->next;
+ prev=prev->next;
+ }
+ }
+ }
+
+
+}
+
+
+void *thread1(void)
+{
+ struct mac_list *temp,*temp2,*prev;
+
+ if(start!=NULL)
+ {
+
+ pthread_mutex_lock( &mutex1 );
+ while(start!=NULL)
+ {
+ if( start->aging_time==0)
+ {
+ temp = start;
+ update_node(temp);
+ start=start->next;
+ free(temp);
+
+ }
+ else
+ break;
+ }
+ // if(start!=NULL)
+ temp = start->next;
+ prev=start;
+ while(temp!= NULL && start!=NULL)
+ {
+
+ if(temp->aging_time==0)
+ {
+ update_node(temp);
+ prev->next=temp->next;
+ temp2=temp;
+ temp=temp->next;
+ if(temp2!=NULL)
+ free(temp2);
+ }
+ else
+ {
+ temp = temp->next;
+ prev=prev->next;
+ }
+ }
+ pthread_mutex_unlock( &mutex1 );
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+void *threadInit(void)
+{
+ pthread_t t1,t2;
+ int err;
+ while(1)
+ {
+ err=pthread_create(&t1, NULL,(void *)thread1,NULL);//for checking the mac table
+ pthread_join(t1,NULL);
+
+
+ err=pthread_create(&t2,NULL,(void *)thread2,NULL);//for updating the mac table
+ pthread_join(t2,NULL);
+
+ if(err!=0)
+ {
+ printf("thread not created\n");
+ exit(0);
+ }
+ }
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct lcore_queue_conf *qconf;
+ struct rte_eth_dev_info dev_info;
+ int ret,err;
+ uint8_t nb_ports;
+ uint8_t nb_ports_available;
+ uint8_t portid, last_port;
+ unsigned lcore_id, rx_lcore_id;
+ unsigned nb_ports_in_mask = 0;
+ pthread_t t3;
+ /* init EAL */
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+ argc -= ret;
+ argv += ret;
+
+ /* parse application arguments (after the EAL ones) */
+ ret = l2fwd_parse_args(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+ /* create the mbuf pool */
+ l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+ 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (l2fwd_pktmbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+ nb_ports = rte_eth_dev_count();
+ if (nb_ports == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+ if (nb_ports > RTE_MAX_ETHPORTS)
+ nb_ports = RTE_MAX_ETHPORTS;
+
+ /* reset l2fwd_dst_ports */
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+ l2fwd_dst_ports[portid] = 0;
+ last_port = 0;
+
+ printf("Entered port : %" PRId64 "\n",l2fwd_user_defined_dst_port);
+
+ /*
+ * Each logical core is assigned a dedicated TX queue on each port.
+ */
+ if(l2fwd_user_defined_dst_port == 0)
+ {
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ if (nb_ports_in_mask % 2) {
+ l2fwd_dst_ports[portid] = last_port;
+ l2fwd_dst_ports[last_port] = portid;
+ }
+ else
+ last_port = portid;
+
+ nb_ports_in_mask++;
+
+ rte_eth_dev_info_get(portid, &dev_info);
+ }
+ if (nb_ports_in_mask % 2) {
+ printf("Notice: odd number of ports in portmask.\n");
+ l2fwd_dst_ports[last_port] = last_port;
+ }
+
+ }
+ rx_lcore_id = 0;
+ qconf = NULL;
+
+ /* Initialize the port/queue configuration of each logical core */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ /* get the lcore_id for this port */
+ while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+ lcore_queue_conf[rx_lcore_id].n_rx_port ==
+ l2fwd_rx_queue_per_lcore) {
+ rx_lcore_id++;
+ if (rx_lcore_id >= RTE_MAX_LCORE)
+ rte_exit(EXIT_FAILURE, "Not enough cores\n");
+ }
+
+ if (qconf != &lcore_queue_conf[rx_lcore_id])
+ /* Assigned a new logical core in the loop above. */
+ qconf = &lcore_queue_conf[rx_lcore_id];
+
+ qconf->rx_port_list[qconf->n_rx_port] = portid;
+ qconf->n_rx_port++;
+ printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+ }
+
+ nb_ports_available = nb_ports;
+
+ /* Initialise each port */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+ printf("Skipping disabled port %u\n", (unsigned) portid);
+ nb_ports_available--;
+ continue;
+ }
+ /* init port */
+ printf("Initializing port %u... ", (unsigned) portid);
+ fflush(stdout);
+ ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+ /* init one RX queue */
+ fflush(stdout);
+ ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+ rte_eth_dev_socket_id(portid),
+ NULL,
+ l2fwd_pktmbuf_pool);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ /* init one TX queue on each port */
+ fflush(stdout);
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid),
+ NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+ /****************************************/
+ err=pthread_create(&t3,NULL,(void *)threadInit,NULL);
+ //thread for checking and updating the mac table
+ if(err!=0)
+ {
+ printf("thread not created\n");
+ exit(0);
+ }
+ /****************************************/
+ /* Start device */
+ ret = rte_eth_dev_start(portid);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ printf("done: \n");
+
+ rte_eth_promiscuous_enable(portid);
+
+ printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+ (unsigned) portid,
+ l2fwd_ports_eth_addr[portid].addr_bytes[0],
+ l2fwd_ports_eth_addr[portid].addr_bytes[1],
+ l2fwd_ports_eth_addr[portid].addr_bytes[2],
+ l2fwd_ports_eth_addr[portid].addr_bytes[3],
+ l2fwd_ports_eth_addr[portid].addr_bytes[4],
+ l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+ /* initialize port stats */
+ memset(&port_statistics, 0, sizeof(port_statistics));
+ }
+
+ if (!nb_ports_available) {
+ rte_exit(EXIT_FAILURE,
+ "All available ports are disabled. Please set portmask.\n");
+ }
+
+ check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+ /* launch per-lcore init on every lcore */
+ rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+ //pthread_join(t1,NULL);
+ //pthread_join(t2,NULL);
+
+ return 0;
+}
--
1.9.1
^ permalink raw reply related
* [PATCH] l2fwd:mac learning
From: Rafat Jahan @ 2016-10-03 5:25 UTC (permalink / raw)
To: dev; +Cc: Rafat Jahan
Added MAC learning to reduce load at l2
Signed-off-by: Rafat Jahan <rafat.jahan@tcs.com>
---
examples/l2fwd-mac/Makefile | 50 ++
examples/l2fwd-mac/main.c | 1325 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1375 insertions(+)
create mode 100644 examples/l2fwd-mac/Makefile
create mode 100644 examples/l2fwd-mac/main.c
diff --git a/examples/l2fwd-mac/Makefile b/examples/l2fwd-mac/Makefile
new file mode 100644
index 0000000..6ab93f4
--- /dev/null
+++ b/examples/l2fwd-mac/Makefile
@@ -0,0 +1,50 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# 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 Intel Corporation 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.
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = l2fwd-mac
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/l2fwd-mac/main.c b/examples/l2fwd-mac/main.c
new file mode 100644
index 0000000..33d6a6e
--- /dev/null
+++ b/examples/l2fwd-mac/main.c
@@ -0,0 +1,1325 @@
+/*-thread created and in which two seperate threads for updation and checking are created infinately
+
+ final working code
+
+
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ * 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 Intel Corporation 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_launch.h>
+#include <rte_atomic.h>
+#include <rte_cycles.h>
+#include <rte_prefetch.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_interrupts.h>
+#include <rte_pci.h>
+#include <rte_random.h>
+#include <rte_debug.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_ring.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_ip.h>
+#include <rte_arp.h>
+
+#define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
+
+#define NB_MBUF 8192
+
+#define MAX_PKT_BURST 32
+#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
+
+#define default_aging_time 30
+pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * Work-around of a compilation error with ICC on invocations of the
+ * rte_be_to_cpu_16() function.
+ */
+#ifdef __GCC__
+#define RTE_BE_TO_CPU_16(be_16_v) rte_be_to_cpu_16((be_16_v))
+#define RTE_CPU_TO_BE_16(cpu_16_v) rte_cpu_to_be_16((cpu_16_v))
+#else
+#if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
+#define RTE_BE_TO_CPU_16(be_16_v) (be_16_v)
+#define RTE_CPU_TO_BE_16(cpu_16_v) (cpu_16_v)
+#else
+#define RTE_BE_TO_CPU_16(be_16_v) \
+ (uint16_t) ((((be_16_v) & 0xFF) << 8) | ((be_16_v) >> 8))
+#define RTE_CPU_TO_BE_16(cpu_16_v) \
+ (uint16_t) ((((cpu_16_v) & 0xFF) << 8) | ((cpu_16_v) >> 8))
+#endif
+#endif /* __GCC__ */
+
+/*
+ * Configurable number of RX/TX ring descriptors
+ */
+#define RTE_TEST_RX_DESC_DEFAULT 128
+#define RTE_TEST_TX_DESC_DEFAULT 512
+static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT;
+static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT;
+
+/* ethernet addresses of ports */
+static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS];
+
+/* mask of enabled ports */
+static uint32_t l2fwd_enabled_port_mask = 0;
+static int64_t l2fwd_user_defined_dst_port = 0;
+static int16_t l2fwd_mac_learning_enabled = 0;
+uint64_t total_duplicate_packets_dropped = 0;
+
+/* list of enabled ports */
+static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS];
+
+static unsigned int l2fwd_rx_queue_per_lcore = 1;
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port);
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport);
+static void l2fwd_mac_display(void);
+static void l2fwd_show_mac_entry(void);
+void source_mac_table(struct ether_hdr *eth,unsigned port);
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port);
+void update_aging(struct ether_hdr *eth);
+void *thread1(void);
+void *thread2(void);
+void *threadInit(void);
+
+
+struct node
+{
+ unsigned port;
+ struct ether_addr s_addr; /**< Source address. */
+ struct ether_addr d_addr; /**< Destination address. */
+ time_t starttime;
+ struct node *next;
+}*head = NULL;
+
+struct mac_list
+{
+ unsigned port;
+ struct ether_addr s_addr;
+ time_t rx_time;
+ char *buff;
+ int aging_time;
+ struct mac_list *next;
+}*start = NULL;
+
+
+struct mbuf_table {
+ unsigned len;
+ struct rte_mbuf *m_table[MAX_PKT_BURST];
+};
+
+void update_node(struct mac_list *ptr);
+#define MAX_RX_QUEUE_PER_LCORE 16
+#define MAX_TX_QUEUE_PER_PORT 16
+struct lcore_queue_conf {
+ unsigned n_rx_port;
+ unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE];
+ struct mbuf_table tx_mbufs[RTE_MAX_ETHPORTS];
+
+} __rte_cache_aligned;
+struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
+
+static const struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .split_hdr_size = 0,
+ .header_split = 0, /**< Header Split disabled */
+ .hw_ip_checksum = 0, /**< IP checksum offload disabled */
+ .hw_vlan_filter = 0, /**< VLAN filtering disabled */
+ .jumbo_frame = 0, /**< Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /**< CRC stripped by hardware */
+ },
+ .txmode = {
+ .mq_mode = ETH_MQ_TX_NONE,
+ },
+};
+
+struct rte_mempool * l2fwd_pktmbuf_pool = NULL;
+
+/* Per-port statistics struct */
+struct l2fwd_port_statistics {
+ uint64_t tx;
+ uint64_t rx;
+ uint64_t dropped;
+} __rte_cache_aligned;
+struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
+
+/* A tsc-based timer responsible for triggering statistics printout */
+#define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
+#define MAX_TIMER_PERIOD 86400 /* 1 day max */
+static int64_t timer_period = 10 * TIMER_MILLISECOND * 1000; /* default period is 10 seconds */
+
+static inline void
+print_ether_addr(const char *what, struct ether_addr *eth_addr)
+{
+ char buf[ETHER_ADDR_FMT_SIZE];
+ ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
+ printf("%s%s", what, buf);
+}
+
+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
+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);
+}
+
+void add_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+ struct node *new = NULL;
+ new = (struct node*)malloc(sizeof(struct node));
+ if(new == NULL)
+ {
+ printf("Memory not allocated for MAC database");
+ }
+
+ source_mac_table(eth,port);
+
+ new->port = port;
+ new->starttime = time(NULL);
+ ether_addr_copy(ð->s_addr, &new->s_addr);
+ ether_addr_copy(ð->d_addr, &new->d_addr);
+ if(head == NULL)
+ {
+ head = new;
+ head->next = NULL;
+
+ }
+ else
+ {
+ new->next = head;
+ head = new;
+
+ }
+}
+
+void source_mac_table(struct ether_hdr *eth,unsigned port)
+{
+
+ struct mac_list *ptr = NULL;
+ ptr = start;
+ if(start == NULL)
+ {
+ printf("Adding entry to the table\n");
+ add_src_mac_entry(eth,port);
+ }
+ else
+ {
+ while(ptr != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+
+ ptr->rx_time=time(NULL);
+ ptr->aging_time=default_aging_time;
+ if(ptr->port != port )
+ {
+ ptr->port = port;
+ break;
+ }
+ else
+ break; // received from same mac
+ }
+ ptr = ptr->next;
+ }
+ if(ptr == NULL)
+ {
+ /*If the mac entry is not found in the table, then add the entry
+ to the mac table */
+ printf("Adding MAC entry to table\n");
+ add_src_mac_entry(eth,port);
+ }
+
+ }
+}
+
+void add_src_mac_entry(struct ether_hdr *eth,unsigned port)
+{
+ struct mac_list *new = NULL;
+ new = (struct mac_list*)malloc(sizeof(struct mac_list));
+ if(new == NULL)
+ {
+ printf("Memory not allocated for MAC database");
+ }
+ new->port = port;
+ ether_addr_copy(ð->s_addr, &new->s_addr);
+ new->rx_time=time(NULL);
+ new->aging_time=default_aging_time;
+ if(start == NULL)
+ {
+ start = new;
+ start->next = NULL;
+ }
+ else
+ {
+ new->next=start;
+ start=new;
+ }
+
+}
+
+/* Print out statistics on packets dropped */
+static void
+print_stats(void)
+{
+ uint64_t total_packets_dropped, total_packets_tx, total_packets_rx;
+ unsigned portid;
+
+ total_packets_dropped = 0;
+ total_packets_tx = 0;
+ total_packets_rx = 0;
+
+ const char clr[] = { 27, '[', '2', 'J', '\0' };
+ const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' };
+
+ /* Clear screen and move to top left */
+ printf("%s%s", clr, topLeft);
+
+ printf("\nPort statistics ====================================");
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ /* skip disabled ports */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+ printf("\nStatistics for port %u ------------------------------"
+ "\nPackets sent: %24"PRIu64
+ "\nPackets received: %20"PRIu64
+ "\nPackets dropped: %21"PRIu64,
+ portid,
+ port_statistics[portid].tx,
+ port_statistics[portid].rx,
+ port_statistics[portid].dropped);
+
+ total_packets_dropped += port_statistics[portid].dropped;
+ total_packets_tx += port_statistics[portid].tx;
+ total_packets_rx += port_statistics[portid].rx;
+ }
+ printf("\nAggregate statistics ==============================="
+ "\nTotal packets sent: %18"PRIu64
+ "\nTotal packets received: %14"PRIu64
+ "\nTotal packets dropped: %15"PRIu64,
+ total_packets_tx,
+ total_packets_rx,
+ total_packets_dropped);
+ printf("\nTotal duplicate packets dropped: %5"PRIu64,
+ total_duplicate_packets_dropped);
+ printf("\n====================================================\n");
+}
+
+
+/* Send the burst of packets on an output interface */
+static int
+l2fwd_send_burst(struct lcore_queue_conf *qconf, unsigned n, uint8_t port)
+{
+ struct rte_mbuf **m_table;
+ unsigned ret;
+ unsigned queueid =0;
+
+ m_table = (struct rte_mbuf **)qconf->tx_mbufs[port].m_table;
+
+ ret = rte_eth_tx_burst(port, (uint16_t) queueid, m_table, (uint16_t) n);
+ port_statistics[port].tx += ret;
+ if (unlikely(ret < n)) {
+ port_statistics[port].dropped += (n - ret);
+ do {
+ rte_pktmbuf_free(m_table[ret]);
+ } while (++ret < n);
+ }
+
+ return 0;
+}
+
+/* Enqueue packets for TX and prepare them to be sent */
+static int
+l2fwd_send_packet(struct rte_mbuf *m, uint8_t port)
+{
+ unsigned lcore_id, len;
+ struct lcore_queue_conf *qconf;
+
+ lcore_id = rte_lcore_id();
+
+ qconf = &lcore_queue_conf[lcore_id];
+ len = qconf->tx_mbufs[port].len;
+ qconf->tx_mbufs[port].m_table[len] = m;
+ len++;
+
+ /* enough pkts to be sent */
+ if (unlikely(len == MAX_PKT_BURST)) {
+ l2fwd_send_burst(qconf, MAX_PKT_BURST, port);
+ len = 0;
+ }
+
+ qconf->tx_mbufs[port].len = len;
+ return 0;
+}
+static void l2fwd_mac_display(void)
+{
+ struct node *node = NULL;
+ printf("\n==============DEBUGGING MAC TABLE=================\n");
+ printf(" SMAC DMAC PORT \n");
+ node = head;
+ while(node != NULL)
+ {
+ print_ether_addr("", &node->s_addr);
+ print_ether_addr(" ",&node->d_addr);
+ printf(" %d\n",node->port);
+ node = node->next;
+ }
+ printf("========================================\n");
+}
+static void l2fwd_show_mac_entry(void)
+{
+ struct mac_list *node = NULL;
+ printf("\n==============MAC TABLE=================\n");
+ printf(" MAC PORT\taging time\n");
+ node = start;
+ while(node != NULL)
+ {
+ print_ether_addr("", &node->s_addr);
+ printf(" %d\t",node->port);
+ printf("%d\n",node->aging_time);
+
+ node = node->next;
+ }
+ printf("========================================\n");
+}
+static void l2fwd_mac_ports_update(struct ether_hdr *eth,unsigned rxport)
+{
+ struct node *ptr = NULL;
+ struct mac_list *ptr1 = NULL;
+
+ ptr = head;
+ while(ptr != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr->port = rxport;
+ }
+ ptr = ptr->next;
+ }
+
+ ptr1 = start;
+ while(ptr1 != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr1->port = rxport;
+ ptr1->rx_time=time(NULL);
+ ptr1->aging_time=default_aging_time;
+ }
+ ptr1 = ptr1->next;
+ }
+
+}
+void update_aging(struct ether_hdr *eth)
+{
+ struct mac_list *ptr1=NULL;
+ ptr1 = start;
+ while(ptr1 != NULL)
+ {
+ if (memcmp(ð->s_addr, &ptr1->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ ptr1->rx_time=time(NULL);
+ ptr1->aging_time=default_aging_time;
+ }
+ ptr1 = ptr1->next;
+ }
+}
+static void
+l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
+{
+ struct ether_hdr *eth;
+ void *tmp;
+ unsigned dst_port;
+ int currenttime,difference,timeout = 8;
+ //int err;
+ //pthread_t t1,t2;
+ dst_port = l2fwd_dst_ports[portid];
+ printf("---------- Forwarding Path ----------\n");
+ printf("Default forwarding dst port : %d\n",dst_port);
+
+ eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
+
+ if(l2fwd_user_defined_dst_port > 0)
+ {
+ dst_port = l2fwd_user_defined_dst_port;
+ printf("User defined dst Port : %d\n",dst_port);
+ printf("----------------------------------------\n");
+ printf("Forwarding path has been modified from default to user defined\n");
+ }
+ else if(l2fwd_mac_learning_enabled)
+ {
+ //l2fwd_mac_display();
+ //l2fwd_show_mac_entry();
+ //pthread_mutex_lock( &mutex1 );
+ struct node *ptr = NULL;
+ struct mac_list *temp = NULL;
+ ptr = head;
+ if(head == NULL)
+ {
+ printf("No MAC address exist in table , adding entry to the table\n");
+ add_mac_entry(eth,portid);
+ }
+ else
+ {
+ /* condition to check and overwrite the 'port' if the same mac address
+ was already received from another 'port' earlier*/
+ while(ptr != NULL)
+ {
+ if ((memcmp(ð->s_addr, &ptr->s_addr, ETHER_ADDR_LEN) == 0) &&
+ (memcmp(ð->d_addr, &ptr->d_addr, ETHER_ADDR_LEN) == 0))
+ {
+ // printf("----->same SMAC DMAC\n");
+ if(portid != ptr->port)
+ {
+ printf("port id is different %d\n",portid);
+ currenttime = time(NULL);
+ difference = currenttime - (ptr->starttime);
+ if(difference > timeout)
+ {
+ printf("----->difference %d\n",difference);
+ ptr->port = portid;
+ ptr->starttime = time(NULL);
+ l2fwd_mac_ports_update(eth,portid);
+ // add_mac_entry(eth,portid);
+ break;
+ } else {
+ printf("Detected duplication,packet dropped \n");
+ //duplicate packet
+ total_duplicate_packets_dropped++;
+ //need to check whether break is needed
+ // return;
+ }
+ }
+
+ ptr->starttime = time(NULL);
+ update_aging(eth);
+ // printf("---->received from same mac diff %d\n",difference);
+ break;
+ }
+ ptr = ptr->next;
+ }
+ if(ptr == NULL)
+ {
+ /*If the mac entry is not found in the table, then add the entry
+ to the mac table */
+ printf("Adding MAC entry to table\n");
+ add_mac_entry(eth,portid);
+ //l2fwd_mac_ports_update(eth,portid);
+ }
+ }
+
+
+ /* lookup to get the dst port if the mac entry is already present in the table*/
+ temp = start;
+ while(temp != NULL)
+ {
+ if (memcmp(ð->d_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ dst_port = temp->port;
+ printf("\n");
+ printf("dst port from table : %d\n",dst_port);
+ break;
+ }
+ temp = temp->next;
+ }
+ /*If the dst mac is not available,then forward the packet in dumping port*/
+ if(temp == NULL)
+ {
+ dst_port = 9;
+ printf("Dumping port : %d\n",dst_port);
+ }
+
+ }
+ else
+ {
+//========================================================
+ /* 02:00:00:00:00:xx */
+ tmp = ð->d_addr.addr_bytes[0];
+ *((uint64_t *)tmp) = 0xffffffffffff ;
+ //*((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
+
+ /* src addr */
+ ether_addr_copy(&l2fwd_ports_eth_addr[dst_port], ð->s_addr);
+ }
+
+ printf("========================================\n");
+ l2fwd_mac_display();
+ l2fwd_show_mac_entry();
+ //pthread_mutex_unlock( &mutex1 );
+ l2fwd_send_packet(m, (uint8_t) dst_port);
+}
+
+/* main processing loop */
+static void
+l2fwd_main_loop(void)
+{
+ struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+ struct rte_mbuf *m;
+ unsigned lcore_id;
+ uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc;
+ unsigned i, j, portid, nb_rx;
+ struct lcore_queue_conf *qconf;
+ const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
+ struct ether_hdr *eth_hdr;
+ uint16_t eth_type;
+ struct ipv4_hdr *ip_h;
+ int l2_len;
+ struct arp_hdr *arp_h;
+ uint32_t sip_addr,tip_addr;
+
+ prev_tsc = 0;
+ timer_tsc = 0;
+
+ lcore_id = rte_lcore_id();
+ qconf = &lcore_queue_conf[lcore_id];
+
+ if (qconf->n_rx_port == 0) {
+ RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id);
+ return;
+ }
+
+ RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
+
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id,
+ portid);
+ }
+
+ while (1) {
+
+ cur_tsc = rte_rdtsc();
+
+ /*
+ * TX burst queue drain
+ */
+ diff_tsc = cur_tsc - prev_tsc;
+ if (unlikely(diff_tsc > drain_tsc)) {
+
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
+ if (qconf->tx_mbufs[portid].len == 0)
+ continue;
+ l2fwd_send_burst(&lcore_queue_conf[lcore_id],
+ qconf->tx_mbufs[portid].len,
+ (uint8_t) portid);
+ qconf->tx_mbufs[portid].len = 0;
+ }
+
+ /* if timer is enabled */
+ if (timer_period > 0) {
+
+ /* advance the timer */
+ timer_tsc += diff_tsc;
+
+ /* if timer has reached its timeout */
+ if (unlikely(timer_tsc >= (uint64_t) timer_period)) {
+
+ /* do this only on master core */
+ if (lcore_id == rte_get_master_lcore()) {
+ print_stats();
+ /* reset the timer */
+ timer_tsc = 0;
+ }
+ }
+ }
+
+ prev_tsc = cur_tsc;
+ }
+
+ /*
+ * Read packet from RX queues
+ */
+ for (i = 0; i < qconf->n_rx_port; i++) {
+
+ portid = qconf->rx_port_list[i];
+ nb_rx = rte_eth_rx_burst((uint8_t) portid, 0,
+ pkts_burst, MAX_PKT_BURST);
+
+ if(nb_rx == 0)
+ continue;
+ port_statistics[portid].rx += nb_rx;
+
+ for (j = 0; j < nb_rx; j++) {
+ m = pkts_burst[j];
+ rte_prefetch0(rte_pktmbuf_mtod(m, void *));
+
+ eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
+ eth_type = RTE_BE_TO_CPU_16(eth_hdr->ether_type);
+ l2_len = sizeof(struct ether_hdr);
+
+ //if (eth_type != ETHER_TYPE_IPv4) {
+ // rte_pktmbuf_free(m);
+ // continue;
+ //}
+
+ printf("========================================\n");
+ printf("Packet received on port :%d\n",portid);
+ printf("------------ L2 Details------------\n");
+ print_ether_addr(" Source MAC : ", ð_hdr->s_addr);
+ print_ether_addr("\n Destination MAC : ", ð_hdr->d_addr);
+ printf("\n Port : %d"
+ "\n Ethernet Type : 0x%04x"
+ "\n Length : %u "
+ "\n Nb_segs : %d",
+ portid,
+ eth_type,
+ (unsigned) m->pkt_len,
+ (int)m->nb_segs);
+ printf("\n");
+
+ if (eth_type == ETHER_TYPE_ARP)
+ {
+ arp_h = (struct arp_hdr *) ((char *)eth_hdr + l2_len);
+ sip_addr = arp_h->arp_data.arp_sip;
+ tip_addr = arp_h->arp_data.arp_tip;
+ } else
+ {
+ if (eth_type != ETHER_TYPE_IPv4) {
+ rte_pktmbuf_free(m);
+ continue;
+ }
+ ip_h = (struct ipv4_hdr *) ((char *)eth_hdr + l2_len);
+ sip_addr = ip_h->src_addr;
+ tip_addr = ip_h->dst_addr;
+ }
+ printf("------------ L3 Details------------\n");
+ ipv4_addr_dump(" Source IP : ", sip_addr);
+ ipv4_addr_dump("\n Destination IP : ", tip_addr);
+ printf("\n");
+
+ l2fwd_simple_forward(m, portid);
+ }
+ }
+ }
+}
+
+static int
+l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy)
+{
+ l2fwd_main_loop();
+ return 0;
+}
+
+/* display usage */
+static void
+l2fwd_usage(const char *prgname)
+{
+ printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n"
+ " -p PORTMASK: hexadecimal bitmask of ports to configure\n"
+ " -q NQ: number of queue (=ports) per lcore (default is 1)\n"
+ " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n"
+ " -d DST PORT: user input to select the destination port\n"
+ " -l MAC LEARNING: enable l2fwd mac learning 1-enable : 0 - disable(default) \n",
+ prgname);
+}
+
+static int
+l2fwd_parse_portmask(const char *portmask)
+{
+ char *end = NULL;
+ unsigned long pm;
+
+ /* parse hexadecimal string */
+ pm = strtoul(portmask, &end, 16);
+ if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+
+ if (pm == 0)
+ return -1;
+
+ return pm;
+}
+
+static unsigned int
+l2fwd_parse_nqueue(const char *q_arg)
+{
+ char *end = NULL;
+ unsigned long n;
+
+ /* parse hexadecimal string */
+ n = strtoul(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return 0;
+ if (n == 0)
+ return 0;
+ if (n >= MAX_RX_QUEUE_PER_LCORE)
+ return 0;
+
+ return n;
+}
+
+static int
+l2fwd_parse_timer_period(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n >= MAX_TIMER_PERIOD)
+ return -1;
+
+ return n;
+}
+
+static int
+pktcap_parse_dst_port(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 10);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n > RTE_MAX_ETHPORTS)
+ return -1;
+
+ return n;
+}
+
+static int
+l2fwd_parse_mac_learning(const char *q_arg)
+{
+ char *end = NULL;
+ int n;
+
+ /* parse number string */
+ n = strtol(q_arg, &end, 0);
+ if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+ return -1;
+ if (n > 1)
+ return -1;
+
+ return n;
+}
+/* Parse the argument given in the command line of the application */
+static int
+l2fwd_parse_args(int argc, char **argv)
+{
+ int opt, ret;
+ char **argvopt;
+ int option_index;
+ char *prgname = argv[0];
+ static struct option lgopts[] = {
+ {NULL, 0, 0, 0}
+ };
+
+ argvopt = argv;
+
+ while ((opt = getopt_long(argc, argvopt, "p:q:T:d:l:",
+ lgopts, &option_index)) != EOF) {
+
+ switch (opt) {
+ /* portmask */
+ case 'p':
+ l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg);
+ if (l2fwd_enabled_port_mask == 0) {
+ printf("invalid portmask\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* nqueue */
+ case 'q':
+ l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg);
+ if (l2fwd_rx_queue_per_lcore == 0) {
+ printf("invalid queue number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* timer period */
+ case 'T':
+ timer_period = l2fwd_parse_timer_period(optarg) * 1000 * TIMER_MILLISECOND;
+ if (timer_period < 0) {
+ printf("invalid timer period\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* user defined dst port*/
+ case 'd':
+ l2fwd_user_defined_dst_port = pktcap_parse_dst_port(optarg);
+ if (l2fwd_user_defined_dst_port < 0) {
+ printf("invalid port number\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+
+ /* l2 mac learning*/
+ case 'l':
+ l2fwd_mac_learning_enabled = l2fwd_parse_mac_learning(optarg);
+ if (l2fwd_mac_learning_enabled < 0) {
+ printf("invalid option\n");
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ break;
+ /* long options */
+ case 0:
+ l2fwd_usage(prgname);
+ return -1;
+
+ default:
+ l2fwd_usage(prgname);
+ return -1;
+ }
+ }
+
+ if (optind >= 0)
+ argv[optind-1] = prgname;
+
+ ret = optind-1;
+ optind = 0; /* reset getopt lib */
+ return ret;
+}
+
+/* Check the link status of all ports in up to 9s, and print them finally */
+static void
+check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
+{
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+ uint8_t portid, count, all_ports_up, print_flag = 0;
+ struct rte_eth_link link;
+
+ printf("\nChecking link status");
+ fflush(stdout);
+ for (count = 0; count <= MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (portid = 0; portid < port_num; portid++) {
+ if ((port_mask & (1 << portid)) == 0)
+ continue;
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(portid, &link);
+ /* print link status if flag set */
+ if (print_flag == 1) {
+ if (link.link_status)
+ printf("Port %d Link Up - speed %u "
+ "Mbps - %s\n", (uint8_t)portid,
+ (unsigned)link.link_speed,
+ (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex\n"));
+ else
+ printf("Port %d Link Down\n",
+ (uint8_t)portid);
+ continue;
+ }
+ /* clear all_ports_up flag if any link down */
+ if (link.link_status == 0) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+ /* after finally printing all link status, get out */
+ if (print_flag == 1)
+ break;
+
+ if (all_ports_up == 0) {
+ printf(".");
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ /* set the print_flag if all ports up or timeout */
+ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
+ print_flag = 1;
+ printf("done\n");
+ }
+ }
+}
+
+void *thread2(void)
+{
+ if(start!=NULL)
+ {
+
+ pthread_mutex_lock( &mutex1 );
+ struct mac_list *temp=start;
+ while(temp!=NULL)
+ {
+ if(temp->aging_time>0)
+ temp->aging_time=default_aging_time-(time(NULL)-temp->rx_time);
+ //strcpy(temp->buff,"check");
+ temp=temp->next;
+ }
+ pthread_mutex_unlock( &mutex1 );
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+
+void update_node(struct mac_list *l_temp)
+{
+ struct node *temp,*temp2,*prev;
+ if(head!=NULL)
+ {
+ while(head!=NULL)
+ {
+ if(memcmp(&l_temp->s_addr, &head->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ temp=head;
+ head=head->next;
+ free(temp);
+ }
+ else
+ break;
+ }
+ // if(head!=NULL)
+ temp=head->next;
+ prev=head;
+ while(temp!=NULL && head!=NULL)
+ {
+ if(memcmp(&l_temp->s_addr, &temp->s_addr, ETHER_ADDR_LEN) == 0)
+ {
+ prev->next=temp->next;
+ temp2=temp;
+ temp=temp->next;
+ free(temp2);
+ }
+ else
+ {
+ temp=temp->next;
+ prev=prev->next;
+ }
+ }
+ }
+
+
+}
+
+
+void *thread1(void)
+{
+ struct mac_list *temp,*temp2,*prev;
+
+ if(start!=NULL)
+ {
+
+ pthread_mutex_lock( &mutex1 );
+ while(start!=NULL)
+ {
+ if( start->aging_time==0)
+ {
+ temp = start;
+ update_node(temp);
+ start=start->next;
+ free(temp);
+
+ }
+ else
+ break;
+ }
+ // if(start!=NULL)
+ temp = start->next;
+ prev=start;
+ while(temp!= NULL && start!=NULL)
+ {
+
+ if(temp->aging_time==0)
+ {
+ update_node(temp);
+ prev->next=temp->next;
+ temp2=temp;
+ temp=temp->next;
+ if(temp2!=NULL)
+ free(temp2);
+ }
+ else
+ {
+ temp = temp->next;
+ prev=prev->next;
+ }
+ }
+ pthread_mutex_unlock( &mutex1 );
+ }
+ pthread_exit(NULL);
+ return NULL;
+}
+void *threadInit(void)
+{
+ pthread_t t1,t2;
+ int err;
+ while(1)
+ {
+ err=pthread_create(&t1, NULL,(void *)thread1,NULL);//for checking the mac table
+ pthread_join(t1,NULL);
+
+
+ err=pthread_create(&t2,NULL,(void *)thread2,NULL);//for updating the mac table
+ pthread_join(t2,NULL);
+
+ if(err!=0)
+ {
+ printf("thread not created\n");
+ exit(0);
+ }
+ }
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct lcore_queue_conf *qconf;
+ struct rte_eth_dev_info dev_info;
+ int ret,err;
+ uint8_t nb_ports;
+ uint8_t nb_ports_available;
+ uint8_t portid, last_port;
+ unsigned lcore_id, rx_lcore_id;
+ unsigned nb_ports_in_mask = 0;
+ pthread_t t3;
+ /* init EAL */
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+ argc -= ret;
+ argv += ret;
+
+ /* parse application arguments (after the EAL ones) */
+ ret = l2fwd_parse_args(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n");
+
+ /* create the mbuf pool */
+ l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF, 32,
+ 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
+ if (l2fwd_pktmbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+ nb_ports = rte_eth_dev_count();
+ if (nb_ports == 0)
+ rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
+
+ if (nb_ports > RTE_MAX_ETHPORTS)
+ nb_ports = RTE_MAX_ETHPORTS;
+
+ /* reset l2fwd_dst_ports */
+ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
+ l2fwd_dst_ports[portid] = 0;
+ last_port = 0;
+
+ printf("Entered port : %" PRId64 "\n",l2fwd_user_defined_dst_port);
+
+ /*
+ * Each logical core is assigned a dedicated TX queue on each port.
+ */
+ if(l2fwd_user_defined_dst_port == 0)
+ {
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ if (nb_ports_in_mask % 2) {
+ l2fwd_dst_ports[portid] = last_port;
+ l2fwd_dst_ports[last_port] = portid;
+ }
+ else
+ last_port = portid;
+
+ nb_ports_in_mask++;
+
+ rte_eth_dev_info_get(portid, &dev_info);
+ }
+ if (nb_ports_in_mask % 2) {
+ printf("Notice: odd number of ports in portmask.\n");
+ l2fwd_dst_ports[last_port] = last_port;
+ }
+
+ }
+ rx_lcore_id = 0;
+ qconf = NULL;
+
+ /* Initialize the port/queue configuration of each logical core */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0)
+ continue;
+
+ /* get the lcore_id for this port */
+ while (rte_lcore_is_enabled(rx_lcore_id) == 0 ||
+ lcore_queue_conf[rx_lcore_id].n_rx_port ==
+ l2fwd_rx_queue_per_lcore) {
+ rx_lcore_id++;
+ if (rx_lcore_id >= RTE_MAX_LCORE)
+ rte_exit(EXIT_FAILURE, "Not enough cores\n");
+ }
+
+ if (qconf != &lcore_queue_conf[rx_lcore_id])
+ /* Assigned a new logical core in the loop above. */
+ qconf = &lcore_queue_conf[rx_lcore_id];
+
+ qconf->rx_port_list[qconf->n_rx_port] = portid;
+ qconf->n_rx_port++;
+ printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned) portid);
+ }
+
+ nb_ports_available = nb_ports;
+
+ /* Initialise each port */
+ for (portid = 0; portid < nb_ports; portid++) {
+ /* skip ports that are not enabled */
+ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) {
+ printf("Skipping disabled port %u\n", (unsigned) portid);
+ nb_ports_available--;
+ continue;
+ }
+ /* init port */
+ printf("Initializing port %u... ", (unsigned) portid);
+ fflush(stdout);
+ ret = rte_eth_dev_configure(portid, 1, 1, &port_conf);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]);
+
+ /* init one RX queue */
+ fflush(stdout);
+ ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd,
+ rte_eth_dev_socket_id(portid),
+ NULL,
+ l2fwd_pktmbuf_pool);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ /* init one TX queue on each port */
+ fflush(stdout);
+ ret = rte_eth_tx_queue_setup(portid, 0, nb_txd,
+ rte_eth_dev_socket_id(portid),
+ NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+ /****************************************/
+ err=pthread_create(&t3,NULL,(void *)threadInit,NULL);
+ //thread for checking and updating the mac table
+ if(err!=0)
+ {
+ printf("thread not created\n");
+ exit(0);
+ }
+ /****************************************/
+ /* Start device */
+ ret = rte_eth_dev_start(portid);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n",
+ ret, (unsigned) portid);
+
+ printf("done: \n");
+
+ rte_eth_promiscuous_enable(portid);
+
+ printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
+ (unsigned) portid,
+ l2fwd_ports_eth_addr[portid].addr_bytes[0],
+ l2fwd_ports_eth_addr[portid].addr_bytes[1],
+ l2fwd_ports_eth_addr[portid].addr_bytes[2],
+ l2fwd_ports_eth_addr[portid].addr_bytes[3],
+ l2fwd_ports_eth_addr[portid].addr_bytes[4],
+ l2fwd_ports_eth_addr[portid].addr_bytes[5]);
+
+ /* initialize port stats */
+ memset(&port_statistics, 0, sizeof(port_statistics));
+ }
+
+ if (!nb_ports_available) {
+ rte_exit(EXIT_FAILURE,
+ "All available ports are disabled. Please set portmask.\n");
+ }
+
+ check_all_ports_link_status(nb_ports, l2fwd_enabled_port_mask);
+
+ /* launch per-lcore init on every lcore */
+ rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER);
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if (rte_eal_wait_lcore(lcore_id) < 0)
+ return -1;
+ }
+ //pthread_join(t1,NULL);
+ //pthread_join(t2,NULL);
+
+ return 0;
+}
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v3 1/2] librte_ether: add internal callback functions
From: Stephen Hemminger @ 2016-10-02 9:12 UTC (permalink / raw)
To: Bernard Iremonger; +Cc: dev, wenzhuo.lu, jerin.jacob, az5157, rahul.r.shah
In-Reply-To: <1475250308-5498-2-git-send-email-bernard.iremonger@intel.com>
I know callbacks are needed, in fact even more are necessary. That is why
I don't like this design. It expands the API for each event. I think
something like the Linux kernel netlink callback mechanism that passes an
event and device handle.
^ permalink raw reply
* Re: [PATCH v7] net/virtio: add set_mtu in virtio
From: Dey, Souvik @ 2016-10-01 14:08 UTC (permalink / raw)
To: mark.b.kavanagh@intel.com, yuanhan.liu@linux.intel.com,
stephen@networkplumber.org, dev@dpdk.org
In-Reply-To: <20160929203130.58712-1-sodey@sonusnet.com>
Hi Liu/Stephen/Mark,
I have submitted Version 7 of this patch. Do let me know if this looks proper.
--
Regards,
Souvik
-----Original Message-----
From: Dey, Souvik
Sent: Thursday, September 29, 2016 4:32 PM
To: mark.b.kavanagh@intel.com; yuanhan.liu@linux.intel.com; stephen@networkplumber.org; dev@dpdk.org
Cc: Dey, Souvik <sodey@sonusnet.com>
Subject: [PATCH v7] net/virtio: add set_mtu in virtio
Virtio interfaces do not currently allow the user to specify a particular
Maximum Transmission Unit (MTU).Consequently, the MTU of Virtio interfaces
is typically set to the Ethernet default value of 1500.
This is problematic in the case of cloud deployments, in which a specific
(and potentially non-standard) MTU needs to be set by a DHCP server, which
needs to be honored by all interfaces across the traffic path.To acheive
this Virtio interfaces should support setting of MTU.
In case when GRE/VXLAN tunneling is used for internal communication, there
will be an overhead added by the infrastructure in the packet over and
above the ETHER MTU of 1518. So to take care of this overhead in these
cases the DHCP server corrects the L3 MTU to 1454. But since virtio
interfaces was not having the MTU set functionality that MTU sent by the
DHCP server was ignored and the instance will still send packets with 1500
MTU which after encapsulation will become more than 1518 and eventually
gets dropped in the infrastructure.
By adding an additional 'set_mtu' function to the Virtio driver, we can
honor the MTU sent by the DHCP server. The dhcp server/controller can
then leverage this 'set_mtu' functionality to resolve the above
mentioned issue of packets getting dropped due to incorrect size.
Signed-off-by: Souvik Dey <sodey@sonusnet.com>
---
Changes in v7:
- Replaced the CRC_LEN with the merge rx buf header length.
- Changed the frame_len max validation to VIRTIO_MAX_RX_PKTLEN.
Changes in v6:
- Description of change corrected
- Corrected the identations
- Corrected the subject line too
- The From line was also not correct
- Re-submitting as the below patch was not proper
Changes in v5:
- Fix log message for out-of-bounds MTU parameter in virtio_mtu_set
- Calculate frame size, based on 'mtu' parameter
- Corrected the upper bound and lower bound checks in virtio_mtu_set
Changes in v4: Incorporated review comments.
Changes in v3: Corrected few style errors as reported by sys-stv.
Changes in v2: Incorporated review comments.
drivers/net/virtio/virtio_ethdev.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index 423c597..1dbfea6 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -653,12 +653,20 @@ virtio_dev_allmulticast_disable(struct rte_eth_dev *dev)
PMD_INIT_LOG(ERR, "Failed to disable allmulticast");
}
+#define VLAN_TAG_LEN 4 /* 802.3ac tag (not DMA'd) */
+static int virtio_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct virtio_hw *hw = dev->data->dev_private;
+ uint32_t ether_hdr_len = ETHER_HDR_LEN + VLAN_TAG_LEN +
+ hw->vtnet_hdr_size;
+ uint32_t frame_size = mtu + ether_hdr_len;
+
+ if (mtu < ETHER_MIN_MTU || frame_size > VIRTIO_MAX_RX_PKTLEN) {
+ PMD_INIT_LOG(ERR, "MTU should be between %d and %d\n",
+ ETHER_MIN_MTU, VIRTIO_MAX_RX_PKTLEN);
+ return -EINVAL;
+ }
+ return 0;
+}
/*
* dev_ops for virtio, bare necessities for basic operation
*/
@@ -677,7 +685,6 @@ static const struct eth_dev_ops virtio_eth_dev_ops = {
.allmulticast_enable = virtio_dev_allmulticast_enable,
.allmulticast_disable = virtio_dev_allmulticast_disable,
+ .mtu_set = virtio_mtu_set,
.dev_infos_get = virtio_dev_info_get,
.stats_get = virtio_dev_stats_get,
.xstats_get = virtio_dev_xstats_get,
--
2.9.3.windows.1
^ permalink raw reply related
* Re: [PATCH v4 0/4] Cuckoo hash enhancements
From: Gobriel, Sameh @ 2016-09-30 19:53 UTC (permalink / raw)
To: De Lara Guarch, Pablo, dev@dpdk.org; +Cc: Richardson, Bruce
In-Reply-To: <1475221136-213246-1-git-send-email-pablo.de.lara.guarch@intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of De Lara Guarch, Pablo
> Sent: Friday, September 30, 2016 12:39 AM
> To: dev@dpdk.org
> Cc: Richardson, Bruce <bruce.richardson@intel.com>; De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com>
> Subject: [dpdk-dev] [PATCH v4 0/4] Cuckoo hash enhancements
>
> This patchset improves lookup performance on the current hash library by
> changing the existing lookup bulk pipeline, with an improved pipeline, based on
> a loop-and-jump model, instead of the current 4-stage 2-entry pipeline.
> Also, x86 vectorized intrinsics are used to improve performance when
> comparing signatures.
>
> First patch reorganizes the order of the hash structure.
> The structure takes more than one 64-byte cache line, but not all the fields are
> used in the lookup operation (the most common operation).
> Therefore, all these fields have been moved to the first part of the structure, so
> they all fit in one cache line, improving slightly the performance in some
> scenarios.
>
> Second patch modifies the order of the bucket structure.
> Currently, the buckets store all the signatures together (current and
> alternative).
> In order to be able to perform a vectorized signature comparison, all current
> signatures have to be together, so the order of the bucket has been changed,
> having separated all the current signatures from the alternative signatures.
>
> Third patch introduces x86 vectorized intrinsics.
> When performing a lookup bulk operation, all current signatures in a bucket
> are compared against the signature of the key being looked up.
> Now that they all are together, a vectorized comparison can be performed,
> which takes less instructions to be carried out.
> In case of having a machine with AVX2, number of entries per bucket are
> increased from 4 to 8, as AVX2 allows comparing two 256-bit values, with
> 8x32-bit integers, which are the 8 signatures on the bucket.
>
> Fourth (and last) patch modifies the current pipeline of the lookup bulk
> function.
> The new pipeline is based on a loop-and-jump model. The two key
> improvements are:
>
> - Better prefetching: in this case, first 4 keys to be looked up are prefetched,
> and after that, the rest of the keys are prefetched at the time the calculation
> of the signatures are being performed. This gives more time for the CPU to
> prefetch the data requesting before actually need it, which result in less
> cache misses and therefore, higher throughput.
>
> - Lower performance penalty when using fallback: the lookup bulk algorithm
> assumes that most times there will not be a collision in a bucket, but it might
> happen that two or more signatures are equal, which means that more than
> one
> key comparison might be necessary. In that case, only the key of the first hit is
> prefetched,
> like in the current implementation. The difference now is that if this
> comparison
> results in a miss, the information of the other keys to be compared has been
> stored,
> unlike the current implementation, which needs to perform an entire simple
> lookup again.
>
> Changes in v4:
> - Reordered hash structure, so alt signature is at the start
> of the next cache line, and explain in the commit message
> why it has been moved
> - Reordered hash structure, so name field is on top of the structure,
> leaving all the fields used in lookup in the next cache line
> (instead of the first cache line)
>
> Changes in v3:
> - Corrected the cover letter (wrong number of patches)
>
> Changes in v2:
> - Increased entries per bucket from 4 to 8 for all cases,
> so it is not architecture dependent any longer.
> - Replaced compile-time signature comparison function election
> with run-time election, so best optimization available
> will be used from a single binary.
> - Reordered the hash structure, so all the fields used by lookup
> are in the same cache line (first).
>
> Byron Marohn (3):
> hash: reorganize bucket structure
> hash: add vectorized comparison
> hash: modify lookup bulk pipeline
>
> Pablo de Lara (1):
> hash: reorder hash structure
>
> lib/librte_hash/rte_cuckoo_hash.c | 455 ++++++++++++++--------------------
> lib/librte_hash/rte_cuckoo_hash.h | 56 +++--
> lib/librte_hash/rte_cuckoo_hash_x86.h | 20 +-
> 3 files changed, 228 insertions(+), 303 deletions(-)
>
> --
> 2.7.4
Series-acked-by: Sameh Gobriel <sameh.gobriel@intel.com>
^ permalink raw reply
* Re: [Qemu-devel] [PATCH 1/2] vhost: enable any layout feature
From: Michael S. Tsirkin @ 2016-09-30 19:16 UTC (permalink / raw)
To: Maxime Coquelin; +Cc: Yuanhan Liu, Stephen Hemminger, dev, qemu-devel
In-Reply-To: <2b458818-01ef-0533-4366-1c35a8452e4a@redhat.com>
On Fri, Sep 30, 2016 at 02:05:10PM +0200, Maxime Coquelin wrote:
>
>
> On 09/29/2016 11:23 PM, Maxime Coquelin wrote:
> >
> >
> > On 09/29/2016 10:21 PM, Michael S. Tsirkin wrote:
> > > On Thu, Sep 29, 2016 at 10:05:22PM +0200, Maxime Coquelin wrote:
> > > >
> > > >
> > > > On 09/29/2016 07:57 PM, Michael S. Tsirkin wrote:
> > > > > On Thu, Sep 29, 2016 at 05:30:53PM +0200, Maxime Coquelin wrote:
> > > > ...
> > > > > >
> > > > > > Before enabling anything by default, we should first optimize the 1
> > > > > > slot
> > > > > > case. Indeed, micro-benchmark using testpmd in txonly[0] shows ~17%
> > > > > > perf regression for 64 bytes case:
> > > > > > - 2 descs per packet: 11.6Mpps
> > > > > > - 1 desc per packet: 9.6Mpps
> > > > > >
> > > > > > This is due to the virtio header clearing in virtqueue_enqueue_xmit().
> > > > > > Removing it, we get better results than with 2 descs (1.20Mpps).
> > > > > > Since the Virtio PMD doesn't support offloads, I wonder whether we can
> > > > > > just drop the memset?
> > > > >
> > > > > What will happen? Will the header be uninitialized?
> > > > Yes..
> > > > I didn't look closely at the spec, but just looked at DPDK's and Linux
> > > > vhost implementations. IIUC, the header is just skipped in the two
> > > > implementations.
> > >
> > > In linux guest skbs are initialized AFAIK. See virtio_net_hdr_from_skb
> > > first thing it does is
> > > memset(hdr, 0, sizeof(*hdr));
> >
> > I meant in vhost-net linux implementation, the header is just skipped:
> >
> > static void handle_tx(struct vhost_net *net)
> > {
> > ...
> > /* Skip header. TODO: support TSO. */
> > len = iov_length(vq->iov, out);
> > iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len);
> > iov_iter_advance(&msg.msg_iter, hdr_size);
> >
> > And the same is done is done in DPDK:
> >
> > static inline int __attribute__((always_inline))
> > copy_desc_to_mbuf(struct virtio_net *dev, struct vring_desc *descs,
> > uint16_t max_desc, struct rte_mbuf *m, uint16_t desc_idx,
> > struct rte_mempool *mbuf_pool)
> > {
> > ...
> > /*
> > * A virtio driver normally uses at least 2 desc buffers
> > * for Tx: the first for storing the header, and others
> > * for storing the data.
> > */
> > if (likely((desc->len == dev->vhost_hlen) &&
> > (desc->flags & VRING_DESC_F_NEXT) != 0)) {
> > desc = &descs[desc->next];
> > if (unlikely(desc->flags & VRING_DESC_F_INDIRECT))
> > return -1;
> >
> > desc_addr = gpa_to_vva(dev, desc->addr);
> > if (unlikely(!desc_addr))
> > return -1;
> >
> > rte_prefetch0((void *)(uintptr_t)desc_addr);
> >
> > desc_offset = 0;
> > desc_avail = desc->len;
> > nr_desc += 1;
> >
> > PRINT_PACKET(dev, (uintptr_t)desc_addr, desc->len, 0);
> > } else {
> > desc_avail = desc->len - dev->vhost_hlen;
> > desc_offset = dev->vhost_hlen;
> > }
>
> Actually, the header is parsed in DPDK vhost implementation.
> But as Virtio PMD provides a zero'ed header, we could just parse
> the header only if VIRTIO_NET_F_NO_TX_HEADER is not negotiated.
host can always skip the header parse if it wants to.
It didn't seem worth it to add branches there but
if I'm wrong, by all means code it up.
> > >
> > >
> > >
> > > > >
> > > > > The spec says:
> > > > > The driver can send a completely checksummed packet. In this
> > > > > case, flags
> > > > > will be zero, and gso_type
> > > > > will be VIRTIO_NET_HDR_GSO_NONE.
> > > > >
> > > > > and
> > > > > The driver MUST set num_buffers to zero.
> > > > > If VIRTIO_NET_F_CSUM is not negotiated, the driver MUST set
> > > > > flags to
> > > > > zero and SHOULD supply a fully
> > > > > checksummed packet to the device.
> > > > >
> > > > > and
> > > > > If none of the VIRTIO_NET_F_HOST_TSO4, TSO6 or UFO options have
> > > > > been
> > > > > negotiated, the driver MUST
> > > > > set gso_type to VIRTIO_NET_HDR_GSO_NONE.
> > > > >
> > > > > so doing this unconditionally would be a spec violation, but if you see
> > > > > value in this, we can add a feature bit.
> > > > Right it would be a spec violation, so it should be done conditionally.
> > > > If a feature bit is to be added, what about VIRTIO_NET_F_NO_TX_HEADER?
> > > > It would imply VIRTIO_NET_F_CSUM not set, and no GSO features set.
> > > > If negotiated, we wouldn't need to prepend a header.
> > >
> > > Yes but two points.
> > >
> > > 1. why is this memset expensive? Is the test completely skipping looking
> > > at the packet otherwise?
> > Yes.
> > >
> > > 2. As long as we are doing this, see
> > > Alignment vs. Networking
> > > ========================
> > > in Documentation/unaligned-memory-access.txt
> > Thanks, I'll have a look tomorrow.
>
> I did a rough prototype which removes Tx headers unconditionally, to
> see what gain we could expect. I expect the results to be a little lower
> with no headers in full implementation, as some more checks will have
> to be done.
>
> For PVP use-case with 0.05% acceptable packets loss:
> - Original (with headers): 9.43Mpps
> - Indirect descs: 9.36 Mpps
> - Prototype (no headers): 10.65Mpps
>
> For PVP use-case with 0% acceptable packets loss:
> - Original (with headers): 5.23Mpps
> - Indirect descs: 7.13 Mpps
> - Prototype (no headers): 7.92Mpps
>
> Maxime
^ permalink raw reply
* Re: [PATCH v2 10/10] bnx2x: Merge debug register operations into headers
From: Harish Patil @ 2016-09-30 18:16 UTC (permalink / raw)
To: Chas Williams, dev@dpdk.org
In-Reply-To: <1475144449-22176-10-git-send-email-3chas3@gmail.com>
>
>The register read/writes should just be static inline instead of
>alternately defined as routines or macros depending on the status of
>debugging.
>
>Fix bnx2x_reg_read32() returning 0 during debug unaligned reads.
>
>Fixes: b5bf7719221d ("bnx2x: driver support routines")
>
>Signed-off-by: Chas Williams <3chas3@gmail.com>
>---
> drivers/net/bnx2x/Makefile | 1 -
> drivers/net/bnx2x/bnx2x.h | 99
>+++++++++++++++++++++++++++++++++++++---------
> drivers/net/bnx2x/debug.c | 96
>--------------------------------------------
> 3 files changed, 80 insertions(+), 116 deletions(-)
> delete mode 100644 drivers/net/bnx2x/debug.c
>
>diff --git a/drivers/net/bnx2x/Makefile b/drivers/net/bnx2x/Makefile
>index ab69680..e971fb6 100644
>--- a/drivers/net/bnx2x/Makefile
>+++ b/drivers/net/bnx2x/Makefile
>@@ -28,7 +28,6 @@ SRCS-$(CONFIG_RTE_LIBRTE_BNX2X_PMD) += bnx2x_ethdev.c
> SRCS-$(CONFIG_RTE_LIBRTE_BNX2X_PMD) += ecore_sp.c
> SRCS-$(CONFIG_RTE_LIBRTE_BNX2X_PMD) += elink.c
> SRCS-$(CONFIG_RTE_LIBRTE_BNX2X_PMD) += bnx2x_vfpf.c
>-SRCS-$(CONFIG_RTE_LIBRTE_BNX2X_DEBUG_PERIODIC) += debug.c
>
> # this lib depends upon:
> DEPDIRS-$(CONFIG_RTE_LIBRTE_BNX2X_PMD) += lib/librte_eal lib/librte_ether
>diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
>index e4979ac..d1dd6aa 100644
>--- a/drivers/net/bnx2x/bnx2x.h
>+++ b/drivers/net/bnx2x/bnx2x.h
>@@ -1414,34 +1414,95 @@ struct bnx2x_func_init_params {
> #define BAR1 2
> #define BAR2 4
>
>+static inline void
>+bnx2x_reg_write8(struct bnx2x_softc *sc, size_t offset, uint8_t val)
>+{
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%02x",
>+ (unsigned long)offset, val);
>+ *((volatile uint8_t*)
>+ ((uintptr_t)sc->bar[BAR0].base_addr + offset)) = val;
>+}
>+
>+static inline void
>+bnx2x_reg_write16(struct bnx2x_softc *sc, size_t offset, uint16_t val)
>+{
>+#ifdef RTE_LIBRTE_BNX2X_DEBUG_PERIODIC
>+ if ((offset % 2) != 0)
>+ PMD_DRV_LOG(NOTICE, "Unaligned 16-bit write to 0x%08lx",
>+ (unsigned long)offset);
>+#endif
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%04x",
>+ (unsigned long)offset, val);
>+ *((volatile uint16_t*)
>+ ((uintptr_t)sc->bar[BAR0].base_addr + offset)) = val;
>+}
>+
>+static inline void
>+bnx2x_reg_write32(struct bnx2x_softc *sc, size_t offset, uint32_t val)
>+{
> #ifdef RTE_LIBRTE_BNX2X_DEBUG_PERIODIC
>-uint8_t bnx2x_reg_read8(struct bnx2x_softc *sc, size_t offset);
>-uint16_t bnx2x_reg_read16(struct bnx2x_softc *sc, size_t offset);
>-uint32_t bnx2x_reg_read32(struct bnx2x_softc *sc, size_t offset);
>+ if ((offset % 4) != 0)
>+ PMD_DRV_LOG(NOTICE, "Unaligned 32-bit write to 0x%08lx",
>+ (unsigned long)offset);
>+#endif
>
>-void bnx2x_reg_write8(struct bnx2x_softc *sc, size_t offset, uint8_t
>val);
>-void bnx2x_reg_write16(struct bnx2x_softc *sc, size_t offset, uint16_t
>val);
>-void bnx2x_reg_write32(struct bnx2x_softc *sc, size_t offset, uint32_t
>val);
>-#else
>-#define bnx2x_reg_write8(sc, offset, val)\
>- *((volatile uint8_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x",
>+ (unsigned long)offset, val);
>+ *((volatile uint32_t*)
>+ ((uintptr_t)sc->bar[BAR0].base_addr + offset)) = val;
>+}
>+
>+static inline uint8_t
>+bnx2x_reg_read8(struct bnx2x_softc *sc, size_t offset)
>+{
>+ uint8_t val;
>+
>+ val = (uint8_t)(*((volatile uint8_t*)
>+ ((uintptr_t) sc->bar[BAR0].base_addr + offset)));
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%02x",
>+ (unsigned long)offset, val);
>+
>+ return val;
>+}
>+
>+static inline uint16_t
>+bnx2x_reg_read16(struct bnx2x_softc *sc, size_t offset)
>+{
>+ uint16_t val;
>
>-#define bnx2x_reg_write16(sc, offset, val)\
>- *((volatile uint16_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val
>+#ifdef RTE_LIBRTE_BNX2X_DEBUG_PERIODIC
>+ if ((offset % 2) != 0)
>+ PMD_DRV_LOG(NOTICE, "Unaligned 16-bit read from 0x%08lx",
>+ (unsigned long)offset);
>+#endif
>
>-#define bnx2x_reg_write32(sc, offset, val)\
>- *((volatile uint32_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val
>+ val = (uint16_t)(*((volatile uint16_t*)
>+ ((uintptr_t) sc->bar[BAR0].base_addr + offset)));
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x",
>+ (unsigned long)offset, val);
>
>-#define bnx2x_reg_read8(sc, offset)\
>- (*((volatile uint8_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)))
>+ return val;
>+}
>
>-#define bnx2x_reg_read16(sc, offset)\
>- (*((volatile uint16_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)))
>+static inline uint32_t
>+bnx2x_reg_read32(struct bnx2x_softc *sc, size_t offset)
>+{
>+ uint32_t val;
>
>-#define bnx2x_reg_read32(sc, offset)\
>- (*((volatile uint32_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)))
>+#ifdef RTE_LIBRTE_BNX2X_DEBUG_PERIODIC
>+ if ((offset % 4) != 0)
>+ PMD_DRV_LOG(NOTICE, "Unaligned 32-bit read from 0x%08lx",
>+ (unsigned long)offset);
> #endif
>
>+ val = (uint32_t)(*((volatile uint32_t*)
>+ ((uintptr_t) sc->bar[BAR0].base_addr + offset)));
>+ PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x",
>+ (unsigned long)offset, val);
>+
>+ return val;
>+}
>+
> #define REG_ADDR(sc, offset) (((uint64_t)sc->bar[BAR0].base_addr) +
>(offset))
>
> #define REG_RD8(sc, offset) bnx2x_reg_read8(sc, (offset))
>diff --git a/drivers/net/bnx2x/debug.c b/drivers/net/bnx2x/debug.c
>deleted file mode 100644
>index cc50845..0000000
>--- a/drivers/net/bnx2x/debug.c
>+++ /dev/null
>@@ -1,96 +0,0 @@
>-/*-
>- * Copyright (c) 2007-2013 QLogic Corporation. All rights reserved.
>- *
>- * Eric Davis <edavis@broadcom.com>
>- * David Christensen <davidch@broadcom.com>
>- * Gary Zambrano <zambrano@broadcom.com>
>- *
>- * Copyright (c) 2013-2015 Brocade Communications Systems, Inc.
>- * Copyright (c) 2015 QLogic Corporation.
>- * All rights reserved.
>- * www.qlogic.com
>- *
>- * See LICENSE.bnx2x_pmd for copyright and licensing details.
>- */
>-
>-#include "bnx2x.h"
>-
>-
>-/*
>- * Debug versions of the 8/16/32 bit OS register read/write functions to
>- * capture/display values read/written from/to the controller.
>- */
>-void
>-bnx2x_reg_write8(struct bnx2x_softc *sc, size_t offset, uint8_t val)
>-{
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%02x", (unsigned
>long)offset, val);
>- *((volatile uint8_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val;
>-}
>-
>-void
>-bnx2x_reg_write16(struct bnx2x_softc *sc, size_t offset, uint16_t val)
>-{
>- if ((offset % 2) != 0) {
>- PMD_DRV_LOG(NOTICE, "Unaligned 16-bit write to 0x%08lx",
>- (unsigned long)offset);
>- }
>-
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%04x", (unsigned
>long)offset, val);
>- *((volatile uint16_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val;
>-}
>-
>-void
>-bnx2x_reg_write32(struct bnx2x_softc *sc, size_t offset, uint32_t val)
>-{
>- if ((offset % 4) != 0) {
>- PMD_DRV_LOG(NOTICE, "Unaligned 32-bit write to 0x%08lx",
>- (unsigned long)offset);
>- }
>-
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x", (unsigned
>long)offset, val);
>- *((volatile uint32_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)) =
>val;
>-}
>-
>-uint8_t
>-bnx2x_reg_read8(struct bnx2x_softc *sc, size_t offset)
>-{
>- uint8_t val;
>-
>- val = (uint8_t)(*((volatile
>uint8_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)));
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%02x", (unsigned
>long)offset, val);
>-
>- return val;
>-}
>-
>-uint16_t
>-bnx2x_reg_read16(struct bnx2x_softc *sc, size_t offset)
>-{
>- uint16_t val;
>-
>- if ((offset % 2) != 0) {
>- PMD_DRV_LOG(NOTICE, "Unaligned 16-bit read from 0x%08lx",
>- (unsigned long)offset);
>- }
>-
>- val = (uint16_t)(*((volatile
>uint16_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)));
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x", (unsigned
>long)offset, val);
>-
>- return val;
>-}
>-
>-uint32_t
>-bnx2x_reg_read32(struct bnx2x_softc *sc, size_t offset)
>-{
>- uint32_t val;
>-
>- if ((offset % 4) != 0) {
>- PMD_DRV_LOG(NOTICE, "Unaligned 32-bit read from 0x%08lx",
>- (unsigned long)offset);
>- return 0;
>- }
>-
>- val = (uint32_t)(*((volatile
>uint32_t*)((uintptr_t)sc->bar[BAR0].base_addr + offset)));
>- PMD_DEBUG_PERIODIC_LOG(DEBUG, "offset=0x%08lx val=0x%08x", (unsigned
>long)offset, val);
>-
>- return val;
>-}
>--
>2.7.4
>
>
There is no cover letter. So please treat this acking the series.
Acked-by: Harish Patil <harish.patil@qlogic.com>
^ permalink raw reply
* Re: [PATCH v4 4/5] app/test: added big data GMAC test for libcrypto
From: Thomas Monjalon @ 2016-09-30 17:18 UTC (permalink / raw)
To: Slawomir Mrozowicz, Piotr Azarewicz; +Cc: dev, Wei Dai
In-Reply-To: <1475253170-29727-3-git-send-email-slawomirx.mrozowicz@intel.com>
2016-09-30 18:32, Slawomir Mrozowicz:
> This patch add big data AES-GMAC test for libcrypto PMD.
>
> Signed-off-by: Piotr Azarewicz <piotrx.t.azarewicz@intel.com>
> ---
> app/test/test_cryptodev.c | 18 +-
> app/test/test_cryptodev_gcm_test_vectors.h | 8245 +++++++++++++++++++++++++++-
> 2 files changed, 8242 insertions(+), 21 deletions(-)
The test data are really too big.
Is it possible to generate them as Wei Dai did for LPM?
http://dpdk.org/patch/16175
http://dpdk.org/patch/16253
^ permalink raw reply
* Re: [PATCH v2 04/22] qede/base: update base driver
From: Ferruh Yigit @ 2016-09-30 16:44 UTC (permalink / raw)
To: Rasesh Mody, dev; +Cc: Dept-EngDPDKDev, Bruce Richardson, Thomas Monjalon
In-Reply-To: <1475219169-8774-5-git-send-email-rasesh.mody@qlogic.com>
Hi Rasesh,
On 9/30/2016 8:05 AM, Rasesh Mody wrote:
> This patch updates the base driver and incorporates necessary changes
> required to bring in the new firmware 8.10.9.0.
>
> In addition, it would allow driver to add new functionalities that might
> be needed in future.
>
> Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
> ---
> doc/guides/nics/features/qede.ini | 2 +
> doc/guides/nics/features/qede_vf.ini | 2 +
> doc/guides/nics/qede.rst | 15 +-
> drivers/net/qede/Makefile | 4 +
> drivers/net/qede/base/bcm_osal.c | 21 +
> drivers/net/qede/base/bcm_osal.h | 10 +
> drivers/net/qede/base/common_hsi.h | 1257 ++++++++++++++++++---
> drivers/net/qede/base/ecore.h | 172 ++-
> drivers/net/qede/base/ecore_chain.h | 31 +-
> drivers/net/qede/base/ecore_cxt.c | 371 +++++-
> drivers/net/qede/base/ecore_cxt.h | 52 +-
> drivers/net/qede/base/ecore_cxt_api.h | 15 -
> drivers/net/qede/base/ecore_dcbx.c | 587 +++++++++-
> drivers/net/qede/base/ecore_dcbx.h | 18 +-
> drivers/net/qede/base/ecore_dcbx_api.h | 128 ++-
> drivers/net/qede/base/ecore_dev.c | 1627 ++++++++++++++++++++-------
> drivers/net/qede/base/ecore_dev_api.h | 129 ++-
> drivers/net/qede/base/ecore_gtt_reg_addr.h | 10 +
> drivers/net/qede/base/ecore_hsi_common.h | 1146 ++++++++++++++-----
> drivers/net/qede/base/ecore_hsi_eth.h | 991 ++++++++++++----
> drivers/net/qede/base/ecore_hw.c | 214 ++--
> drivers/net/qede/base/ecore_hw.h | 47 +-
> drivers/net/qede/base/ecore_hw_defs.h | 33 +-
> drivers/net/qede/base/ecore_init_fw_funcs.c | 327 ++++--
> drivers/net/qede/base/ecore_init_fw_funcs.h | 182 ++-
> drivers/net/qede/base/ecore_init_ops.c | 5 +-
> drivers/net/qede/base/ecore_init_ops.h | 14 +-
> drivers/net/qede/base/ecore_int.c | 313 +++---
> drivers/net/qede/base/ecore_int.h | 19 +-
> drivers/net/qede/base/ecore_int_api.h | 11 +
> drivers/net/qede/base/ecore_iov_api.h | 473 ++------
> drivers/net/qede/base/ecore_iro.h | 222 ++--
> drivers/net/qede/base/ecore_iro_values.h | 108 +-
> drivers/net/qede/base/ecore_l2.c | 407 +++----
> drivers/net/qede/base/ecore_l2.h | 57 +-
> drivers/net/qede/base/ecore_l2_api.h | 18 +-
> drivers/net/qede/base/ecore_mcp.c | 707 +++++++++---
> drivers/net/qede/base/ecore_mcp.h | 85 +-
> drivers/net/qede/base/ecore_mcp_api.h | 194 +++-
> drivers/net/qede/base/ecore_proto_if.h | 59 +
> drivers/net/qede/base/ecore_rt_defs.h | 639 +++++------
> drivers/net/qede/base/ecore_sp_api.h | 5 +-
> drivers/net/qede/base/ecore_sp_commands.c | 83 +-
> drivers/net/qede/base/ecore_sp_commands.h | 30 +
> drivers/net/qede/base/ecore_spq.c | 181 +--
> drivers/net/qede/base/ecore_spq.h | 26 +-
> drivers/net/qede/base/ecore_sriov.c | 1596 ++++++++++++++++----------
> drivers/net/qede/base/ecore_sriov.h | 149 +--
> drivers/net/qede/base/ecore_vf.c | 736 +++++++-----
> drivers/net/qede/base/ecore_vf.h | 224 +---
> drivers/net/qede/base/ecore_vf_api.h | 93 +-
> drivers/net/qede/base/ecore_vfpf_if.h | 165 ++-
> drivers/net/qede/base/eth_common.h | 387 ++++---
> drivers/net/qede/base/mcp_public.h | 629 +++++++++--
> drivers/net/qede/base/nvm_cfg.h | 623 ++++++++--
> drivers/net/qede/base/reg_addr.h | 36 +
> drivers/net/qede/qede_eth_if.c | 1 +
> drivers/net/qede/qede_main.c | 20 +-
> drivers/net/qede/qede_rxtx.h | 4 +
> 59 files changed, 10857 insertions(+), 4853 deletions(-)
Thank you for the update, base driver patch update now reduced from
"14653 insertions(+), 8536 deletions(-)" to
"10857 insertions(+), 4853 deletions(-)"
But this is still to big for reviewing, specially there are some low
hanging fruits for cleanup, like big chunk of comment updates or
whitespace updates or non base driver codes in the patch.
If the expectation is that somebody non maintainer review the code,
understand it and highlight any possible defects, I believe this patch
is too big and needs to be split more into logical pieces,
but since this is a driver code and a little special, and it may not be
possible to completely understand the code without knowing underlying
hardware, I am not sure how to proceed and adding Bruce and Thomas to cc
for guidance.
Thanks,
ferruh
^ permalink raw reply
* Re: [PATCH] log: do not drop debug logs at compile time
From: Wiles, Keith @ 2016-09-30 15:48 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev@dpdk.org, Olivier Matz, david.marchand@6wind.com
In-Reply-To: <2969629.OOuc7vtRSA@xps13>
Regards,
Keith
> On Sep 30, 2016, at 4:33 AM, Thomas Monjalon <thomas.monjalon@6wind.com> wrote:
>
> 2016-09-16 09:43, Olivier Matz:
>> Today, all logs whose level is lower than INFO are dropped at
>> compile-time. This prevents from enabling debug logs at runtime using
>> --log-level=8.
>>
>> The rationale was to remove debug logs from the data path at
>> compile-time, avoiding a test at run-time.
>>
>> This patch changes the behavior of RTE_LOG() to avoid the compile-time
>> optimization, and introduces the RTE_LOG_DP() macro that has the same
>> behavior than the previous RTE_LOG(), for the rare cases where debug
>> logs are in the data path.
>>
>> So it is now possible to enable debug logs at run-time by just
>> specifying --log-level=8. Some drivers still have special compile-time
>> options to enable more debug log. Maintainers may consider to
>> remove/reduce them.
>>
>> Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
>
> I think it is a good change.
> However I'm not sure we should take it for 16.11 as it was sent late and
> there is no review comment.
> It is neither really a fix nor really a feature.
> If there are some +1, and no opinions against, it will go in 16.11.
> Note that some drivers would need some changes to fully benefit of
> debug logs enabled at run-time.
Would this be easier to add a new LOG level instead say DEBUG_DATAPATH and then change the RTE_LOG to exclude the new log level?
^ permalink raw reply
* [PATCH v3 2/2] net/ixgbe: add callback to user app on VF to PF mbox msg
From: Bernard Iremonger @ 2016-09-30 15:45 UTC (permalink / raw)
To: dev, rahul.r.shah, wenzhuo.lu, az5157, jerin.jacob; +Cc: Bernard Iremonger
In-Reply-To: <1475250308-5498-1-git-send-email-bernard.iremonger@intel.com>
call _rte_eth_dev_callback_process_vf from ixgbe_rcv_msg_from_vf function.
The callback asks the user application if it is allowed to perform
the function.
If the cb_param.retval is RTE_PMD_IXGBE_MB_EVENT_PROCEED then continue,
if 0, do nothing and send ACK to VF
if > 1, do nothing and send NAK to VF.
Signed-off-by: Alex Zelezniak <az5157@att.com>
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
drivers/net/ixgbe/ixgbe_pf.c | 42 +++++++++++++++++++++++++++++++++------
drivers/net/ixgbe/rte_pmd_ixgbe.h | 11 ++++++++++
2 files changed, 47 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_pf.c b/drivers/net/ixgbe/ixgbe_pf.c
index 56393ff..3c5bf38 100644
--- a/drivers/net/ixgbe/ixgbe_pf.c
+++ b/drivers/net/ixgbe/ixgbe_pf.c
@@ -1,7 +1,7 @@
/*-
* BSD LICENSE
*
- * Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ * Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@
#include "base/ixgbe_common.h"
#include "ixgbe_ethdev.h"
+#include "rte_pmd_ixgbe.h"
#define IXGBE_MAX_VFTA (128)
#define IXGBE_VF_MSG_SIZE_DEFAULT 1
@@ -660,6 +661,7 @@ ixgbe_rcv_msg_from_vf(struct rte_eth_dev *dev, uint16_t vf)
struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
struct ixgbe_vf_info *vfinfo =
*IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private);
+ struct rte_eth_mb_event_param cb_param;
retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
if (retval) {
@@ -674,27 +676,54 @@ ixgbe_rcv_msg_from_vf(struct rte_eth_dev *dev, uint16_t vf)
/* flush the ack before we write any messages back */
IXGBE_WRITE_FLUSH(hw);
+ /**
+ * initialise structure to send to user application
+ * will return response from user in retval field
+ */
+ cb_param.retval = RTE_PMD_IXGBE_MB_EVENT_PROCEED;
+ cb_param.vfid = vf;
+ cb_param.msg_type = msgbuf[0] & 0xFFFF;
+ cb_param.userdata = (void *)msgbuf;
+
/* perform VF reset */
if (msgbuf[0] == IXGBE_VF_RESET) {
int ret = ixgbe_vf_reset(dev, vf, msgbuf);
vfinfo[vf].clear_to_send = true;
+
+ /* notify application about VF reset */
+ _rte_eth_dev_callback_process_vf(dev, RTE_ETH_EVENT_VF_MBOX, &cb_param);
return ret;
}
+ /**
+ * ask user application if we allowed to perform those functions
+ * if we get cb_param.retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED then business
+ * as usual,
+ * if 0, do nothing and send ACK to VF
+ * if cb_param.retval > 1, do nothing and send NAK to VF
+ */
+ _rte_eth_dev_callback_process_vf(dev, RTE_ETH_EVENT_VF_MBOX, &cb_param);
+
+ retval = cb_param.retval;
+
/* check & process VF to PF mailbox message */
switch ((msgbuf[0] & 0xFFFF)) {
case IXGBE_VF_SET_MAC_ADDR:
- retval = ixgbe_vf_set_mac_addr(dev, vf, msgbuf);
+ if (retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED)
+ retval = ixgbe_vf_set_mac_addr(dev, vf, msgbuf);
break;
case IXGBE_VF_SET_MULTICAST:
- retval = ixgbe_vf_set_multicast(dev, vf, msgbuf);
+ if (retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED)
+ retval = ixgbe_vf_set_multicast(dev, vf, msgbuf);
break;
case IXGBE_VF_SET_LPE:
- retval = ixgbe_set_vf_lpe(dev, vf, msgbuf);
+ if (retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED)
+ retval = ixgbe_set_vf_lpe(dev, vf, msgbuf);
break;
case IXGBE_VF_SET_VLAN:
- retval = ixgbe_vf_set_vlan(dev, vf, msgbuf);
+ if (retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED)
+ retval = ixgbe_vf_set_vlan(dev, vf, msgbuf);
break;
case IXGBE_VF_API_NEGOTIATE:
retval = ixgbe_negotiate_vf_api(dev, vf, msgbuf);
@@ -704,7 +733,8 @@ ixgbe_rcv_msg_from_vf(struct rte_eth_dev *dev, uint16_t vf)
msg_size = IXGBE_VF_GET_QUEUE_MSG_SIZE;
break;
case IXGBE_VF_UPDATE_XCAST_MODE:
- retval = ixgbe_set_vf_mc_promisc(dev, vf, msgbuf);
+ if (retval == RTE_PMD_IXGBE_MB_EVENT_PROCEED)
+ retval = ixgbe_set_vf_mc_promisc(dev, vf, msgbuf);
break;
default:
PMD_DRV_LOG(DEBUG, "Unhandled Msg %8.8x", (unsigned)msgbuf[0]);
diff --git a/drivers/net/ixgbe/rte_pmd_ixgbe.h b/drivers/net/ixgbe/rte_pmd_ixgbe.h
index 33b5b2d..212cc5d 100644
--- a/drivers/net/ixgbe/rte_pmd_ixgbe.h
+++ b/drivers/net/ixgbe/rte_pmd_ixgbe.h
@@ -181,4 +181,15 @@ int rte_pmd_ixgbe_set_vf_split_drop_en(uint8_t port, uint16_t vf, uint8_t on);
*/
int
rte_pmd_ixgbe_set_vf_vlan_stripq(uint8_t port, uint16_t vf, uint8_t on);
+
+/**
+ * Response sent back to ixgbe driver from user app after callback
+ */
+enum rte_pmd_ixgbe_mb_event_rsp {
+ RTE_PMD_IXGBE_MB_EVENT_NOOP_ACK, /**< skip mbox request and ACK */
+ RTE_PMD_IXGBE_MB_EVENT_NOOP_NACK, /**< skip mbox request and NACK */
+ RTE_PMD_IXGBE_MB_EVENT_PROCEED, /**< proceed with mbox request */
+ RTE_PMD_IXGBE_MB_EVENT_MAX /**< max value of this enum */
+};
+
#endif /* _PMD_IXGBE_H_ */
--
2.9.0
^ permalink raw reply related
* [PATCH v3 1/2] librte_ether: add internal callback functions
From: Bernard Iremonger @ 2016-09-30 15:45 UTC (permalink / raw)
To: dev, rahul.r.shah, wenzhuo.lu, az5157, jerin.jacob; +Cc: Bernard Iremonger
In-Reply-To: <1475250308-5498-1-git-send-email-bernard.iremonger@intel.com>
add _rte_eth_dev_callback_process_vf function.
add _rte_eth_dev_callback_process_generic function
Adding a callback to the user application on VF to PF mailbox message,
allows passing information to the application controlling the PF
when a VF mailbox event message is received, such as VF reset.
Signed-off-by: Alex Zelezniak <az5157@att.com>
Signed-off-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
lib/librte_ether/rte_ethdev.c | 17 ++++++++++++
lib/librte_ether/rte_ethdev.h | 51 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 7 +++++
3 files changed, 75 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 382c959..6d93fcf 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2689,6 +2689,20 @@ void
_rte_eth_dev_callback_process(struct rte_eth_dev *dev,
enum rte_eth_event_type event)
{
+ return _rte_eth_dev_callback_process_generic(dev, event, NULL);
+}
+
+void
+_rte_eth_dev_callback_process_vf(struct rte_eth_dev *dev,
+ enum rte_eth_event_type event, void *param)
+{
+ return _rte_eth_dev_callback_process_generic(dev, event, param);
+}
+
+void
+_rte_eth_dev_callback_process_generic(struct rte_eth_dev *dev,
+ enum rte_eth_event_type event, void *param)
+{
struct rte_eth_dev_callback *cb_lst;
struct rte_eth_dev_callback dev_cb;
@@ -2698,6 +2712,9 @@ _rte_eth_dev_callback_process(struct rte_eth_dev *dev,
continue;
dev_cb = *cb_lst;
cb_lst->active = 1;
+ if (param != NULL)
+ dev_cb.cb_arg = (void *) param;
+
rte_spinlock_unlock(&rte_eth_dev_cb_lock);
dev_cb.cb_fn(dev->data->port_id, dev_cb.event,
dev_cb.cb_arg);
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 96575e8..a61905c 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3051,9 +3051,17 @@ enum rte_eth_event_type {
/**< queue state event (enabled/disabled) */
RTE_ETH_EVENT_INTR_RESET,
/**< reset interrupt event, sent to VF on PF reset */
+ RTE_ETH_EVENT_VF_MBOX, /**< PF mailbox processing callback */
RTE_ETH_EVENT_MAX /**< max value of this enum */
};
+struct rte_eth_mb_event_param {
+ uint16_t vfid;
+ uint16_t msg_type;
+ uint16_t retval;
+ void *userdata;
+};
+
typedef void (*rte_eth_dev_cb_fn)(uint8_t port_id, \
enum rte_eth_event_type event, void *cb_arg);
/**< user application callback to be registered for interrupts */
@@ -3118,6 +3126,49 @@ void _rte_eth_dev_callback_process(struct rte_eth_dev *dev,
enum rte_eth_event_type event);
/**
+ * @internal Executes all the user application registered callbacks for
+ * the specific device where parameter have to be passed to user application.
+ * It is for DPDK internal user only. User application should not call it
+ * directly.
+ *
+ * @param dev
+ * Pointer to struct rte_eth_dev.
+ * @param event
+ * Eth device interrupt event type.
+ *
+ * @param param
+ * parameters to pass back to user application.
+ *
+ * @return
+ * void
+ */
+
+void
+_rte_eth_dev_callback_process_vf(struct rte_eth_dev *dev,
+ enum rte_eth_event_type event, void *param);
+
+/**
+ * @internal Executes all the user application registered callbacks. Used by:
+ * _rte_eth_dev_callback_process and _rte_eth_dev_callback_process_vf
+ * It is for DPDK internal user only. User application should not call it
+ * directly.
+ *
+ * @param dev
+ * Pointer to struct rte_eth_dev.
+ * @param event
+ * Eth device interrupt event type.
+ *
+ * @param param
+ * parameters to pass back to user application.
+ *
+ * @return
+ * void
+ */
+void
+_rte_eth_dev_callback_process_generic(struct rte_eth_dev *dev,
+ enum rte_eth_event_type event, void *param);
+
+/**
* When there is no rx packet coming in Rx Queue for a long time, we can
* sleep lcore related to RX Queue for power saving, and enable rx interrupt
* to be triggered when rx packect arrives.
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 45ddf44..cb7ef15 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -139,3 +139,10 @@ DPDK_16.07 {
rte_eth_dev_get_port_by_name;
rte_eth_xstats_get_names;
} DPDK_16.04;
+
+DPDK_16.11 {
+ global:
+
+ _rte_eth_dev_callback_process_generic;
+ _rte_eth_dev_callback_process_vf;
+} DPDK_16.07;
--
2.9.0
^ permalink raw reply related
* [PATCH v3 0/2] add callbacks for VF management
From: Bernard Iremonger @ 2016-09-30 15:45 UTC (permalink / raw)
To: dev, rahul.r.shah, wenzhuo.lu, az5157, jerin.jacob; +Cc: Bernard Iremonger
This patchset contains new callback functions requested by AT&T for use
with the Virtual Function Daemon (VFD).
Two new callback functions have been added.
Changes have been made to the ixgbe_rcv_msg_from_vf function to
use the callback functions.
This patchset depends on the following patch.
http://dpdk.org/dev/patchwork/patch/16296/
[dpdk-dev,v6,1/2] net/ixgbe: add API's for VF management
These patches were part of the RFC PATCH v2 of the above patchset,
but were dropped from the v3 patchset.
Changes in v3:
rebase to latest master
submitted as a seperate patchset.
Moved the response enums from the ethdev to the ixgbe PMD.
Bernard Iremonger (2):
librte_ether: add internal callback functions
net/ixgbe: add callback to user app on VF to PF mbox msg
drivers/net/ixgbe/ixgbe_pf.c | 42 ++++++++++++++++++++++++----
drivers/net/ixgbe/rte_pmd_ixgbe.h | 11 ++++++++
lib/librte_ether/rte_ethdev.c | 17 ++++++++++++
lib/librte_ether/rte_ethdev.h | 51 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 7 +++++
5 files changed, 122 insertions(+), 6 deletions(-)
--
2.9.0
^ permalink raw reply
* Re: [PATCH v1 0/4] Generalize PCI specific EAL function/structures
From: David Marchand @ 2016-09-30 15:31 UTC (permalink / raw)
To: Shreyansh Jain; +Cc: dev@dpdk.org, Jan Viktorin, Thomas Monjalon
In-Reply-To: <1474985551-14219-1-git-send-email-shreyansh.jain@nxp.com>
On Tue, Sep 27, 2016 at 4:12 PM, Shreyansh Jain <shreyansh.jain@nxp.com> wrote:
> (I rebased these over HEAD 7b3c4f3)
>
> These patches were initially part of Jan's original series on SoC
> Framework ([1],[2]). An update to that series, without these patches,
> was posted here [3].
>
> Main motivation for these is aim of introducing a non-PCI centric
> subsystem in EAL. As of now the first usecase is SoC, but not limited to
> it.
>
> 4 patches in this series are independent of each other, as well as SoC
> framework. All these focus on generalizing some structure or functions
> present with the PCI specific code to EAL Common area (or splitting a
> function to be more userful).
Those patches move linux specifics (binding pci devices using sysfs)
to common infrastucture.
We have no proper hotplug support on bsd, but if we had some common
code we should at least try to make the apis generic.
--
David Marchand
^ permalink raw reply
* Re: [PATCH] pci:fix missing free
From: David Marchand @ 2016-09-30 15:27 UTC (permalink / raw)
To: Thomas Monjalon; +Cc: dev@dpdk.org, stable, Yangchao Zhou
In-Reply-To: <CALwxeUtVz_A-xqRN2xEwicuxv9mru=BUivKCLf_0BG3ZtC4Vnw@mail.gmail.com>
On Fri, Sep 30, 2016 at 5:19 PM, David Marchand
<david.marchand@6wind.com> wrote:
> Hello,
>
> On Thu, Sep 29, 2016 at 3:41 AM, Yangchao Zhou <zhouyates@gmail.com> wrote:
>> Signed-off-by: Yangchao Zhou <zhouyates@gmail.com>
>> ---
>> lib/librte_eal/common/eal_common_pci.c | 1 +
>> 1 files changed, 1 insertions(+), 0 deletions(-)
>>
>> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
>> index 7248c38..eb44998 100644
>> --- a/lib/librte_eal/common/eal_common_pci.c
>> +++ b/lib/librte_eal/common/eal_common_pci.c
>> @@ -378,6 +378,7 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
>> goto err_return;
>>
>> TAILQ_REMOVE(&pci_device_list, dev, next);
>> + free(dev);
>> return 0;
>> }
>> return -1;
>> --
>> 1.7.1
>>
>
> For the title, how about:
> pci: fix memory leak when detaching devices
>
> Afaics the fixes tag would be :
>
> Fixes: dbe6b4b61b0e ("pci: probe or close device")
>
> + CC stable
Thomas, can you apply this with my ack ?
Thanks.
--
David Marchand
^ permalink raw reply
* Re: [PATCH] pci:fix missing free
From: David Marchand @ 2016-09-30 15:19 UTC (permalink / raw)
To: Yangchao Zhou; +Cc: Thomas Monjalon, dev@dpdk.org, stable
In-Reply-To: <1475113270-21983-1-git-send-email-zhouyates@gmail.com>
Hello,
On Thu, Sep 29, 2016 at 3:41 AM, Yangchao Zhou <zhouyates@gmail.com> wrote:
> Signed-off-by: Yangchao Zhou <zhouyates@gmail.com>
> ---
> lib/librte_eal/common/eal_common_pci.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/lib/librte_eal/common/eal_common_pci.c b/lib/librte_eal/common/eal_common_pci.c
> index 7248c38..eb44998 100644
> --- a/lib/librte_eal/common/eal_common_pci.c
> +++ b/lib/librte_eal/common/eal_common_pci.c
> @@ -378,6 +378,7 @@ rte_eal_pci_detach(const struct rte_pci_addr *addr)
> goto err_return;
>
> TAILQ_REMOVE(&pci_device_list, dev, next);
> + free(dev);
> return 0;
> }
> return -1;
> --
> 1.7.1
>
For the title, how about:
pci: fix memory leak when detaching devices
Afaics the fixes tag would be :
Fixes: dbe6b4b61b0e ("pci: probe or close device")
+ CC stable
--
David Marchand
^ permalink raw reply
* Re: [PATCH v2 13/15] net/thunderx: document secondary queue set support
From: Mcnamara, John @ 2016-09-30 15:12 UTC (permalink / raw)
To: Kamil Rytarowski, dev@dpdk.org
Cc: maciej.czekaj@caviumnetworks.com, zyta.szpak@semihalf.com,
slawomir.rosek@semihalf.com, rad@semihalf.com,
jerin.jacob@caviumnetworks.com, Yigit, Ferruh, Kamil Rytarowski
In-Reply-To: <1475237154-25388-14-git-send-email-krytarowski@caviumnetworks.com>
> -----Original Message-----
> From: Kamil Rytarowski [mailto:krytarowski@caviumnetworks.com]
> Sent: Friday, September 30, 2016 1:06 PM
> To: dev@dpdk.org
> Cc: maciej.czekaj@caviumnetworks.com; zyta.szpak@semihalf.com;
> slawomir.rosek@semihalf.com; rad@semihalf.com;
> jerin.jacob@caviumnetworks.com; Yigit, Ferruh <ferruh.yigit@intel.com>;
> Mcnamara, John <john.mcnamara@intel.com>; Kamil Rytarowski
> <kamil.rytarowski@caviumnetworks.com>
> Subject: [PATCH v2 13/15] net/thunderx: document secondary queue set
> support
>
> From: Kamil Rytarowski <kamil.rytarowski@caviumnetworks.com>
>
> Signed-off-by: Maciej Czekaj <maciej.czekaj@caviumnetworks.com>
> Signed-off-by: Kamil Rytarowski <kamil.rytarowski@caviumnetworks.com>
> Signed-off-by: Zyta Szpak <zyta.szpak@semihalf.com>
> Signed-off-by: Slawomir Rosek <slawomir.rosek@semihalf.com>
> Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
> Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH v2 21/22] doc: update qede pmd documentation
From: Mcnamara, John @ 2016-09-30 15:11 UTC (permalink / raw)
To: Rasesh Mody, dev@dpdk.org; +Cc: Dept-EngDPDKDev@qlogic.com
In-Reply-To: <1475219169-8774-22-git-send-email-rasesh.mody@qlogic.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Rasesh Mody
> Sent: Friday, September 30, 2016 8:06 AM
> To: dev@dpdk.org
> Cc: Dept-EngDPDKDev@qlogic.com; Rasesh Mody <rasesh.mody@qlogic.com>
> Subject: [dpdk-dev] [PATCH v2 21/22] doc: update qede pmd documentation
>
> Signed-off-by: Rasesh Mody <rasesh.mody@qlogic.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH v3] doc: add limitations for i40e PMD
From: Mcnamara, John @ 2016-09-30 15:09 UTC (permalink / raw)
To: Wu, Jingjing, dev@dpdk.org; +Cc: Xing, Beilei
In-Reply-To: <1475217983-6906-1-git-send-email-jingjing.wu@intel.com>
> -----Original Message-----
> From: Wu, Jingjing
> Sent: Friday, September 30, 2016 7:46 AM
> To: dev@dpdk.org
> Cc: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei
> <beilei.xing@intel.com>; Mcnamara, John <john.mcnamara@intel.com>
> Subject: [PATCH v3] doc: add limitations for i40e PMD
>
> This patch adds "Limitations or Known issues" section for i40e PMD,
> including two items:
> 1. MPLS packet classification on X710/XL710 2. 16 Byte Descriptor cannot
> be used on DPDK VF 3. Link down with i40e kernel driver after DPDK
> application exist
>
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH v3 9/9] doc: update ipsec-secgw sample app guide
From: Mcnamara, John @ 2016-09-30 15:04 UTC (permalink / raw)
To: Gonzalez Monroy, Sergio, dev@dpdk.org; +Cc: De Lara Guarch, Pablo
In-Reply-To: <1475163857-142366-11-git-send-email-sergio.gonzalez.monroy@intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Thursday, September 29, 2016 4:44 PM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>
> Subject: [dpdk-dev] [PATCH v3 9/9] doc: update ipsec-secgw sample app
> guide
>
> Update sample guide to reflect support for new algorithms.
>
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH 4/4] bnxt: Update the Broadcom PMD driver documentation
From: Mcnamara, John @ 2016-09-30 15:07 UTC (permalink / raw)
To: Ajit Khaparde, dev@dpdk.org
In-Reply-To: <20160929170408.GA52227@C02PT1RBG8WP.aus.broadcom.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ajit Khaparde
> Sent: Thursday, September 29, 2016 6:04 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH 4/4] bnxt: Update the Broadcom PMD driver
> documentation
>
> This patch reformats the Broadcom PMD driver documentation based on
> recommendations from previous review referenced below:
> http://dpdk.org/dev/patchwork/patch/16144/
>
> Also since the PMD now loads on a VF interface, update the documentation
> accordingly.
>
> Signed-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH v3 8/9] doc: ipsec-secgw release notes
From: Mcnamara, John @ 2016-09-30 15:04 UTC (permalink / raw)
To: Gonzalez Monroy, Sergio, dev@dpdk.org; +Cc: De Lara Guarch, Pablo
In-Reply-To: <1475163857-142366-9-git-send-email-sergio.gonzalez.monroy@intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Sergio Gonzalez
> Monroy
> Sent: Thursday, September 29, 2016 4:44 PM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>
> Subject: [dpdk-dev] [PATCH v3 8/9] doc: ipsec-secgw release notes
>
> Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply
* Re: [PATCH v5 0/2] app/testpmd: improve multiprocess support
From: Pattan, Reshma @ 2016-09-30 15:03 UTC (permalink / raw)
To: Kerlin, MarcinX, dev@dpdk.org
Cc: De Lara Guarch, Pablo, thomas.monjalon@6wind.com, Kerlin, MarcinX
In-Reply-To: <1475244055-6309-1-git-send-email-marcinx.kerlin@intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Marcin Kerlin
> Sent: Friday, September 30, 2016 3:01 PM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>;
> thomas.monjalon@6wind.com; Kerlin, MarcinX <marcinx.kerlin@intel.com>
> Subject: [dpdk-dev] [PATCH v5 0/2] app/testpmd: improve multiprocess support
>
> This patch ensure not overwrite device data in the multiprocess application.
>
> 1)Changes in the library introduces continuity in array rte_eth_dev_data[] shared
> between all processes. Secondary process adds new entries in free space instead
> of overwriting existing entries.
>
> 2)Changes in application testpmd allow secondary process to attach the
> mempool created by primary process rather than create new and in the case of
> quit or force quit to free devices data from shared array rte_eth_dev_data[].
>
> -------------------------
> How to reproduce the bug:
>
> 1) Run primary process:
> ./testpmd -c 0xf -n 4 --socket-mem='512,0' -w 03:00.1 -w 03:00.0 --proc-
> type=primary --file-prefix=xz1 -- -i
>
> (gdb) print rte_eth_devices[0].data.name
> $52 = "3:0.1"
> (gdb) print rte_eth_devices[1].data.name
> $53 = "3:0.0"
>
> 2) Run secondary process:
> ./testpmd -c 0xf0 --socket-mem='512,0' -n 4 -v -b 03:00.1 -b 03:00.0 --vdev
> 'eth_pcap0,rx_pcap=/var/log/device1.pcap, tx_pcap=/var/log/device2.pcap'
> --proc-type=secondary --file-prefix=xz1 -- -i
>
> (gdb) print rte_eth_devices[0].data.name
> $52 = "eth_pcap0"
> (gdb) print rte_eth_devices[1].data.name
> $53 = "eth_pcap1"
>
> 3) Go back to the primary and re-check:
> (gdb) print rte_eth_devices[0].data.name
> $54 = "eth_pcap0"
> (gdb) print rte_eth_devices[1].data.name
> $55 = "eth_pcap1"
>
> It means that secondary process overwrite data of primary process.
>
> This patch fix it and now if we go back to the primary and re-check then
> everything is fine:
> (gdb) print rte_eth_devices[0].data.name
> $56 = "3:0.1"
> (gdb) print rte_eth_devices[1].data.name
> $57 = "3:0.0"
>
> So after this fix structure rte_eth_dev_data[] will keep all data one after the
> other instead of overwriting:
> (gdb) print rte_eth_dev_data[0].name
> $52 = "3:0.1"
> (gdb) print rte_eth_dev_data[1].name
> $53 = "3:0.0"
> (gdb) print rte_eth_dev_data[2].name
> $54 = "eth_pcap0"
> (gdb) print rte_eth_dev_data[3].name
> $55 = "eth_pcap1"
> and so on will be append in the next indexes
>
> If secondary process will be turned off then also will be deleted from array:
> (gdb) print rte_eth_dev_data[0].name
> $52 = "3:0.1"
> (gdb) print rte_eth_dev_data[1].name
> $53 = "3:0.0"
> (gdb) print rte_eth_dev_data[2].name
> $54 = ""
> (gdb) print rte_eth_dev_data[3].name
> $55 = ""
> this also allows re-use index 2 and 3 for next another process
> -------------------------
>
> Breaking ABI:
> Changes in the library librte_ether causes extending existing structure
> rte_eth_dev_data with a new field lock. The reason is that this structure is
> sharing between all the processes so it should be protected against attempting
> to write from two different processes.
>
> Tomasz Kulasek sent announce ABI change in librte_ether on 21 July 2016.
> I would like to join to this breaking ABI, if it is possible.
>
> v2:
> * fix syntax error in version script
> v3:
> * changed scope of function
> * improved description
> v4:
> * fix syntax error in version script
> v5:
> * fix header file
>
> Marcin Kerlin (2):
> librte_ether: add protection against overwrite device data
> app/testpmd: improve handling of multiprocess
>
> app/test-pmd/testpmd.c | 37 +++++++++++++-
> app/test-pmd/testpmd.h | 1 +
> lib/librte_ether/rte_ethdev.c | 90 +++++++++++++++++++++++++++++++---
> lib/librte_ether/rte_ethdev.h | 12 +++++
> lib/librte_ether/rte_ether_version.map | 6 +++
> 5 files changed, 136 insertions(+), 10 deletions(-)
>
> --
> 1.9.1
Acked-by: Reshma Pattan <reshma.pattan@intel.com>
^ permalink raw reply
* Re: [PATCH v5 2/2] app/testpmd: improve handling of multiprocess
From: Pattan, Reshma @ 2016-09-30 15:02 UTC (permalink / raw)
To: Kerlin, MarcinX, dev@dpdk.org
Cc: De Lara Guarch, Pablo, thomas.monjalon@6wind.com, Kerlin, MarcinX
In-Reply-To: <1475245454-6396-1-git-send-email-marcinx.kerlin@intel.com>
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Marcin Kerlin
> Sent: Friday, September 30, 2016 3:24 PM
> To: dev@dpdk.org
> Cc: De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>;
> thomas.monjalon@6wind.com; Kerlin, MarcinX <marcinx.kerlin@intel.com>
> Subject: [dpdk-dev] [PATCH v5 2/2] app/testpmd: improve handling of
> multiprocess
>
> Added lookup for pool name because secondary process should attach to
> mempool created by primary process rather than create new one.
>
> Added function free_shared_dev_data() used at the exit of the testpmd.
> This causes detach devices data from array rte_eth_dev_data[] shared between
> all processes. This allows to have a up-to-date list of devices data and run again
> secondary application with the same name.
>
> Signed-off-by: Marcin Kerlin <marcinx.kerlin@intel.com>
Acked-by: Reshma Pattan <reshma.pattan@intel.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox