blob: 291f1484a1b74c0a793ab3c4f3ef90804d1f9932 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Thomas Richter6812baa2017-01-09 16:55:15 +01002/*
3 * Shared Memory Communications over RDMA (SMC-R) and RoCE
4 *
5 * Generic netlink support functions to configure an SMC-R PNET table
6 *
7 * Copyright IBM Corp. 2016
8 *
9 * Author(s): Thomas Richter <tmricht@linux.vnet.ibm.com>
10 */
11
12#include <linux/module.h>
13#include <linux/list.h>
14#include <linux/ctype.h>
Ursula Braun92f3cb02020-07-08 17:05:13 +020015#include <linux/mutex.h>
Thomas Richter6812baa2017-01-09 16:55:15 +010016#include <net/netlink.h>
17#include <net/genetlink.h>
18
19#include <uapi/linux/if.h>
20#include <uapi/linux/smc.h>
21
22#include <rdma/ib_verbs.h>
23
Hans Wippel64e28b52019-02-21 13:01:02 +010024#include <net/netns/generic.h>
25#include "smc_netns.h"
26
Thomas Richter6812baa2017-01-09 16:55:15 +010027#include "smc_pnet.h"
28#include "smc_ib.h"
Hans Wippel1619f772018-06-28 19:05:08 +020029#include "smc_ism.h"
Karsten Graulbc36d2f2019-04-12 12:57:26 +020030#include "smc_core.h"
Thomas Richter6812baa2017-01-09 16:55:15 +010031
Ursula Braune888a2e2020-09-26 12:44:26 +020032static struct net_device *__pnet_find_base_ndev(struct net_device *ndev);
Hans Wippel890a2cb2019-02-21 13:01:00 +010033static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
34
Dmitry Vyukov09d03102020-05-25 17:31:58 +020035static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
Thomas Richter6812baa2017-01-09 16:55:15 +010036 [SMC_PNETID_NAME] = {
37 .type = NLA_NUL_STRING,
Hans Wippelca8dc132019-01-30 18:51:01 +010038 .len = SMC_MAX_PNETID_LEN
Thomas Richter6812baa2017-01-09 16:55:15 +010039 },
40 [SMC_PNETID_ETHNAME] = {
41 .type = NLA_NUL_STRING,
42 .len = IFNAMSIZ - 1
43 },
44 [SMC_PNETID_IBNAME] = {
45 .type = NLA_NUL_STRING,
46 .len = IB_DEVICE_NAME_MAX - 1
47 },
48 [SMC_PNETID_IBPORT] = { .type = NLA_U8 }
49};
50
51static struct genl_family smc_pnet_nl_family;
52
Karsten Graulfdff7042020-04-29 17:10:37 +020053enum smc_pnet_nametype {
54 SMC_PNET_ETH = 1,
55 SMC_PNET_IB = 2,
Thomas Richter6812baa2017-01-09 16:55:15 +010056};
57
Hans Wippel890a2cb2019-02-21 13:01:00 +010058/* pnet entry stored in pnet table */
59struct smc_pnetentry {
60 struct list_head list;
61 char pnet_name[SMC_MAX_PNETID_LEN + 1];
Karsten Graulfdff7042020-04-29 17:10:37 +020062 enum smc_pnet_nametype type;
63 union {
64 struct {
65 char eth_name[IFNAMSIZ + 1];
66 struct net_device *ndev;
Eric Dumazetb6064522021-12-06 17:30:36 -080067 netdevice_tracker dev_tracker;
Karsten Graulfdff7042020-04-29 17:10:37 +020068 };
69 struct {
70 char ib_name[IB_DEVICE_NAME_MAX + 1];
71 u8 ib_port;
72 };
73 };
Hans Wippel890a2cb2019-02-21 13:01:00 +010074};
Thomas Richter6812baa2017-01-09 16:55:15 +010075
Karsten Graula304e292020-09-26 12:44:19 +020076/* Check if the pnetid is set */
Ursula Braund70bf4f2020-09-26 12:44:27 +020077bool smc_pnet_is_pnetid_set(u8 *pnetid)
Karsten Graula304e292020-09-26 12:44:19 +020078{
79 if (pnetid[0] == 0 || pnetid[0] == _S)
80 return false;
81 return true;
82}
83
Hans Wippel890a2cb2019-02-21 13:01:00 +010084/* Check if two given pnetids match */
85static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
Thomas Richter6812baa2017-01-09 16:55:15 +010086{
Hans Wippel890a2cb2019-02-21 13:01:00 +010087 int i;
Thomas Richter6812baa2017-01-09 16:55:15 +010088
Hans Wippel890a2cb2019-02-21 13:01:00 +010089 for (i = 0; i < SMC_MAX_PNETID_LEN; i++) {
Karsten Graula304e292020-09-26 12:44:19 +020090 if ((pnetid1[i] == 0 || pnetid1[i] == _S) &&
91 (pnetid2[i] == 0 || pnetid2[i] == _S))
Thomas Richter6812baa2017-01-09 16:55:15 +010092 break;
Hans Wippel890a2cb2019-02-21 13:01:00 +010093 if (pnetid1[i] != pnetid2[i])
94 return false;
Thomas Richter6812baa2017-01-09 16:55:15 +010095 }
Hans Wippel890a2cb2019-02-21 13:01:00 +010096 return true;
Thomas Richter6812baa2017-01-09 16:55:15 +010097}
98
99/* Remove a pnetid from the pnet table.
100 */
Hans Wippel64e28b52019-02-21 13:01:02 +0100101static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
Thomas Richter6812baa2017-01-09 16:55:15 +0100102{
103 struct smc_pnetentry *pnetelem, *tmp_pe;
Hans Wippel64e28b52019-02-21 13:01:02 +0100104 struct smc_pnettable *pnettable;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100105 struct smc_ib_device *ibdev;
Hans Wippelf3d74b22019-02-21 13:01:01 +0100106 struct smcd_dev *smcd_dev;
Hans Wippel64e28b52019-02-21 13:01:02 +0100107 struct smc_net *sn;
Thomas Richter6812baa2017-01-09 16:55:15 +0100108 int rc = -ENOENT;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100109 int ibport;
Thomas Richter6812baa2017-01-09 16:55:15 +0100110
Hans Wippel64e28b52019-02-21 13:01:02 +0100111 /* get pnettable for namespace */
112 sn = net_generic(net, smc_net_id);
113 pnettable = &sn->pnettable;
114
Karsten Graulfdff7042020-04-29 17:10:37 +0200115 /* remove table entry */
Hans Wippel64e28b52019-02-21 13:01:02 +0100116 write_lock(&pnettable->lock);
117 list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist,
Thomas Richter6812baa2017-01-09 16:55:15 +0100118 list) {
Hans Wippel890a2cb2019-02-21 13:01:00 +0100119 if (!pnet_name ||
120 smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
Thomas Richter6812baa2017-01-09 16:55:15 +0100121 list_del(&pnetelem->list);
Karsten Graul0a99be42020-05-05 15:01:20 +0200122 if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) {
Eric Dumazetb6064522021-12-06 17:30:36 -0800123 dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
Karsten Graul0a99be42020-05-05 15:01:20 +0200124 pr_warn_ratelimited("smc: net device %s "
125 "erased user defined "
126 "pnetid %.16s\n",
127 pnetelem->eth_name,
128 pnetelem->pnet_name);
129 }
Thomas Richter6812baa2017-01-09 16:55:15 +0100130 kfree(pnetelem);
131 rc = 0;
Thomas Richter6812baa2017-01-09 16:55:15 +0100132 }
133 }
Hans Wippel64e28b52019-02-21 13:01:02 +0100134 write_unlock(&pnettable->lock);
135
136 /* if this is not the initial namespace, stop here */
137 if (net != &init_net)
138 return rc;
139
Hans Wippel890a2cb2019-02-21 13:01:00 +0100140 /* remove ib devices */
Ursula Braun92f3cb02020-07-08 17:05:13 +0200141 mutex_lock(&smc_ib_devices.mutex);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100142 list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
143 for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
144 if (ibdev->pnetid_by_user[ibport] &&
145 (!pnet_name ||
146 smc_pnet_match(pnet_name,
147 ibdev->pnetid[ibport]))) {
Karsten Graul0a99be42020-05-05 15:01:20 +0200148 pr_warn_ratelimited("smc: ib device %s ibport "
149 "%d erased user defined "
150 "pnetid %.16s\n",
151 ibdev->ibdev->name,
152 ibport + 1,
153 ibdev->pnetid[ibport]);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100154 memset(ibdev->pnetid[ibport], 0,
155 SMC_MAX_PNETID_LEN);
156 ibdev->pnetid_by_user[ibport] = false;
157 rc = 0;
158 }
159 }
160 }
Ursula Braun92f3cb02020-07-08 17:05:13 +0200161 mutex_unlock(&smc_ib_devices.mutex);
Hans Wippelf3d74b22019-02-21 13:01:01 +0100162 /* remove smcd devices */
Ursula Braun82087c02020-07-08 17:05:14 +0200163 mutex_lock(&smcd_dev_list.mutex);
Hans Wippelf3d74b22019-02-21 13:01:01 +0100164 list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
165 if (smcd_dev->pnetid_by_user &&
166 (!pnet_name ||
167 smc_pnet_match(pnet_name, smcd_dev->pnetid))) {
Karsten Graul0a99be42020-05-05 15:01:20 +0200168 pr_warn_ratelimited("smc: smcd device %s "
169 "erased user defined pnetid "
170 "%.16s\n", dev_name(&smcd_dev->dev),
171 smcd_dev->pnetid);
Hans Wippelf3d74b22019-02-21 13:01:01 +0100172 memset(smcd_dev->pnetid, 0, SMC_MAX_PNETID_LEN);
173 smcd_dev->pnetid_by_user = false;
174 rc = 0;
175 }
176 }
Ursula Braun82087c02020-07-08 17:05:14 +0200177 mutex_unlock(&smcd_dev_list.mutex);
Thomas Richter6812baa2017-01-09 16:55:15 +0100178 return rc;
179}
180
Karsten Graulfdff7042020-04-29 17:10:37 +0200181/* Add the reference to a given network device to the pnet table.
182 */
183static int smc_pnet_add_by_ndev(struct net_device *ndev)
184{
185 struct smc_pnetentry *pnetelem, *tmp_pe;
186 struct smc_pnettable *pnettable;
187 struct net *net = dev_net(ndev);
188 struct smc_net *sn;
189 int rc = -ENOENT;
190
191 /* get pnettable for namespace */
192 sn = net_generic(net, smc_net_id);
193 pnettable = &sn->pnettable;
194
195 write_lock(&pnettable->lock);
196 list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
197 if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
198 !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
Eric Dumazetb6064522021-12-06 17:30:36 -0800199 dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC);
Karsten Graulfdff7042020-04-29 17:10:37 +0200200 pnetelem->ndev = ndev;
201 rc = 0;
Karsten Graul0a99be42020-05-05 15:01:20 +0200202 pr_warn_ratelimited("smc: adding net device %s with "
203 "user defined pnetid %.16s\n",
204 pnetelem->eth_name,
205 pnetelem->pnet_name);
Karsten Graulfdff7042020-04-29 17:10:37 +0200206 break;
207 }
208 }
209 write_unlock(&pnettable->lock);
210 return rc;
211}
212
213/* Remove the reference to a given network device from the pnet table.
Thomas Richter6812baa2017-01-09 16:55:15 +0100214 */
215static int smc_pnet_remove_by_ndev(struct net_device *ndev)
216{
217 struct smc_pnetentry *pnetelem, *tmp_pe;
Hans Wippel64e28b52019-02-21 13:01:02 +0100218 struct smc_pnettable *pnettable;
219 struct net *net = dev_net(ndev);
220 struct smc_net *sn;
Thomas Richter6812baa2017-01-09 16:55:15 +0100221 int rc = -ENOENT;
222
Hans Wippel64e28b52019-02-21 13:01:02 +0100223 /* get pnettable for namespace */
224 sn = net_generic(net, smc_net_id);
225 pnettable = &sn->pnettable;
226
227 write_lock(&pnettable->lock);
228 list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200229 if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
Eric Dumazetb6064522021-12-06 17:30:36 -0800230 dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
Karsten Graulfdff7042020-04-29 17:10:37 +0200231 pnetelem->ndev = NULL;
Thomas Richter6812baa2017-01-09 16:55:15 +0100232 rc = 0;
Karsten Graul0a99be42020-05-05 15:01:20 +0200233 pr_warn_ratelimited("smc: removing net device %s with "
234 "user defined pnetid %.16s\n",
235 pnetelem->eth_name,
236 pnetelem->pnet_name);
Thomas Richter6812baa2017-01-09 16:55:15 +0100237 break;
238 }
239 }
Hans Wippel64e28b52019-02-21 13:01:02 +0100240 write_unlock(&pnettable->lock);
Thomas Richter6812baa2017-01-09 16:55:15 +0100241 return rc;
242}
243
Karsten Graulfdff7042020-04-29 17:10:37 +0200244/* Apply pnetid to ib device when no pnetid is set.
Thomas Richter6812baa2017-01-09 16:55:15 +0100245 */
Karsten Graulfdff7042020-04-29 17:10:37 +0200246static bool smc_pnet_apply_ib(struct smc_ib_device *ib_dev, u8 ib_port,
247 char *pnet_name)
Thomas Richter6812baa2017-01-09 16:55:15 +0100248{
Karsten Graulfdff7042020-04-29 17:10:37 +0200249 bool applied = false;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100250
Ursula Braun92f3cb02020-07-08 17:05:13 +0200251 mutex_lock(&smc_ib_devices.mutex);
Karsten Graula304e292020-09-26 12:44:19 +0200252 if (!smc_pnet_is_pnetid_set(ib_dev->pnetid[ib_port - 1])) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200253 memcpy(ib_dev->pnetid[ib_port - 1], pnet_name,
254 SMC_MAX_PNETID_LEN);
255 ib_dev->pnetid_by_user[ib_port - 1] = true;
256 applied = true;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100257 }
Ursula Braun92f3cb02020-07-08 17:05:13 +0200258 mutex_unlock(&smc_ib_devices.mutex);
Karsten Graulfdff7042020-04-29 17:10:37 +0200259 return applied;
260}
Hans Wippelf3d74b22019-02-21 13:01:01 +0100261
Karsten Graulfdff7042020-04-29 17:10:37 +0200262/* Apply pnetid to smcd device when no pnetid is set.
263 */
264static bool smc_pnet_apply_smcd(struct smcd_dev *smcd_dev, char *pnet_name)
265{
Karsten Graulfdff7042020-04-29 17:10:37 +0200266 bool applied = false;
267
Ursula Braun82087c02020-07-08 17:05:14 +0200268 mutex_lock(&smcd_dev_list.mutex);
Karsten Graula304e292020-09-26 12:44:19 +0200269 if (!smc_pnet_is_pnetid_set(smcd_dev->pnetid)) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200270 memcpy(smcd_dev->pnetid, pnet_name, SMC_MAX_PNETID_LEN);
271 smcd_dev->pnetid_by_user = true;
272 applied = true;
Hans Wippelf3d74b22019-02-21 13:01:01 +0100273 }
Ursula Braun82087c02020-07-08 17:05:14 +0200274 mutex_unlock(&smcd_dev_list.mutex);
Karsten Graulfdff7042020-04-29 17:10:37 +0200275 return applied;
Thomas Richter6812baa2017-01-09 16:55:15 +0100276}
277
278/* The limit for pnetid is 16 characters.
279 * Valid characters should be (single-byte character set) a-z, A-Z, 0-9.
280 * Lower case letters are converted to upper case.
281 * Interior blanks should not be used.
282 */
283static bool smc_pnetid_valid(const char *pnet_name, char *pnetid)
284{
285 char *bf = skip_spaces(pnet_name);
286 size_t len = strlen(bf);
287 char *end = bf + len;
288
289 if (!len)
290 return false;
291 while (--end >= bf && isspace(*end))
292 ;
Ursula Braun0afff912018-06-28 19:05:05 +0200293 if (end - bf >= SMC_MAX_PNETID_LEN)
Thomas Richter6812baa2017-01-09 16:55:15 +0100294 return false;
295 while (bf <= end) {
296 if (!isalnum(*bf))
297 return false;
298 *pnetid++ = islower(*bf) ? toupper(*bf) : *bf;
299 bf++;
300 }
301 *pnetid = '\0';
302 return true;
303}
304
305/* Find an infiniband device by a given name. The device might not exist. */
Ursula Braun249633a2017-04-10 14:57:57 +0200306static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
Thomas Richter6812baa2017-01-09 16:55:15 +0100307{
308 struct smc_ib_device *ibdev;
309
Ursula Braun92f3cb02020-07-08 17:05:13 +0200310 mutex_lock(&smc_ib_devices.mutex);
Thomas Richter6812baa2017-01-09 16:55:15 +0100311 list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
312 if (!strncmp(ibdev->ibdev->name, ib_name,
Hans Wippelaf5f60c2019-02-21 13:01:03 +0100313 sizeof(ibdev->ibdev->name)) ||
314 !strncmp(dev_name(ibdev->ibdev->dev.parent), ib_name,
315 IB_DEVICE_NAME_MAX - 1)) {
Thomas Richter6812baa2017-01-09 16:55:15 +0100316 goto out;
317 }
318 }
319 ibdev = NULL;
320out:
Ursula Braun92f3cb02020-07-08 17:05:13 +0200321 mutex_unlock(&smc_ib_devices.mutex);
Thomas Richter6812baa2017-01-09 16:55:15 +0100322 return ibdev;
323}
324
Hans Wippelf3d74b22019-02-21 13:01:01 +0100325/* Find an smcd device by a given name. The device might not exist. */
326static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
327{
328 struct smcd_dev *smcd_dev;
329
Ursula Braun82087c02020-07-08 17:05:14 +0200330 mutex_lock(&smcd_dev_list.mutex);
Hans Wippelf3d74b22019-02-21 13:01:01 +0100331 list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
332 if (!strncmp(dev_name(&smcd_dev->dev), smcd_name,
333 IB_DEVICE_NAME_MAX - 1))
334 goto out;
335 }
336 smcd_dev = NULL;
337out:
Ursula Braun82087c02020-07-08 17:05:14 +0200338 mutex_unlock(&smcd_dev_list.mutex);
Hans Wippelf3d74b22019-02-21 13:01:01 +0100339 return smcd_dev;
340}
341
Karsten Graulfdff7042020-04-29 17:10:37 +0200342static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
343 char *eth_name, char *pnet_name)
Thomas Richter6812baa2017-01-09 16:55:15 +0100344{
Karsten Graulfdff7042020-04-29 17:10:37 +0200345 struct smc_pnetentry *tmp_pe, *new_pe;
346 struct net_device *ndev, *base_ndev;
347 u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
348 bool new_netdev;
Eric Biggersd49baa72018-05-13 17:01:30 -0700349 int rc;
Thomas Richter6812baa2017-01-09 16:55:15 +0100350
Karsten Graulfdff7042020-04-29 17:10:37 +0200351 /* check if (base) netdev already has a pnetid. If there is one, we do
352 * not want to add a pnet table entry
353 */
354 rc = -EEXIST;
355 ndev = dev_get_by_name(net, eth_name); /* dev_hold() */
356 if (ndev) {
357 base_ndev = pnet_find_base_ndev(ndev);
358 if (!smc_pnetid_by_dev_port(base_ndev->dev.parent,
359 base_ndev->dev_port, ndev_pnetid))
360 goto out_put;
361 }
362
363 /* add a new netdev entry to the pnet table if there isn't one */
364 rc = -ENOMEM;
365 new_pe = kzalloc(sizeof(*new_pe), GFP_KERNEL);
366 if (!new_pe)
367 goto out_put;
368 new_pe->type = SMC_PNET_ETH;
369 memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
370 strncpy(new_pe->eth_name, eth_name, IFNAMSIZ);
371 new_pe->ndev = ndev;
Eric Dumazet7b9b1d42022-01-12 04:59:39 -0800372 if (ndev)
373 netdev_tracker_alloc(ndev, &new_pe->dev_tracker, GFP_KERNEL);
Karsten Graulfdff7042020-04-29 17:10:37 +0200374 rc = -EEXIST;
375 new_netdev = true;
376 write_lock(&pnettable->lock);
377 list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
378 if (tmp_pe->type == SMC_PNET_ETH &&
379 !strncmp(tmp_pe->eth_name, eth_name, IFNAMSIZ)) {
380 new_netdev = false;
381 break;
382 }
383 }
384 if (new_netdev) {
385 list_add_tail(&new_pe->list, &pnettable->pnetlist);
386 write_unlock(&pnettable->lock);
387 } else {
388 write_unlock(&pnettable->lock);
389 kfree(new_pe);
390 goto out_put;
391 }
Karsten Graul0a99be42020-05-05 15:01:20 +0200392 if (ndev)
393 pr_warn_ratelimited("smc: net device %s "
394 "applied user defined pnetid %.16s\n",
395 new_pe->eth_name, new_pe->pnet_name);
Karsten Graulfdff7042020-04-29 17:10:37 +0200396 return 0;
397
398out_put:
Yajun Deng1160dfa2021-08-05 19:55:27 +0800399 dev_put(ndev);
Karsten Graulfdff7042020-04-29 17:10:37 +0200400 return rc;
401}
402
403static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
404 u8 ib_port, char *pnet_name)
405{
406 struct smc_pnetentry *tmp_pe, *new_pe;
407 struct smc_ib_device *ib_dev;
408 bool smcddev_applied = true;
409 bool ibdev_applied = true;
410 struct smcd_dev *smcd_dev;
411 bool new_ibdev;
412
413 /* try to apply the pnetid to active devices */
414 ib_dev = smc_pnet_find_ib(ib_name);
Karsten Graul0a99be42020-05-05 15:01:20 +0200415 if (ib_dev) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200416 ibdev_applied = smc_pnet_apply_ib(ib_dev, ib_port, pnet_name);
Karsten Graul0a99be42020-05-05 15:01:20 +0200417 if (ibdev_applied)
418 pr_warn_ratelimited("smc: ib device %s ibport %d "
419 "applied user defined pnetid "
420 "%.16s\n", ib_dev->ibdev->name,
421 ib_port,
422 ib_dev->pnetid[ib_port - 1]);
423 }
Karsten Graulfdff7042020-04-29 17:10:37 +0200424 smcd_dev = smc_pnet_find_smcd(ib_name);
Karsten Graul0a99be42020-05-05 15:01:20 +0200425 if (smcd_dev) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200426 smcddev_applied = smc_pnet_apply_smcd(smcd_dev, pnet_name);
Karsten Graul0a99be42020-05-05 15:01:20 +0200427 if (smcddev_applied)
428 pr_warn_ratelimited("smc: smcd device %s "
429 "applied user defined pnetid "
430 "%.16s\n", dev_name(&smcd_dev->dev),
431 smcd_dev->pnetid);
432 }
Karsten Graulfdff7042020-04-29 17:10:37 +0200433 /* Apply fails when a device has a hardware-defined pnetid set, do not
434 * add a pnet table entry in that case.
435 */
436 if (!ibdev_applied || !smcddev_applied)
437 return -EEXIST;
438
439 /* add a new ib entry to the pnet table if there isn't one */
440 new_pe = kzalloc(sizeof(*new_pe), GFP_KERNEL);
441 if (!new_pe)
442 return -ENOMEM;
443 new_pe->type = SMC_PNET_IB;
444 memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
445 strncpy(new_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX);
446 new_pe->ib_port = ib_port;
447
448 new_ibdev = true;
449 write_lock(&pnettable->lock);
450 list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
451 if (tmp_pe->type == SMC_PNET_IB &&
452 !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
453 new_ibdev = false;
454 break;
455 }
456 }
457 if (new_ibdev) {
458 list_add_tail(&new_pe->list, &pnettable->pnetlist);
459 write_unlock(&pnettable->lock);
460 } else {
461 write_unlock(&pnettable->lock);
462 kfree(new_pe);
463 }
464 return (new_ibdev) ? 0 : -EEXIST;
465}
466
467/* Append a pnetid to the end of the pnet table if not already on this list.
468 */
469static int smc_pnet_enter(struct net *net, struct nlattr *tb[])
470{
471 char pnet_name[SMC_MAX_PNETID_LEN + 1];
472 struct smc_pnettable *pnettable;
473 bool new_netdev = false;
474 bool new_ibdev = false;
475 struct smc_net *sn;
476 u8 ibport = 1;
477 char *string;
478 int rc;
479
480 /* get pnettable for namespace */
481 sn = net_generic(net, smc_net_id);
482 pnettable = &sn->pnettable;
Eric Biggersd49baa72018-05-13 17:01:30 -0700483
484 rc = -EINVAL;
485 if (!tb[SMC_PNETID_NAME])
486 goto error;
487 string = (char *)nla_data(tb[SMC_PNETID_NAME]);
Karsten Graulfdff7042020-04-29 17:10:37 +0200488 if (!smc_pnetid_valid(string, pnet_name))
Eric Biggersd49baa72018-05-13 17:01:30 -0700489 goto error;
490
Hans Wippel890a2cb2019-02-21 13:01:00 +0100491 if (tb[SMC_PNETID_ETHNAME]) {
492 string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
Karsten Graulfdff7042020-04-29 17:10:37 +0200493 rc = smc_pnet_add_eth(pnettable, net, string, pnet_name);
494 if (!rc)
495 new_netdev = true;
496 else if (rc != -EEXIST)
Hans Wippel890a2cb2019-02-21 13:01:00 +0100497 goto error;
498 }
Eric Biggersd49baa72018-05-13 17:01:30 -0700499
Hans Wippel64e28b52019-02-21 13:01:02 +0100500 /* if this is not the initial namespace, stop here */
501 if (net != &init_net)
Karsten Graulfdff7042020-04-29 17:10:37 +0200502 return new_netdev ? 0 : -EEXIST;
Hans Wippel64e28b52019-02-21 13:01:02 +0100503
Eric Biggersd49baa72018-05-13 17:01:30 -0700504 rc = -EINVAL;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100505 if (tb[SMC_PNETID_IBNAME]) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200506 string = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
507 string = strim(string);
508 if (tb[SMC_PNETID_IBPORT]) {
509 ibport = nla_get_u8(tb[SMC_PNETID_IBPORT]);
510 if (ibport < 1 || ibport > SMC_MAX_PORTS)
Hans Wippel890a2cb2019-02-21 13:01:00 +0100511 goto error;
512 }
Karsten Graulfdff7042020-04-29 17:10:37 +0200513 rc = smc_pnet_add_ib(pnettable, string, ibport, pnet_name);
514 if (!rc)
515 new_ibdev = true;
516 else if (rc != -EEXIST)
517 goto error;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100518 }
Karsten Graulfdff7042020-04-29 17:10:37 +0200519 return (new_netdev || new_ibdev) ? 0 : -EEXIST;
Thomas Richter6812baa2017-01-09 16:55:15 +0100520
521error:
Thomas Richter6812baa2017-01-09 16:55:15 +0100522 return rc;
523}
524
525/* Convert an smc_pnetentry to a netlink attribute sequence */
Hans Wippel890a2cb2019-02-21 13:01:00 +0100526static int smc_pnet_set_nla(struct sk_buff *msg,
Karsten Graulfdff7042020-04-29 17:10:37 +0200527 struct smc_pnetentry *pnetelem)
Thomas Richter6812baa2017-01-09 16:55:15 +0100528{
Hans Wippel890a2cb2019-02-21 13:01:00 +0100529 if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name))
Thomas Richter6812baa2017-01-09 16:55:15 +0100530 return -1;
Karsten Graulfdff7042020-04-29 17:10:37 +0200531 if (pnetelem->type == SMC_PNET_ETH) {
Hans Wippel890a2cb2019-02-21 13:01:00 +0100532 if (nla_put_string(msg, SMC_PNETID_ETHNAME,
Karsten Graulfdff7042020-04-29 17:10:37 +0200533 pnetelem->eth_name))
Hans Wippel890a2cb2019-02-21 13:01:00 +0100534 return -1;
535 } else {
536 if (nla_put_string(msg, SMC_PNETID_ETHNAME, "n/a"))
537 return -1;
538 }
Karsten Graulfdff7042020-04-29 17:10:37 +0200539 if (pnetelem->type == SMC_PNET_IB) {
540 if (nla_put_string(msg, SMC_PNETID_IBNAME, pnetelem->ib_name) ||
Hans Wippel890a2cb2019-02-21 13:01:00 +0100541 nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
542 return -1;
543 } else {
544 if (nla_put_string(msg, SMC_PNETID_IBNAME, "n/a") ||
545 nla_put_u8(msg, SMC_PNETID_IBPORT, 0xff))
546 return -1;
547 }
548
Thomas Richter6812baa2017-01-09 16:55:15 +0100549 return 0;
550}
551
Thomas Richter6812baa2017-01-09 16:55:15 +0100552static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
553{
554 struct net *net = genl_info_net(info);
Thomas Richter6812baa2017-01-09 16:55:15 +0100555
Karsten Graulfdff7042020-04-29 17:10:37 +0200556 return smc_pnet_enter(net, info->attrs);
Thomas Richter6812baa2017-01-09 16:55:15 +0100557}
558
559static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info)
560{
Hans Wippel64e28b52019-02-21 13:01:02 +0100561 struct net *net = genl_info_net(info);
562
Eric Biggersd49baa72018-05-13 17:01:30 -0700563 if (!info->attrs[SMC_PNETID_NAME])
564 return -EINVAL;
Hans Wippel64e28b52019-02-21 13:01:02 +0100565 return smc_pnet_remove_by_pnetid(net,
Thomas Richter6812baa2017-01-09 16:55:15 +0100566 (char *)nla_data(info->attrs[SMC_PNETID_NAME]));
567}
568
569static int smc_pnet_dump_start(struct netlink_callback *cb)
570{
571 cb->args[0] = 0;
572 return 0;
573}
574
575static int smc_pnet_dumpinfo(struct sk_buff *skb,
576 u32 portid, u32 seq, u32 flags,
Karsten Graulfdff7042020-04-29 17:10:37 +0200577 struct smc_pnetentry *pnetelem)
Thomas Richter6812baa2017-01-09 16:55:15 +0100578{
579 void *hdr;
580
581 hdr = genlmsg_put(skb, portid, seq, &smc_pnet_nl_family,
582 flags, SMC_PNETID_GET);
583 if (!hdr)
584 return -ENOMEM;
585 if (smc_pnet_set_nla(skb, pnetelem) < 0) {
586 genlmsg_cancel(skb, hdr);
587 return -EMSGSIZE;
588 }
589 genlmsg_end(skb, hdr);
590 return 0;
591}
592
Hans Wippel64e28b52019-02-21 13:01:02 +0100593static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
594 u32 seq, u8 *pnetid, int start_idx)
Thomas Richter6812baa2017-01-09 16:55:15 +0100595{
Hans Wippel64e28b52019-02-21 13:01:02 +0100596 struct smc_pnettable *pnettable;
Thomas Richter6812baa2017-01-09 16:55:15 +0100597 struct smc_pnetentry *pnetelem;
Hans Wippel64e28b52019-02-21 13:01:02 +0100598 struct smc_net *sn;
Thomas Richter6812baa2017-01-09 16:55:15 +0100599 int idx = 0;
600
Hans Wippel64e28b52019-02-21 13:01:02 +0100601 /* get pnettable for namespace */
602 sn = net_generic(net, smc_net_id);
603 pnettable = &sn->pnettable;
604
Karsten Graulfdff7042020-04-29 17:10:37 +0200605 /* dump pnettable entries */
Hans Wippel64e28b52019-02-21 13:01:02 +0100606 read_lock(&pnettable->lock);
607 list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
Hans Wippel890a2cb2019-02-21 13:01:00 +0100608 if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
Thomas Richter6812baa2017-01-09 16:55:15 +0100609 continue;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100610 if (idx++ < start_idx)
611 continue;
Karsten Graulfdff7042020-04-29 17:10:37 +0200612 /* if this is not the initial namespace, dump only netdev */
613 if (net != &init_net && pnetelem->type != SMC_PNET_ETH)
614 continue;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100615 if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
Karsten Graulfdff7042020-04-29 17:10:37 +0200616 pnetelem)) {
Thomas Richter6812baa2017-01-09 16:55:15 +0100617 --idx;
618 break;
619 }
620 }
Hans Wippel64e28b52019-02-21 13:01:02 +0100621 read_unlock(&pnettable->lock);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100622 return idx;
623}
624
625static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
626{
Hans Wippel64e28b52019-02-21 13:01:02 +0100627 struct net *net = sock_net(skb->sk);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100628 int idx;
629
Hans Wippel64e28b52019-02-21 13:01:02 +0100630 idx = _smc_pnet_dump(net, skb, NETLINK_CB(cb->skb).portid,
Hans Wippel890a2cb2019-02-21 13:01:00 +0100631 cb->nlh->nlmsg_seq, NULL, cb->args[0]);
632
633 cb->args[0] = idx;
Thomas Richter6812baa2017-01-09 16:55:15 +0100634 return skb->len;
635}
636
Hans Wippel890a2cb2019-02-21 13:01:00 +0100637/* Retrieve one PNETID entry */
638static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
639{
Hans Wippel64e28b52019-02-21 13:01:02 +0100640 struct net *net = genl_info_net(info);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100641 struct sk_buff *msg;
642 void *hdr;
643
644 if (!info->attrs[SMC_PNETID_NAME])
645 return -EINVAL;
646
647 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
648 if (!msg)
649 return -ENOMEM;
650
Hans Wippel64e28b52019-02-21 13:01:02 +0100651 _smc_pnet_dump(net, msg, info->snd_portid, info->snd_seq,
Hans Wippel890a2cb2019-02-21 13:01:00 +0100652 nla_data(info->attrs[SMC_PNETID_NAME]), 0);
653
654 /* finish multi part message and send it */
655 hdr = nlmsg_put(msg, info->snd_portid, info->snd_seq, NLMSG_DONE, 0,
656 NLM_F_MULTI);
657 if (!hdr) {
658 nlmsg_free(msg);
659 return -EMSGSIZE;
660 }
661 return genlmsg_reply(msg, info);
662}
663
Thomas Richter6812baa2017-01-09 16:55:15 +0100664/* Remove and delete all pnetids from pnet table.
665 */
666static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
667{
Hans Wippel64e28b52019-02-21 13:01:02 +0100668 struct net *net = genl_info_net(info);
669
Karsten Graul8ef659f2019-04-11 11:17:33 +0200670 smc_pnet_remove_by_pnetid(net, NULL);
671 return 0;
Thomas Richter6812baa2017-01-09 16:55:15 +0100672}
673
674/* SMC_PNETID generic netlink operation definition */
675static const struct genl_ops smc_pnet_ops[] = {
676 {
677 .cmd = SMC_PNETID_GET,
Johannes Bergef6243a2019-04-26 14:07:31 +0200678 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Hans Wippel29237d22020-01-21 01:04:46 +0100679 /* can be retrieved by unprivileged users */
Thomas Richter6812baa2017-01-09 16:55:15 +0100680 .doit = smc_pnet_get,
681 .dumpit = smc_pnet_dump,
682 .start = smc_pnet_dump_start
683 },
684 {
685 .cmd = SMC_PNETID_ADD,
Johannes Bergef6243a2019-04-26 14:07:31 +0200686 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thomas Richter6812baa2017-01-09 16:55:15 +0100687 .flags = GENL_ADMIN_PERM,
Thomas Richter6812baa2017-01-09 16:55:15 +0100688 .doit = smc_pnet_add
689 },
690 {
691 .cmd = SMC_PNETID_DEL,
Johannes Bergef6243a2019-04-26 14:07:31 +0200692 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thomas Richter6812baa2017-01-09 16:55:15 +0100693 .flags = GENL_ADMIN_PERM,
Thomas Richter6812baa2017-01-09 16:55:15 +0100694 .doit = smc_pnet_del
695 },
696 {
697 .cmd = SMC_PNETID_FLUSH,
Johannes Bergef6243a2019-04-26 14:07:31 +0200698 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
Thomas Richter6812baa2017-01-09 16:55:15 +0100699 .flags = GENL_ADMIN_PERM,
Thomas Richter6812baa2017-01-09 16:55:15 +0100700 .doit = smc_pnet_flush
701 }
702};
703
704/* SMC_PNETID family definition */
Johannes Berg56ce3c52018-09-20 09:27:30 +0200705static struct genl_family smc_pnet_nl_family __ro_after_init = {
Thomas Richter6812baa2017-01-09 16:55:15 +0100706 .hdrsize = 0,
707 .name = SMCR_GENL_FAMILY_NAME,
708 .version = SMCR_GENL_FAMILY_VERSION,
709 .maxattr = SMC_PNETID_MAX,
Johannes Berg3b0f31f2019-03-21 22:51:02 +0100710 .policy = smc_pnet_policy,
Thomas Richter6812baa2017-01-09 16:55:15 +0100711 .netnsok = true,
712 .module = THIS_MODULE,
713 .ops = smc_pnet_ops,
714 .n_ops = ARRAY_SIZE(smc_pnet_ops)
715};
716
Ursula Braune888a2e2020-09-26 12:44:26 +0200717bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid)
718{
719 struct smc_net *sn = net_generic(net, smc_net_id);
720 struct smc_pnetids_ndev_entry *pe;
721 bool rc = false;
722
723 read_lock(&sn->pnetids_ndev.lock);
724 list_for_each_entry(pe, &sn->pnetids_ndev.list, list) {
725 if (smc_pnet_match(pnetid, pe->pnetid)) {
726 rc = true;
727 goto unlock;
728 }
729 }
730
731unlock:
732 read_unlock(&sn->pnetids_ndev.lock);
733 return rc;
734}
735
736static int smc_pnet_add_pnetid(struct net *net, u8 *pnetid)
737{
738 struct smc_net *sn = net_generic(net, smc_net_id);
739 struct smc_pnetids_ndev_entry *pe, *pi;
740
741 pe = kzalloc(sizeof(*pe), GFP_KERNEL);
742 if (!pe)
743 return -ENOMEM;
744
745 write_lock(&sn->pnetids_ndev.lock);
746 list_for_each_entry(pi, &sn->pnetids_ndev.list, list) {
747 if (smc_pnet_match(pnetid, pe->pnetid)) {
748 refcount_inc(&pi->refcnt);
749 kfree(pe);
750 goto unlock;
751 }
752 }
753 refcount_set(&pe->refcnt, 1);
754 memcpy(pe->pnetid, pnetid, SMC_MAX_PNETID_LEN);
755 list_add_tail(&pe->list, &sn->pnetids_ndev.list);
756
757unlock:
758 write_unlock(&sn->pnetids_ndev.lock);
759 return 0;
760}
761
762static void smc_pnet_remove_pnetid(struct net *net, u8 *pnetid)
763{
764 struct smc_net *sn = net_generic(net, smc_net_id);
765 struct smc_pnetids_ndev_entry *pe, *pe2;
766
767 write_lock(&sn->pnetids_ndev.lock);
768 list_for_each_entry_safe(pe, pe2, &sn->pnetids_ndev.list, list) {
769 if (smc_pnet_match(pnetid, pe->pnetid)) {
770 if (refcount_dec_and_test(&pe->refcnt)) {
771 list_del(&pe->list);
772 kfree(pe);
773 }
774 break;
775 }
776 }
777 write_unlock(&sn->pnetids_ndev.lock);
778}
779
780static void smc_pnet_add_base_pnetid(struct net *net, struct net_device *dev,
781 u8 *ndev_pnetid)
782{
783 struct net_device *base_dev;
784
785 base_dev = __pnet_find_base_ndev(dev);
786 if (base_dev->flags & IFF_UP &&
787 !smc_pnetid_by_dev_port(base_dev->dev.parent, base_dev->dev_port,
788 ndev_pnetid)) {
789 /* add to PNETIDs list */
790 smc_pnet_add_pnetid(net, ndev_pnetid);
791 }
792}
793
794/* create initial list of netdevice pnetids */
795static void smc_pnet_create_pnetids_list(struct net *net)
796{
797 u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
798 struct net_device *dev;
799
800 rtnl_lock();
801 for_each_netdev(net, dev)
802 smc_pnet_add_base_pnetid(net, dev, ndev_pnetid);
803 rtnl_unlock();
804}
805
806/* clean up list of netdevice pnetids */
807static void smc_pnet_destroy_pnetids_list(struct net *net)
808{
809 struct smc_net *sn = net_generic(net, smc_net_id);
810 struct smc_pnetids_ndev_entry *pe, *temp_pe;
811
812 write_lock(&sn->pnetids_ndev.lock);
813 list_for_each_entry_safe(pe, temp_pe, &sn->pnetids_ndev.list, list) {
814 list_del(&pe->list);
815 kfree(pe);
816 }
817 write_unlock(&sn->pnetids_ndev.lock);
818}
819
Thomas Richter6812baa2017-01-09 16:55:15 +0100820static int smc_pnet_netdev_event(struct notifier_block *this,
821 unsigned long event, void *ptr)
822{
823 struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
Ursula Braune888a2e2020-09-26 12:44:26 +0200824 struct net *net = dev_net(event_dev);
825 u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
Thomas Richter6812baa2017-01-09 16:55:15 +0100826
827 switch (event) {
828 case NETDEV_REBOOT:
829 case NETDEV_UNREGISTER:
830 smc_pnet_remove_by_ndev(event_dev);
Guvenc Gulce3d453f52020-12-01 20:20:40 +0100831 smc_ib_ndev_change(event_dev, event);
Ursula Braunbe6a3f32018-06-28 19:05:04 +0200832 return NOTIFY_OK;
Karsten Graulfdff7042020-04-29 17:10:37 +0200833 case NETDEV_REGISTER:
834 smc_pnet_add_by_ndev(event_dev);
Guvenc Gulce3d453f52020-12-01 20:20:40 +0100835 smc_ib_ndev_change(event_dev, event);
Karsten Graulfdff7042020-04-29 17:10:37 +0200836 return NOTIFY_OK;
Ursula Braune888a2e2020-09-26 12:44:26 +0200837 case NETDEV_UP:
838 smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid);
839 return NOTIFY_OK;
840 case NETDEV_DOWN:
841 event_dev = __pnet_find_base_ndev(event_dev);
842 if (!smc_pnetid_by_dev_port(event_dev->dev.parent,
843 event_dev->dev_port, ndev_pnetid)) {
844 /* remove from PNETIDs list */
845 smc_pnet_remove_pnetid(net, ndev_pnetid);
846 }
847 return NOTIFY_OK;
Thomas Richter6812baa2017-01-09 16:55:15 +0100848 default:
Ursula Braunbe6a3f32018-06-28 19:05:04 +0200849 return NOTIFY_DONE;
Thomas Richter6812baa2017-01-09 16:55:15 +0100850 }
Thomas Richter6812baa2017-01-09 16:55:15 +0100851}
852
853static struct notifier_block smc_netdev_notifier = {
854 .notifier_call = smc_pnet_netdev_event
855};
856
Hans Wippel64e28b52019-02-21 13:01:02 +0100857/* init network namespace */
858int smc_pnet_net_init(struct net *net)
859{
860 struct smc_net *sn = net_generic(net, smc_net_id);
861 struct smc_pnettable *pnettable = &sn->pnettable;
Ursula Braune888a2e2020-09-26 12:44:26 +0200862 struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;
Hans Wippel64e28b52019-02-21 13:01:02 +0100863
864 INIT_LIST_HEAD(&pnettable->pnetlist);
865 rwlock_init(&pnettable->lock);
Ursula Braune888a2e2020-09-26 12:44:26 +0200866 INIT_LIST_HEAD(&pnetids_ndev->list);
867 rwlock_init(&pnetids_ndev->lock);
868
869 smc_pnet_create_pnetids_list(net);
Hans Wippel64e28b52019-02-21 13:01:02 +0100870
871 return 0;
872}
873
Thomas Richter6812baa2017-01-09 16:55:15 +0100874int __init smc_pnet_init(void)
875{
876 int rc;
877
878 rc = genl_register_family(&smc_pnet_nl_family);
879 if (rc)
880 return rc;
881 rc = register_netdevice_notifier(&smc_netdev_notifier);
882 if (rc)
883 genl_unregister_family(&smc_pnet_nl_family);
Ursula Braune888a2e2020-09-26 12:44:26 +0200884
Thomas Richter6812baa2017-01-09 16:55:15 +0100885 return rc;
886}
887
Hans Wippel64e28b52019-02-21 13:01:02 +0100888/* exit network namespace */
889void smc_pnet_net_exit(struct net *net)
890{
891 /* flush pnet table */
892 smc_pnet_remove_by_pnetid(net, NULL);
Ursula Braune888a2e2020-09-26 12:44:26 +0200893 smc_pnet_destroy_pnetids_list(net);
Hans Wippel64e28b52019-02-21 13:01:02 +0100894}
895
Thomas Richter6812baa2017-01-09 16:55:15 +0100896void smc_pnet_exit(void)
897{
Thomas Richter6812baa2017-01-09 16:55:15 +0100898 unregister_netdevice_notifier(&smc_netdev_notifier);
899 genl_unregister_family(&smc_pnet_nl_family);
900}
901
Ursula Braune888a2e2020-09-26 12:44:26 +0200902static struct net_device *__pnet_find_base_ndev(struct net_device *ndev)
Thomas Richter6812baa2017-01-09 16:55:15 +0100903{
Ursula Braun0afff912018-06-28 19:05:05 +0200904 int i, nest_lvl;
905
Ursula Braune888a2e2020-09-26 12:44:26 +0200906 ASSERT_RTNL();
Taehee Yoof3b0a182019-10-21 18:47:58 +0000907 nest_lvl = ndev->lower_level;
Ursula Braun0afff912018-06-28 19:05:05 +0200908 for (i = 0; i < nest_lvl; i++) {
909 struct list_head *lower = &ndev->adj_list.lower;
910
911 if (list_empty(lower))
912 break;
913 lower = lower->next;
914 ndev = netdev_lower_get_next(ndev, &lower);
915 }
Ursula Braune888a2e2020-09-26 12:44:26 +0200916 return ndev;
917}
918
919/* Determine one base device for stacked net devices.
920 * If the lower device level contains more than one devices
921 * (for instance with bonding slaves), just the first device
922 * is used to reach a base device.
923 */
924static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
925{
926 rtnl_lock();
927 ndev = __pnet_find_base_ndev(ndev);
Ursula Braun0afff912018-06-28 19:05:05 +0200928 rtnl_unlock();
929 return ndev;
930}
931
Hans Wippel64e28b52019-02-21 13:01:02 +0100932static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
Hans Wippel890a2cb2019-02-21 13:01:00 +0100933 u8 *pnetid)
934{
Hans Wippel64e28b52019-02-21 13:01:02 +0100935 struct smc_pnettable *pnettable;
936 struct net *net = dev_net(ndev);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100937 struct smc_pnetentry *pnetelem;
Hans Wippel64e28b52019-02-21 13:01:02 +0100938 struct smc_net *sn;
Hans Wippel890a2cb2019-02-21 13:01:00 +0100939 int rc = -ENOENT;
940
Hans Wippel64e28b52019-02-21 13:01:02 +0100941 /* get pnettable for namespace */
942 sn = net_generic(net, smc_net_id);
943 pnettable = &sn->pnettable;
944
945 read_lock(&pnettable->lock);
946 list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
Karsten Graulfdff7042020-04-29 17:10:37 +0200947 if (pnetelem->type == SMC_PNET_ETH && ndev == pnetelem->ndev) {
Hans Wippel890a2cb2019-02-21 13:01:00 +0100948 /* get pnetid of netdev device */
949 memcpy(pnetid, pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
950 rc = 0;
951 break;
952 }
953 }
Hans Wippel64e28b52019-02-21 13:01:02 +0100954 read_unlock(&pnettable->lock);
Hans Wippel890a2cb2019-02-21 13:01:00 +0100955 return rc;
956}
957
Karsten Graul24fb6812021-10-16 11:37:48 +0200958static int smc_pnet_determine_gid(struct smc_ib_device *ibdev, int i,
959 struct smc_init_info *ini)
960{
961 if (!ini->check_smcrv2 &&
962 !smc_ib_determine_gid(ibdev, i, ini->vlan_id, ini->ib_gid, NULL,
963 NULL)) {
964 ini->ib_dev = ibdev;
965 ini->ib_port = i;
966 return 0;
967 }
968 if (ini->check_smcrv2 &&
969 !smc_ib_determine_gid(ibdev, i, ini->vlan_id, ini->smcrv2.ib_gid_v2,
970 NULL, &ini->smcrv2)) {
971 ini->smcrv2.ib_dev_v2 = ibdev;
972 ini->smcrv2.ib_port_v2 = i;
973 return 0;
974 }
975 return -ENODEV;
976}
977
Karsten Graulfdff7042020-04-29 17:10:37 +0200978/* find a roce device for the given pnetid */
979static void _smc_pnet_find_roce_by_pnetid(u8 *pnet_id,
Karsten Graul6c868a32020-05-01 12:48:11 +0200980 struct smc_init_info *ini,
Tony Lu0237a3a2021-12-28 21:06:09 +0800981 struct smc_ib_device *known_dev,
982 struct net *net)
Karsten Graulfdff7042020-04-29 17:10:37 +0200983{
984 struct smc_ib_device *ibdev;
985 int i;
986
Ursula Braun92f3cb02020-07-08 17:05:13 +0200987 mutex_lock(&smc_ib_devices.mutex);
Karsten Graulfdff7042020-04-29 17:10:37 +0200988 list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
Tony Lu0237a3a2021-12-28 21:06:09 +0800989 if (ibdev == known_dev ||
990 !rdma_dev_access_netns(ibdev->ibdev, net))
Karsten Graul6c868a32020-05-01 12:48:11 +0200991 continue;
Karsten Graulfdff7042020-04-29 17:10:37 +0200992 for (i = 1; i <= SMC_MAX_PORTS; i++) {
993 if (!rdma_is_port_valid(ibdev->ibdev, i))
994 continue;
995 if (smc_pnet_match(ibdev->pnetid[i - 1], pnet_id) &&
996 smc_ib_port_active(ibdev, i) &&
Karsten Graul24fb6812021-10-16 11:37:48 +0200997 !test_bit(i - 1, ibdev->ports_going_away)) {
998 if (!smc_pnet_determine_gid(ibdev, i, ini))
999 goto out;
Karsten Graulfdff7042020-04-29 17:10:37 +02001000 }
1001 }
1002 }
1003out:
Ursula Braun92f3cb02020-07-08 17:05:13 +02001004 mutex_unlock(&smc_ib_devices.mutex);
Karsten Graulfdff7042020-04-29 17:10:37 +02001005}
1006
Tony Lu0237a3a2021-12-28 21:06:09 +08001007/* find alternate roce device with same pnet_id, vlan_id and net namespace */
Karsten Graul6c868a32020-05-01 12:48:11 +02001008void smc_pnet_find_alt_roce(struct smc_link_group *lgr,
1009 struct smc_init_info *ini,
1010 struct smc_ib_device *known_dev)
1011{
Tony Lu0237a3a2021-12-28 21:06:09 +08001012 struct net *net = lgr->net;
1013
1014 _smc_pnet_find_roce_by_pnetid(lgr->pnet_id, ini, known_dev, net);
Karsten Graul6c868a32020-05-01 12:48:11 +02001015}
1016
Ursula Braun54903572019-02-28 15:10:08 +01001017/* if handshake network device belongs to a roce device, return its
1018 * IB device and port
1019 */
1020static void smc_pnet_find_rdma_dev(struct net_device *netdev,
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001021 struct smc_init_info *ini)
Ursula Braun54903572019-02-28 15:10:08 +01001022{
Tony Lu0237a3a2021-12-28 21:06:09 +08001023 struct net *net = dev_net(netdev);
Ursula Braun54903572019-02-28 15:10:08 +01001024 struct smc_ib_device *ibdev;
1025
Ursula Braun92f3cb02020-07-08 17:05:13 +02001026 mutex_lock(&smc_ib_devices.mutex);
Ursula Braun54903572019-02-28 15:10:08 +01001027 list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
1028 struct net_device *ndev;
1029 int i;
1030
Tony Lu0237a3a2021-12-28 21:06:09 +08001031 /* check rdma net namespace */
1032 if (!rdma_dev_access_netns(ibdev->ibdev, net))
1033 continue;
1034
Ursula Braun54903572019-02-28 15:10:08 +01001035 for (i = 1; i <= SMC_MAX_PORTS; i++) {
1036 if (!rdma_is_port_valid(ibdev->ibdev, i))
1037 continue;
1038 if (!ibdev->ibdev->ops.get_netdev)
1039 continue;
1040 ndev = ibdev->ibdev->ops.get_netdev(ibdev->ibdev, i);
1041 if (!ndev)
1042 continue;
1043 dev_put(ndev);
1044 if (netdev == ndev &&
1045 smc_ib_port_active(ibdev, i) &&
Karsten Graul24fb6812021-10-16 11:37:48 +02001046 !test_bit(i - 1, ibdev->ports_going_away)) {
1047 if (!smc_pnet_determine_gid(ibdev, i, ini))
1048 break;
Ursula Braun54903572019-02-28 15:10:08 +01001049 }
1050 }
1051 }
Ursula Braun92f3cb02020-07-08 17:05:13 +02001052 mutex_unlock(&smc_ib_devices.mutex);
Ursula Braun54903572019-02-28 15:10:08 +01001053}
1054
Ursula Braun0afff912018-06-28 19:05:05 +02001055/* Determine the corresponding IB device port based on the hardware PNETID.
Ursula Braun7005ada2018-07-25 16:35:31 +02001056 * Searching stops at the first matching active IB device port with vlan_id
1057 * configured.
Ursula Braun54903572019-02-28 15:10:08 +01001058 * If nothing found, check pnetid table.
1059 * If nothing found, try to use handshake device
Ursula Braun0afff912018-06-28 19:05:05 +02001060 */
1061static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001062 struct smc_init_info *ini)
Ursula Braun0afff912018-06-28 19:05:05 +02001063{
1064 u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
Tony Lu0237a3a2021-12-28 21:06:09 +08001065 struct net *net;
Ursula Braun0afff912018-06-28 19:05:05 +02001066
1067 ndev = pnet_find_base_ndev(ndev);
Tony Lu0237a3a2021-12-28 21:06:09 +08001068 net = dev_net(ndev);
Ursula Braun0afff912018-06-28 19:05:05 +02001069 if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
Hans Wippel890a2cb2019-02-21 13:01:00 +01001070 ndev_pnetid) &&
Ursula Braun54903572019-02-28 15:10:08 +01001071 smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid)) {
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001072 smc_pnet_find_rdma_dev(ndev, ini);
Ursula Braun0afff912018-06-28 19:05:05 +02001073 return; /* pnetid could not be determined */
Ursula Braun54903572019-02-28 15:10:08 +01001074 }
Tony Lu0237a3a2021-12-28 21:06:09 +08001075 _smc_pnet_find_roce_by_pnetid(ndev_pnetid, ini, NULL, net);
Ursula Braun0afff912018-06-28 19:05:05 +02001076}
1077
Hans Wippel1619f772018-06-28 19:05:08 +02001078static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001079 struct smc_init_info *ini)
Hans Wippel1619f772018-06-28 19:05:08 +02001080{
1081 u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
1082 struct smcd_dev *ismdev;
1083
1084 ndev = pnet_find_base_ndev(ndev);
1085 if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
Hans Wippelf3d74b22019-02-21 13:01:01 +01001086 ndev_pnetid) &&
1087 smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
Hans Wippel1619f772018-06-28 19:05:08 +02001088 return; /* pnetid could not be determined */
1089
Ursula Braun82087c02020-07-08 17:05:14 +02001090 mutex_lock(&smcd_dev_list.mutex);
Hans Wippel1619f772018-06-28 19:05:08 +02001091 list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
Ursula Braunc3d94942019-10-09 10:07:46 +02001092 if (smc_pnet_match(ismdev->pnetid, ndev_pnetid) &&
Ursula Braun7b2977d2020-09-10 18:48:24 +02001093 !ismdev->going_away &&
Ursula Braun3fc64932020-09-26 12:44:23 +02001094 (!ini->ism_peer_gid[0] ||
1095 !smc_ism_cantalk(ini->ism_peer_gid[0], ini->vlan_id,
Ursula Braun7b2977d2020-09-10 18:48:24 +02001096 ismdev))) {
Ursula Braun3fc64932020-09-26 12:44:23 +02001097 ini->ism_dev[0] = ismdev;
Hans Wippel1619f772018-06-28 19:05:08 +02001098 break;
1099 }
1100 }
Ursula Braun82087c02020-07-08 17:05:14 +02001101 mutex_unlock(&smcd_dev_list.mutex);
Hans Wippel1619f772018-06-28 19:05:08 +02001102}
1103
Ursula Braun0afff912018-06-28 19:05:05 +02001104/* PNET table analysis for a given sock:
1105 * determine ib_device and port belonging to used internal TCP socket
1106 * ethernet interface.
1107 */
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001108void smc_pnet_find_roce_resource(struct sock *sk, struct smc_init_info *ini)
Ursula Braun0afff912018-06-28 19:05:05 +02001109{
1110 struct dst_entry *dst = sk_dst_get(sk);
1111
Ursula Braun0afff912018-06-28 19:05:05 +02001112 if (!dst)
1113 goto out;
1114 if (!dst->dev)
1115 goto out_rel;
1116
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001117 smc_pnet_find_roce_by_pnetid(dst->dev, ini);
Ursula Braun0afff912018-06-28 19:05:05 +02001118
Thomas Richter6812baa2017-01-09 16:55:15 +01001119out_rel:
1120 dst_release(dst);
Ursula Braun0afff912018-06-28 19:05:05 +02001121out:
1122 return;
Thomas Richter6812baa2017-01-09 16:55:15 +01001123}
Hans Wippel1619f772018-06-28 19:05:08 +02001124
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001125void smc_pnet_find_ism_resource(struct sock *sk, struct smc_init_info *ini)
Hans Wippel1619f772018-06-28 19:05:08 +02001126{
1127 struct dst_entry *dst = sk_dst_get(sk);
1128
Ursula Braun3fc64932020-09-26 12:44:23 +02001129 ini->ism_dev[0] = NULL;
Hans Wippel1619f772018-06-28 19:05:08 +02001130 if (!dst)
1131 goto out;
1132 if (!dst->dev)
1133 goto out_rel;
1134
Karsten Graulbc36d2f2019-04-12 12:57:26 +02001135 smc_pnet_find_ism_by_pnetid(dst->dev, ini);
Hans Wippel1619f772018-06-28 19:05:08 +02001136
1137out_rel:
1138 dst_release(dst);
1139out:
1140 return;
1141}
Karsten Graulfdff7042020-04-29 17:10:37 +02001142
1143/* Lookup and apply a pnet table entry to the given ib device.
1144 */
1145int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
1146{
1147 char *ib_name = smcibdev->ibdev->name;
1148 struct smc_pnettable *pnettable;
1149 struct smc_pnetentry *tmp_pe;
1150 struct smc_net *sn;
1151 int rc = -ENOENT;
1152
1153 /* get pnettable for init namespace */
1154 sn = net_generic(&init_net, smc_net_id);
1155 pnettable = &sn->pnettable;
1156
1157 read_lock(&pnettable->lock);
1158 list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
1159 if (tmp_pe->type == SMC_PNET_IB &&
1160 !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX) &&
1161 tmp_pe->ib_port == ib_port) {
1162 smc_pnet_apply_ib(smcibdev, ib_port, tmp_pe->pnet_name);
1163 rc = 0;
1164 break;
1165 }
1166 }
1167 read_unlock(&pnettable->lock);
1168
1169 return rc;
1170}
1171
1172/* Lookup and apply a pnet table entry to the given smcd device.
1173 */
1174int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
1175{
1176 const char *ib_name = dev_name(&smcddev->dev);
1177 struct smc_pnettable *pnettable;
1178 struct smc_pnetentry *tmp_pe;
1179 struct smc_net *sn;
1180 int rc = -ENOENT;
1181
1182 /* get pnettable for init namespace */
1183 sn = net_generic(&init_net, smc_net_id);
1184 pnettable = &sn->pnettable;
1185
1186 read_lock(&pnettable->lock);
1187 list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
1188 if (tmp_pe->type == SMC_PNET_IB &&
1189 !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
1190 smc_pnet_apply_smcd(smcddev, tmp_pe->pnet_name);
1191 rc = 0;
1192 break;
1193 }
1194 }
1195 read_unlock(&pnettable->lock);
1196
1197 return rc;
1198}