xref: /linux/drivers/infiniband/hw/mlx5/macsec.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */
3 
4 #include "macsec.h"
5 #include <linux/mlx5/macsec.h>
6 
7 struct mlx5_reserved_gids {
8 	int macsec_index;
9 	const struct ib_gid_attr *physical_gid;
10 };
11 
12 struct 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 
21 struct 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 
29 static 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 
40 static 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_obj(*macsec_device);
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 
68 static 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(&current_gid->roce_gid_list_entry);
76 			kfree(current_gid);
77 		}
78 }
79 
80 static 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_obj(*roce_gids);
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 	else
93 		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 
98 static 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 
116 static 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 
129 static 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 
149 void 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 
161 void 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 
172 int 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 = kzalloc_objs(*dev->port[i].reserved_gids,
184 							  max_gids);
185 		if (!dev->port[i].reserved_gids)
186 			goto err;
187 
188 		for (j = 0; j < max_gids; j++)
189 			dev->port[i].reserved_gids[j].macsec_index = -1;
190 	}
191 
192 	INIT_LIST_HEAD(&dev->macsec.macsec_devices_list);
193 	mutex_init(&dev->macsec.lock);
194 
195 	return 0;
196 err:
197 	while (i >= 0) {
198 		kfree(dev->port[i].reserved_gids);
199 		i--;
200 	}
201 	return -ENOMEM;
202 }
203 
204 void mlx5r_macsec_dealloc_gids(struct mlx5_ib_dev *dev)
205 {
206 	int i;
207 
208 	if (!mlx5_is_macsec_roce_supported(dev->mdev))
209 		mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
210 
211 	for (i = 0; i < dev->num_ports; i++)
212 		kfree(dev->port[i].reserved_gids);
213 
214 	mutex_destroy(&dev->macsec.lock);
215 }
216 
217 int mlx5r_add_gid_macsec_operations(const struct ib_gid_attr *attr)
218 {
219 	struct mlx5_ib_dev *dev = to_mdev(attr->device);
220 	struct mlx5_macsec_device *macsec_device;
221 	const struct ib_gid_attr *physical_gid;
222 	struct mlx5_reserved_gids *mgids;
223 	struct net_device *ndev;
224 	int ret = 0;
225 	union {
226 		struct sockaddr_in  sockaddr_in;
227 		struct sockaddr_in6 sockaddr_in6;
228 	} addr;
229 
230 	if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
231 		return 0;
232 
233 	if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
234 		mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
235 		return 0;
236 	}
237 
238 	rcu_read_lock();
239 	ndev = rcu_dereference(attr->ndev);
240 	if (!ndev) {
241 		rcu_read_unlock();
242 		return -ENODEV;
243 	}
244 
245 	if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
246 		rcu_read_unlock();
247 		return 0;
248 	}
249 	dev_hold(ndev);
250 	rcu_read_unlock();
251 
252 	mutex_lock(&dev->macsec.lock);
253 	macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
254 	if (!macsec_device) {
255 		ret = -ENOMEM;
256 		goto dev_err;
257 	}
258 
259 	physical_gid = rdma_find_gid(attr->device, &attr->gid,
260 				     attr->gid_type, NULL);
261 	if (!IS_ERR(physical_gid)) {
262 		ret = set_roce_addr(to_mdev(physical_gid->device),
263 				    physical_gid->port_num,
264 				    physical_gid->index, NULL,
265 				    physical_gid);
266 		if (ret)
267 			goto gid_err;
268 
269 		mgids = &dev->port[attr->port_num - 1].reserved_gids[physical_gid->index];
270 		mgids->macsec_index = attr->index;
271 		mgids->physical_gid = physical_gid;
272 	}
273 
274 	/* Proceed with adding steering rules, regardless if there was gid ambiguity or not.*/
275 	rdma_gid2ip((struct sockaddr *)&addr, &attr->gid);
276 	ret = mlx5_macsec_add_roce_rule(ndev, (struct sockaddr *)&addr, attr->index,
277 					&macsec_device->tx_rules_list,
278 					&macsec_device->rx_rules_list, dev->mdev->macsec_fs);
279 	if (ret && !IS_ERR(physical_gid))
280 		goto rule_err;
281 
282 	mlx5_macsec_save_roce_gid(macsec_device, (struct sockaddr *)&addr, attr->index);
283 
284 	dev_put(ndev);
285 	mutex_unlock(&dev->macsec.lock);
286 	return ret;
287 
288 rule_err:
289 	set_roce_addr(to_mdev(physical_gid->device), physical_gid->port_num,
290 		      physical_gid->index, &physical_gid->gid, physical_gid);
291 	mgids->macsec_index = -1;
292 gid_err:
293 	rdma_put_gid_attr(physical_gid);
294 	cleanup_macsec_device(macsec_device);
295 dev_err:
296 	dev_put(ndev);
297 	mutex_unlock(&dev->macsec.lock);
298 	return ret;
299 }
300 
301 void mlx5r_del_gid_macsec_operations(const struct ib_gid_attr *attr)
302 {
303 	struct mlx5_ib_dev *dev = to_mdev(attr->device);
304 	struct mlx5_macsec_device *macsec_device;
305 	struct mlx5_reserved_gids *mgids;
306 	struct net_device *ndev;
307 	int i, max_gids;
308 
309 	if (attr->gid_type != IB_GID_TYPE_ROCE_UDP_ENCAP)
310 		return;
311 
312 	if (!mlx5_is_macsec_roce_supported(dev->mdev)) {
313 		mlx5_ib_dbg(dev, "RoCE MACsec not supported due to capabilities\n");
314 		return;
315 	}
316 
317 	mgids = &dev->port[attr->port_num - 1].reserved_gids[attr->index];
318 	if (mgids->macsec_index != -1) { /* Checking if physical gid has ambiguous IP */
319 		rdma_put_gid_attr(mgids->physical_gid);
320 		mgids->macsec_index = -1;
321 		return;
322 	}
323 
324 	rcu_read_lock();
325 	ndev = rcu_dereference(attr->ndev);
326 	if (!ndev) {
327 		rcu_read_unlock();
328 		return;
329 	}
330 
331 	if (!netif_is_macsec(ndev) || !macsec_netdev_is_offloaded(ndev)) {
332 		rcu_read_unlock();
333 		return;
334 	}
335 	dev_hold(ndev);
336 	rcu_read_unlock();
337 
338 	mutex_lock(&dev->macsec.lock);
339 	max_gids = MLX5_CAP_ROCE(dev->mdev, roce_address_table_size);
340 	for (i = 0; i < max_gids; i++) { /* Checking if macsec gid has ambiguous IP */
341 		mgids = &dev->port[attr->port_num - 1].reserved_gids[i];
342 		if (mgids->macsec_index == attr->index) {
343 			const struct ib_gid_attr *physical_gid = mgids->physical_gid;
344 
345 			set_roce_addr(to_mdev(physical_gid->device),
346 				      physical_gid->port_num,
347 				      physical_gid->index,
348 				      &physical_gid->gid, physical_gid);
349 
350 			rdma_put_gid_attr(physical_gid);
351 			mgids->macsec_index = -1;
352 			break;
353 		}
354 	}
355 	macsec_device = get_macsec_device(ndev, &dev->macsec.macsec_devices_list);
356 	mlx5_macsec_del_roce_rule(attr->index, dev->mdev->macsec_fs,
357 				  &macsec_device->tx_rules_list, &macsec_device->rx_rules_list);
358 	mlx5_macsec_del_roce_gid(macsec_device, attr->index);
359 	cleanup_macsec_device(macsec_device);
360 
361 	dev_put(ndev);
362 	mutex_unlock(&dev->macsec.lock);
363 }
364