365 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB2/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */3 4#include "macsec.h"5#include <linux/mlx5/macsec.h>6 7struct mlx5_reserved_gids {8 int macsec_index;9 const struct ib_gid_attr *physical_gid;10};11 12struct mlx5_roce_gids {13 struct list_head roce_gid_list_entry;14 u16 gid_idx;15 union {16 struct sockaddr_in sockaddr_in;17 struct sockaddr_in6 sockaddr_in6;18 } addr;19};20 21struct mlx5_macsec_device {22 struct list_head macsec_devices_list_entry;23 void *macdev;24 struct list_head macsec_roce_gids;25 struct list_head tx_rules_list;26 struct list_head rx_rules_list;27};28 29static void cleanup_macsec_device(struct mlx5_macsec_device *macsec_device)30{31 if (!list_empty(&macsec_device->tx_rules_list) ||32 !list_empty(&macsec_device->rx_rules_list) ||33 !list_empty(&macsec_device->macsec_roce_gids))34 return;35 36 list_del(&macsec_device->macsec_devices_list_entry);37 kfree(macsec_device);38}39 40static struct mlx5_macsec_device *get_macsec_device(void *macdev,41 struct list_head *macsec_devices_list)42{43 struct mlx5_macsec_device *iter, *macsec_device = NULL;44 45 list_for_each_entry(iter, macsec_devices_list, macsec_devices_list_entry) {46 if (iter->macdev == macdev) {47 macsec_device = iter;48 break;49 }50 }51 52 if (macsec_device)53 return macsec_device;54 55 macsec_device = kzalloc(sizeof(*macsec_device), GFP_KERNEL);56 if (!macsec_device)57 return NULL;58 59 macsec_device->macdev = macdev;60 INIT_LIST_HEAD(&macsec_device->tx_rules_list);61 INIT_LIST_HEAD(&macsec_device->rx_rules_list);62 INIT_LIST_HEAD(&macsec_device->macsec_roce_gids);63 list_add(&macsec_device->macsec_devices_list_entry, macsec_devices_list);64 65 return macsec_device;66}67 68static void mlx5_macsec_del_roce_gid(struct mlx5_macsec_device *macsec_device, u16 gid_idx)69{70 struct mlx5_roce_gids *current_gid, *next_gid;71 72 list_for_each_entry_safe(current_gid, next_gid, &macsec_device->macsec_roce_gids,73 roce_gid_list_entry)74 if (current_gid->gid_idx == gid_idx) {75 list_del(¤t_gid->roce_gid_list_entry);76 kfree(current_gid);77 }78}79 80static void mlx5_macsec_save_roce_gid(struct mlx5_macsec_device *macsec_device,81 const struct sockaddr *addr, u16 gid_idx)82{83 struct mlx5_roce_gids *roce_gids;84 85 roce_gids = kzalloc(sizeof(*roce_gids), GFP_KERNEL);86 if (!roce_gids)87 return;88 89 roce_gids->gid_idx = gid_idx;90 if (addr->sa_family == AF_INET)91 memcpy(&roce_gids->addr.sockaddr_in, addr, sizeof(roce_gids->addr.sockaddr_in));92 else93 memcpy(&roce_gids->addr.sockaddr_in6, addr, sizeof(roce_gids->addr.sockaddr_in6));94 95 list_add_tail(&roce_gids->roce_gid_list_entry, &macsec_device->macsec_roce_gids);96}97 98static void handle_macsec_gids(struct list_head *macsec_devices_list,99 struct mlx5_macsec_event_data *data)100{101 struct mlx5_macsec_device *macsec_device;102 struct mlx5_roce_gids *gid;103 104 macsec_device = get_macsec_device(data->macdev, macsec_devices_list);105 if (!macsec_device)106 return;107 108 list_for_each_entry(gid, &macsec_device->macsec_roce_gids, roce_gid_list_entry) {109 mlx5_macsec_add_roce_sa_rules(data->fs_id, (struct sockaddr *)&gid->addr,110 gid->gid_idx, &macsec_device->tx_rules_list,111 &macsec_device->rx_rules_list, data->macsec_fs,112 data->is_tx);113 }114}115 116static void del_sa_roce_rule(struct list_head *macsec_devices_list,117 struct mlx5_macsec_event_data *data)118{119 struct mlx5_macsec_device *macsec_device;120 121 macsec_device = get_macsec_device(data->macdev, macsec_devices_list);122 WARN_ON(!macsec_device);123 124 mlx5_macsec_del_roce_sa_rules(data->fs_id, data->macsec_fs,125 &macsec_device->tx_rules_list,126 &macsec_device->rx_rules_list, data->is_tx);127}128 129static int macsec_event(struct notifier_block *nb, unsigned long event, void *data)130{131 struct mlx5_macsec *macsec = container_of(nb, struct mlx5_macsec, blocking_events_nb);132 133 mutex_lock(&macsec->lock);134 switch (event) {135 case MLX5_DRIVER_EVENT_MACSEC_SA_ADDED:136 handle_macsec_gids(&macsec->macsec_devices_list, data);137 break;138 case MLX5_DRIVER_EVENT_MACSEC_SA_DELETED:139 del_sa_roce_rule(&macsec->macsec_devices_list, data);140 break;141 default:142 mutex_unlock(&macsec->lock);143 return NOTIFY_DONE;144 }145 mutex_unlock(&macsec->lock);146 return NOTIFY_OK;147}148 149void mlx5r_macsec_event_register(struct mlx5_ib_dev *dev)150{151 if (!mlx5_is_macsec_roce_supported(dev->mdev)) {152 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");153 return;154 }155 156 dev->macsec.blocking_events_nb.notifier_call = macsec_event;157 blocking_notifier_chain_register(&dev->mdev->macsec_nh,158 &dev->macsec.blocking_events_nb);159}160 161void mlx5r_macsec_event_unregister(struct mlx5_ib_dev *dev)162{163 if (!mlx5_is_macsec_roce_supported(dev->mdev)) {164 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");165 return;166 }167 168 blocking_notifier_chain_unregister(&dev->mdev->macsec_nh,169 &dev->macsec.blocking_events_nb);170}171 172int mlx5r_macsec_init_gids_and_devlist(struct mlx5_ib_dev *dev)173{174 int i, j, max_gids;175 176 if (!mlx5_is_macsec_roce_supported(dev->mdev)) {177 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");178 return 0;179 }180 181 max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);182 for (i = 0; i < dev->num_ports; i++) {183 dev->port[i].reserved_gids = kcalloc(max_gids,184 sizeof(*dev->port[i].reserved_gids),185 GFP_KERNEL);186 if (!dev->port[i].reserved_gids)187 goto err;188 189 for (j = 0; j < max_gids; j++)190 dev->port[i].reserved_gids[j].macsec_index = -1;191 }192 193 INIT_LIST_HEAD(&dev->macsec.macsec_devices_list);194 mutex_init(&dev->macsec.lock);195 196 return 0;197err:198 while (i >= 0) {199 kfree(dev->port[i].reserved_gids);200 i--;201 }202 return -ENOMEM;203}204 205void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev)206{207 int i;208 209 if (!mlx5_is_macsec_roce_supported(dev->mdev))210 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");211 212 for (i = 0; i < dev->num_ports; i++)213 kfree(dev->port[i].reserved_gids);214 215 mutex_destroy(&dev->macsec.lock);216}217 218int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr)219{220 struct mlx5_ib_dev *dev = to_mdev(attr->device);221 struct mlx5_macsec_device *macsec_device;222 const struct ib_gid_attr *physical_gid;223 struct mlx5_reserved_gids *mgids;224 struct net_device *ndev;225 int ret = 0;226 union {227 struct sockaddr_in sockaddr_in;228 struct sockaddr_in6 sockaddr_in6;229 } addr;230 231 if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)232 return 0;233 234 if (!mlx5_is_macsec_roce_supported(dev->mdev)) {235 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");236 return 0;237 }238 239 rcu_read_lock();240 ndev = rcu_dereference(attr->ndev);241 if (!ndev) {242 rcu_read_unlock();243 return -ENODEV;244 }245 246 if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {247 rcu_read_unlock();248 return 0;249 }250 dev_hold(ndev);251 rcu_read_unlock();252 253 mutex_lock(&dev->macsec.lock);254 macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);255 if (!macsec_device) {256 ret = -ENOMEM;257 goto dev_err;258 }259 260 physical_gid = rdma_find_gid(attr->device, &attr->gid,261 attr->gid_type, NULL);262 if (!IS_ERR(physical_gid)) {263 ret = set_roce_addr(to_mdev(physical_gid->device),264 physical_gid->port_num,265 physical_gid->index, NULL,266 physical_gid);267 if (ret)268 goto gid_err;269 270 mgids = &dev->port[attr->port_num - 1].reserved_gids[physical_gid->index];271 mgids->macsec_index = attr->index;272 mgids->physical_gid = physical_gid;273 }274 275 /* Proceed with adding steering rules, regardless if there was gid ambiguity or not.*/276 rdma_gid2ip((struct sockaddr *)&addr, &attr->gid);277 ret = mlx5_macsec_add_roce_rule(ndev, (struct sockaddr *)&addr, attr->index,278 &macsec_device->tx_rules_list,279 &macsec_device->rx_rules_list, dev->mdev->macsec_fs);280 if (ret && !IS_ERR(physical_gid))281 goto rule_err;282 283 mlx5_macsec_save_roce_gid(macsec_device, (struct sockaddr *)&addr, attr->index);284 285 dev_put(ndev);286 mutex_unlock(&dev->macsec.lock);287 return ret;288 289rule_err:290 set_roce_addr(to_mdev(physical_gid->device), physical_gid->port_num,291 physical_gid->index, &physical_gid->gid, physical_gid);292 mgids->macsec_index = -1;293gid_err:294 rdma_put_gid_attr(physical_gid);295 cleanup_macsec_device(macsec_device);296dev_err:297 dev_put(ndev);298 mutex_unlock(&dev->macsec.lock);299 return ret;300}301 302void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr)303{304 struct mlx5_ib_dev *dev = to_mdev(attr->device);305 struct mlx5_macsec_device *macsec_device;306 struct mlx5_reserved_gids *mgids;307 struct net_device *ndev;308 int i, max_gids;309 310 if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)311 return;312 313 if (!mlx5_is_macsec_roce_supported(dev->mdev)) {314 mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");315 return;316 }317 318 mgids = &dev->port[attr->port_num - 1].reserved_gids[attr->index];319 if (mgids->macsec_index != -1) { /* Checking if physical gid has ambiguous IP */320 rdma_put_gid_attr(mgids->physical_gid);321 mgids->macsec_index = -1;322 return;323 }324 325 rcu_read_lock();326 ndev = rcu_dereference(attr->ndev);327 if (!ndev) {328 rcu_read_unlock();329 return;330 }331 332 if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {333 rcu_read_unlock();334 return;335 }336 dev_hold(ndev);337 rcu_read_unlock();338 339 mutex_lock(&dev->macsec.lock);340 max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);341 for (i = 0; i < max_gids; i++) { /* Checking if macsec gid has ambiguous IP */342 mgids = &dev->port[attr->port_num - 1].reserved_gids[i];343 if (mgids->macsec_index == attr->index) {344 const struct ib_gid_attr *physical_gid = mgids->physical_gid;345 346 set_roce_addr(to_mdev(physical_gid->device),347 physical_gid->port_num,348 physical_gid->index,349 &physical_gid->gid, physical_gid);350 351 rdma_put_gid_attr(physical_gid);352 mgids->macsec_index = -1;353 break;354 }355 }356 macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);357 mlx5_macsec_del_roce_rule(attr->index, dev->mdev->macsec_fs,358 &macsec_device->tx_rules_list, &macsec_device->rx_rules_list);359 mlx5_macsec_del_roce_gid(macsec_device, attr->index);360 cleanup_macsec_device(macsec_device);361 362 dev_put(ndev);363 mutex_unlock(&dev->macsec.lock);364}365