qed: PF enforce MAC limitation of VFs
authorYuval Mintz <Yuval.Mintz@qlogic.com>
Sun, 5 Jun 2016 10:11:15 +0000 (13:11 +0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 7 Jun 2016 22:40:12 +0000 (15:40 -0700)
The only limitation relating to MACs the PF enforce today on its VFs
is in case it has a forced-unicast MAC address for them, in which case
they can't configure other unicast addresses.
Specifically, the PF isn't enforcing the number of MAC addresse a VF can
configure regardless of the nubmer of such filters agreed upon by PF and
VF during the acquisition process.

PF's shadow-config is now extended to also contain information about its
VFs' unicast addresses configuration, allowing such enforcement.

Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed_sriov.c
drivers/net/ethernet/qlogic/qed/qed_sriov.h

index 0ecd522fedd0a25f1f2494a6e509b36bc66f5aa3..c20437387c1926e624f3e96e7bbd93d90c7dc050 100644 (file)
@@ -2309,15 +2309,12 @@ out:
        qed_iov_send_response(p_hwfn, p_ptt, vf, length, status);
 }
 
-static int qed_iov_vf_update_unicast_shadow(struct qed_hwfn *p_hwfn,
-                                           struct qed_vf_info *p_vf,
-                                           struct qed_filter_ucast *p_params)
+static int qed_iov_vf_update_vlan_shadow(struct qed_hwfn *p_hwfn,
+                                        struct qed_vf_info *p_vf,
+                                        struct qed_filter_ucast *p_params)
 {
        int i;
 
-       if (p_params->type == QED_FILTER_MAC)
-               return 0;
-
        /* First remove entries and then add new ones */
        if (p_params->opcode == QED_FILTER_REMOVE) {
                for (i = 0; i < QED_ETH_VF_NUM_VLAN_FILTERS + 1; i++)
@@ -2370,6 +2367,80 @@ static int qed_iov_vf_update_unicast_shadow(struct qed_hwfn *p_hwfn,
        return 0;
 }
 
+static int qed_iov_vf_update_mac_shadow(struct qed_hwfn *p_hwfn,
+                                       struct qed_vf_info *p_vf,
+                                       struct qed_filter_ucast *p_params)
+{
+       int i;
+
+       /* If we're in forced-mode, we don't allow any change */
+       if (p_vf->bulletin.p_virt->valid_bitmap & (1 << MAC_ADDR_FORCED))
+               return 0;
+
+       /* First remove entries and then add new ones */
+       if (p_params->opcode == QED_FILTER_REMOVE) {
+               for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) {
+                       if (ether_addr_equal(p_vf->shadow_config.macs[i],
+                                            p_params->mac)) {
+                               memset(p_vf->shadow_config.macs[i], 0,
+                                      ETH_ALEN);
+                               break;
+                       }
+               }
+
+               if (i == QED_ETH_VF_NUM_MAC_FILTERS) {
+                       DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                                  "MAC isn't configured\n");
+                       return -EINVAL;
+               }
+       } else if (p_params->opcode == QED_FILTER_REPLACE ||
+                  p_params->opcode == QED_FILTER_FLUSH) {
+               for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++)
+                       memset(p_vf->shadow_config.macs[i], 0, ETH_ALEN);
+       }
+
+       /* List the new MAC address */
+       if (p_params->opcode != QED_FILTER_ADD &&
+           p_params->opcode != QED_FILTER_REPLACE)
+               return 0;
+
+       for (i = 0; i < QED_ETH_VF_NUM_MAC_FILTERS; i++) {
+               if (is_zero_ether_addr(p_vf->shadow_config.macs[i])) {
+                       ether_addr_copy(p_vf->shadow_config.macs[i],
+                                       p_params->mac);
+                       DP_VERBOSE(p_hwfn, QED_MSG_IOV,
+                                  "Added MAC at %d entry in shadow\n", i);
+                       break;
+               }
+       }
+
+       if (i == QED_ETH_VF_NUM_MAC_FILTERS) {
+               DP_VERBOSE(p_hwfn, QED_MSG_IOV, "No available place for MAC\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+qed_iov_vf_update_unicast_shadow(struct qed_hwfn *p_hwfn,
+                                struct qed_vf_info *p_vf,
+                                struct qed_filter_ucast *p_params)
+{
+       int rc = 0;
+
+       if (p_params->type == QED_FILTER_MAC) {
+               rc = qed_iov_vf_update_mac_shadow(p_hwfn, p_vf, p_params);
+               if (rc)
+                       return rc;
+       }
+
+       if (p_params->type == QED_FILTER_VLAN)
+               rc = qed_iov_vf_update_vlan_shadow(p_hwfn, p_vf, p_params);
+
+       return rc;
+}
+
 int qed_iov_chk_ucast(struct qed_hwfn *hwfn,
                      int vfid, struct qed_filter_ucast *params)
 {
index ea24795e6befdb9e7c22190a8b076dfd716bf1e2..96a72737f97a870ec04b846e88b820ee6aa20e8c 100644 (file)
@@ -120,6 +120,8 @@ struct qed_vf_shadow_config {
        /* Shadow copy of all guest vlans */
        struct qed_vf_vlan_shadow vlans[QED_ETH_VF_NUM_VLAN_FILTERS + 1];
 
+       /* Shadow copy of all configured MACs; Empty if forcing MACs */
+       u8 macs[QED_ETH_VF_NUM_MAC_FILTERS][ETH_ALEN];
        u8 inner_vlan_removal;
 };