net/smc: rework pnet table
[linux-2.6-microblaze.git] / net / smc / smc_pnet.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
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>
15 #include <net/netlink.h>
16 #include <net/genetlink.h>
17
18 #include <uapi/linux/if.h>
19 #include <uapi/linux/smc.h>
20
21 #include <rdma/ib_verbs.h>
22
23 #include "smc_pnet.h"
24 #include "smc_ib.h"
25 #include "smc_ism.h"
26
27 #define SMC_ASCII_BLANK 32
28
29 static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
30
31 static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
32         [SMC_PNETID_NAME] = {
33                 .type = NLA_NUL_STRING,
34                 .len = SMC_MAX_PNETID_LEN
35         },
36         [SMC_PNETID_ETHNAME] = {
37                 .type = NLA_NUL_STRING,
38                 .len = IFNAMSIZ - 1
39         },
40         [SMC_PNETID_IBNAME] = {
41                 .type = NLA_NUL_STRING,
42                 .len = IB_DEVICE_NAME_MAX - 1
43         },
44         [SMC_PNETID_IBPORT] = { .type = NLA_U8 }
45 };
46
47 static struct genl_family smc_pnet_nl_family;
48
49 /**
50  * struct smc_pnettable - SMC PNET table anchor
51  * @lock: Lock for list action
52  * @pnetlist: List of PNETIDs
53  */
54 static struct smc_pnettable {
55         rwlock_t lock;
56         struct list_head pnetlist;
57 } smc_pnettable = {
58         .pnetlist = LIST_HEAD_INIT(smc_pnettable.pnetlist),
59         .lock = __RW_LOCK_UNLOCKED(smc_pnettable.lock)
60 };
61
62 /**
63  * struct smc_user_pnetentry - pnet identifier name entry for/from user
64  * @list: List node.
65  * @pnet_name: Pnet identifier name
66  * @ndev: pointer to network device.
67  * @smcibdev: Pointer to IB device.
68  * @ib_port: Port of IB device.
69  */
70 struct smc_user_pnetentry {
71         struct list_head list;
72         char pnet_name[SMC_MAX_PNETID_LEN + 1];
73         struct net_device *ndev;
74         struct smc_ib_device *smcibdev;
75         u8 ib_port;
76 };
77
78 /* pnet entry stored in pnet table */
79 struct smc_pnetentry {
80         struct list_head list;
81         char pnet_name[SMC_MAX_PNETID_LEN + 1];
82         struct net_device *ndev;
83 };
84
85 /* Check if two given pnetids match */
86 static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
87 {
88         int i;
89
90         for (i = 0; i < SMC_MAX_PNETID_LEN; i++) {
91                 if ((pnetid1[i] == 0 || pnetid1[i] == SMC_ASCII_BLANK) &&
92                     (pnetid2[i] == 0 || pnetid2[i] == SMC_ASCII_BLANK))
93                         break;
94                 if (pnetid1[i] != pnetid2[i])
95                         return false;
96         }
97         return true;
98 }
99
100 /* Remove a pnetid from the pnet table.
101  */
102 static int smc_pnet_remove_by_pnetid(char *pnet_name)
103 {
104         struct smc_pnetentry *pnetelem, *tmp_pe;
105         struct smc_ib_device *ibdev;
106         int rc = -ENOENT;
107         int ibport;
108
109         /* remove netdevices */
110         write_lock(&smc_pnettable.lock);
111         list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
112                                  list) {
113                 if (!pnet_name ||
114                     smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
115                         list_del(&pnetelem->list);
116                         dev_put(pnetelem->ndev);
117                         kfree(pnetelem);
118                         rc = 0;
119                 }
120         }
121         write_unlock(&smc_pnettable.lock);
122         /* remove ib devices */
123         spin_lock(&smc_ib_devices.lock);
124         list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
125                 for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
126                         if (ibdev->pnetid_by_user[ibport] &&
127                             (!pnet_name ||
128                              smc_pnet_match(pnet_name,
129                                             ibdev->pnetid[ibport]))) {
130                                 memset(ibdev->pnetid[ibport], 0,
131                                        SMC_MAX_PNETID_LEN);
132                                 ibdev->pnetid_by_user[ibport] = false;
133                                 rc = 0;
134                         }
135                 }
136         }
137         spin_unlock(&smc_ib_devices.lock);
138         return rc;
139 }
140
141 /* Remove a pnet entry mentioning a given network device from the pnet table.
142  */
143 static int smc_pnet_remove_by_ndev(struct net_device *ndev)
144 {
145         struct smc_pnetentry *pnetelem, *tmp_pe;
146         int rc = -ENOENT;
147
148         write_lock(&smc_pnettable.lock);
149         list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
150                                  list) {
151                 if (pnetelem->ndev == ndev) {
152                         list_del(&pnetelem->list);
153                         dev_put(pnetelem->ndev);
154                         kfree(pnetelem);
155                         rc = 0;
156                         break;
157                 }
158         }
159         write_unlock(&smc_pnettable.lock);
160         return rc;
161 }
162
163 /* Append a pnetid to the end of the pnet table if not already on this list.
164  */
165 static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
166 {
167         u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
168         u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
169         struct smc_pnetentry *tmp_pnetelem;
170         struct smc_pnetentry *pnetelem;
171         struct net_device *ndev;
172         bool new_netdev = true;
173         bool new_ibdev = false;
174
175         if (new_pnetelem->smcibdev) {
176                 struct smc_ib_device *ib_dev = new_pnetelem->smcibdev;
177                 int ib_port = new_pnetelem->ib_port;
178
179                 spin_lock(&smc_ib_devices.lock);
180                 if (smc_pnet_match(ib_dev->pnetid[ib_port - 1], pnet_null)) {
181                         memcpy(ib_dev->pnetid[ib_port - 1],
182                                new_pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
183                         ib_dev->pnetid_by_user[ib_port - 1] = true;
184                         new_ibdev = true;
185                 }
186                 spin_unlock(&smc_ib_devices.lock);
187         }
188
189         if (!new_pnetelem->ndev)
190                 return new_ibdev ? 0 : -EEXIST;
191
192         /* check if (base) netdev already has a pnetid. If there is one, we do
193          * not want to add a pnet table entry
194          */
195         ndev = pnet_find_base_ndev(new_pnetelem->ndev);
196         if (!smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
197                                     ndev_pnetid))
198                 return new_ibdev ? 0 : -EEXIST;
199
200         /* add a new netdev entry to the pnet table if there isn't one */
201         tmp_pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL);
202         if (!tmp_pnetelem)
203                 return -ENOMEM;
204         memcpy(tmp_pnetelem->pnet_name, new_pnetelem->pnet_name,
205                SMC_MAX_PNETID_LEN);
206         tmp_pnetelem->ndev = new_pnetelem->ndev;
207
208         write_lock(&smc_pnettable.lock);
209         list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
210                 if (pnetelem->ndev == new_pnetelem->ndev)
211                         new_netdev = false;
212         }
213         if (new_netdev) {
214                 dev_hold(tmp_pnetelem->ndev);
215                 list_add_tail(&tmp_pnetelem->list, &smc_pnettable.pnetlist);
216                 write_unlock(&smc_pnettable.lock);
217         } else {
218                 write_unlock(&smc_pnettable.lock);
219                 kfree(tmp_pnetelem);
220         }
221
222         return (new_netdev || new_ibdev) ? 0 : -EEXIST;
223 }
224
225 /* The limit for pnetid is 16 characters.
226  * Valid characters should be (single-byte character set) a-z, A-Z, 0-9.
227  * Lower case letters are converted to upper case.
228  * Interior blanks should not be used.
229  */
230 static bool smc_pnetid_valid(const char *pnet_name, char *pnetid)
231 {
232         char *bf = skip_spaces(pnet_name);
233         size_t len = strlen(bf);
234         char *end = bf + len;
235
236         if (!len)
237                 return false;
238         while (--end >= bf && isspace(*end))
239                 ;
240         if (end - bf >= SMC_MAX_PNETID_LEN)
241                 return false;
242         while (bf <= end) {
243                 if (!isalnum(*bf))
244                         return false;
245                 *pnetid++ = islower(*bf) ? toupper(*bf) : *bf;
246                 bf++;
247         }
248         *pnetid = '\0';
249         return true;
250 }
251
252 /* Find an infiniband device by a given name. The device might not exist. */
253 static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
254 {
255         struct smc_ib_device *ibdev;
256
257         spin_lock(&smc_ib_devices.lock);
258         list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
259                 if (!strncmp(ibdev->ibdev->name, ib_name,
260                              sizeof(ibdev->ibdev->name))) {
261                         goto out;
262                 }
263         }
264         ibdev = NULL;
265 out:
266         spin_unlock(&smc_ib_devices.lock);
267         return ibdev;
268 }
269
270 /* Parse the supplied netlink attributes and fill a pnetentry structure.
271  * For ethernet and infiniband device names verify that the devices exist.
272  */
273 static int smc_pnet_fill_entry(struct net *net,
274                                struct smc_user_pnetentry *pnetelem,
275                                struct nlattr *tb[])
276 {
277         char *string, *ibname;
278         int rc;
279
280         memset(pnetelem, 0, sizeof(*pnetelem));
281         INIT_LIST_HEAD(&pnetelem->list);
282
283         rc = -EINVAL;
284         if (!tb[SMC_PNETID_NAME])
285                 goto error;
286         string = (char *)nla_data(tb[SMC_PNETID_NAME]);
287         if (!smc_pnetid_valid(string, pnetelem->pnet_name))
288                 goto error;
289
290         rc = -EINVAL;
291         if (tb[SMC_PNETID_ETHNAME]) {
292                 string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
293                 pnetelem->ndev = dev_get_by_name(net, string);
294                 if (!pnetelem->ndev)
295                         goto error;
296         }
297
298         rc = -EINVAL;
299         if (tb[SMC_PNETID_IBNAME]) {
300                 ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
301                 ibname = strim(ibname);
302                 pnetelem->smcibdev = smc_pnet_find_ib(ibname);
303                 if (!pnetelem->smcibdev)
304                         goto error;
305                 if (pnetelem->smcibdev) {
306                         if (!tb[SMC_PNETID_IBPORT])
307                                 goto error;
308                         pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
309                         if (pnetelem->ib_port < 1 ||
310                             pnetelem->ib_port > SMC_MAX_PORTS)
311                                 goto error;
312                 }
313         }
314
315         return 0;
316
317 error:
318         if (pnetelem->ndev)
319                 dev_put(pnetelem->ndev);
320         return rc;
321 }
322
323 /* Convert an smc_pnetentry to a netlink attribute sequence */
324 static int smc_pnet_set_nla(struct sk_buff *msg,
325                             struct smc_user_pnetentry *pnetelem)
326 {
327         if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name))
328                 return -1;
329         if (pnetelem->ndev) {
330                 if (nla_put_string(msg, SMC_PNETID_ETHNAME,
331                                    pnetelem->ndev->name))
332                         return -1;
333         } else {
334                 if (nla_put_string(msg, SMC_PNETID_ETHNAME, "n/a"))
335                         return -1;
336         }
337         if (pnetelem->smcibdev) {
338                 if (nla_put_string(msg, SMC_PNETID_IBNAME,
339                                    pnetelem->smcibdev->ibdev->name) ||
340                     nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
341                         return -1;
342         } else {
343                 if (nla_put_string(msg, SMC_PNETID_IBNAME, "n/a") ||
344                     nla_put_u8(msg, SMC_PNETID_IBPORT, 0xff))
345                         return -1;
346         }
347
348         return 0;
349 }
350
351 static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
352 {
353         struct net *net = genl_info_net(info);
354         struct smc_user_pnetentry pnetelem;
355         int rc;
356
357         rc = smc_pnet_fill_entry(net, &pnetelem, info->attrs);
358         if (!rc)
359                 rc = smc_pnet_enter(&pnetelem);
360         if (pnetelem.ndev)
361                 dev_put(pnetelem.ndev);
362         return rc;
363 }
364
365 static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info)
366 {
367         if (!info->attrs[SMC_PNETID_NAME])
368                 return -EINVAL;
369         return smc_pnet_remove_by_pnetid(
370                                 (char *)nla_data(info->attrs[SMC_PNETID_NAME]));
371 }
372
373 static int smc_pnet_dump_start(struct netlink_callback *cb)
374 {
375         cb->args[0] = 0;
376         return 0;
377 }
378
379 static int smc_pnet_dumpinfo(struct sk_buff *skb,
380                              u32 portid, u32 seq, u32 flags,
381                              struct smc_user_pnetentry *pnetelem)
382 {
383         void *hdr;
384
385         hdr = genlmsg_put(skb, portid, seq, &smc_pnet_nl_family,
386                           flags, SMC_PNETID_GET);
387         if (!hdr)
388                 return -ENOMEM;
389         if (smc_pnet_set_nla(skb, pnetelem) < 0) {
390                 genlmsg_cancel(skb, hdr);
391                 return -EMSGSIZE;
392         }
393         genlmsg_end(skb, hdr);
394         return 0;
395 }
396
397 static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
398                           int start_idx)
399 {
400         struct smc_user_pnetentry tmp_entry;
401         struct smc_pnetentry *pnetelem;
402         struct smc_ib_device *ibdev;
403         int idx = 0;
404         int ibport;
405
406         /* dump netdevices */
407         read_lock(&smc_pnettable.lock);
408         list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
409                 if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
410                         continue;
411                 if (idx++ < start_idx)
412                         continue;
413                 memset(&tmp_entry, 0, sizeof(tmp_entry));
414                 memcpy(&tmp_entry.pnet_name, pnetelem->pnet_name,
415                        SMC_MAX_PNETID_LEN);
416                 tmp_entry.ndev = pnetelem->ndev;
417                 if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
418                                       &tmp_entry)) {
419                         --idx;
420                         break;
421                 }
422         }
423         read_unlock(&smc_pnettable.lock);
424
425         /* dump ib devices */
426         spin_lock(&smc_ib_devices.lock);
427         list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
428                 for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
429                         if (ibdev->pnetid_by_user[ibport]) {
430                                 if (pnetid &&
431                                     !smc_pnet_match(ibdev->pnetid[ibport],
432                                                     pnetid))
433                                         continue;
434                                 if (idx++ < start_idx)
435                                         continue;
436                                 memset(&tmp_entry, 0, sizeof(tmp_entry));
437                                 memcpy(&tmp_entry.pnet_name,
438                                        ibdev->pnetid[ibport],
439                                        SMC_MAX_PNETID_LEN);
440                                 tmp_entry.smcibdev = ibdev;
441                                 tmp_entry.ib_port = ibport + 1;
442                                 if (smc_pnet_dumpinfo(skb, portid, seq,
443                                                       NLM_F_MULTI,
444                                                       &tmp_entry)) {
445                                         --idx;
446                                         break;
447                                 }
448                         }
449                 }
450         }
451         spin_unlock(&smc_ib_devices.lock);
452
453         return idx;
454 }
455
456 static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
457 {
458         int idx;
459
460         idx = _smc_pnet_dump(skb, NETLINK_CB(cb->skb).portid,
461                              cb->nlh->nlmsg_seq, NULL, cb->args[0]);
462
463         cb->args[0] = idx;
464         return skb->len;
465 }
466
467 /* Retrieve one PNETID entry */
468 static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
469 {
470         struct sk_buff *msg;
471         void *hdr;
472
473         if (!info->attrs[SMC_PNETID_NAME])
474                 return -EINVAL;
475
476         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
477         if (!msg)
478                 return -ENOMEM;
479
480         _smc_pnet_dump(msg, info->snd_portid, info->snd_seq,
481                        nla_data(info->attrs[SMC_PNETID_NAME]), 0);
482
483         /* finish multi part message and send it */
484         hdr = nlmsg_put(msg, info->snd_portid, info->snd_seq, NLMSG_DONE, 0,
485                         NLM_F_MULTI);
486         if (!hdr) {
487                 nlmsg_free(msg);
488                 return -EMSGSIZE;
489         }
490         return genlmsg_reply(msg, info);
491 }
492
493 /* Remove and delete all pnetids from pnet table.
494  */
495 static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
496 {
497         return smc_pnet_remove_by_pnetid(NULL);
498 }
499
500 /* SMC_PNETID generic netlink operation definition */
501 static const struct genl_ops smc_pnet_ops[] = {
502         {
503                 .cmd = SMC_PNETID_GET,
504                 .flags = GENL_ADMIN_PERM,
505                 .policy = smc_pnet_policy,
506                 .doit = smc_pnet_get,
507                 .dumpit = smc_pnet_dump,
508                 .start = smc_pnet_dump_start
509         },
510         {
511                 .cmd = SMC_PNETID_ADD,
512                 .flags = GENL_ADMIN_PERM,
513                 .policy = smc_pnet_policy,
514                 .doit = smc_pnet_add
515         },
516         {
517                 .cmd = SMC_PNETID_DEL,
518                 .flags = GENL_ADMIN_PERM,
519                 .policy = smc_pnet_policy,
520                 .doit = smc_pnet_del
521         },
522         {
523                 .cmd = SMC_PNETID_FLUSH,
524                 .flags = GENL_ADMIN_PERM,
525                 .policy = smc_pnet_policy,
526                 .doit = smc_pnet_flush
527         }
528 };
529
530 /* SMC_PNETID family definition */
531 static struct genl_family smc_pnet_nl_family __ro_after_init = {
532         .hdrsize = 0,
533         .name = SMCR_GENL_FAMILY_NAME,
534         .version = SMCR_GENL_FAMILY_VERSION,
535         .maxattr = SMC_PNETID_MAX,
536         .netnsok = true,
537         .module = THIS_MODULE,
538         .ops = smc_pnet_ops,
539         .n_ops =  ARRAY_SIZE(smc_pnet_ops)
540 };
541
542 static int smc_pnet_netdev_event(struct notifier_block *this,
543                                  unsigned long event, void *ptr)
544 {
545         struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
546
547         switch (event) {
548         case NETDEV_REBOOT:
549         case NETDEV_UNREGISTER:
550                 smc_pnet_remove_by_ndev(event_dev);
551                 return NOTIFY_OK;
552         default:
553                 return NOTIFY_DONE;
554         }
555 }
556
557 static struct notifier_block smc_netdev_notifier = {
558         .notifier_call = smc_pnet_netdev_event
559 };
560
561 int __init smc_pnet_init(void)
562 {
563         int rc;
564
565         rc = genl_register_family(&smc_pnet_nl_family);
566         if (rc)
567                 return rc;
568         rc = register_netdevice_notifier(&smc_netdev_notifier);
569         if (rc)
570                 genl_unregister_family(&smc_pnet_nl_family);
571         return rc;
572 }
573
574 void smc_pnet_exit(void)
575 {
576         smc_pnet_flush(NULL, NULL);
577         unregister_netdevice_notifier(&smc_netdev_notifier);
578         genl_unregister_family(&smc_pnet_nl_family);
579 }
580
581 /* Determine one base device for stacked net devices.
582  * If the lower device level contains more than one devices
583  * (for instance with bonding slaves), just the first device
584  * is used to reach a base device.
585  */
586 static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
587 {
588         int i, nest_lvl;
589
590         rtnl_lock();
591         nest_lvl = dev_get_nest_level(ndev);
592         for (i = 0; i < nest_lvl; i++) {
593                 struct list_head *lower = &ndev->adj_list.lower;
594
595                 if (list_empty(lower))
596                         break;
597                 lower = lower->next;
598                 ndev = netdev_lower_get_next(ndev, &lower);
599         }
600         rtnl_unlock();
601         return ndev;
602 }
603
604 static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *netdev,
605                                               u8 *pnetid)
606 {
607         struct smc_pnetentry *pnetelem;
608         int rc = -ENOENT;
609
610         read_lock(&smc_pnettable.lock);
611         list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
612                 if (netdev == pnetelem->ndev) {
613                         /* get pnetid of netdev device */
614                         memcpy(pnetid, pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
615                         rc = 0;
616                         break;
617                 }
618         }
619         read_unlock(&smc_pnettable.lock);
620         return rc;
621 }
622
623 /* Determine the corresponding IB device port based on the hardware PNETID.
624  * Searching stops at the first matching active IB device port with vlan_id
625  * configured.
626  */
627 static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
628                                          struct smc_ib_device **smcibdev,
629                                          u8 *ibport, unsigned short vlan_id,
630                                          u8 gid[])
631 {
632         u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
633         struct smc_ib_device *ibdev;
634         int i;
635
636         ndev = pnet_find_base_ndev(ndev);
637         if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
638                                    ndev_pnetid) &&
639             smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
640                 return; /* pnetid could not be determined */
641
642         spin_lock(&smc_ib_devices.lock);
643         list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
644                 for (i = 1; i <= SMC_MAX_PORTS; i++) {
645                         if (!rdma_is_port_valid(ibdev->ibdev, i))
646                                 continue;
647                         if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) &&
648                             smc_ib_port_active(ibdev, i) &&
649                             !smc_ib_determine_gid(ibdev, i, vlan_id, gid,
650                                                   NULL))  {
651                                 *smcibdev = ibdev;
652                                 *ibport = i;
653                                 goto out;
654                         }
655                 }
656         }
657 out:
658         spin_unlock(&smc_ib_devices.lock);
659 }
660
661 static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
662                                         struct smcd_dev **smcismdev)
663 {
664         u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
665         struct smcd_dev *ismdev;
666
667         ndev = pnet_find_base_ndev(ndev);
668         if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
669                                    ndev_pnetid))
670                 return; /* pnetid could not be determined */
671
672         spin_lock(&smcd_dev_list.lock);
673         list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
674                 if (!memcmp(ismdev->pnetid, ndev_pnetid, SMC_MAX_PNETID_LEN)) {
675                         *smcismdev = ismdev;
676                         break;
677                 }
678         }
679         spin_unlock(&smcd_dev_list.lock);
680 }
681
682 /* PNET table analysis for a given sock:
683  * determine ib_device and port belonging to used internal TCP socket
684  * ethernet interface.
685  */
686 void smc_pnet_find_roce_resource(struct sock *sk,
687                                  struct smc_ib_device **smcibdev, u8 *ibport,
688                                  unsigned short vlan_id, u8 gid[])
689 {
690         struct dst_entry *dst = sk_dst_get(sk);
691
692         *smcibdev = NULL;
693         *ibport = 0;
694
695         if (!dst)
696                 goto out;
697         if (!dst->dev)
698                 goto out_rel;
699
700         smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport, vlan_id, gid);
701
702 out_rel:
703         dst_release(dst);
704 out:
705         return;
706 }
707
708 void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev)
709 {
710         struct dst_entry *dst = sk_dst_get(sk);
711
712         *smcismdev = NULL;
713         if (!dst)
714                 goto out;
715         if (!dst->dev)
716                 goto out_rel;
717
718         /* if possible, lookup via hardware-defined pnetid */
719         smc_pnet_find_ism_by_pnetid(dst->dev, smcismdev);
720
721 out_rel:
722         dst_release(dst);
723 out:
724         return;
725 }