app/testpmd: new command to add/remove multicast MAC addresses
authorIvan Boule <ivan.boule@6wind.com>
Thu, 28 May 2015 15:05:20 +0000 (17:05 +0200)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 12 Jun 2015 13:55:38 +0000 (15:55 +0200)
Add the new interactive command:
    mcast_addr add|remove X <mcast_addr>
to add/remove the multicast MAC address <mcast_addr> to/from the set of
multicast addresses filtered by port <X>.
Command used to test the function "rte_eth_dev_set_mc_addr_list"
that has been added to the API of PMDs.

Signed-off-by: Ivan Boule <ivan.boule@6wind.com>
app/test-pmd/cmdline.c
app/test-pmd/config.c
app/test-pmd/testpmd.h

index f01db2a..952a9df 100644 (file)
@@ -8733,6 +8733,57 @@ cmdline_parse_inst_t cmd_set_hash_global_config = {
        },
 };
 
+/* *** ADD/REMOVE A MULTICAST MAC ADDRESS TO/FROM A PORT *** */
+struct cmd_mcast_addr_result {
+       cmdline_fixed_string_t mcast_addr_cmd;
+       cmdline_fixed_string_t what;
+       uint8_t port_num;
+       struct ether_addr mc_addr;
+};
+
+static void cmd_mcast_addr_parsed(void *parsed_result,
+               __attribute__((unused)) struct cmdline *cl,
+               __attribute__((unused)) void *data)
+{
+       struct cmd_mcast_addr_result *res = parsed_result;
+
+       if (!is_multicast_ether_addr(&res->mc_addr)) {
+               printf("Invalid multicast addr %02X:%02X:%02X:%02X:%02X:%02X\n",
+                      res->mc_addr.addr_bytes[0], res->mc_addr.addr_bytes[1],
+                      res->mc_addr.addr_bytes[2], res->mc_addr.addr_bytes[3],
+                      res->mc_addr.addr_bytes[4], res->mc_addr.addr_bytes[5]);
+               return;
+       }
+       if (strcmp(res->what, "add") == 0)
+               mcast_addr_add(res->port_num, &res->mc_addr);
+       else
+               mcast_addr_remove(res->port_num, &res->mc_addr);
+}
+
+cmdline_parse_token_string_t cmd_mcast_addr_cmd =
+       TOKEN_STRING_INITIALIZER(struct cmd_mcast_addr_result,
+                                mcast_addr_cmd, "mcast_addr");
+cmdline_parse_token_string_t cmd_mcast_addr_what =
+       TOKEN_STRING_INITIALIZER(struct cmd_mcast_addr_result, what,
+                                "add#remove");
+cmdline_parse_token_num_t cmd_mcast_addr_portnum =
+       TOKEN_NUM_INITIALIZER(struct cmd_mcast_addr_result, port_num, UINT8);
+cmdline_parse_token_etheraddr_t cmd_mcast_addr_addr =
+       TOKEN_ETHERADDR_INITIALIZER(struct cmd_mac_addr_result, address);
+
+cmdline_parse_inst_t cmd_mcast_addr = {
+       .f = cmd_mcast_addr_parsed,
+       .data = (void *)0,
+       .help_str = "mcast_addr add|remove X <mcast_addr>: add/remove multicast MAC address on port X",
+       .tokens = {
+               (void *)&cmd_mcast_addr_cmd,
+               (void *)&cmd_mcast_addr_what,
+               (void *)&cmd_mcast_addr_portnum,
+               (void *)&cmd_mcast_addr_addr,
+               NULL,
+       },
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -8862,6 +8913,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
        (cmdline_parse_inst_t *)&cmd_get_hash_global_config,
        (cmdline_parse_inst_t *)&cmd_set_hash_global_config,
+       (cmdline_parse_inst_t *)&cmd_mcast_addr,
        NULL,
 };
 
index f788ed5..52917c7 100644 (file)
@@ -2130,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);
+}
index c3b6700..f2c84d9 100644 (file)
@@ -162,6 +162,8 @@ struct rte_port {
        uint8_t                 dcb_flag;   /**< enable dcb */
        struct rte_eth_rxconf   rx_conf;    /**< rx configuration */
        struct rte_eth_txconf   tx_conf;    /**< tx configuration */
+       struct ether_addr       *mc_addr_pool; /**< pool of multicast addrs */
+       uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
 };
 
 extern portid_t __rte_unused
@@ -563,6 +565,10 @@ void get_5tuple_filter(uint8_t port_id, uint16_t index);
 int rx_queue_id_is_invalid(queueid_t rxq_id);
 int tx_queue_id_is_invalid(queueid_t txq_id);
 
+/* Functions to manage the set of filtered Multicast MAC addresses */
+void mcast_addr_add(uint8_t port_id, struct ether_addr *mc_addr);
+void mcast_addr_remove(uint8_t port_id, struct ether_addr *mc_addr);
+
 enum print_warning {
        ENABLED_WARN = 0,
        DISABLED_WARN