@@ -261,6 +261,8 @@ Chelsio cxgbe
M: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
F: drivers/net/cxgbe/
F: doc/guides/nics/cxgbe.rst
+F: examples/test-cxgbe-filters/
+F: doc/guides/sample_app_ug/test_cxgbe_filters.rst
Cisco enic
M: John Daley <johndale@cisco.com>
@@ -73,6 +73,7 @@ Sample Applications User Guide
proc_info
ptpclient
performance_thread
+ test_cxgbe_filters
**Figures**
new file mode 100644
@@ -0,0 +1,694 @@
+.. BSD LICENSE
+ Copyright 2015-2016 Chelsio Communications.
+ 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 Chelsio Communications 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.
+
+Test CXGBE Filters Application
+==============================
+
+The test cxgbe filters application provides a command line interface to
+test Chelsio NIC packet classification and filtering features available
+in hardware.
+
+Overview
+--------
+
+Chelsio T5 NICs support packet classification and filtering in hardware.
+This feature can be used in the ingress path to:
+
+- Steer ingress packets that meet ACL (Access Control List) accept criteria
+ to a particular receive queue.
+
+- Switch (proxy) ingress packets that meet ACL accept criteria to an output
+ port, with optional header rewrite.
+
+- Drop ingress packets that fail ACL accept criteria.
+
+There are two types of filters that can be set, namely LE-TCAM (Maskfull)
+filters and HASH (Maskless) filters. LE-TCAM filters allow specifying masks
+to the accept criteria to allow specifying a match for a range of values;
+whereas, HASH filters ignore masks and hence enforce a more strict accept
+criteria.
+
+The fields that can be specified for the accept criteria are based on the
+filter selection combination set in the firmware configuration (t5-config.txt)
+file flashed. Please see *CXGBE Poll Mode Driver NIC Guide* for instructions
+on how to flash the firmware configuration file onto Chelsio NICs.
+
+By default, the selection combination automatically includes source/
+destination IPV4/IPV6 address, and source/destination layer 4 port
+addresses. In addition to the above, more combinations can be added by
+modifying the t5-config.txt firmware configuration file.
+
+For example, consider the following combination that has been set in
+t5-config.txt:
+
+.. code-block:: console
+
+ filterMode = ethertype, protocol, tos, vlan, port
+ filterMask = ethertype, protocol, tos, vlan, port
+
+In the above example, in addition to source/destination IPV4/IPV6
+addresses and layer 4 source/destination port addresses, a packet can also
+be matched against ethertype field set in the ethernet header, IP protocol
+and tos field set in the IP header, inner VLAN tag, and physical ingress
+port number, respectively.
+
+You can create 496 LE-TCAM filters and ~0.5 million HASH filter rules.
+For more information, please visit `Chelsio Communications Official Website
+<http://www.chelsio.com>`_.
+
+Compiling the Application
+-------------------------
+
+To compile the application:
+
+#. Turn on command line library in the corresponding config/common_*
+ configuration file. For example, for x86_64-native-linuxapp-gcc target,
+ enable ``CONFIG_RTE_LIBRTE_CMDLINE`` in config/common_linuxapp as follows:
+
+ .. code-block:: console
+
+ CONFIG_RTE_LIBRTE_CMDLINE=y
+
+#. Go to the sample application directory:
+
+ .. code-block:: console
+
+ export RTE_SDK=/path/to/rte_sdk
+ cd ${RTE_SDK}/examples/test-cxgbe-filters
+
+#. Set the target (a default target is used if not specified). For example:
+
+ .. code-block:: console
+
+ export RTE_TARGET=x86_64-native-linuxapp-gcc
+
+ See the *DPDK Getting Started* Guide for possible ``RTE_TARGET`` values.
+
+#. Build the application as follows:
+
+ .. code-block:: console
+
+ make
+
+Running the Application
+-----------------------
+
+Ensure, that the Chelsio NICs are bound to DPDK, and run the application
+from the build directory as follows:
+
+.. code-block:: console
+
+ ./build/test_cxgbe_filters
+
+When successful, a command line prompt appears as shown below:
+
+.. code-block:: console
+
+ [...]
+ PMD: rte_cxgbe_pmd: 0000:04:00.4 Chelsio rev 0 1000/10GBASE-SFP
+ PMD: rte_cxgbe_pmd: 0000:04:00.4 Chelsio rev 0 1000/10GBASE-SFP
+ USER1: Initializing NIC port 0 ...
+ Port 0: 00:07:43:2F:08:60
+ USER1: Initializing NIC port 1 ...
+ Port 1: 00:07:43:2F:08:68
+ PMD: rte_cxgbe_pmd: Port0: passive DA port module inserted
+ PMD: rte_cxgbe_pmd: Port1: passive DA port module inserted
+ USER1: Port 0 (10 Gbps) UP
+ USER1: Port 1 (10 Gbps) UP
+ USER1: Core 1 is doing RX for port 0
+ USER1: Core 2 is doing RX for port 1
+ cxgbe>
+
+There are a number of commands available. Run **help** to get the command list.
+
+.. code-block:: console
+
+ cxgbe> help
+
+ Help:
+ -----
+
+ show (stats|port|fdir) (port_id)
+ Display information for port_id.
+
+ show_all (stats|port)
+ Display information for all ports.
+
+ clear stats (port_id)
+ Clear information for port_id.
+
+ clear_all stats
+ Clear information for all ports.
+
+ quit
+ Quit to prompt.
+
+ filter (port_id) (add|del) (ipv4|ipv6)
+ mode (maskfull|maskless) (no-prio|prio)
+ ingress-port (iport) (iport_mask)
+ ether (ether_type) (ether_type_mask)
+ vlan (inner_vlan) (inner_vlan_mask) (outer_vlan) (outer_vlan_mask)
+ ip (tos) (tos_mask) (proto) (proto_mask)
+ (src_ip_address) (src_ip_mask) (dst_ip_address) (dst_ip_mask)
+ (src_port) (src_port_mask) (dst_port) (dst_port_mask)
+ (drop|fwd|switch) queue (queue_id)
+ (port-none|port-redirect) (egress_port)
+ (ether-none|mac-rewrite|mac-swap) (src_mac) (dst_mac)
+ (vlan-none|vlan-rewrite|vlan-delete) (new_vlan)
+ (nat-none|nat-rewrite) (nat_src_ip) (nat_dst_ip)
+ (nat_src_port) (nat_dst_port)
+ fd_id (fd_id_value)
+ Add/Del a cxgbe flow director filter.
+
+Add/Delete Filters
+------------------
+
+The command line to add/delete filters is given below. Note that the
+command is too long to fit on one line and hence is shown wrapped
+at "\\" for display purposes. In real prompt, these commands should
+be on a single line without the "\\".
+
+ .. code-block:: console
+
+ cxgbe> filter (port_id) (add|del) (ipv4|ipv6) \
+ mode (maskfull|maskless) (no-prio|prio) \
+ ingress-port (iport) (iport_mask) \
+ ether (ether_type) (ether_type_mask) \
+ vlan (inner_vlan) (inner_vlan_mask) \
+ (outer_vlan) (outer_vlan_mask) \
+ ip (tos) (tos_mask) (proto) (proto_mask) \
+ (src_ip_address) (src_ip_mask) \
+ (dst_ip_address) (dst_ip_mask) \
+ (src_port) (src_port_mask) (dst_port) (dst_port_mask) \
+ (drop|fwd|switch) queue (queue_id) \
+ (port-none|port-redirect) (egress_port) \
+ (ether-none|mac-rewrite|mac-swap) (src_mac) (dst_mac) \
+ (vlan-none|vlan-rewrite|vlan-delete) (new_vlan) \
+ (nat-none|nat-rewrite) (nat_src_ip) (nat_dst_ip) \
+ (nat_src_port) (nat_dst_port) \
+ fd_id (fd_id_value)
+
+LE-TCAM (Maskfull) Filters
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For maskfull filters, if the match field and its corresponding mask in
+the accept criteria are both set to 0, then they are not considered for
+accept criteria against the packet.
+
+The **fd_id** value specified for maskfull filters have a priority with
+value 0 having the highest priority. If a packet matches a filter rule
+with lower **fd_id**, then its action is executed immediately and the
+remaining filter rules are ignored.
+
+Maskfull IPv6 filters occupy 4 **fd_id** slots and hence must be on 4 slot
+boundary. IPv4 filters on the other hand occupy only 1 slot. Thus, if
+a slot is being occupied by an IPv6 filter rule, then an IPv4 filter rule
+can not be set on the occupied slot.
+
+By default, maskless filter rules have higher priority over the maskfull
+filter rules. Thus, if a packet could match both a maskfull and a maskless
+filter rule, then **prio** value can be specified to allow maskfull filter
+rule to have a higher priority over the maskless filter rule.
+
+DROP Filter Example
+^^^^^^^^^^^^^^^^^^^
+
+An example to set a drop maskfull filter is given below:
+
+#. Generate some traffic destined for 102.1.2.0/24 network. The app's rxq
+ should have successfully received the traffic as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show stats 0
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 1000000
+ tx_good_packets: 0
+ rx_good_bytes: 64000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. To drop all traffic coming for 102.1.2.0/24 network, add a maskfull
+ filter as follows:
+
+ .. code-block:: console
+
+ cxgbe> filter 0 add ipv4 mode maskfull \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 0.0.0.0 0.0.0.0 102.1.2.0 255.255.255.0 0 0 0 0 \
+ drop queue 0 port-none 0 \
+ ether-none 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-none 0.0.0.0 0.0.0.0 0 0 \
+ fd_id 0
+
+#. Generate the same traffic destined for 102.1.2.0/24 network again. The
+ traffic would have been arrived at the port, but the app's rxq should not
+ have received the traffic; i.e. the traffic had been successfully dropped
+ by the hardware, as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show stats 0
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 2000000
+ tx_good_packets: 0
+ rx_good_bytes: 128000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. Delete the maskfull filter as follows:
+
+ .. code-block:: console
+
+ cxgbe> filter 0 del ipv4 mode maskfull \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0 0 0 0 \
+ drop queue 0 port-none 0 \
+ ether-none 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-none 0.0.0.0 0.0.0.0 0 0 \
+ fd_id 0
+
+#. Generate the same traffic destined for 102.1.2.0/24 network again.
+ The app's rxq should have successfully received the traffic again
+ as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show stats 0
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 2000000
+
+ Port Extended Stats
+ rx_good_packets: 3000000
+ tx_good_packets: 0
+ rx_good_bytes: 192000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 2000000
+ rx_q0_bytes: 128000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+STEER Filter Example
+^^^^^^^^^^^^^^^^^^^^
+
+An example to set a steering maskfull filter to steer traffic from port
+0 to port 1's rxq is given below:
+
+#. Generate some traffic destined for 102.1.2.0/24 network to port 0.
+ The port 0's rxq should have successfully received the traffic,
+ as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 1000000
+ tx_good_packets: 0
+ rx_good_bytes: 64000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 0
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 0
+ rx_good_bytes: 0
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 0
+ rx_q0_bytes: 0
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. To steer all traffic coming for 102.1.2.0/24 network from port 0 to
+ port 1's rxq, add a maskfull filter as follows:
+
+ .. code-block:: console
+
+ cxgbe> filter 1 add ipv4 mode maskfull \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 0.0.0.0 0.0.0.0 102.1.2.0 255.255.255.0 0 0 0 0 \
+ fwd queue 0 port-none 0 \
+ ether-none 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-none 0.0.0.0 0.0.0.0 0 0 \
+ fd_id 0
+
+#. Generate the same traffic destined for 102.1.2.0/24 network to port 0
+ again. The traffic would have arrived at port 0, but it should be
+ steered to port 1's rxq, as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 2000000
+ tx_good_packets: 0
+ rx_good_bytes: 128000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 0
+ rx_good_bytes: 0
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+HASH (Maskless) Filters
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Maskless filters perform match based on the hash generated from the
+fields selected in the accept criteria. Maskless filters ignore masks
+if specified. Both IPv4 and IPv6 filter rules occupy only 1 **fd_id**
+slot for maskless filters.
+
+Maskless filters require a special firmware configuration file. Please
+see *CXGBE Poll Mode Driver NIC Guide* for instructions on how to flash
+the firmware configuration file onto Chelsio NICs.
+
+SWITCH Filter Example
+^^^^^^^^^^^^^^^^^^^^^
+
+An example to set a switch maskless filter with source and destination
+mac addresses swapped is given below:
+
+#. Generate some TCP traffic destined for 102.1.2.2 with destination port
+ 12865 coming from 102.1.2.1 with source port 12000. The app's port 0
+ rxq should have successfully received the traffic as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 1000000
+ tx_good_packets: 0
+ rx_good_bytes: 64000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 0
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 0
+ rx_good_bytes: 0
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 0
+ rx_q0_bytes: 0
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. To switch the traffic from port 0 to port 1 and swap the source and
+ destination mac addresses, add a maskless filter as follows:
+
+ .. code-block:: console
+
+ cxgbe> filter 0 add ipv4 mode maskless \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 102.1.2.1 0.0.0.0 102.1.2.2 0.0.0.0 12000 0 12865 0 \
+ switch queue 0 port-redirect 1 \
+ mac-swap 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-none 0.0.0.0 0.0.0.0 0 0 \
+ fd_id 0
+
+#. Generate the same traffic again and the traffic from port 0 gets
+ switched to port 1 without reaching the app's rx queues as shown below.
+ Also, the source and destination mac addresses should have been swapped
+ if the traffic had been captured.
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 2000000
+ tx_good_packets: 0
+ rx_good_bytes: 128000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 0
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 1000000
+ rx_good_bytes: 0
+ tx_good_bytes: 64000000
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 0
+ rx_q0_bytes: 0
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. To delete the maskless filter, run:
+
+ .. code-block:: console
+
+ cxgbe> filter 0 del ipv4 mode maskless \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 0.0.0.0 0.0.0.0 0.0.0.0 0.0.0.0 0 0 0 0 \
+ fwd queue 0 port-none 0 \
+ ether-none 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-none 0.0.0.0 0.0.0.0 0 0 \
+ fd_id 0
+
+NAT Offload Filter Example
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+An example to perform NAT with a switch maskless filter with destination
+ip and port addresses re-written is given below:
+
+#. Generate some TCP traffic destined for 102.1.2.2 with destination port
+ 12865 coming from 102.1.2.1 with source port 12000. The app's port 0
+ rxq should have successfully received the traffic as shown below:
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 1000000
+ tx_good_packets: 0
+ rx_good_bytes: 64000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 0
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 0
+ rx_good_bytes: 0
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 0
+ rx_q0_bytes: 0
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+
+#. To perform NAT and switch the traffic from port 0 to port 1 with
+ destination ip and port addresses re-written to 10.1.1.1 and 14000
+ respectively, add a maskless filter as follows:
+
+ .. code-block:: console
+
+ cxgbe> filter 0 add ipv4 mode maskless \
+ no-prio ingress-port 0 0 ether 0 0 vlan 0 0 0 0 \
+ ip 0 0 0 0 102.1.2.1 0.0.0.0 102.1.2.2 0.0.0.0 12000 0 12865 0 \
+ switch queue 0 port-redirect 1 \
+ ether-none 00:00:00:00:00:00 00:00:00:00:00:00 \
+ vlan-none 0 nat-rewrite 102.1.2.1 10.1.1.1 12000 14000 \
+ fd_id 0
+
+#. Generate the same traffic again and the traffic from port 0 gets
+ switched to port 1 without reaching the app's rx queues as shown below.
+ Also, the destination ip and port addresses should have been re-written
+ if the traffic had been captured.
+
+ .. code-block:: console
+
+ cxgbe> show_all stats
+ ################################################################
+ App Stats for port: 0
+ # of Received Packets: 1000000
+
+ Port Extended Stats
+ rx_good_packets: 2000000
+ tx_good_packets: 0
+ rx_good_bytes: 128000000
+ tx_good_bytes: 0
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 1000000
+ rx_q0_bytes: 64000000
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
+ ################################################################
+ App Stats for port: 1
+ # of Received Packets: 0
+
+ Port Extended Stats
+ rx_good_packets: 0
+ tx_good_packets: 1000000
+ rx_good_bytes: 0
+ tx_good_bytes: 64000000
+ rx_errors: 0
+ tx_errors: 0
+ rx_mbuf_allocation_errors: 0
+ rx_q0_packets: 0
+ rx_q0_bytes: 0
+ rx_q0_errors: 0
+ tx_q0_packets: 0
+ tx_q0_bytes: 0
+ ################################################################
@@ -71,6 +71,7 @@ DIRS-y += quota_watermark
DIRS-$(CONFIG_RTE_ETHDEV_RXTX_CALLBACKS) += rxtx_callbacks
DIRS-y += skeleton
DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += tep_termination
+DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += test-cxgbe-filters
DIRS-$(CONFIG_RTE_LIBRTE_TIMER) += timer
DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += vhost
DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += vhost_xen
new file mode 100644
@@ -0,0 +1,63 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015-2016 Chelsio Communications.
+# 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 Chelsio Communications 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 overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(CONFIG_RTE_LIBRTE_CMDLINE), y)
+
+# binary name
+APP = test_cxgbe_filters
+
+VPATH += $(SRCDIR)/cxgbe
+
+INC += $(wildcard *.h) $(wildcard cxgbe/*.h)
+
+# all source are stored in SRCS-y
+SRCS-y := main.c
+SRCS-y += config.c
+SRCS-y += init.c
+SRCS-y += runtime.c
+SRCS-y += commands.c
+SRCS-y += cxgbe_commands.c
+
+CFLAGS += -I$(SRCDIR) -I$(SRCDIR)/cxgbe
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
+endif
new file mode 100644
@@ -0,0 +1,429 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <string.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline.h>
+
+#include <rte_common.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+
+#include "main.h"
+#include "commands.h"
+
+static int
+port_id_is_invalid(uint8_t port_id)
+{
+ if (port_id < app.n_ports)
+ return 0;
+
+ printf("Invalid port %d. Must be < %d\n", port_id, app.n_ports);
+ return 1;
+}
+
+/****************/
+
+struct cmd_help_result {
+ cmdline_fixed_string_t help;
+};
+
+static void
+cmd_help_parsed(__rte_unused void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ cmdline_printf(cl,
+ "\n"
+ "Help:\n"
+ "-----\n\n"
+
+ "show (stats|port|fdir) (port_id)\n"
+ " Display information for port_id.\n\n"
+
+ "show_all (stats|port)\n"
+ " Display information for all ports.\n\n"
+
+ "clear stats (port_id)\n"
+ " Clear information for port_id.\n\n"
+
+ "clear_all stats\n"
+ " Clear information for all ports.\n\n"
+
+ "quit\n"
+ " Quit to prompt.\n\n"
+
+ "filter (port_id) (add|del) (ipv4|ipv6)"
+ " mode (maskfull|maskless) (no-prio|prio)"
+ " ingress-port (iport) (iport_mask)"
+ " ether (ether_type) (ether_type_mask)"
+ " vlan (inner_vlan) (inner_vlan_mask)"
+ " (outer_vlan) (outer_vlan_mask)"
+ " ip (tos) (tos_mask) (proto) (proto_mask)"
+ " (src_ip_address) (src_ip_mask)"
+ " (dst_ip_address) (dst_ip_mask)"
+ " (src_port) (src_port_mask) (dst_port) (dst_port_mask)"
+ " (drop|fwd|switch) queue (queue_id)"
+ " (port-none|port-redirect) (egress_port)"
+ " (ether-none|mac-rewrite|mac-swap) (src_mac) (dst_mac)"
+ " (vlan-none|vlan-rewrite|vlan-delete) (new_vlan)"
+ " (nat-none|nat-rewrite) (nat_src_ip) (nat_dst_ip)"
+ " (nat_src_port) (nat_dst_port)"
+ " fd_id (fd_id_value)\n"
+ " Add/Del a cxgbe flow director filter.\n\n"
+ );
+}
+
+cmdline_parse_token_string_t cmd_help_help =
+ TOKEN_STRING_INITIALIZER(struct cmd_help_result, help,
+ "help");
+
+cmdline_parse_inst_t cmd_help = {
+ .f = cmd_help_parsed,
+ .data = NULL,
+ .help_str = "print help",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_help_help,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_show_result {
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t op;
+ uint8_t port_id;
+};
+
+static void
+print_xstats(uint8_t port_id)
+{
+ struct rte_eth_xstats *xstats;
+ int len, ret, i;
+
+ if (port_id_is_invalid(port_id))
+ return;
+
+ printf("App Stats for port: %d\n", port_id);
+ printf("# of Received Packets: %" PRIu64 "\n",
+ app.mbuf_rx[port_id].pkts);
+
+ printf("\nPort Extended Stats\n");
+ len = rte_eth_xstats_get(port_id, NULL, 0);
+ if (len < 0) {
+ printf("Cannot get extended stats\n");
+ return;
+ }
+
+ xstats = malloc(sizeof(xstats[0]) * len);
+ if (!xstats) {
+ printf("Cannot allocate memory for xstats\n");
+ return;
+ }
+
+ ret = rte_eth_xstats_get(port_id, xstats, len);
+ if (ret < 0 || ret > len) {
+ printf("Cannot get xstats\n");
+ free(xstats);
+ return;
+ }
+
+ for (i = 0; i < len; i++)
+ printf("%s: %" PRIu64 "\n", xstats[i].name, xstats[i].value);
+
+ free(xstats);
+}
+
+static void
+print_port(uint8_t port_id)
+{
+ struct ether_addr mac_addr;
+ struct rte_eth_link link;
+ char buf[ETHER_ADDR_FMT_SIZE];
+
+ if (port_id_is_invalid(port_id))
+ return;
+
+ rte_eth_link_get_nowait(port_id, &link);
+ printf("\nInfos for port %d\n", port_id);
+
+ rte_eth_macaddr_get(port_id, &mac_addr);
+ ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, &mac_addr);
+ printf("MAC address: %s", buf);
+
+ printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
+ printf("Link speed: %u Mbps\n", (unsigned)link.link_speed);
+ printf("Link duplex: %s\n", (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
+ ("full-duplex") : ("half-duplex"));
+ printf("Promiscuous mode: %s\n",
+ rte_eth_promiscuous_get(port_id) ? "enabled" : "disabled");
+ printf("Allmulticast mode: %s\n",
+ rte_eth_allmulticast_get(port_id) ? "enabled" : "disabled");
+}
+
+static void
+print_fdir(uint8_t port_id)
+{
+ struct rte_eth_fdir_stats fdir_stat;
+ int ret;
+
+ if (port_id_is_invalid(port_id))
+ return;
+
+ ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
+ if (ret < 0) {
+ printf("FDIR is not supported on port %d\n", port_id);
+ return;
+ }
+
+ memset(&fdir_stat, 0, sizeof(fdir_stat));
+ rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_STATS, &fdir_stat);
+ printf("FDIR stats for port %d\n", port_id);
+ printf(" free: %" PRIu32 "\n"
+ " add: %-10" PRIu64 " remove: %" PRIu64 "\n"
+ " f_add: %-10" PRIu64 " f_remove: %" PRIu64 "\n",
+ fdir_stat.free,
+ fdir_stat.add, fdir_stat.remove,
+ fdir_stat.f_add, fdir_stat.f_remove);
+}
+
+static void
+cmd_show_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_result *res = parsed_result;
+ const char *border = "#######################################";
+
+ printf("%s%s\n", border, border);
+ if (!strcmp(res->op, "stats"))
+ print_xstats(res->port_id);
+ else if (!strcmp(res->op, "port"))
+ print_port(res->port_id);
+ else if (!strcmp(res->op, "fdir"))
+ print_fdir(res->port_id);
+ printf("%s%s\n", border, border);
+}
+
+cmdline_parse_token_string_t cmd_show_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_result, show, "show");
+cmdline_parse_token_string_t cmd_show_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_result, op, "stats#port#fdir");
+cmdline_parse_token_num_t cmd_show_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_show_result, port_id, UINT8);
+
+cmdline_parse_inst_t cmd_show = {
+ .f = cmd_show_parsed,
+ .data = NULL,
+ .help_str = "show information",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_show_show,
+ (void *)&cmd_show_op,
+ (void *)&cmd_show_port_id,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_show_all_result {
+ cmdline_fixed_string_t show_all;
+ cmdline_fixed_string_t op;
+};
+
+static void
+cmd_show_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_show_all_result *res = parsed_result;
+ const char *border = "#######################################";
+ unsigned int i;
+
+ for (i = 0; i < app.n_ports; i++) {
+ printf("%s%s\n", border, border);
+ if (!strcmp(res->op, "stats"))
+ print_xstats(i);
+ else if (!strcmp(res->op, "port"))
+ print_port(i);
+ printf("%s%s\n", border, border);
+ }
+}
+
+cmdline_parse_token_string_t cmd_show_all_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_all_result, show_all,
+ "show_all");
+cmdline_parse_token_string_t cmd_show_all_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_show_all_result, op, "stats#port");
+
+cmdline_parse_inst_t cmd_show_all = {
+ .f = cmd_show_all_parsed,
+ .data = NULL,
+ .help_str = "show information for all ports",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_show_all_show,
+ (void *)&cmd_show_all_op,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_clear_result {
+ cmdline_fixed_string_t clear;
+ cmdline_fixed_string_t op;
+ uint8_t port_id;
+};
+
+static void
+cmd_clear_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_clear_result *res = parsed_result;
+
+ if (port_id_is_invalid(res->port_id))
+ return;
+
+ if (!strcmp(res->op, "stats")) {
+ app.mbuf_rx[res->port_id].pkts = 0;
+ rte_eth_xstats_reset(res->port_id);
+ }
+}
+
+cmdline_parse_token_string_t cmd_clear_clear =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_result, clear, "clear");
+cmdline_parse_token_string_t cmd_clear_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_result, op, "stats");
+cmdline_parse_token_num_t cmd_clear_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_clear_result, port_id, UINT8);
+
+cmdline_parse_inst_t cmd_clear = {
+ .f = cmd_clear_parsed,
+ .data = NULL,
+ .help_str = "clear information",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_clear_clear,
+ (void *)&cmd_clear_op,
+ (void *)&cmd_clear_port_id,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_clear_all_result {
+ cmdline_fixed_string_t clear_all;
+ cmdline_fixed_string_t op;
+};
+
+static void
+cmd_clear_all_parsed(void *parsed_result,
+ __rte_unused struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_clear_all_result *res = parsed_result;
+ unsigned int i;
+
+ for (i = 0; i < app.n_ports; i++) {
+ if (!strcmp(res->op, "stats")) {
+ app.mbuf_rx[i].pkts = 0;
+ rte_eth_xstats_reset(i);
+ }
+ }
+}
+
+cmdline_parse_token_string_t cmd_clear_all_clear =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_all_result, clear_all,
+ "clear_all");
+cmdline_parse_token_string_t cmd_clear_all_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_clear_all_result, op, "stats");
+
+cmdline_parse_inst_t cmd_clear_all = {
+ .f = cmd_clear_all_parsed,
+ .data = NULL,
+ .help_str = "clear information for all ports",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_clear_all_clear,
+ (void *)&cmd_clear_all_op,
+ NULL,
+ },
+};
+
+/****************/
+
+struct cmd_quit_result {
+ cmdline_fixed_string_t quit;
+};
+
+static void
+cmd_quit_parsed(__rte_unused void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ cmdline_quit(cl);
+}
+
+cmdline_parse_token_string_t cmd_quit_quit =
+ TOKEN_STRING_INITIALIZER(struct cmd_quit_result, quit,
+ "quit");
+
+cmdline_parse_inst_t cmd_quit = {
+ .f = cmd_quit_parsed,
+ .data = NULL,
+ .help_str = "exit application",
+ .tokens = { /* token list, NULL terminated */
+ (void *)&cmd_quit_quit,
+ NULL,
+ },
+};
+
+/****************/
+
+cmdline_parse_ctx_t main_ctx[] = {
+ (cmdline_parse_inst_t *)&cmd_help,
+ (cmdline_parse_inst_t *)&cmd_show,
+ (cmdline_parse_inst_t *)&cmd_show_all,
+ (cmdline_parse_inst_t *)&cmd_clear,
+ (cmdline_parse_inst_t *)&cmd_clear_all,
+ (cmdline_parse_inst_t *)&cmd_quit,
+ (cmdline_parse_inst_t *)&cmd_add_del_cxgbe_flow_director,
+ NULL,
+};
new file mode 100644
@@ -0,0 +1,40 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _COMMANDS_H_
+#define _COMMANDS_H_
+
+#include <cmdline_parse.h>
+
+extern cmdline_parse_inst_t cmd_add_del_cxgbe_flow_director;
+#endif /* _COMMANDS_H_ */
new file mode 100644
@@ -0,0 +1,79 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_ethdev.h>
+
+#include "main.h"
+
+struct app_params app;
+
+int
+app_init_config(void)
+{
+ uint32_t n_lcores, lcore_id;
+
+ app.n_ports = rte_eth_dev_count();
+ if (!app.n_ports) {
+ RTE_LOG(ERR, USER1, "No probed ethernet devices\n");
+ return -1;
+ }
+
+ n_lcores = 0;
+ for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
+ if (!rte_lcore_is_enabled(lcore_id))
+ continue;
+
+ if (lcore_id == rte_get_master_lcore())
+ continue;
+
+ if (n_lcores >= APP_MAX_PORTS || n_lcores >= app.n_ports)
+ break;
+
+ app.core_rx[n_lcores] = lcore_id;
+ n_lcores++;
+ }
+
+ if (n_lcores < 2) {
+ RTE_LOG(ERR, USER1, "Number of cores must be at least 3\n");
+ return -1;
+ } else if (n_lcores < app.n_ports) {
+ RTE_LOG(ERR, USER1, "Not enough cores for all ports\n");
+ return -1;
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,554 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <string.h>
+#ifndef __linux__
+#ifndef __FreeBSD__
+#include <net/socket.h>
+#else
+#include <sys/socket.h>
+#endif
+#endif
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_ipaddr.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline.h>
+
+#include <rte_common.h>
+#include <rte_byteorder.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+
+#include "main.h"
+#include "commands.h"
+#include "cxgbe_fdir.h"
+
+/****************/
+
+static void
+ipv4_addr_to_uint(cmdline_ipaddr_t ip_addr, uint8_t *ip)
+{
+ do {
+ if (ip_addr.family == AF_INET) {
+ rte_memcpy(ip, &ip_addr.addr.ipv4.s_addr,
+ sizeof(struct in_addr));
+ } else {
+ printf("invalid parameter.\n");
+ return;
+ }
+ } while (0);
+}
+
+static void
+ipv6_addr_to_array(cmdline_ipaddr_t ip_addr, uint8_t *ip)
+{
+ do {
+ if (ip_addr.family == AF_INET6) {
+ rte_memcpy(ip, &ip_addr.addr.ipv6,
+ sizeof(struct in6_addr));
+ } else {
+ printf("invalid parameter.\n");
+ return;
+ }
+ } while (0);
+}
+
+/* *** cxgbe flow director *** */
+struct cmd_cxgbe_flow_director_result {
+ cmdline_fixed_string_t cxgbe_flow_director;
+ uint8_t port_id;
+ cmdline_fixed_string_t ops;
+
+ /* Match fields without mask */
+ cmdline_fixed_string_t flow_type;
+ cmdline_fixed_string_t flow_mode;
+ cmdline_fixed_string_t flow_mode_value;
+ cmdline_fixed_string_t flow_prio;
+
+ /* Match fields with mask */
+ cmdline_fixed_string_t iport;
+ uint8_t iport_value;
+ uint8_t iport_mask;
+ cmdline_fixed_string_t ether;
+ uint16_t ether_type;
+ uint16_t ether_type_mask;
+ cmdline_fixed_string_t vlan;
+ uint16_t ivlan;
+ uint16_t ivlan_mask;
+ uint16_t ovlan;
+ uint16_t ovlan_mask;
+ cmdline_fixed_string_t ip;
+ uint8_t tos;
+ uint8_t tos_mask;
+ uint8_t proto;
+ uint8_t proto_mask;
+ cmdline_ipaddr_t src_ip;
+ cmdline_ipaddr_t src_ip_mask;
+ cmdline_ipaddr_t dst_ip;
+ cmdline_ipaddr_t dst_ip_mask;
+ uint16_t src_port;
+ uint16_t src_port_mask;
+ uint16_t dst_port;
+ uint16_t dst_port_mask;
+
+ /* Action */
+ cmdline_fixed_string_t action;
+ cmdline_fixed_string_t queue;
+ uint16_t queue_id;
+
+ /* Action arguments */
+ cmdline_fixed_string_t port_op;
+ uint8_t eport;
+ cmdline_fixed_string_t ether_op;
+ struct ether_addr smac;
+ struct ether_addr dmac;
+ cmdline_fixed_string_t vlan_op;
+ uint16_t new_vlan;
+ cmdline_fixed_string_t nat_op;
+ cmdline_ipaddr_t nat_src_ip;
+ cmdline_ipaddr_t nat_dst_ip;
+ uint16_t nat_src_port;
+ uint16_t nat_dst_port;
+
+ cmdline_fixed_string_t fd_id;
+ uint32_t fd_id_value;
+};
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_cxgbe =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ cxgbe_flow_director,
+ "filter");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ port_id, UINT8);
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_ops =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ops, "add#del");
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_flow_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ flow_type, "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_flow_mode =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ flow_mode, "mode");
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_flow_mode_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ flow_mode_value, "maskfull#maskless");
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_flow_prio =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ flow_prio, "no-prio#prio");
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_iport =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ iport, "ingress-port");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_iport_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ iport_value, UINT8);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_iport_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ iport_mask, UINT8);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_ether =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ether, "ether");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ether_type =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ether_type, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ether_type_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ether_type_mask, UINT16);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ vlan, "vlan");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ivlan =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ivlan, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ivlan_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ivlan_mask, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ovlan =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ovlan, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_ovlan_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ovlan_mask, UINT16);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ip, "ip");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_tos =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ tos, UINT8);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_tos_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ tos_mask, UINT8);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_proto =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ proto, UINT8);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_proto_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ proto_mask, UINT8);
+cmdline_parse_token_ipaddr_t cmd_cxgbe_flow_director_src_ip =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ src_ip);
+cmdline_parse_token_ipaddr_t cmd_cxgbe_flow_director_src_ip_mask =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ src_ip_mask);
+cmdline_parse_token_ipaddr_t cmd_cxgbe_flow_director_dst_ip =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ dst_ip);
+cmdline_parse_token_ipaddr_t cmd_cxgbe_flow_director_dst_ip_mask =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ dst_ip_mask);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_src_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ src_port, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_src_port_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ src_port_mask, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_dst_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ dst_port, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_dst_port_mask =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ dst_port_mask, UINT16);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ action, "drop#fwd#switch");
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_queue =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ queue, "queue");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_queue_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ queue_id, UINT16);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_port_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ port_op, "port-none#port-redirect");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_eport =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ eport, UINT8);
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_ether_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ ether_op, "ether-none#mac-rewrite#mac-swap");
+cmdline_parse_token_etheraddr_t cmd_cxgbe_flow_director_smac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ smac);
+cmdline_parse_token_etheraddr_t cmd_cxgbe_flow_director_dmac =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ dmac);
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_vlan_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ vlan_op, "vlan-none#vlan-rewrite#vlan-delete");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_new_vlan =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ new_vlan, UINT16);
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_nat_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ nat_op, "nat-none#nat-rewrite");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_nat_src_ip =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ nat_src_ip);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_nat_dst_ip =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ nat_dst_ip);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_nat_src_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ nat_src_port, UINT16);
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_nat_dst_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ nat_dst_port, UINT16);
+
+cmdline_parse_token_string_t cmd_cxgbe_flow_director_fd_id =
+ TOKEN_STRING_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ fd_id, "fd_id");
+cmdline_parse_token_num_t cmd_cxgbe_flow_director_fd_id_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_cxgbe_flow_director_result,
+ fd_id_value, UINT32);
+
+static void
+cxgbe_fill_in_match_fields(struct rte_eth_fdir_input *input,
+ struct cmd_cxgbe_flow_director_result *res)
+{
+ struct cxgbe_fdir_input_admin admin;
+ struct cxgbe_fdir_input_flow val, mask;
+ uint8_t *raw_pkt_flow;
+
+ memset(&admin, 0, sizeof(admin));
+ memset(&val, 0, sizeof(val));
+ memset(&mask, 0, sizeof(mask));
+
+ /* Fill in match admin fields that don't have masks */
+ if (!strcmp(res->flow_type, "ipv4"))
+ admin.type = 0;
+ else
+ admin.type = 1;
+
+ if (!strcmp(res->flow_mode_value, "maskfull"))
+ admin.cap = 0;
+ else
+ admin.cap = 1;
+
+ /*
+ * If a packet can match both a maskfull and maskless filter,
+ * enable prio bit to allow maskfull filter to have priority
+ * over the maskless filter.
+ */
+ if (!strcmp(res->flow_prio, "prio"))
+ admin.prio = 1;
+ else
+ admin.prio = 0;
+
+ /* Fill in match fields that have masks */
+ val.iport = res->iport_value;
+ if (val.iport > 7) {
+ printf("iport must be < 8. Using 0\n");
+ val.iport = 0;
+ }
+ val.ethtype = rte_cpu_to_be_16(res->ether_type);
+
+ val.ivlan = rte_cpu_to_be_16(res->ivlan);
+ val.ovlan = rte_cpu_to_be_16(res->ovlan);
+
+ val.tos = res->tos;
+ val.proto = res->proto;
+ if (!admin.type) {
+ ipv4_addr_to_uint(res->dst_ip, &val.lip[0]);
+ ipv4_addr_to_uint(res->src_ip, &val.fip[0]);
+ } else {
+ ipv6_addr_to_array(res->dst_ip, &val.lip[0]);
+ ipv6_addr_to_array(res->src_ip, &val.fip[0]);
+ }
+
+ val.lport = rte_cpu_to_be_16(res->dst_port);
+ val.fport = rte_cpu_to_be_16(res->src_port);
+
+ /* Fill in match mask fields */
+ mask.iport = res->iport_mask;
+ if (mask.iport > 7) {
+ printf("iport_mask must be < 8. Using 0\n");
+ mask.iport = 0;
+ }
+ mask.ethtype = rte_cpu_to_be_16(res->ether_type_mask);
+
+ mask.ivlan = rte_cpu_to_be_16(res->ivlan_mask);
+ mask.ovlan = rte_cpu_to_be_16(res->ovlan_mask);
+
+ mask.tos = res->tos_mask;
+ mask.proto = res->proto_mask;
+ if (!admin.type) {
+ ipv4_addr_to_uint(res->dst_ip_mask, &mask.lip[0]);
+ ipv4_addr_to_uint(res->src_ip_mask, &mask.fip[0]);
+ } else {
+ ipv6_addr_to_array(res->dst_ip_mask, &mask.lip[0]);
+ ipv6_addr_to_array(res->src_ip_mask, &mask.fip[0]);
+ }
+
+ mask.lport = rte_cpu_to_be_16(res->dst_port_mask);
+ mask.fport = rte_cpu_to_be_16(res->src_port_mask);
+
+ /* Fill in the above data to raw_pkt_flow array */
+ raw_pkt_flow = &input->flow.raw_pkt_flow[0];
+ rte_memcpy(raw_pkt_flow, &admin, sizeof(admin));
+ raw_pkt_flow += sizeof(admin);
+ rte_memcpy(raw_pkt_flow, &val, sizeof(val));
+ rte_memcpy(&input->flow_mask.raw_pkt_flow[0], &mask, sizeof(mask));
+}
+
+static void
+cxgbe_fill_in_action_fields(struct rte_eth_fdir_action *behavior,
+ struct cmd_cxgbe_flow_director_result *res)
+{
+ struct cxgbe_fdir_action action;
+
+ memset(&action, 0, sizeof(action));
+
+ /* Fill in port behavior arguments */
+ if (!strcmp(res->port_op, "port-redirect")) {
+ action.eport = res->eport;
+ if (action.eport > 3) {
+ printf("eport must be < 4. Using 0\n");
+ action.eport = 0;
+ }
+ }
+
+ /* Fill in ether behavior arguments */
+ if (!strcmp(res->ether_op, "mac-rewrite")) {
+ rte_memcpy(&action.dmac, &res->dmac, sizeof(struct ether_addr));
+ rte_memcpy(&action.smac, &res->smac, sizeof(struct ether_addr));
+ action.newdmac = 1;
+ action.newsmac = 1;
+ } else if (!strcmp(res->ether_op, "mac-swap")) {
+ action.swapmac = 1;
+ }
+
+ /* Fill in vlan behavior arguments */
+ if (!strcmp(res->vlan_op, "vlan-delete")) {
+ action.vlan = rte_cpu_to_be_16(res->new_vlan);
+ action.newvlan = 1; /* VLAN delete */
+ } else if (!strcmp(res->vlan_op, "vlan-rewrite")) {
+ action.vlan = rte_cpu_to_be_16(res->new_vlan);
+ action.newvlan = 3; /* VLAN rewrite */
+ }
+
+ /* Fill in nat behavior arguments */
+ if (!strcmp(res->nat_op, "nat-rewrite")) {
+ action.nat_mode = 7; /* Rewrite IP and port */
+ if (!strcmp(res->flow_type, "ipv4")) {
+ ipv4_addr_to_uint(res->nat_dst_ip, &action.nat_lip[0]);
+ ipv4_addr_to_uint(res->nat_src_ip, &action.nat_fip[0]);
+ } else {
+ ipv6_addr_to_array(res->nat_dst_ip, &action.nat_lip[0]);
+ ipv6_addr_to_array(res->nat_src_ip, &action.nat_fip[0]);
+ }
+ action.nat_lport = rte_cpu_to_be_16(res->nat_dst_port);
+ action.nat_fport = rte_cpu_to_be_16(res->nat_src_port);
+ }
+
+ /* Fill in the above data to behavior_arg array */
+ rte_memcpy(&behavior->behavior_arg[0], &action, sizeof(action));
+}
+
+static void
+cmd_cxgbe_flow_director_parsed(void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_cxgbe_flow_director_result *res = parsed_result;
+ struct rte_eth_fdir_filter entry;
+ struct rte_eth_dev_info dev_info;
+ int ret;
+
+ rte_eth_dev_info_get(res->port_id, &dev_info);
+ if (strcmp(dev_info.driver_name, "rte_cxgbe_pmd")) {
+ printf("Not a Chelsio Device\n");
+ return;
+ }
+
+ ret = rte_eth_dev_filter_supported(res->port_id, RTE_ETH_FILTER_FDIR);
+ if (ret < 0) {
+ printf("flow director is not supported on port %u.\n",
+ res->port_id);
+ return;
+ }
+
+ memset(&entry, 0, sizeof(entry));
+ entry.input.flow_type = RTE_ETH_FLOW_RAW_PKT;
+
+ cxgbe_fill_in_match_fields(&entry.input, res);
+
+ if (!strcmp(res->action, "drop"))
+ entry.action.behavior = RTE_ETH_FDIR_REJECT;
+ else if (!strcmp(res->action, "fwd"))
+ entry.action.behavior = RTE_ETH_FDIR_ACCEPT;
+ else
+ entry.action.behavior = RTE_ETH_FDIR_SWITCH;
+
+ cxgbe_fill_in_action_fields(&entry.action, res);
+
+ entry.action.rx_queue = res->queue_id;
+ entry.soft_id = res->fd_id_value;
+ if (!strcmp(res->ops, "add"))
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_ADD, &entry);
+ else
+ ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_FDIR,
+ RTE_ETH_FILTER_DELETE, &entry);
+ if (ret < 0)
+ printf("flow director programming error: (%s)\n",
+ strerror(-ret));
+}
+
+cmdline_parse_inst_t cmd_add_del_cxgbe_flow_director = {
+ .f = cmd_cxgbe_flow_director_parsed,
+ .data = NULL,
+ .help_str = "add or delete fdir entry on a cxgbe device",
+ .tokens = {
+ (void *)&cmd_cxgbe_flow_director_cxgbe,
+ (void *)&cmd_cxgbe_flow_director_port_id,
+ (void *)&cmd_cxgbe_flow_director_ops,
+ (void *)&cmd_cxgbe_flow_director_flow_type,
+ (void *)&cmd_cxgbe_flow_director_flow_mode,
+ (void *)&cmd_cxgbe_flow_director_flow_mode_value,
+ (void *)&cmd_cxgbe_flow_director_flow_prio,
+ (void *)&cmd_cxgbe_flow_director_iport,
+ (void *)&cmd_cxgbe_flow_director_iport_value,
+ (void *)&cmd_cxgbe_flow_director_iport_mask,
+ (void *)&cmd_cxgbe_flow_director_ether,
+ (void *)&cmd_cxgbe_flow_director_ether_type,
+ (void *)&cmd_cxgbe_flow_director_ether_type_mask,
+ (void *)&cmd_cxgbe_flow_director_vlan,
+ (void *)&cmd_cxgbe_flow_director_ivlan,
+ (void *)&cmd_cxgbe_flow_director_ivlan_mask,
+ (void *)&cmd_cxgbe_flow_director_ovlan,
+ (void *)&cmd_cxgbe_flow_director_ovlan_mask,
+ (void *)&cmd_cxgbe_flow_director_ip,
+ (void *)&cmd_cxgbe_flow_director_tos,
+ (void *)&cmd_cxgbe_flow_director_tos_mask,
+ (void *)&cmd_cxgbe_flow_director_proto,
+ (void *)&cmd_cxgbe_flow_director_proto_mask,
+ (void *)&cmd_cxgbe_flow_director_src_ip,
+ (void *)&cmd_cxgbe_flow_director_src_ip_mask,
+ (void *)&cmd_cxgbe_flow_director_dst_ip,
+ (void *)&cmd_cxgbe_flow_director_dst_ip_mask,
+ (void *)&cmd_cxgbe_flow_director_src_port,
+ (void *)&cmd_cxgbe_flow_director_src_port_mask,
+ (void *)&cmd_cxgbe_flow_director_dst_port,
+ (void *)&cmd_cxgbe_flow_director_dst_port_mask,
+ (void *)&cmd_cxgbe_flow_director_action,
+ (void *)&cmd_cxgbe_flow_director_queue,
+ (void *)&cmd_cxgbe_flow_director_queue_id,
+ (void *)&cmd_cxgbe_flow_director_port_op,
+ (void *)&cmd_cxgbe_flow_director_eport,
+ (void *)&cmd_cxgbe_flow_director_ether_op,
+ (void *)&cmd_cxgbe_flow_director_smac,
+ (void *)&cmd_cxgbe_flow_director_dmac,
+ (void *)&cmd_cxgbe_flow_director_vlan_op,
+ (void *)&cmd_cxgbe_flow_director_new_vlan,
+ (void *)&cmd_cxgbe_flow_director_nat_op,
+ (void *)&cmd_cxgbe_flow_director_nat_src_ip,
+ (void *)&cmd_cxgbe_flow_director_nat_dst_ip,
+ (void *)&cmd_cxgbe_flow_director_nat_src_port,
+ (void *)&cmd_cxgbe_flow_director_nat_dst_port,
+ (void *)&cmd_cxgbe_flow_director_fd_id,
+ (void *)&cmd_cxgbe_flow_director_fd_id_value,
+ NULL,
+ },
+};
new file mode 100644
@@ -0,0 +1,79 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _APP_CXGBE_FDIR_H_
+#define _APP_CXGBE_FDIR_H_
+
+/*
+ * RTE_ETH_FLOW_RAW_PKT representation.
+ * Must be kept in sync with the representation in
+ * drivers/net/cxgbe/cxgbe_fdir.h.
+ */
+struct cxgbe_fdir_input_admin {
+ uint8_t prio; /* filter has priority over maskless */
+ uint8_t type; /* 0 => IPv4, 1 => IPv6 */
+ uint8_t cap; /* 0 => Maskfull, 1 => Maskless */
+};
+
+struct cxgbe_fdir_input_flow {
+ uint16_t ethtype; /* ethernet type */
+ uint8_t iport; /* ingress port */
+ uint8_t proto; /* protocol type */
+ uint8_t tos; /* TOS/Traffic Type */
+ uint16_t ivlan; /* inner VLAN */
+ uint16_t ovlan; /* outer VLAN */
+
+ uint8_t lip[16]; /* local IP address (IPv4 in [3:0]) */
+ uint8_t fip[16]; /* foreign IP address (IPv4 in [3:0]) */
+ uint16_t lport; /* local port */
+ uint16_t fport; /* foreign port */
+};
+
+struct cxgbe_fdir_action {
+ uint8_t eport; /* egress port to switch packet out */
+ uint8_t newdmac; /* rewrite destination MAC address */
+ uint8_t newsmac; /* rewrite source MAC address */
+ uint8_t swapmac; /* swap SMAC/DMAC for loopback packet */
+ uint8_t newvlan; /* rewrite VLAN Tag */
+ uint8_t nat_mode; /* specify NAT operation mode */
+
+ uint8_t dmac[ETHER_ADDR_LEN]; /* new destination MAC address */
+ uint8_t smac[ETHER_ADDR_LEN]; /* new source MAC address */
+ uint16_t vlan; /* VLAN Tag to insert */
+
+ uint8_t nat_lip[16]; /* local IP to use after NAT'ing */
+ uint8_t nat_fip[16]; /* foreign IP to use after NAT'ing */
+ uint16_t nat_lport; /* local port to use after NAT'ing */
+ uint16_t nat_fport; /* foreign port to use after NAT'ing */
+};
+#endif /* _APP_CXGBE_FDIR_H_ */
new file mode 100644
@@ -0,0 +1,201 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <rte_log.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_cycles.h>
+
+#include "main.h"
+
+struct app_params app = {
+ /* Ports*/
+ .n_ports = APP_MAX_PORTS,
+ .port_rx_ring_size = 128,
+ .port_tx_ring_size = 512,
+
+ /* Buffer pool */
+ .pool_buffer_size = RTE_MBUF_DEFAULT_BUF_SIZE,
+ .pool_size = 32 * 1024,
+ .pool_cache_size = 256,
+
+ /* Burst sizes */
+ .burst_size_rx_read = 64,
+};
+
+static struct rte_eth_conf port_conf = {
+ .rxmode = {
+ .max_rx_pkt_len = ETHER_MAX_LEN,
+ .split_hdr_size = 0,
+ .header_split = 0, /* Header Split disabled */
+ .hw_ip_checksum = 1, /* IP checksum offload enabled */
+ .hw_vlan_filter = 0, /* VLAN filtering disabled */
+ .jumbo_frame = 0, /* Jumbo Frame Support disabled */
+ .hw_strip_crc = 0, /* CRC stripped by hardware */
+ },
+ .fdir_conf = {
+ .mode = RTE_FDIR_MODE_NONE,
+ .pballoc = RTE_FDIR_PBALLOC_64K,
+ .status = RTE_FDIR_REPORT_STATUS,
+ .mask = {
+ .vlan_tci_mask = 0x0,
+ .ipv4_mask = {
+ .src_ip = 0xFFFFFFFF,
+ .dst_ip = 0xFFFFFFFF,
+ },
+ .ipv6_mask = {
+ .src_ip = {0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF},
+ .dst_ip = {0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF},
+ },
+ .src_port_mask = 0xFFFF,
+ .dst_port_mask = 0xFFFF,
+ .mac_addr_byte_mask = 0xFF,
+ .tunnel_type_mask = 1,
+ .tunnel_id_mask = 0xFFFFFFFF,
+ },
+ .drop_queue = 127,
+ },
+};
+
+static void
+app_init_mbuf_pools(void)
+{
+ /* Init the buffer pool */
+ app.pool = rte_pktmbuf_pool_create("mempool", app.pool_size,
+ app.pool_cache_size, 0,
+ app.pool_buffer_size,
+ rte_socket_id());
+ if (!app.pool)
+ rte_panic("Cannot create mbuf pool\n");
+}
+
+static void
+app_ports_check_link(void)
+{
+ uint32_t all_ports_up, port, count, print_flag = 0;
+
+#define CHECK_INTERVAL 100 /* 100ms */
+#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
+
+ for (count = 0; count < MAX_CHECK_TIME; count++) {
+ all_ports_up = 1;
+ for (port = 0; port < app.n_ports; port++) {
+ struct rte_eth_link link;
+
+ memset(&link, 0, sizeof(link));
+ rte_eth_link_get_nowait(port, &link);
+ if (print_flag == 1) {
+ RTE_LOG(INFO, USER1, "Port %u (%u Gbps) %s\n",
+ port, link.link_speed / 1000,
+ link.link_status ? "UP" : "DOWN");
+ }
+
+ if (!link.link_status) {
+ all_ports_up = 0;
+ break;
+ }
+ }
+
+ if (print_flag == 1)
+ break;
+
+ if (!all_ports_up) {
+ fflush(stdout);
+ rte_delay_ms(CHECK_INTERVAL);
+ }
+
+ if (all_ports_up || count == (MAX_CHECK_TIME - 1))
+ print_flag = 1;
+ }
+}
+
+static void
+app_init_ports(void)
+{
+ struct ether_addr mac_addr;
+ unsigned int port;
+ int ret;
+
+ /* Init NIC ports, then start the ports */
+ for (port = 0; port < app.n_ports; port++) {
+ RTE_LOG(INFO, USER1, "Initializing NIC port %u ...\n", port);
+
+ /* Init port */
+ ret = rte_eth_dev_configure(port, 1, 1, &port_conf);
+ if (ret < 0)
+ rte_panic("Cannot init NIC port %u (%d)\n", port, ret);
+
+ /* Init RX queues */
+ ret = rte_eth_rx_queue_setup(port, 0, app.port_rx_ring_size,
+ rte_eth_dev_socket_id(port), NULL,
+ app.pool);
+ if (ret < 0)
+ rte_panic("Cannot init RX for port %u (%d)\n",
+ port, ret);
+
+ /* Init TX queues */
+ ret = rte_eth_tx_queue_setup(port, 0, app.port_tx_ring_size,
+ rte_eth_dev_socket_id(port), NULL);
+ if (ret < 0)
+ rte_panic("Cannot init TX for port %u (%d)\n",
+ port, ret);
+
+ /* Start port */
+ ret = rte_eth_dev_start(port);
+ if (ret < 0)
+ rte_panic("Cannot start port %u (%d)\n", port, ret);
+
+ rte_eth_macaddr_get(port, &mac_addr);
+ printf("Port %d: %02X:%02X:%02X:%02X:%02X:%02X\n", port,
+ mac_addr.addr_bytes[0], mac_addr.addr_bytes[1],
+ mac_addr.addr_bytes[2], mac_addr.addr_bytes[3],
+ mac_addr.addr_bytes[4], mac_addr.addr_bytes[5]);
+
+ rte_eth_promiscuous_enable(port);
+ }
+
+ app_ports_check_link();
+}
+
+void
+app_init(void)
+{
+ app_init_mbuf_pools();
+ app_init_ports();
+}
new file mode 100644
@@ -0,0 +1,79 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <rte_eal.h>
+#include <rte_common.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+
+#include <cmdline_rdline.h>
+#include <cmdline_parse.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "main.h"
+
+int
+main(int argc, char **argv)
+{
+ struct cmdline *cl;
+ unsigned int i;
+ int ret;
+
+ ret = rte_eal_init(argc, argv);
+ if (ret < 0)
+ return -1;
+
+ if (app_init_config() < 0)
+ return -1;
+
+ app_init();
+
+ for (i = 0; i < app.n_ports; i++) {
+ /* Launch rx main loop on every lcore except master */
+ rte_eal_remote_launch(app_main_loop_rx, NULL, app.core_rx[i]);
+ }
+
+ cl = cmdline_stdin_new(main_ctx, "cxgbe> ");
+ if (!cl) {
+ printf("cmdline init failed\n");
+ return -1;
+ }
+
+ cmdline_interact(cl);
+ cmdline_stdin_exit(cl);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,77 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CXGBE_APP_MAIN_H_
+#define _CXGBE_APP_MAIN_H_
+
+#include <cmdline_parse.h>
+
+#define APP_MBUF_ARRAY_SIZE 256
+#define APP_MAX_PORTS 4
+
+struct app_mbuf_array {
+ struct rte_mbuf *array[APP_MBUF_ARRAY_SIZE];
+ uint64_t pkts; /* Number of received packets */
+};
+
+struct app_params {
+ /* CPU cores */
+ uint32_t core_rx[APP_MAX_PORTS];
+
+ /* Ports*/
+ uint32_t n_ports;
+ uint32_t port_rx_ring_size;
+ uint32_t port_tx_ring_size;
+
+ /* Internal buffers */
+ struct app_mbuf_array mbuf_rx[APP_MAX_PORTS];
+
+ /* Buffer pool */
+ struct rte_mempool *pool;
+ uint32_t pool_buffer_size;
+ uint32_t pool_size;
+ uint32_t pool_cache_size;
+
+ /* Burst sizes */
+ uint32_t burst_size_rx_read;
+} __rte_cache_aligned;
+
+extern struct app_params app;
+
+extern cmdline_parse_ctx_t main_ctx[];
+
+int app_init_config(void);
+void app_init(void);
+
+int app_main_loop_rx(void *arg);
+#endif /* _CXGBE_APP_MAIN_H_ */
new file mode 100644
@@ -0,0 +1,74 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015-2016 Chelsio Communications.
+ * 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 Chelsio Communications 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 <rte_log.h>
+#include <rte_ethdev.h>
+
+#include "main.h"
+
+int
+app_main_loop_rx(void *arg)
+{
+ uint32_t lcore_id;
+ uint16_t i;
+ uint8_t port_id = 0;
+
+ RTE_SET_USED(arg);
+
+ lcore_id = rte_lcore_id();
+
+ for (i = 0; i < app.n_ports; i++)
+ if (app.core_rx[i] == lcore_id)
+ port_id = i;
+
+ app.mbuf_rx[port_id].pkts = 0;
+
+ RTE_LOG(INFO, USER1, "Core %u is doing RX for port %d\n",
+ lcore_id, port_id);
+
+ while (1) {
+ uint16_t n_mbufs;
+
+ n_mbufs = rte_eth_rx_burst(port_id, 0,
+ app.mbuf_rx[port_id].array,
+ app.burst_size_rx_read);
+
+ if (!n_mbufs)
+ continue;
+
+ app.mbuf_rx[port_id].pkts += n_mbufs;
+ for (i = 0; i < n_mbufs; i++)
+ rte_pktmbuf_free(app.mbuf_rx[port_id].array[i]);
+ }
+ return 0;
+}