Skip to content

Commit e888a2e

Browse files
Ursula Braundavem330
authored andcommitted
net/smc: introduce list of pnetids for Ethernet devices
SMCD version 2 allows usage of ISM devices with hardware PNETID only, if an Ethernet net_device exists with the same hardware PNETID. This requires to maintain a list of pnetids belonging to Ethernet net_devices, which is covered by this patch. Signed-off-by: Ursula Braun <[email protected]> Signed-off-by: Karsten Graul <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8caaccf commit e888a2e

File tree

3 files changed

+153
-7
lines changed

3 files changed

+153
-7
lines changed

net/smc/smc_netns.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ extern unsigned int smc_net_id;
1616
/* per-network namespace private data */
1717
struct smc_net {
1818
struct smc_pnettable pnettable;
19+
struct smc_pnetids_ndev pnetids_ndev;
1920
};
2021
#endif

net/smc/smc_pnet.c

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "smc_ism.h"
3030
#include "smc_core.h"
3131

32+
static struct net_device *__pnet_find_base_ndev(struct net_device *ndev);
3233
static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
3334

3435
static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
@@ -712,10 +713,115 @@ static struct genl_family smc_pnet_nl_family __ro_after_init = {
712713
.n_ops = ARRAY_SIZE(smc_pnet_ops)
713714
};
714715

716+
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid)
717+
{
718+
struct smc_net *sn = net_generic(net, smc_net_id);
719+
struct smc_pnetids_ndev_entry *pe;
720+
bool rc = false;
721+
722+
read_lock(&sn->pnetids_ndev.lock);
723+
list_for_each_entry(pe, &sn->pnetids_ndev.list, list) {
724+
if (smc_pnet_match(pnetid, pe->pnetid)) {
725+
rc = true;
726+
goto unlock;
727+
}
728+
}
729+
730+
unlock:
731+
read_unlock(&sn->pnetids_ndev.lock);
732+
return rc;
733+
}
734+
735+
static int smc_pnet_add_pnetid(struct net *net, u8 *pnetid)
736+
{
737+
struct smc_net *sn = net_generic(net, smc_net_id);
738+
struct smc_pnetids_ndev_entry *pe, *pi;
739+
740+
pe = kzalloc(sizeof(*pe), GFP_KERNEL);
741+
if (!pe)
742+
return -ENOMEM;
743+
744+
write_lock(&sn->pnetids_ndev.lock);
745+
list_for_each_entry(pi, &sn->pnetids_ndev.list, list) {
746+
if (smc_pnet_match(pnetid, pe->pnetid)) {
747+
refcount_inc(&pi->refcnt);
748+
kfree(pe);
749+
goto unlock;
750+
}
751+
}
752+
refcount_set(&pe->refcnt, 1);
753+
memcpy(pe->pnetid, pnetid, SMC_MAX_PNETID_LEN);
754+
list_add_tail(&pe->list, &sn->pnetids_ndev.list);
755+
756+
unlock:
757+
write_unlock(&sn->pnetids_ndev.lock);
758+
return 0;
759+
}
760+
761+
static void smc_pnet_remove_pnetid(struct net *net, u8 *pnetid)
762+
{
763+
struct smc_net *sn = net_generic(net, smc_net_id);
764+
struct smc_pnetids_ndev_entry *pe, *pe2;
765+
766+
write_lock(&sn->pnetids_ndev.lock);
767+
list_for_each_entry_safe(pe, pe2, &sn->pnetids_ndev.list, list) {
768+
if (smc_pnet_match(pnetid, pe->pnetid)) {
769+
if (refcount_dec_and_test(&pe->refcnt)) {
770+
list_del(&pe->list);
771+
kfree(pe);
772+
}
773+
break;
774+
}
775+
}
776+
write_unlock(&sn->pnetids_ndev.lock);
777+
}
778+
779+
static void smc_pnet_add_base_pnetid(struct net *net, struct net_device *dev,
780+
u8 *ndev_pnetid)
781+
{
782+
struct net_device *base_dev;
783+
784+
base_dev = __pnet_find_base_ndev(dev);
785+
if (base_dev->flags & IFF_UP &&
786+
!smc_pnetid_by_dev_port(base_dev->dev.parent, base_dev->dev_port,
787+
ndev_pnetid)) {
788+
/* add to PNETIDs list */
789+
smc_pnet_add_pnetid(net, ndev_pnetid);
790+
}
791+
}
792+
793+
/* create initial list of netdevice pnetids */
794+
static void smc_pnet_create_pnetids_list(struct net *net)
795+
{
796+
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
797+
struct net_device *dev;
798+
799+
rtnl_lock();
800+
for_each_netdev(net, dev)
801+
smc_pnet_add_base_pnetid(net, dev, ndev_pnetid);
802+
rtnl_unlock();
803+
}
804+
805+
/* clean up list of netdevice pnetids */
806+
static void smc_pnet_destroy_pnetids_list(struct net *net)
807+
{
808+
struct smc_net *sn = net_generic(net, smc_net_id);
809+
struct smc_pnetids_ndev_entry *pe, *temp_pe;
810+
811+
write_lock(&sn->pnetids_ndev.lock);
812+
list_for_each_entry_safe(pe, temp_pe, &sn->pnetids_ndev.list, list) {
813+
list_del(&pe->list);
814+
kfree(pe);
815+
}
816+
write_unlock(&sn->pnetids_ndev.lock);
817+
}
818+
715819
static int smc_pnet_netdev_event(struct notifier_block *this,
716820
unsigned long event, void *ptr)
717821
{
718822
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
823+
struct net *net = dev_net(event_dev);
824+
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
719825

720826
switch (event) {
721827
case NETDEV_REBOOT:
@@ -725,6 +831,17 @@ static int smc_pnet_netdev_event(struct notifier_block *this,
725831
case NETDEV_REGISTER:
726832
smc_pnet_add_by_ndev(event_dev);
727833
return NOTIFY_OK;
834+
case NETDEV_UP:
835+
smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid);
836+
return NOTIFY_OK;
837+
case NETDEV_DOWN:
838+
event_dev = __pnet_find_base_ndev(event_dev);
839+
if (!smc_pnetid_by_dev_port(event_dev->dev.parent,
840+
event_dev->dev_port, ndev_pnetid)) {
841+
/* remove from PNETIDs list */
842+
smc_pnet_remove_pnetid(net, ndev_pnetid);
843+
}
844+
return NOTIFY_OK;
728845
default:
729846
return NOTIFY_DONE;
730847
}
@@ -739,9 +856,14 @@ int smc_pnet_net_init(struct net *net)
739856
{
740857
struct smc_net *sn = net_generic(net, smc_net_id);
741858
struct smc_pnettable *pnettable = &sn->pnettable;
859+
struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;
742860

743861
INIT_LIST_HEAD(&pnettable->pnetlist);
744862
rwlock_init(&pnettable->lock);
863+
INIT_LIST_HEAD(&pnetids_ndev->list);
864+
rwlock_init(&pnetids_ndev->lock);
865+
866+
smc_pnet_create_pnetids_list(net);
745867

746868
return 0;
747869
}
@@ -756,6 +878,7 @@ int __init smc_pnet_init(void)
756878
rc = register_netdevice_notifier(&smc_netdev_notifier);
757879
if (rc)
758880
genl_unregister_family(&smc_pnet_nl_family);
881+
759882
return rc;
760883
}
761884

@@ -764,6 +887,7 @@ void smc_pnet_net_exit(struct net *net)
764887
{
765888
/* flush pnet table */
766889
smc_pnet_remove_by_pnetid(net, NULL);
890+
smc_pnet_destroy_pnetids_list(net);
767891
}
768892

769893
void smc_pnet_exit(void)
@@ -772,16 +896,11 @@ void smc_pnet_exit(void)
772896
genl_unregister_family(&smc_pnet_nl_family);
773897
}
774898

775-
/* Determine one base device for stacked net devices.
776-
* If the lower device level contains more than one devices
777-
* (for instance with bonding slaves), just the first device
778-
* is used to reach a base device.
779-
*/
780-
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
899+
static struct net_device *__pnet_find_base_ndev(struct net_device *ndev)
781900
{
782901
int i, nest_lvl;
783902

784-
rtnl_lock();
903+
ASSERT_RTNL();
785904
nest_lvl = ndev->lower_level;
786905
for (i = 0; i < nest_lvl; i++) {
787906
struct list_head *lower = &ndev->adj_list.lower;
@@ -791,6 +910,18 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
791910
lower = lower->next;
792911
ndev = netdev_lower_get_next(ndev, &lower);
793912
}
913+
return ndev;
914+
}
915+
916+
/* Determine one base device for stacked net devices.
917+
* If the lower device level contains more than one devices
918+
* (for instance with bonding slaves), just the first device
919+
* is used to reach a base device.
920+
*/
921+
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
922+
{
923+
rtnl_lock();
924+
ndev = __pnet_find_base_ndev(ndev);
794925
rtnl_unlock();
795926
return ndev;
796927
}

net/smc/smc_pnet.h

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

15+
#include <net/smc.h>
16+
1517
#if IS_ENABLED(CONFIG_HAVE_PNETID)
1618
#include <asm/pnet.h>
1719
#endif
@@ -31,6 +33,17 @@ struct smc_pnettable {
3133
struct list_head pnetlist;
3234
};
3335

36+
struct smc_pnetids_ndev { /* list of pnetids for net devices in UP state*/
37+
struct list_head list;
38+
rwlock_t lock;
39+
};
40+
41+
struct smc_pnetids_ndev_entry {
42+
struct list_head list;
43+
u8 pnetid[SMC_MAX_PNETID_LEN];
44+
refcount_t refcnt;
45+
};
46+
3447
static inline int smc_pnetid_by_dev_port(struct device *dev,
3548
unsigned short port, u8 *pnetid)
3649
{
@@ -52,4 +65,5 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcd);
5265
void smc_pnet_find_alt_roce(struct smc_link_group *lgr,
5366
struct smc_init_info *ini,
5467
struct smc_ib_device *known_dev);
68+
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid);
5569
#endif

0 commit comments

Comments
 (0)