Skip to content

Commit 0afff91

Browse files
Ursula Braundavem330
authored andcommitted
net/smc: add pnetid support
s390 hardware supports the definition of a so-call Physical NETwork IDentifier (short PNETID) per network device port. These PNETIDS can be used to identify network devices that are attached to the same physical network (broadcast domain). On s390 try to use the PNETID of the ethernet device port used for initial connecting, and derive the IB device port used for SMC RDMA traffic. On platforms without PNETID support fall back to the existing solution of a configured pnet table. Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent be6a3f3 commit 0afff91

File tree

5 files changed

+114
-20
lines changed

5 files changed

+114
-20
lines changed

include/net/smc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#ifndef _SMC_H
1212
#define _SMC_H
1313

14+
#define SMC_MAX_PNETID_LEN 16 /* Max. length of PNET id */
15+
1416
struct smc_hashinfo {
1517
rwlock_t lock;
1618
struct hlist_head ht;

net/smc/smc_ib.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,12 @@ static void smc_ib_add_dev(struct ib_device *ibdev)
504504
port_cnt = smcibdev->ibdev->phys_port_cnt;
505505
for (i = 0;
506506
i < min_t(size_t, port_cnt, SMC_MAX_PORTS);
507-
i++)
507+
i++) {
508508
set_bit(i, &smcibdev->port_event_mask);
509+
/* determine pnetids of the port */
510+
smc_pnetid_by_dev_port(ibdev->dev.parent, i,
511+
smcibdev->pnetid[i]);
512+
}
509513
schedule_work(&smcibdev->port_event_work);
510514
}
511515

net/smc/smc_ib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/interrupt.h>
1616
#include <linux/if_ether.h>
1717
#include <rdma/ib_verbs.h>
18+
#include <net/smc.h>
1819

1920
#define SMC_MAX_PORTS 2 /* Max # of ports */
2021
#define SMC_GID_SIZE sizeof(union ib_gid)
@@ -40,6 +41,8 @@ struct smc_ib_device { /* ib-device infos for smc */
4041
char mac[SMC_MAX_PORTS][ETH_ALEN];
4142
/* mac address per port*/
4243
union ib_gid gid[SMC_MAX_PORTS]; /* gid per port */
44+
u8 pnetid[SMC_MAX_PORTS][SMC_MAX_PNETID_LEN];
45+
/* pnetid per port */
4346
u8 initialized : 1; /* ib dev CQ, evthdl done */
4447
struct work_struct port_event_work;
4548
unsigned long port_event_mask;

net/smc/smc_pnet.c

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@
2323
#include "smc_pnet.h"
2424
#include "smc_ib.h"
2525

26-
#define SMC_MAX_PNET_ID_LEN 16 /* Max. length of PNET id */
27-
2826
static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
2927
[SMC_PNETID_NAME] = {
3028
.type = NLA_NUL_STRING,
31-
.len = SMC_MAX_PNET_ID_LEN - 1
29+
.len = SMC_MAX_PNETID_LEN - 1
3230
},
3331
[SMC_PNETID_ETHNAME] = {
3432
.type = NLA_NUL_STRING,
@@ -65,7 +63,7 @@ static struct smc_pnettable {
6563
*/
6664
struct smc_pnetentry {
6765
struct list_head list;
68-
char pnet_name[SMC_MAX_PNET_ID_LEN + 1];
66+
char pnet_name[SMC_MAX_PNETID_LEN + 1];
6967
struct net_device *ndev;
7068
struct smc_ib_device *smcibdev;
7169
u8 ib_port;
@@ -209,7 +207,7 @@ static bool smc_pnetid_valid(const char *pnet_name, char *pnetid)
209207
return false;
210208
while (--end >= bf && isspace(*end))
211209
;
212-
if (end - bf >= SMC_MAX_PNET_ID_LEN)
210+
if (end - bf >= SMC_MAX_PNETID_LEN)
213211
return false;
214212
while (bf <= end) {
215213
if (!isalnum(*bf))
@@ -512,26 +510,70 @@ void smc_pnet_exit(void)
512510
genl_unregister_family(&smc_pnet_nl_family);
513511
}
514512

515-
/* PNET table analysis for a given sock:
516-
* determine ib_device and port belonging to used internal TCP socket
517-
* ethernet interface.
513+
/* Determine one base device for stacked net devices.
514+
* If the lower device level contains more than one devices
515+
* (for instance with bonding slaves), just the first device
516+
* is used to reach a base device.
518517
*/
519-
void smc_pnet_find_roce_resource(struct sock *sk,
520-
struct smc_ib_device **smcibdev, u8 *ibport)
518+
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
521519
{
522-
struct dst_entry *dst = sk_dst_get(sk);
523-
struct smc_pnetentry *pnetelem;
520+
int i, nest_lvl;
524521

525-
*smcibdev = NULL;
526-
*ibport = 0;
522+
rtnl_lock();
523+
nest_lvl = dev_get_nest_level(ndev);
524+
for (i = 0; i < nest_lvl; i++) {
525+
struct list_head *lower = &ndev->adj_list.lower;
526+
527+
if (list_empty(lower))
528+
break;
529+
lower = lower->next;
530+
ndev = netdev_lower_get_next(ndev, &lower);
531+
}
532+
rtnl_unlock();
533+
return ndev;
534+
}
535+
536+
/* Determine the corresponding IB device port based on the hardware PNETID.
537+
* Searching stops at the first matching active IB device port.
538+
*/
539+
static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
540+
struct smc_ib_device **smcibdev,
541+
u8 *ibport)
542+
{
543+
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
544+
struct smc_ib_device *ibdev;
545+
int i;
546+
547+
ndev = pnet_find_base_ndev(ndev);
548+
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
549+
ndev_pnetid))
550+
return; /* pnetid could not be determined */
551+
552+
spin_lock(&smc_ib_devices.lock);
553+
list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
554+
for (i = 1; i <= SMC_MAX_PORTS; i++) {
555+
if (!memcmp(ibdev->pnetid[i - 1], ndev_pnetid,
556+
SMC_MAX_PNETID_LEN) &&
557+
smc_ib_port_active(ibdev, i)) {
558+
*smcibdev = ibdev;
559+
*ibport = i;
560+
break;
561+
}
562+
}
563+
}
564+
spin_unlock(&smc_ib_devices.lock);
565+
}
566+
567+
/* Lookup of coupled ib_device via SMC pnet table */
568+
static void smc_pnet_find_roce_by_table(struct net_device *netdev,
569+
struct smc_ib_device **smcibdev,
570+
u8 *ibport)
571+
{
572+
struct smc_pnetentry *pnetelem;
527573

528-
if (!dst)
529-
return;
530-
if (!dst->dev)
531-
goto out_rel;
532574
read_lock(&smc_pnettable.lock);
533575
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
534-
if (dst->dev == pnetelem->ndev) {
576+
if (netdev == pnetelem->ndev) {
535577
if (smc_ib_port_active(pnetelem->smcibdev,
536578
pnetelem->ib_port)) {
537579
*smcibdev = pnetelem->smcibdev;
@@ -541,6 +583,35 @@ void smc_pnet_find_roce_resource(struct sock *sk,
541583
}
542584
}
543585
read_unlock(&smc_pnettable.lock);
586+
}
587+
588+
/* PNET table analysis for a given sock:
589+
* determine ib_device and port belonging to used internal TCP socket
590+
* ethernet interface.
591+
*/
592+
void smc_pnet_find_roce_resource(struct sock *sk,
593+
struct smc_ib_device **smcibdev, u8 *ibport)
594+
{
595+
struct dst_entry *dst = sk_dst_get(sk);
596+
597+
*smcibdev = NULL;
598+
*ibport = 0;
599+
600+
if (!dst)
601+
goto out;
602+
if (!dst->dev)
603+
goto out_rel;
604+
605+
/* if possible, lookup via hardware-defined pnetid */
606+
smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport);
607+
if (*smcibdev)
608+
goto out_rel;
609+
610+
/* lookup via SMC PNET table */
611+
smc_pnet_find_roce_by_table(dst->dev, smcibdev, ibport);
612+
544613
out_rel:
545614
dst_release(dst);
615+
out:
616+
return;
546617
}

net/smc/smc_pnet.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,22 @@
1212
#ifndef _SMC_PNET_H
1313
#define _SMC_PNET_H
1414

15+
#if IS_ENABLED(CONFIG_HAVE_PNETID)
16+
#include <asm/pnet.h>
17+
#endif
18+
1519
struct smc_ib_device;
1620

21+
static inline int smc_pnetid_by_dev_port(struct device *dev,
22+
unsigned short port, u8 *pnetid)
23+
{
24+
#if IS_ENABLED(CONFIG_HAVE_PNETID)
25+
return pnet_id_by_dev_port(dev, port, pnetid);
26+
#else
27+
return -ENOENT;
28+
#endif
29+
}
30+
1731
int smc_pnet_init(void) __init;
1832
void smc_pnet_exit(void);
1933
int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev);

0 commit comments

Comments
 (0)