net/hinic: add unicast and multicast MAC set
authorXiaoyun Wang <cloud.wangxiaoyun@huawei.com>
Thu, 10 Oct 2019 14:51:50 +0000 (22:51 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 23 Oct 2019 14:43:08 +0000 (16:43 +0200)
This patch adds unicast and multicast set interfaces.
Application can add or remove unicast MAC address, also can set
multicast MAC address, the maximum multicast list size is 2048.

Signed-off-by: Xiaoyun Wang <cloud.wangxiaoyun@huawei.com>
doc/guides/nics/hinic.rst
doc/guides/rel_notes/release_19_11.rst
drivers/net/hinic/base/hinic_pmd_niccfg.c
drivers/net/hinic/hinic_pmd_ethdev.c
drivers/net/hinic/hinic_pmd_ethdev.h

index 681519c..4df5f16 100644 (file)
@@ -28,6 +28,8 @@ Features
 - VLAN filter and VLAN offload
 - Allmulticast mode
 - MTU update
+- Unicast MAC filter
+- Multicast MAC filter
 
 Prerequisites
 -------------
index 803a0ff..db0aceb 100644 (file)
@@ -117,6 +117,7 @@ New Features
 
   * Enabled SR-IOV - Partially supported at this point, VFIO only.
   * Supported VLAN filter and VLAN offload.
+  * Supported Unicast MAC filter and Multicast MAC filter.
 
 * **Added Marvell NITROX symmetric crypto PMD.**
 
index 8bd7ed6..054925c 100644 (file)
@@ -249,6 +249,61 @@ int hinic_get_default_mac(void *hwdev, u8 *mac_addr)
        return 0;
 }
 
+/**
+*  hinic_update_mac - Update mac address to hardware.
+*
+* @param hwdev
+*   The hardware interface of a nic device.
+* @param old_mac
+*   Old mac address.
+* @param new_mac
+*   New mac address.
+* @param vlan_id
+*   Set 0 for mac_vlan table initialization.
+* @param func_id
+*   Global function id of NIC.
+*
+* @return
+*   0 on success.
+*   negative error value otherwise.
+*/
+int hinic_update_mac(void *hwdev, u8 *old_mac, u8 *new_mac, u16 vlan_id,
+                    u16 func_id)
+{
+       struct hinic_port_mac_update mac_info;
+       u16 out_size = sizeof(mac_info);
+       int err;
+
+       if (!hwdev || !old_mac || !new_mac) {
+               PMD_DRV_LOG(ERR, "Hwdev, old_mac or new_mac is NULL\n");
+               return -EINVAL;
+       }
+
+       memset(&mac_info, 0, sizeof(mac_info));
+       mac_info.mgmt_msg_head.resp_aeq_num = HINIC_AEQ1;
+       mac_info.func_id = func_id;
+       mac_info.vlan_id = vlan_id;
+       memcpy(mac_info.old_mac, old_mac, ETH_ALEN);
+       memcpy(mac_info.new_mac, new_mac, ETH_ALEN);
+
+       err = l2nic_msg_to_mgmt_sync(hwdev, HINIC_PORT_CMD_UPDATE_MAC,
+                                    &mac_info, sizeof(mac_info),
+                                    &mac_info, &out_size);
+       if (err || !out_size ||
+           (mac_info.mgmt_msg_head.status &&
+            mac_info.mgmt_msg_head.status != HINIC_PF_SET_VF_ALREADY)) {
+               PMD_DRV_LOG(ERR, "Failed to update MAC, err: %d, status: 0x%x, out size: 0x%x\n",
+                           err, mac_info.mgmt_msg_head.status, out_size);
+               return -EINVAL;
+       }
+       if (mac_info.mgmt_msg_head.status == HINIC_PF_SET_VF_ALREADY) {
+               PMD_DRV_LOG(WARNING, "PF has already set vf mac, Ignore update operation.\n");
+               return HINIC_PF_SET_VF_ALREADY;
+       }
+
+       return 0;
+}
+
 /**
  * hinic_set_port_mtu -  Set MTU to port.
  *
index 96967a3..91b4f98 100644 (file)
@@ -51,8 +51,8 @@
 #define NR_MAX_COS                     8
 
 #define HINIC_MIN_RX_BUF_SIZE          1024
-#define HINIC_MAX_MAC_ADDRS            1
-
+#define HINIC_MAX_UC_MAC_ADDRS         128
+#define HINIC_MAX_MC_MAC_ADDRS         2048
 /*
  * vlan_id is a 12 bit number.
  * The VFTA array is actually a 4096 bit array, 128 of 32bit elements.
@@ -716,7 +716,7 @@ hinic_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
        info->max_tx_queues  = nic_dev->nic_cap.max_sqs;
        info->min_rx_bufsize = HINIC_MIN_RX_BUF_SIZE;
        info->max_rx_pktlen  = HINIC_MAX_JUMBO_FRAME_SIZE;
-       info->max_mac_addrs  = HINIC_MAX_MAC_ADDRS;
+       info->max_mac_addrs  = HINIC_MAX_UC_MAC_ADDRS;
        info->min_mtu = HINIC_MIN_MTU_SIZE;
        info->max_mtu = HINIC_MAX_MTU_SIZE;
 
@@ -1342,21 +1342,41 @@ static int hinic_init_mac_addr(struct rte_eth_dev *eth_dev)
        if (rc)
                return rc;
 
-       memmove(eth_dev->data->mac_addrs->addr_bytes,
-               addr_bytes, RTE_ETHER_ADDR_LEN);
-
-       if (rte_is_zero_ether_addr(eth_dev->data->mac_addrs))
-               hinic_gen_random_mac_addr(eth_dev->data->mac_addrs);
+       rte_ether_addr_copy((struct rte_ether_addr *)addr_bytes,
+               &eth_dev->data->mac_addrs[0]);
+       if (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[0]))
+               hinic_gen_random_mac_addr(&eth_dev->data->mac_addrs[0]);
 
        func_id = hinic_global_func_id(nic_dev->hwdev);
-       rc = hinic_set_mac(nic_dev->hwdev, eth_dev->data->mac_addrs->addr_bytes,
-                          0, func_id);
+       rc = hinic_set_mac(nic_dev->hwdev,
+                       eth_dev->data->mac_addrs[0].addr_bytes,
+                       0, func_id);
        if (rc && rc != HINIC_PF_SET_VF_ALREADY)
                return rc;
 
+       rte_ether_addr_copy(&eth_dev->data->mac_addrs[0],
+                       &nic_dev->default_addr);
+
        return 0;
 }
 
+static void hinic_delete_mc_addr_list(struct hinic_nic_dev *nic_dev)
+{
+       u16 func_id;
+       u32 i;
+
+       func_id = hinic_global_func_id(nic_dev->hwdev);
+
+       for (i = 0; i < HINIC_MAX_MC_MAC_ADDRS; i++) {
+               if (rte_is_zero_ether_addr(&nic_dev->mc_list[i]))
+                       break;
+
+               hinic_del_mac(nic_dev->hwdev, nic_dev->mc_list[i].addr_bytes,
+                             0, func_id);
+               memset(&nic_dev->mc_list[i], 0, sizeof(struct rte_ether_addr));
+       }
+}
+
 /**
  * Deinit mac_vlan table in NIC.
  *
@@ -1371,19 +1391,29 @@ static void hinic_deinit_mac_addr(struct rte_eth_dev *eth_dev)
 {
        struct hinic_nic_dev *nic_dev =
                                HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
-       int rc;
        u16 func_id = 0;
-
-       if (rte_is_zero_ether_addr(eth_dev->data->mac_addrs))
-               return;
+       int rc;
+       int i;
 
        func_id = hinic_global_func_id(nic_dev->hwdev);
-       rc = hinic_del_mac(nic_dev->hwdev,
-                          eth_dev->data->mac_addrs->addr_bytes,
-                          0, func_id);
-       if (rc && rc != HINIC_PF_SET_VF_ALREADY)
-               PMD_DRV_LOG(ERR, "Delete mac table failed, dev_name: %s",
-                           eth_dev->data->name);
+
+       for (i = 0; i < HINIC_MAX_UC_MAC_ADDRS; i++) {
+               if (rte_is_zero_ether_addr(&eth_dev->data->mac_addrs[i]))
+                       continue;
+
+               rc = hinic_del_mac(nic_dev->hwdev,
+                                  eth_dev->data->mac_addrs[i].addr_bytes,
+                                  0, func_id);
+               if (rc && rc != HINIC_PF_SET_VF_ALREADY)
+                       PMD_DRV_LOG(ERR, "Delete mac table failed, dev_name: %s",
+                                   eth_dev->data->name);
+
+               memset(&eth_dev->data->mac_addrs[i], 0,
+                      sizeof(struct rte_ether_addr));
+       }
+
+       /* delete multicast mac addrs */
+       hinic_delete_mc_addr_list(nic_dev);
 }
 
 static int hinic_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
@@ -2091,6 +2121,169 @@ static int hinic_dev_xstats_get_names(struct rte_eth_dev *dev,
 
        return count;
 }
+/**
+ *  DPDK callback to set mac address
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param addr
+ *   Pointer to mac address
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int hinic_set_mac_addr(struct rte_eth_dev *dev,
+                             struct rte_ether_addr *addr)
+{
+       struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       u16 func_id;
+       int err;
+
+       func_id = hinic_global_func_id(nic_dev->hwdev);
+       err = hinic_update_mac(nic_dev->hwdev, nic_dev->default_addr.addr_bytes,
+                              addr->addr_bytes, 0, func_id);
+       if (err)
+               return err;
+
+       rte_ether_addr_copy(addr, &nic_dev->default_addr);
+
+       PMD_DRV_LOG(INFO, "Set new mac address %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   addr->addr_bytes[0], addr->addr_bytes[1],
+                   addr->addr_bytes[2], addr->addr_bytes[3],
+                   addr->addr_bytes[4], addr->addr_bytes[5]);
+
+       return 0;
+}
+
+/**
+ * DPDK callback to remove a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param index
+ *   MAC address index.
+ */
+static void hinic_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+       struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       u16 func_id;
+       int ret;
+
+       if (index >= HINIC_MAX_UC_MAC_ADDRS) {
+               PMD_DRV_LOG(INFO, "Remove mac index(%u) is out of range",
+                           index);
+               return;
+       }
+
+       func_id = hinic_global_func_id(nic_dev->hwdev);
+       ret = hinic_del_mac(nic_dev->hwdev,
+                           dev->data->mac_addrs[index].addr_bytes, 0, func_id);
+       if (ret)
+               return;
+
+       memset(&dev->data->mac_addrs[index], 0, sizeof(struct rte_ether_addr));
+}
+
+/**
+ * DPDK callback to add a MAC address.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mac_addr
+ *   MAC address to register.
+ * @param index
+ *   MAC address index.
+ * @param vmdq
+ *   VMDq pool index to associate address with (ignored).
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+
+static int hinic_mac_addr_add(struct rte_eth_dev *dev,
+                             struct rte_ether_addr *mac_addr, uint32_t index,
+                             __rte_unused uint32_t vmdq)
+{
+       struct hinic_nic_dev  *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       unsigned int i;
+       u16 func_id;
+       int ret;
+
+       if (index >= HINIC_MAX_UC_MAC_ADDRS) {
+               PMD_DRV_LOG(INFO, "Add mac index(%u) is out of range,", index);
+               return -EINVAL;
+       }
+
+       /* First, make sure this address isn't already configured. */
+       for (i = 0; (i != HINIC_MAX_UC_MAC_ADDRS); ++i) {
+               /* Skip this index, it's going to be reconfigured. */
+               if (i == index)
+                       continue;
+
+               if (memcmp(&dev->data->mac_addrs[i],
+                       mac_addr, sizeof(*mac_addr)))
+                       continue;
+
+               PMD_DRV_LOG(INFO, "MAC address already configured");
+               return -EADDRINUSE;
+       }
+
+       func_id = hinic_global_func_id(nic_dev->hwdev);
+       ret = hinic_set_mac(nic_dev->hwdev, mac_addr->addr_bytes, 0, func_id);
+       if (ret)
+               return ret;
+
+       dev->data->mac_addrs[index] = *mac_addr;
+       return 0;
+}
+
+/**
+ *  DPDK callback to set multicast mac address
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param mc_addr_set
+ *   Pointer to multicast mac address
+ * @param nb_mc_addr
+ *   mc addr count
+ * @return
+ *   0 on success, negative error value otherwise.
+ */
+static int hinic_set_mc_addr_list(struct rte_eth_dev *dev,
+                                 struct rte_ether_addr *mc_addr_set,
+                                 uint32_t nb_mc_addr)
+{
+       struct hinic_nic_dev *nic_dev = HINIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+       u16 func_id;
+       int ret;
+       u32 i;
+
+       func_id = hinic_global_func_id(nic_dev->hwdev);
+
+       /* delete old multi_cast addrs firstly */
+       hinic_delete_mc_addr_list(nic_dev);
+
+       if (nb_mc_addr > HINIC_MAX_MC_MAC_ADDRS)
+               goto allmulti;
+
+       for (i = 0; i < nb_mc_addr; i++) {
+               ret = hinic_set_mac(nic_dev->hwdev, mc_addr_set[i].addr_bytes,
+                                   0, func_id);
+               /* if add mc addr failed, set all multi_cast */
+               if (ret) {
+                       hinic_delete_mc_addr_list(nic_dev);
+                       goto allmulti;
+               }
+
+               rte_ether_addr_copy(&mc_addr_set[i], &nic_dev->mc_list[i]);
+       }
+
+       return 0;
+
+allmulti:
+       hinic_dev_allmulticast_enable(dev);
+
+       return 0;
+}
 
 static int hinic_set_default_pause_feature(struct hinic_nic_dev *nic_dev)
 {
@@ -2539,6 +2732,10 @@ static const struct eth_dev_ops hinic_pmd_ops = {
        .xstats_get                    = hinic_dev_xstats_get,
        .xstats_reset                  = hinic_dev_xstats_reset,
        .xstats_get_names              = hinic_dev_xstats_get_names,
+       .mac_addr_set                  = hinic_set_mac_addr,
+       .mac_addr_remove               = hinic_mac_addr_remove,
+       .mac_addr_add                  = hinic_mac_addr_add,
+       .set_mc_addr_list              = hinic_set_mc_addr_list,
 };
 
 static const struct eth_dev_ops hinic_pmd_vf_ops = {
@@ -2566,6 +2763,10 @@ static const struct eth_dev_ops hinic_pmd_vf_ops = {
        .xstats_get                    = hinic_dev_xstats_get,
        .xstats_reset                  = hinic_dev_xstats_reset,
        .xstats_get_names              = hinic_dev_xstats_get_names,
+       .mac_addr_set                  = hinic_set_mac_addr,
+       .mac_addr_remove               = hinic_mac_addr_remove,
+       .mac_addr_add                  = hinic_mac_addr_add,
+       .set_mc_addr_list              = hinic_set_mc_addr_list,
 };
 
 static int hinic_func_init(struct rte_eth_dev *eth_dev)
@@ -2573,6 +2774,7 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
        struct rte_pci_device *pci_dev;
        struct rte_ether_addr *eth_addr;
        struct hinic_nic_dev *nic_dev;
+       u32 mac_size;
        int rc;
 
        pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
@@ -2599,7 +2801,8 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
                 pci_dev->addr.devid, pci_dev->addr.function);
 
        /* alloc mac_addrs */
-       eth_addr = rte_zmalloc("hinic_mac", sizeof(*eth_addr), 0);
+       mac_size = HINIC_MAX_UC_MAC_ADDRS * sizeof(struct rte_ether_addr);
+       eth_addr = rte_zmalloc("hinic_mac", mac_size, 0);
        if (!eth_addr) {
                PMD_DRV_LOG(ERR, "Allocate ethernet addresses' memory failed, dev_name: %s",
                            eth_dev->data->name);
@@ -2608,6 +2811,15 @@ static int hinic_func_init(struct rte_eth_dev *eth_dev)
        }
        eth_dev->data->mac_addrs = eth_addr;
 
+       mac_size = HINIC_MAX_MC_MAC_ADDRS * sizeof(struct rte_ether_addr);
+       nic_dev->mc_list = rte_zmalloc("hinic_mc", mac_size, 0);
+       if (!nic_dev->mc_list) {
+               PMD_DRV_LOG(ERR, "Allocate mcast address' memory failed, dev_name: %s",
+                           eth_dev->data->name);
+               rc = -ENOMEM;
+               goto mc_addr_fail;
+       }
+
        /*
         * Pass the information to the rte_eth_dev_close() that it should also
         * release the private port resources.
@@ -2672,6 +2884,10 @@ init_mac_fail:
        hinic_nic_dev_destroy(eth_dev);
 
 create_nic_dev_fail:
+       rte_free(nic_dev->mc_list);
+       nic_dev->mc_list = NULL;
+
+mc_addr_fail:
        rte_free(eth_addr);
        eth_dev->data->mac_addrs = NULL;
 
@@ -2716,6 +2932,8 @@ static int hinic_dev_uninit(struct rte_eth_dev *dev)
        dev->rx_pkt_burst = NULL;
        dev->tx_pkt_burst = NULL;
 
+       rte_free(nic_dev->mc_list);
+
        rte_free(dev->data->mac_addrs);
        dev->data->mac_addrs = NULL;
 
index f7a1167..b4f93ad 100644 (file)
@@ -56,6 +56,8 @@ struct hinic_nic_dev {
 
        u32 vfta[HINIC_VFTA_SIZE];      /* VLAN bitmap */
 
+       struct rte_ether_addr default_addr;
+       struct rte_ether_addr *mc_list;
        /* info */
        unsigned int flags;
        struct nic_service_cap nic_cap;