port: fix unaligned access to metadata
[dpdk.git] / app / test-pmd / config.c
index 492cbfe..52917c7 100644 (file)
@@ -79,7 +79,6 @@
 #include <rte_memcpy.h>
 #include <rte_memzone.h>
 #include <rte_launch.h>
-#include <rte_tailq.h>
 #include <rte_eal.h>
 #include <rte_per_lcore.h>
 #include <rte_lcore.h>
@@ -112,11 +111,15 @@ nic_stats_display(portid_t port_id)
        struct rte_eth_stats stats;
        struct rte_port *port = &ports[port_id];
        uint8_t i;
+       portid_t pid;
 
        static const char *nic_stats_border = "########################";
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        rte_eth_stats_get(port_id, &stats);
@@ -189,8 +192,13 @@ nic_stats_display(portid_t port_id)
 void
 nic_stats_clear(portid_t port_id)
 {
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       portid_t pid;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        rte_eth_stats_reset(port_id);
@@ -237,11 +245,15 @@ nic_stats_mapping_display(portid_t port_id)
 {
        struct rte_port *port = &ports[port_id];
        uint16_t i;
+       portid_t pid;
 
        static const char *nic_stats_mapping_border = "########################";
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
 
@@ -290,9 +302,13 @@ port_infos_display(portid_t port_id)
        int vlan_offload;
        struct rte_mempool * mp;
        static const char *info_border = "*********************";
+       portid_t pid;
 
-       if (port_id >= nb_ports) {
-               printf("Invalid port, range is [0, %d]\n", nb_ports - 1);
+       if (port_id_is_invalid(port_id, ENABLED_WARN)) {
+               printf("Valid port range is [0");
+               FOREACH_PORT(pid, ports)
+                       printf(", %d", pid);
+               printf("]\n");
                return;
        }
        port = &ports[port_id];
@@ -365,11 +381,17 @@ port_infos_display(portid_t port_id)
 }
 
 int
-port_id_is_invalid(portid_t port_id)
+port_id_is_invalid(portid_t port_id, enum print_warning warning)
 {
-       if (port_id < nb_ports)
+       if (port_id == (portid_t)RTE_PORT_ALL)
+               return 0;
+
+       if (ports[port_id].enabled)
                return 0;
-       printf("Invalid port %d (must be < nb_ports=%d)\n", port_id, nb_ports);
+
+       if (warning == ENABLED_WARN)
+               printf("Invalid port %d\n", port_id);
+
        return 1;
 }
 
@@ -428,7 +450,7 @@ port_reg_bit_display(portid_t port_id, uint32_t reg_off, uint8_t bit_x)
        uint32_t reg_v;
 
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -447,7 +469,7 @@ port_reg_bit_field_display(portid_t port_id, uint32_t reg_off,
        uint8_t  l_bit;
        uint8_t  h_bit;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -474,7 +496,7 @@ port_reg_display(portid_t port_id, uint32_t reg_off)
 {
        uint32_t reg_v;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -488,7 +510,7 @@ port_reg_bit_set(portid_t port_id, uint32_t reg_off, uint8_t bit_pos,
 {
        uint32_t reg_v;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -516,7 +538,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
        uint8_t  l_bit;
        uint8_t  h_bit;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -550,7 +572,7 @@ port_reg_bit_field_set(portid_t port_id, uint32_t reg_off,
 void
 port_reg_set(portid_t port_id, uint32_t reg_off, uint32_t reg_v)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (port_reg_off_is_invalid(port_id, reg_off))
                return;
@@ -563,7 +585,7 @@ port_mtu_set(portid_t port_id, uint16_t mtu)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        diag = rte_eth_dev_set_mtu(port_id, mtu);
        if (diag == 0)
@@ -726,7 +748,7 @@ rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id)
 {
        const struct rte_memzone *rx_mz;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (rx_queue_id_is_invalid(rxq_id))
                return;
@@ -743,7 +765,7 @@ tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id)
 {
        const struct rte_memzone *tx_mz;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (tx_queue_id_is_invalid(txq_id))
                return;
@@ -804,7 +826,7 @@ port_rss_reta_info(portid_t port_id,
        uint16_t i, idx, shift;
        int ret;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries);
@@ -859,7 +881,7 @@ port_rss_hash_conf_show(portid_t port_id, int show_rss_key)
        uint8_t i;
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        /* Get RSS hash key if asked to display it */
        rss_conf.rss_key = (show_rss_key) ? rss_key : NULL;
@@ -1423,12 +1445,8 @@ set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt)
  again:
        for (i = 0; i < nb_pt; i++) {
                port_id = (portid_t) portlist[i];
-               if (port_id >= nb_ports) {
-                       printf("Invalid port id %u >= %u\n",
-                              (unsigned int) port_id,
-                              (unsigned int) nb_ports);
+               if (port_id_is_invalid(port_id, ENABLED_WARN))
                        return;
-               }
                if (record_now)
                        fwd_ports_ids[i] = port_id;
        }
@@ -1586,7 +1604,7 @@ vlan_extend_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1608,7 +1626,7 @@ rx_vlan_strip_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1629,7 +1647,7 @@ rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        diag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on);
@@ -1644,7 +1662,7 @@ rx_vlan_filter_set(portid_t port_id, int on)
        int diag;
        int vlan_offload;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        vlan_offload = rte_eth_dev_get_vlan_offload(port_id);
@@ -1660,21 +1678,22 @@ rx_vlan_filter_set(portid_t port_id, int on)
               "diag=%d\n", port_id, on, diag);
 }
 
-void
+int
 rx_vft_set(portid_t port_id, uint16_t vlan_id, int on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
-               return;
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return 1;
        if (vlan_id_is_invalid(vlan_id))
-               return;
+               return 1;
        diag = rte_eth_dev_vlan_filter(port_id, vlan_id, on);
        if (diag == 0)
-               return;
+               return 0;
        printf("rte_eth_dev_vlan_filter(port_pi=%d, vlan_id=%d, on=%d) failed "
               "diag=%d\n",
               port_id, vlan_id, on, diag);
+       return -1;
 }
 
 void
@@ -1682,17 +1701,19 @@ rx_vlan_all_filter_set(portid_t port_id, int on)
 {
        uint16_t vlan_id;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
-       for (vlan_id = 0; vlan_id < 4096; vlan_id++)
-               rx_vft_set(port_id, vlan_id, on);
+       for (vlan_id = 0; vlan_id < 4096; vlan_id++) {
+               if (rx_vft_set(port_id, vlan_id, on))
+                       break;
+       }
 }
 
 void
 vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 {
        int diag;
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        diag = rte_eth_dev_set_vlan_ether_type(port_id, tp_id);
@@ -1707,7 +1728,7 @@ vlan_tpid_set(portid_t port_id, uint16_t tp_id)
 void
 tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
@@ -1718,7 +1739,7 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)
 void
 tx_vlan_reset(portid_t port_id)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        ports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;
 }
@@ -1726,7 +1747,7 @@ tx_vlan_reset(portid_t port_id)
 void
 tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on)
 {
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on);
@@ -1738,7 +1759,7 @@ set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value)
        uint16_t i;
        uint8_t existing_mapping_found = 0;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
 
        if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id)))
@@ -1904,7 +1925,7 @@ fdir_get_infos(portid_t port_id)
 
        static const char *fdir_stats_border = "########################";
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_FDIR);
        if (ret < 0) {
@@ -1923,11 +1944,11 @@ fdir_get_infos(portid_t port_id)
               fdir_stats_border, port_id, fdir_stats_border);
        printf("  MODE: ");
        if (fdir_info.mode == RTE_FDIR_MODE_PERFECT)
-                       printf("  PERFECT\n");
+               printf("  PERFECT\n");
        else if (fdir_info.mode == RTE_FDIR_MODE_SIGNATURE)
-                       printf("  SIGNATURE\n");
+               printf("  SIGNATURE\n");
        else
-                       printf("  DISABLE\n");
+               printf("  DISABLE\n");
        printf("  SUPPORTED FLOW TYPE: ");
        print_fdir_flow_type(fdir_info.flow_types_mask[0]);
        printf("  FLEX PAYLOAD INFO:\n");
@@ -2030,7 +2051,7 @@ set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (is_rx)
                diag = rte_eth_dev_set_vf_rx(port_id,vf,on);
@@ -2052,7 +2073,7 @@ set_vf_rx_vlan(portid_t port_id, uint16_t vlan_id, uint64_t vf_mask, uint8_t on)
 {
        int diag;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
@@ -2069,7 +2090,7 @@ set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)
        int diag;
        struct rte_eth_link link;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return 1;
        rte_eth_link_get_nowait(port_id, &link);
        if (rate > link.link_speed) {
@@ -2094,7 +2115,7 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
        if (q_msk == 0)
                return 0;
 
-       if (port_id_is_invalid(port_id))
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
                return 1;
        rte_eth_link_get_nowait(port_id, &link);
        if (rate > link.link_speed) {
@@ -2109,3 +2130,145 @@ set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
                port_id, diag);
        return diag;
 }
+
+/*
+ * Functions to manage the set of filtered Multicast MAC addresses.
+ *
+ * A pool of filtered multicast MAC addresses is associated with each port.
+ * The pool is allocated in chunks of MCAST_POOL_INC multicast addresses.
+ * The address of the pool and the number of valid multicast MAC addresses
+ * recorded in the pool are stored in the fields "mc_addr_pool" and
+ * "mc_addr_nb" of the "rte_port" data structure.
+ *
+ * The function "rte_eth_dev_set_mc_addr_list" of the PMDs API imposes
+ * to be supplied a contiguous array of multicast MAC addresses.
+ * To comply with this constraint, the set of multicast addresses recorded
+ * into the pool are systematically compacted at the beginning of the pool.
+ * Hence, when a multicast address is removed from the pool, all following
+ * addresses, if any, are copied back to keep the set contiguous.
+ */
+#define MCAST_POOL_INC 32
+
+static int
+mcast_addr_pool_extend(struct rte_port *port)
+{
+       struct ether_addr *mc_pool;
+       size_t mc_pool_size;
+
+       /*
+        * If a free entry is available at the end of the pool, just
+        * increment the number of recorded multicast addresses.
+        */
+       if ((port->mc_addr_nb % MCAST_POOL_INC) != 0) {
+               port->mc_addr_nb++;
+               return 0;
+       }
+
+       /*
+        * [re]allocate a pool with MCAST_POOL_INC more entries.
+        * The previous test guarantees that port->mc_addr_nb is a multiple
+        * of MCAST_POOL_INC.
+        */
+       mc_pool_size = sizeof(struct ether_addr) * (port->mc_addr_nb +
+                                                   MCAST_POOL_INC);
+       mc_pool = (struct ether_addr *) realloc(port->mc_addr_pool,
+                                               mc_pool_size);
+       if (mc_pool == NULL) {
+               printf("allocation of pool of %u multicast addresses failed\n",
+                      port->mc_addr_nb + MCAST_POOL_INC);
+               return -ENOMEM;
+       }
+
+       port->mc_addr_pool = mc_pool;
+       port->mc_addr_nb++;
+       return 0;
+
+}
+
+static void
+mcast_addr_pool_remove(struct rte_port *port, uint32_t addr_idx)
+{
+       port->mc_addr_nb--;
+       if (addr_idx == port->mc_addr_nb) {
+               /* No need to recompact the set of multicast addressses. */
+               if (port->mc_addr_nb == 0) {
+                       /* free the pool of multicast addresses. */
+                       free(port->mc_addr_pool);
+                       port->mc_addr_pool = NULL;
+               }
+               return;
+       }
+       memmove(&port->mc_addr_pool[addr_idx],
+               &port->mc_addr_pool[addr_idx + 1],
+               sizeof(struct ether_addr) * (port->mc_addr_nb - addr_idx));
+}
+
+static void
+eth_port_multicast_addr_list_set(uint8_t port_id)
+{
+       struct rte_port *port;
+       int diag;
+
+       port = &ports[port_id];
+       diag = rte_eth_dev_set_mc_addr_list(port_id, port->mc_addr_pool,
+                                           port->mc_addr_nb);
+       if (diag == 0)
+               return;
+       printf("rte_eth_dev_set_mc_addr_list(port=%d, nb=%u) failed. diag=%d\n",
+              port->mc_addr_nb, port_id, -diag);
+}
+
+void
+mcast_addr_add(uint8_t port_id, struct ether_addr *mc_addr)
+{
+       struct rte_port *port;
+       uint32_t i;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return;
+
+       port = &ports[port_id];
+
+       /*
+        * Check that the added multicast MAC address is not already recorded
+        * in the pool of multicast addresses.
+        */
+       for (i = 0; i < port->mc_addr_nb; i++) {
+               if (is_same_ether_addr(mc_addr, &port->mc_addr_pool[i])) {
+                       printf("multicast address already filtered by port\n");
+                       return;
+               }
+       }
+
+       if (mcast_addr_pool_extend(port) != 0)
+               return;
+       ether_addr_copy(mc_addr, &port->mc_addr_pool[i]);
+       eth_port_multicast_addr_list_set(port_id);
+}
+
+void
+mcast_addr_remove(uint8_t port_id, struct ether_addr *mc_addr)
+{
+       struct rte_port *port;
+       uint32_t i;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return;
+
+       port = &ports[port_id];
+
+       /*
+        * Search the pool of multicast MAC addresses for the removed address.
+        */
+       for (i = 0; i < port->mc_addr_nb; i++) {
+               if (is_same_ether_addr(mc_addr, &port->mc_addr_pool[i]))
+                       break;
+       }
+       if (i == port->mc_addr_nb) {
+               printf("multicast address not filtered by port %d\n", port_id);
+               return;
+       }
+
+       mcast_addr_pool_remove(port, i);
+       eth_port_multicast_addr_list_set(port_id);
+}