aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx4
diff options
context:
space:
mode:
authorYan Burman <yanb@mellanox.com>2013-02-06 21:25:26 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-07 23:26:13 -0500
commitcc5387f7346a9f35aaf7f35133666fa8acbcbde3 (patch)
tree1c22c0c9d2eefda65a11bcc2a0acaa72dc8360c8 /drivers/net/ethernet/mellanox/mlx4
parentc07cb4b0ab78f279ea94c3b4661cad86eb02a5d9 (diff)
net/mlx4_en: Add unicast MAC filtering
Implement and advertise unicast MAC filtering, such that setting macvlan instance over mlx4_en interfaces will not require the networking core to put mlx4_en devices in promiscuous mode. If for some reason adding a unicast address filter fails e.g as of missing space in the HW mac table, the device forces itself into promiscuous mode (and out of this forced state when enough space is available). Signed-off-by: Yan Burman <yanb@mellanox.com> Signed-off-by: Amir Vadai <amirv@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c129
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h3
2 files changed, 130 insertions, 2 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 8eb24ee598e2..2c19dabccb9a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1016,6 +1016,126 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
1016 } 1016 }
1017} 1017}
1018 1018
1019static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
1020 struct net_device *dev,
1021 struct mlx4_en_dev *mdev)
1022{
1023 struct netdev_hw_addr *ha;
1024 struct mlx4_mac_entry *entry;
1025 struct hlist_node *n, *tmp;
1026 bool found;
1027 u64 mac;
1028 int err = 0;
1029 struct hlist_head *bucket;
1030 unsigned int i;
1031 int removed = 0;
1032 u32 prev_flags;
1033
1034 /* Note that we do not need to protect our mac_hash traversal with rcu,
1035 * since all modification code is protected by mdev->state_lock
1036 */
1037
1038 /* find what to remove */
1039 for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
1040 bucket = &priv->mac_hash[i];
1041 hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
1042 found = false;
1043 netdev_for_each_uc_addr(ha, dev) {
1044 if (ether_addr_equal_64bits(entry->mac,
1045 ha->addr)) {
1046 found = true;
1047 break;
1048 }
1049 }
1050
1051 /* MAC address of the port is not in uc list */
1052 if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
1053 found = true;
1054
1055 if (!found) {
1056 mac = mlx4_en_mac_to_u64(entry->mac);
1057 mlx4_en_uc_steer_release(priv, entry->mac,
1058 priv->base_qpn,
1059 entry->reg_id);
1060 mlx4_unregister_mac(mdev->dev, priv->port, mac);
1061
1062 hlist_del_rcu(&entry->hlist);
1063 kfree_rcu(entry, rcu);
1064 en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n",
1065 entry->mac, priv->port);
1066 ++removed;
1067 }
1068 }
1069 }
1070
1071 /* if we didn't remove anything, there is no use in trying to add
1072 * again once we are in a forced promisc mode state
1073 */
1074 if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed)
1075 return;
1076
1077 prev_flags = priv->flags;
1078 priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
1079
1080 /* find what to add */
1081 netdev_for_each_uc_addr(ha, dev) {
1082 found = false;
1083 bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]];
1084 hlist_for_each_entry(entry, n, bucket, hlist) {
1085 if (ether_addr_equal_64bits(entry->mac, ha->addr)) {
1086 found = true;
1087 break;
1088 }
1089 }
1090
1091 if (!found) {
1092 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1093 if (!entry) {
1094 en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n",
1095 ha->addr, priv->port);
1096 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1097 break;
1098 }
1099 mac = mlx4_en_mac_to_u64(ha->addr);
1100 memcpy(entry->mac, ha->addr, ETH_ALEN);
1101 err = mlx4_register_mac(mdev->dev, priv->port, mac);
1102 if (err < 0) {
1103 en_err(priv, "Failed registering MAC %pM on port %d: %d\n",
1104 ha->addr, priv->port, err);
1105 kfree(entry);
1106 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1107 break;
1108 }
1109 err = mlx4_en_uc_steer_add(priv, ha->addr,
1110 &priv->base_qpn,
1111 &entry->reg_id);
1112 if (err) {
1113 en_err(priv, "Failed adding MAC %pM on port %d: %d\n",
1114 ha->addr, priv->port, err);
1115 mlx4_unregister_mac(mdev->dev, priv->port, mac);
1116 kfree(entry);
1117 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1118 break;
1119 } else {
1120 unsigned int mac_hash;
1121 en_dbg(DRV, priv, "Added MAC %pM on port:%d\n",
1122 ha->addr, priv->port);
1123 mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX];
1124 bucket = &priv->mac_hash[mac_hash];
1125 hlist_add_head_rcu(&entry->hlist, bucket);
1126 }
1127 }
1128 }
1129
1130 if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) {
1131 en_warn(priv, "Forcing promiscuous mode on port:%d\n",
1132 priv->port);
1133 } else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) {
1134 en_warn(priv, "Stop forcing promiscuous mode on port:%d\n",
1135 priv->port);
1136 }
1137}
1138
1019static void mlx4_en_do_set_rx_mode(struct work_struct *work) 1139static void mlx4_en_do_set_rx_mode(struct work_struct *work)
1020{ 1140{
1021 struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1141 struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
@@ -1043,8 +1163,12 @@ static void mlx4_en_do_set_rx_mode(struct work_struct *work)
1043 } 1163 }
1044 } 1164 }
1045 1165
1166 if (dev->priv_flags & IFF_UNICAST_FLT)
1167 mlx4_en_do_uc_filter(priv, dev, mdev);
1168
1046 /* Promsicuous mode: disable all filters */ 1169 /* Promsicuous mode: disable all filters */
1047 if (dev->flags & IFF_PROMISC) { 1170 if ((dev->flags & IFF_PROMISC) ||
1171 (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) {
1048 mlx4_en_set_promisc_mode(priv, mdev); 1172 mlx4_en_set_promisc_mode(priv, mdev);
1049 goto out; 1173 goto out;
1050 } 1174 }
@@ -1961,6 +2085,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
1961 MLX4_STEERING_MODE_DEVICE_MANAGED) 2085 MLX4_STEERING_MODE_DEVICE_MANAGED)
1962 dev->hw_features |= NETIF_F_NTUPLE; 2086 dev->hw_features |= NETIF_F_NTUPLE;
1963 2087
2088 if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
2089 dev->priv_flags |= IFF_UNICAST_FLT;
2090
1964 mdev->pndev[port] = dev; 2091 mdev->pndev[port] = dev;
1965 2092
1966 netif_carrier_off(dev); 2093 netif_carrier_off(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 0ff99e0b2ea3..c313d7e943a9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -439,7 +439,8 @@ enum {
439 */ 439 */
440 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2), 440 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
441 /* whether we need to drop packets that hardware loopback-ed */ 441 /* whether we need to drop packets that hardware loopback-ed */
442 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3) 442 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3),
443 MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4)
443}; 444};
444 445
445#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) 446#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)