aboutsummaryrefslogtreecommitdiffstats
path: root/net/smc
diff options
context:
space:
mode:
authorUrsula Braun <ubraun@linux.ibm.com>2018-06-28 13:05:05 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-30 07:42:25 -0400
commit0afff91c6f5ecef27715ea71e34dc2baacba1060 (patch)
treed90ff2e8ba3cb962dd7ea451fdf7fe2a652ad516 /net/smc
parentbe6a3f38ff2a2bfd2e591fdc566940a0d4d9428c (diff)
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>
Diffstat (limited to 'net/smc')
-rw-r--r--net/smc/smc_ib.c6
-rw-r--r--net/smc/smc_ib.h3
-rw-r--r--net/smc/smc_pnet.c109
-rw-r--r--net/smc/smc_pnet.h14
4 files changed, 112 insertions, 20 deletions
diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c
index f8b159ced032..36de2fd76170 100644
--- a/net/smc/smc_ib.c
+++ b/net/smc/smc_ib.c
@@ -504,8 +504,12 @@ static void smc_ib_add_dev(struct ib_device *ibdev)
504 port_cnt = smcibdev->ibdev->phys_port_cnt; 504 port_cnt = smcibdev->ibdev->phys_port_cnt;
505 for (i = 0; 505 for (i = 0;
506 i < min_t(size_t, port_cnt, SMC_MAX_PORTS); 506 i < min_t(size_t, port_cnt, SMC_MAX_PORTS);
507 i++) 507 i++) {
508 set_bit(i, &smcibdev->port_event_mask); 508 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 }
509 schedule_work(&smcibdev->port_event_work); 513 schedule_work(&smcibdev->port_event_work);
510} 514}
511 515
diff --git a/net/smc/smc_ib.h b/net/smc/smc_ib.h
index 2c480b352928..7c1223c91229 100644
--- a/net/smc/smc_ib.h
+++ b/net/smc/smc_ib.h
@@ -15,6 +15,7 @@
15#include <linux/interrupt.h> 15#include <linux/interrupt.h>
16#include <linux/if_ether.h> 16#include <linux/if_ether.h>
17#include <rdma/ib_verbs.h> 17#include <rdma/ib_verbs.h>
18#include <net/smc.h>
18 19
19#define SMC_MAX_PORTS 2 /* Max # of ports */ 20#define SMC_MAX_PORTS 2 /* Max # of ports */
20#define SMC_GID_SIZE sizeof(union ib_gid) 21#define SMC_GID_SIZE sizeof(union ib_gid)
@@ -40,6 +41,8 @@ struct smc_ib_device { /* ib-device infos for smc */
40 char mac[SMC_MAX_PORTS][ETH_ALEN]; 41 char mac[SMC_MAX_PORTS][ETH_ALEN];
41 /* mac address per port*/ 42 /* mac address per port*/
42 union ib_gid gid[SMC_MAX_PORTS]; /* gid per port */ 43 union ib_gid gid[SMC_MAX_PORTS]; /* gid per port */
44 u8 pnetid[SMC_MAX_PORTS][SMC_MAX_PNETID_LEN];
45 /* pnetid per port */
43 u8 initialized : 1; /* ib dev CQ, evthdl done */ 46 u8 initialized : 1; /* ib dev CQ, evthdl done */
44 struct work_struct port_event_work; 47 struct work_struct port_event_work;
45 unsigned long port_event_mask; 48 unsigned long port_event_mask;
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index a82a5cad0282..cdc6e23b6ce1 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -23,12 +23,10 @@
23#include "smc_pnet.h" 23#include "smc_pnet.h"
24#include "smc_ib.h" 24#include "smc_ib.h"
25 25
26#define SMC_MAX_PNET_ID_LEN 16 /* Max. length of PNET id */
27
28static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { 26static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
29 [SMC_PNETID_NAME] = { 27 [SMC_PNETID_NAME] = {
30 .type = NLA_NUL_STRING, 28 .type = NLA_NUL_STRING,
31 .len = SMC_MAX_PNET_ID_LEN - 1 29 .len = SMC_MAX_PNETID_LEN - 1
32 }, 30 },
33 [SMC_PNETID_ETHNAME] = { 31 [SMC_PNETID_ETHNAME] = {
34 .type = NLA_NUL_STRING, 32 .type = NLA_NUL_STRING,
@@ -65,7 +63,7 @@ static struct smc_pnettable {
65 */ 63 */
66struct smc_pnetentry { 64struct smc_pnetentry {
67 struct list_head list; 65 struct list_head list;
68 char pnet_name[SMC_MAX_PNET_ID_LEN + 1]; 66 char pnet_name[SMC_MAX_PNETID_LEN + 1];
69 struct net_device *ndev; 67 struct net_device *ndev;
70 struct smc_ib_device *smcibdev; 68 struct smc_ib_device *smcibdev;
71 u8 ib_port; 69 u8 ib_port;
@@ -209,7 +207,7 @@ static bool smc_pnetid_valid(const char *pnet_name, char *pnetid)
209 return false; 207 return false;
210 while (--end >= bf && isspace(*end)) 208 while (--end >= bf && isspace(*end))
211 ; 209 ;
212 if (end - bf >= SMC_MAX_PNET_ID_LEN) 210 if (end - bf >= SMC_MAX_PNETID_LEN)
213 return false; 211 return false;
214 while (bf <= end) { 212 while (bf <= end) {
215 if (!isalnum(*bf)) 213 if (!isalnum(*bf))
@@ -512,26 +510,70 @@ void smc_pnet_exit(void)
512 genl_unregister_family(&smc_pnet_nl_family); 510 genl_unregister_family(&smc_pnet_nl_family);
513} 511}
514 512
515/* PNET table analysis for a given sock: 513/* Determine one base device for stacked net devices.
516 * determine ib_device and port belonging to used internal TCP socket 514 * If the lower device level contains more than one devices
517 * ethernet interface. 515 * (for instance with bonding slaves), just the first device
516 * is used to reach a base device.
518 */ 517 */
519void smc_pnet_find_roce_resource(struct sock *sk, 518static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
520 struct smc_ib_device **smcibdev, u8 *ibport)
521{ 519{
522 struct dst_entry *dst = sk_dst_get(sk); 520 int i, nest_lvl;
523 struct smc_pnetentry *pnetelem;
524 521
525 *smcibdev = NULL; 522 rtnl_lock();
526 *ibport = 0; 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 */
539static 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 */
568static 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;
527 573
528 if (!dst)
529 return;
530 if (!dst->dev)
531 goto out_rel;
532 read_lock(&smc_pnettable.lock); 574 read_lock(&smc_pnettable.lock);
533 list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) { 575 list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
534 if (dst->dev == pnetelem->ndev) { 576 if (netdev == pnetelem->ndev) {
535 if (smc_ib_port_active(pnetelem->smcibdev, 577 if (smc_ib_port_active(pnetelem->smcibdev,
536 pnetelem->ib_port)) { 578 pnetelem->ib_port)) {
537 *smcibdev = pnetelem->smcibdev; 579 *smcibdev = pnetelem->smcibdev;
@@ -541,6 +583,35 @@ void smc_pnet_find_roce_resource(struct sock *sk,
541 } 583 }
542 } 584 }
543 read_unlock(&smc_pnettable.lock); 585 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 */
592void 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
544out_rel: 613out_rel:
545 dst_release(dst); 614 dst_release(dst);
615out:
616 return;
546} 617}
diff --git a/net/smc/smc_pnet.h b/net/smc/smc_pnet.h
index 5a29519db976..ad4455cde9e7 100644
--- a/net/smc/smc_pnet.h
+++ b/net/smc/smc_pnet.h
@@ -12,8 +12,22 @@
12#ifndef _SMC_PNET_H 12#ifndef _SMC_PNET_H
13#define _SMC_PNET_H 13#define _SMC_PNET_H
14 14
15#if IS_ENABLED(CONFIG_HAVE_PNETID)
16#include <asm/pnet.h>
17#endif
18
15struct smc_ib_device; 19struct smc_ib_device;
16 20
21static 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
17int smc_pnet_init(void) __init; 31int smc_pnet_init(void) __init;
18void smc_pnet_exit(void); 32void smc_pnet_exit(void);
19int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev); 33int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev);