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(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 
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(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 	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 = 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;
197 err:
198 	while (i >= 0) {
199 		kfree(dev->port[i].reserved_gids);
200 		i--;
201 	}
202 	return -ENOMEM;
203 }
204 
205 void 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 
218 int 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 
289 rule_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;
293 gid_err:
294 	rdma_put_gid_attr(physical_gid);
295 	cleanup_macsec_device(macsec_device);
296 dev_err:
297 	dev_put(ndev);
298 	mutex_unlock(&dev->macsec.lock);
299 	return ret;
300 }
301 
302 void 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