mirror of
https://github.com/torvalds/linux
synced 2024-09-06 18:01:05 +00:00
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 <ubraun@linux.ibm.com> Signed-off-by: Karsten Graul <kgraul@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8caaccf521
commit
e888a2e833
|
@ -16,5 +16,6 @@ extern unsigned int smc_net_id;
|
||||||
/* per-network namespace private data */
|
/* per-network namespace private data */
|
||||||
struct smc_net {
|
struct smc_net {
|
||||||
struct smc_pnettable pnettable;
|
struct smc_pnettable pnettable;
|
||||||
|
struct smc_pnetids_ndev pnetids_ndev;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "smc_ism.h"
|
#include "smc_ism.h"
|
||||||
#include "smc_core.h"
|
#include "smc_core.h"
|
||||||
|
|
||||||
|
static struct net_device *__pnet_find_base_ndev(struct net_device *ndev);
|
||||||
static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
|
static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
|
||||||
|
|
||||||
static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
|
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 = {
|
||||||
.n_ops = ARRAY_SIZE(smc_pnet_ops)
|
.n_ops = ARRAY_SIZE(smc_pnet_ops)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid)
|
||||||
|
{
|
||||||
|
struct smc_net *sn = net_generic(net, smc_net_id);
|
||||||
|
struct smc_pnetids_ndev_entry *pe;
|
||||||
|
bool rc = false;
|
||||||
|
|
||||||
|
read_lock(&sn->pnetids_ndev.lock);
|
||||||
|
list_for_each_entry(pe, &sn->pnetids_ndev.list, list) {
|
||||||
|
if (smc_pnet_match(pnetid, pe->pnetid)) {
|
||||||
|
rc = true;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
read_unlock(&sn->pnetids_ndev.lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smc_pnet_add_pnetid(struct net *net, u8 *pnetid)
|
||||||
|
{
|
||||||
|
struct smc_net *sn = net_generic(net, smc_net_id);
|
||||||
|
struct smc_pnetids_ndev_entry *pe, *pi;
|
||||||
|
|
||||||
|
pe = kzalloc(sizeof(*pe), GFP_KERNEL);
|
||||||
|
if (!pe)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
write_lock(&sn->pnetids_ndev.lock);
|
||||||
|
list_for_each_entry(pi, &sn->pnetids_ndev.list, list) {
|
||||||
|
if (smc_pnet_match(pnetid, pe->pnetid)) {
|
||||||
|
refcount_inc(&pi->refcnt);
|
||||||
|
kfree(pe);
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refcount_set(&pe->refcnt, 1);
|
||||||
|
memcpy(pe->pnetid, pnetid, SMC_MAX_PNETID_LEN);
|
||||||
|
list_add_tail(&pe->list, &sn->pnetids_ndev.list);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
write_unlock(&sn->pnetids_ndev.lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smc_pnet_remove_pnetid(struct net *net, u8 *pnetid)
|
||||||
|
{
|
||||||
|
struct smc_net *sn = net_generic(net, smc_net_id);
|
||||||
|
struct smc_pnetids_ndev_entry *pe, *pe2;
|
||||||
|
|
||||||
|
write_lock(&sn->pnetids_ndev.lock);
|
||||||
|
list_for_each_entry_safe(pe, pe2, &sn->pnetids_ndev.list, list) {
|
||||||
|
if (smc_pnet_match(pnetid, pe->pnetid)) {
|
||||||
|
if (refcount_dec_and_test(&pe->refcnt)) {
|
||||||
|
list_del(&pe->list);
|
||||||
|
kfree(pe);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_unlock(&sn->pnetids_ndev.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void smc_pnet_add_base_pnetid(struct net *net, struct net_device *dev,
|
||||||
|
u8 *ndev_pnetid)
|
||||||
|
{
|
||||||
|
struct net_device *base_dev;
|
||||||
|
|
||||||
|
base_dev = __pnet_find_base_ndev(dev);
|
||||||
|
if (base_dev->flags & IFF_UP &&
|
||||||
|
!smc_pnetid_by_dev_port(base_dev->dev.parent, base_dev->dev_port,
|
||||||
|
ndev_pnetid)) {
|
||||||
|
/* add to PNETIDs list */
|
||||||
|
smc_pnet_add_pnetid(net, ndev_pnetid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create initial list of netdevice pnetids */
|
||||||
|
static void smc_pnet_create_pnetids_list(struct net *net)
|
||||||
|
{
|
||||||
|
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
|
||||||
|
struct net_device *dev;
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
for_each_netdev(net, dev)
|
||||||
|
smc_pnet_add_base_pnetid(net, dev, ndev_pnetid);
|
||||||
|
rtnl_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up list of netdevice pnetids */
|
||||||
|
static void smc_pnet_destroy_pnetids_list(struct net *net)
|
||||||
|
{
|
||||||
|
struct smc_net *sn = net_generic(net, smc_net_id);
|
||||||
|
struct smc_pnetids_ndev_entry *pe, *temp_pe;
|
||||||
|
|
||||||
|
write_lock(&sn->pnetids_ndev.lock);
|
||||||
|
list_for_each_entry_safe(pe, temp_pe, &sn->pnetids_ndev.list, list) {
|
||||||
|
list_del(&pe->list);
|
||||||
|
kfree(pe);
|
||||||
|
}
|
||||||
|
write_unlock(&sn->pnetids_ndev.lock);
|
||||||
|
}
|
||||||
|
|
||||||
static int smc_pnet_netdev_event(struct notifier_block *this,
|
static int smc_pnet_netdev_event(struct notifier_block *this,
|
||||||
unsigned long event, void *ptr)
|
unsigned long event, void *ptr)
|
||||||
{
|
{
|
||||||
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
|
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
|
||||||
|
struct net *net = dev_net(event_dev);
|
||||||
|
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case NETDEV_REBOOT:
|
case NETDEV_REBOOT:
|
||||||
|
@ -725,6 +831,17 @@ static int smc_pnet_netdev_event(struct notifier_block *this,
|
||||||
case NETDEV_REGISTER:
|
case NETDEV_REGISTER:
|
||||||
smc_pnet_add_by_ndev(event_dev);
|
smc_pnet_add_by_ndev(event_dev);
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
|
case NETDEV_UP:
|
||||||
|
smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid);
|
||||||
|
return NOTIFY_OK;
|
||||||
|
case NETDEV_DOWN:
|
||||||
|
event_dev = __pnet_find_base_ndev(event_dev);
|
||||||
|
if (!smc_pnetid_by_dev_port(event_dev->dev.parent,
|
||||||
|
event_dev->dev_port, ndev_pnetid)) {
|
||||||
|
/* remove from PNETIDs list */
|
||||||
|
smc_pnet_remove_pnetid(net, ndev_pnetid);
|
||||||
|
}
|
||||||
|
return NOTIFY_OK;
|
||||||
default:
|
default:
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
@ -739,9 +856,14 @@ int smc_pnet_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
struct smc_net *sn = net_generic(net, smc_net_id);
|
struct smc_net *sn = net_generic(net, smc_net_id);
|
||||||
struct smc_pnettable *pnettable = &sn->pnettable;
|
struct smc_pnettable *pnettable = &sn->pnettable;
|
||||||
|
struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&pnettable->pnetlist);
|
INIT_LIST_HEAD(&pnettable->pnetlist);
|
||||||
rwlock_init(&pnettable->lock);
|
rwlock_init(&pnettable->lock);
|
||||||
|
INIT_LIST_HEAD(&pnetids_ndev->list);
|
||||||
|
rwlock_init(&pnetids_ndev->lock);
|
||||||
|
|
||||||
|
smc_pnet_create_pnetids_list(net);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -756,6 +878,7 @@ int __init smc_pnet_init(void)
|
||||||
rc = register_netdevice_notifier(&smc_netdev_notifier);
|
rc = register_netdevice_notifier(&smc_netdev_notifier);
|
||||||
if (rc)
|
if (rc)
|
||||||
genl_unregister_family(&smc_pnet_nl_family);
|
genl_unregister_family(&smc_pnet_nl_family);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,6 +887,7 @@ void smc_pnet_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
/* flush pnet table */
|
/* flush pnet table */
|
||||||
smc_pnet_remove_by_pnetid(net, NULL);
|
smc_pnet_remove_by_pnetid(net, NULL);
|
||||||
|
smc_pnet_destroy_pnetids_list(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
void smc_pnet_exit(void)
|
void smc_pnet_exit(void)
|
||||||
|
@ -772,16 +896,11 @@ void smc_pnet_exit(void)
|
||||||
genl_unregister_family(&smc_pnet_nl_family);
|
genl_unregister_family(&smc_pnet_nl_family);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine one base device for stacked net devices.
|
static struct net_device *__pnet_find_base_ndev(struct net_device *ndev)
|
||||||
* If the lower device level contains more than one devices
|
|
||||||
* (for instance with bonding slaves), just the first device
|
|
||||||
* is used to reach a base device.
|
|
||||||
*/
|
|
||||||
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
|
|
||||||
{
|
{
|
||||||
int i, nest_lvl;
|
int i, nest_lvl;
|
||||||
|
|
||||||
rtnl_lock();
|
ASSERT_RTNL();
|
||||||
nest_lvl = ndev->lower_level;
|
nest_lvl = ndev->lower_level;
|
||||||
for (i = 0; i < nest_lvl; i++) {
|
for (i = 0; i < nest_lvl; i++) {
|
||||||
struct list_head *lower = &ndev->adj_list.lower;
|
struct list_head *lower = &ndev->adj_list.lower;
|
||||||
|
@ -791,6 +910,18 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
|
||||||
lower = lower->next;
|
lower = lower->next;
|
||||||
ndev = netdev_lower_get_next(ndev, &lower);
|
ndev = netdev_lower_get_next(ndev, &lower);
|
||||||
}
|
}
|
||||||
|
return ndev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine one base device for stacked net devices.
|
||||||
|
* If the lower device level contains more than one devices
|
||||||
|
* (for instance with bonding slaves), just the first device
|
||||||
|
* is used to reach a base device.
|
||||||
|
*/
|
||||||
|
static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
|
||||||
|
{
|
||||||
|
rtnl_lock();
|
||||||
|
ndev = __pnet_find_base_ndev(ndev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return ndev;
|
return ndev;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef _SMC_PNET_H
|
#ifndef _SMC_PNET_H
|
||||||
#define _SMC_PNET_H
|
#define _SMC_PNET_H
|
||||||
|
|
||||||
|
#include <net/smc.h>
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_HAVE_PNETID)
|
#if IS_ENABLED(CONFIG_HAVE_PNETID)
|
||||||
#include <asm/pnet.h>
|
#include <asm/pnet.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +33,17 @@ struct smc_pnettable {
|
||||||
struct list_head pnetlist;
|
struct list_head pnetlist;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct smc_pnetids_ndev { /* list of pnetids for net devices in UP state*/
|
||||||
|
struct list_head list;
|
||||||
|
rwlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smc_pnetids_ndev_entry {
|
||||||
|
struct list_head list;
|
||||||
|
u8 pnetid[SMC_MAX_PNETID_LEN];
|
||||||
|
refcount_t refcnt;
|
||||||
|
};
|
||||||
|
|
||||||
static inline int smc_pnetid_by_dev_port(struct device *dev,
|
static inline int smc_pnetid_by_dev_port(struct device *dev,
|
||||||
unsigned short port, u8 *pnetid)
|
unsigned short port, u8 *pnetid)
|
||||||
{
|
{
|
||||||
|
@ -52,4 +65,5 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcd);
|
||||||
void smc_pnet_find_alt_roce(struct smc_link_group *lgr,
|
void smc_pnet_find_alt_roce(struct smc_link_group *lgr,
|
||||||
struct smc_init_info *ini,
|
struct smc_init_info *ini,
|
||||||
struct smc_ib_device *known_dev);
|
struct smc_ib_device *known_dev);
|
||||||
|
bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue