Commit 9311defc authored by David S. Miller's avatar David S. Miller

Merge branch 'smc-next'

Ursula Braun says:

====================
net/smc: patches 2019-02-21

here are patches for SMC:
* patch 1 is a cleanup without functional change
* patches 2-6 enhance SMC pnetid support
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 64ccfd2d af5f60c7
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <asm/ccwgroup.h> #include <asm/ccwgroup.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/pnet.h> #include <asm/pnet.h>
#include <asm/ebcdic.h>
#define PNETIDS_LEN 64 /* Total utility string length in bytes #define PNETIDS_LEN 64 /* Total utility string length in bytes
* to cover up to 4 PNETIDs of 16 bytes * to cover up to 4 PNETIDs of 16 bytes
...@@ -48,6 +49,7 @@ static int pnet_ids_by_device(struct device *dev, u8 *pnetids) ...@@ -48,6 +49,7 @@ static int pnet_ids_by_device(struct device *dev, u8 *pnetids)
if (!util_str) if (!util_str)
return -ENOMEM; return -ENOMEM;
memcpy(pnetids, util_str, PNETIDS_LEN); memcpy(pnetids, util_str, PNETIDS_LEN);
EBCASC(pnetids, PNETIDS_LEN);
kfree(util_str); kfree(util_str);
return 0; return 0;
} }
...@@ -55,6 +57,7 @@ static int pnet_ids_by_device(struct device *dev, u8 *pnetids) ...@@ -55,6 +57,7 @@ static int pnet_ids_by_device(struct device *dev, u8 *pnetids)
struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
memcpy(pnetids, zdev->util_str, sizeof(zdev->util_str)); memcpy(pnetids, zdev->util_str, sizeof(zdev->util_str));
EBCASC(pnetids, sizeof(zdev->util_str));
return 0; return 0;
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -74,6 +74,7 @@ struct smcd_dev { ...@@ -74,6 +74,7 @@ struct smcd_dev {
struct list_head vlan; struct list_head vlan;
struct workqueue_struct *event_wq; struct workqueue_struct *event_wq;
u8 pnetid[SMC_MAX_PNETID_LEN]; u8 pnetid[SMC_MAX_PNETID_LEN];
bool pnetid_by_user;
}; };
struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
......
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
#include <net/smc.h> #include <net/smc.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include "smc_netns.h"
#include "smc.h" #include "smc.h"
#include "smc_clc.h" #include "smc_clc.h"
#include "smc_llc.h" #include "smc_llc.h"
...@@ -1966,10 +1970,33 @@ static const struct net_proto_family smc_sock_family_ops = { ...@@ -1966,10 +1970,33 @@ static const struct net_proto_family smc_sock_family_ops = {
.create = smc_create, .create = smc_create,
}; };
unsigned int smc_net_id;
static __net_init int smc_net_init(struct net *net)
{
return smc_pnet_net_init(net);
}
static void __net_exit smc_net_exit(struct net *net)
{
smc_pnet_net_exit(net);
}
static struct pernet_operations smc_net_ops = {
.init = smc_net_init,
.exit = smc_net_exit,
.id = &smc_net_id,
.size = sizeof(struct smc_net),
};
static int __init smc_init(void) static int __init smc_init(void)
{ {
int rc; int rc;
rc = register_pernet_subsys(&smc_net_ops);
if (rc)
return rc;
rc = smc_pnet_init(); rc = smc_pnet_init();
if (rc) if (rc)
return rc; return rc;
...@@ -2035,6 +2062,7 @@ static void __exit smc_exit(void) ...@@ -2035,6 +2062,7 @@ static void __exit smc_exit(void)
proto_unregister(&smc_proto6); proto_unregister(&smc_proto6);
proto_unregister(&smc_proto); proto_unregister(&smc_proto);
smc_pnet_exit(); smc_pnet_exit();
unregister_pernet_subsys(&smc_net_ops);
} }
module_init(smc_init); module_init(smc_init);
......
...@@ -564,7 +564,6 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data) ...@@ -564,7 +564,6 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
spin_lock(&smc_ib_devices.lock); spin_lock(&smc_ib_devices.lock);
list_del_init(&smcibdev->list); /* remove from smc_ib_devices */ list_del_init(&smcibdev->list); /* remove from smc_ib_devices */
spin_unlock(&smc_ib_devices.lock); spin_unlock(&smc_ib_devices.lock);
smc_pnet_remove_by_ibdev(smcibdev);
smc_ib_cleanup_per_ibdev(smcibdev); smc_ib_cleanup_per_ibdev(smcibdev);
ib_unregister_event_handler(&smcibdev->event_handler); ib_unregister_event_handler(&smcibdev->event_handler);
kfree(smcibdev); kfree(smcibdev);
......
...@@ -42,6 +42,8 @@ struct smc_ib_device { /* ib-device infos for smc */ ...@@ -42,6 +42,8 @@ struct smc_ib_device { /* ib-device infos for smc */
/* mac address per port*/ /* mac address per port*/
u8 pnetid[SMC_MAX_PORTS][SMC_MAX_PNETID_LEN]; u8 pnetid[SMC_MAX_PORTS][SMC_MAX_PNETID_LEN];
/* pnetid per port */ /* pnetid per port */
bool pnetid_by_user[SMC_MAX_PORTS];
/* pnetid defined by user? */
u8 initialized : 1; /* ib dev CQ, evthdl done */ u8 initialized : 1; /* ib dev CQ, evthdl done */
struct work_struct port_event_work; struct work_struct port_event_work;
unsigned long port_event_mask; unsigned long port_event_mask;
......
/* SPDX-License-Identifier: GPL-2.0 */
/* Shared Memory Communications
*
* Network namespace definitions.
*
* Copyright IBM Corp. 2018
*/
#ifndef SMC_NETNS_H
#define SMC_NETNS_H
#include "smc_pnet.h"
extern unsigned int smc_net_id;
/* per-network namespace private data */
struct smc_net {
struct smc_pnettable pnettable;
};
#endif
...@@ -20,10 +20,17 @@ ...@@ -20,10 +20,17 @@
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <net/netns/generic.h>
#include "smc_netns.h"
#include "smc_pnet.h" #include "smc_pnet.h"
#include "smc_ib.h" #include "smc_ib.h"
#include "smc_ism.h" #include "smc_ism.h"
#define SMC_ASCII_BLANK 32
static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
[SMC_PNETID_NAME] = { [SMC_PNETID_NAME] = {
.type = NLA_NUL_STRING, .type = NLA_NUL_STRING,
...@@ -43,118 +50,127 @@ static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { ...@@ -43,118 +50,127 @@ static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
static struct genl_family smc_pnet_nl_family; static struct genl_family smc_pnet_nl_family;
/** /**
* struct smc_pnettable - SMC PNET table anchor * struct smc_user_pnetentry - pnet identifier name entry for/from user
* @lock: Lock for list action
* @pnetlist: List of PNETIDs
*/
static struct smc_pnettable {
rwlock_t lock;
struct list_head pnetlist;
} smc_pnettable = {
.pnetlist = LIST_HEAD_INIT(smc_pnettable.pnetlist),
.lock = __RW_LOCK_UNLOCKED(smc_pnettable.lock)
};
/**
* struct smc_pnetentry - pnet identifier name entry
* @list: List node. * @list: List node.
* @pnet_name: Pnet identifier name * @pnet_name: Pnet identifier name
* @ndev: pointer to network device. * @ndev: pointer to network device.
* @smcibdev: Pointer to IB device. * @smcibdev: Pointer to IB device.
* @ib_port: Port of IB device.
* @smcd_dev: Pointer to smcd device.
*/ */
struct smc_pnetentry { struct smc_user_pnetentry {
struct list_head list; struct list_head list;
char pnet_name[SMC_MAX_PNETID_LEN + 1]; char pnet_name[SMC_MAX_PNETID_LEN + 1];
struct net_device *ndev; struct net_device *ndev;
struct smc_ib_device *smcibdev; struct smc_ib_device *smcibdev;
u8 ib_port; u8 ib_port;
struct smcd_dev *smcd_dev;
}; };
/* Check if two RDMA device entries are identical. Use device name and port /* pnet entry stored in pnet table */
* number for comparison. struct smc_pnetentry {
*/ struct list_head list;
static bool smc_pnet_same_ibname(struct smc_pnetentry *pnetelem, char *ibname, char pnet_name[SMC_MAX_PNETID_LEN + 1];
u8 ibport) struct net_device *ndev;
{ };
return pnetelem->ib_port == ibport &&
!strncmp(pnetelem->smcibdev->ibdev->name, ibname,
sizeof(pnetelem->smcibdev->ibdev->name));
}
/* Find a pnetid in the pnet table. /* Check if two given pnetids match */
*/ static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
static struct smc_pnetentry *smc_pnet_find_pnetid(char *pnet_name)
{ {
struct smc_pnetentry *pnetelem, *found_pnetelem = NULL; int i;
read_lock(&smc_pnettable.lock); for (i = 0; i < SMC_MAX_PNETID_LEN; i++) {
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) { if ((pnetid1[i] == 0 || pnetid1[i] == SMC_ASCII_BLANK) &&
if (!strncmp(pnetelem->pnet_name, pnet_name, (pnetid2[i] == 0 || pnetid2[i] == SMC_ASCII_BLANK))
sizeof(pnetelem->pnet_name))) {
found_pnetelem = pnetelem;
break; break;
} if (pnetid1[i] != pnetid2[i])
return false;
} }
read_unlock(&smc_pnettable.lock); return true;
return found_pnetelem;
} }
/* Remove a pnetid from the pnet table. /* Remove a pnetid from the pnet table.
*/ */
static int smc_pnet_remove_by_pnetid(char *pnet_name) static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
{ {
struct smc_pnetentry *pnetelem, *tmp_pe; struct smc_pnetentry *pnetelem, *tmp_pe;
struct smc_pnettable *pnettable;
struct smc_ib_device *ibdev;
struct smcd_dev *smcd_dev;
struct smc_net *sn;
int rc = -ENOENT; int rc = -ENOENT;
int ibport;
/* get pnettable for namespace */
sn = net_generic(net, smc_net_id);
pnettable = &sn->pnettable;
write_lock(&smc_pnettable.lock); /* remove netdevices */
list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist, write_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist,
list) { list) {
if (!strncmp(pnetelem->pnet_name, pnet_name, if (!pnet_name ||
sizeof(pnetelem->pnet_name))) { smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
list_del(&pnetelem->list); list_del(&pnetelem->list);
dev_put(pnetelem->ndev); dev_put(pnetelem->ndev);
kfree(pnetelem); kfree(pnetelem);
rc = 0; rc = 0;
break;
} }
} }
write_unlock(&smc_pnettable.lock); write_unlock(&pnettable->lock);
return rc;
}
/* Remove a pnet entry mentioning a given network device from the pnet table. /* if this is not the initial namespace, stop here */
*/ if (net != &init_net)
static int smc_pnet_remove_by_ndev(struct net_device *ndev) return rc;
{
struct smc_pnetentry *pnetelem, *tmp_pe;
int rc = -ENOENT;
write_lock(&smc_pnettable.lock); /* remove ib devices */
list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist, spin_lock(&smc_ib_devices.lock);
list) { list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
if (pnetelem->ndev == ndev) { for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
list_del(&pnetelem->list); if (ibdev->pnetid_by_user[ibport] &&
dev_put(pnetelem->ndev); (!pnet_name ||
kfree(pnetelem); smc_pnet_match(pnet_name,
ibdev->pnetid[ibport]))) {
memset(ibdev->pnetid[ibport], 0,
SMC_MAX_PNETID_LEN);
ibdev->pnetid_by_user[ibport] = false;
rc = 0;
}
}
}
spin_unlock(&smc_ib_devices.lock);
/* remove smcd devices */
spin_lock(&smcd_dev_list.lock);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
if (smcd_dev->pnetid_by_user &&
(!pnet_name ||
smc_pnet_match(pnet_name, smcd_dev->pnetid))) {
memset(smcd_dev->pnetid, 0, SMC_MAX_PNETID_LEN);
smcd_dev->pnetid_by_user = false;
rc = 0; rc = 0;
break;
} }
} }
write_unlock(&smc_pnettable.lock); spin_unlock(&smcd_dev_list.lock);
return rc; return rc;
} }
/* Remove a pnet entry mentioning a given ib device from the pnet table. /* Remove a pnet entry mentioning a given network device from the pnet table.
*/ */
int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev) static int smc_pnet_remove_by_ndev(struct net_device *ndev)
{ {
struct smc_pnetentry *pnetelem, *tmp_pe; struct smc_pnetentry *pnetelem, *tmp_pe;
struct smc_pnettable *pnettable;
struct net *net = dev_net(ndev);
struct smc_net *sn;
int rc = -ENOENT; int rc = -ENOENT;
write_lock(&smc_pnettable.lock); /* get pnettable for namespace */
list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist, sn = net_generic(net, smc_net_id);
list) { pnettable = &sn->pnettable;
if (pnetelem->smcibdev == ibdev) {
write_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->ndev == ndev) {
list_del(&pnetelem->list); list_del(&pnetelem->list);
dev_put(pnetelem->ndev); dev_put(pnetelem->ndev);
kfree(pnetelem); kfree(pnetelem);
...@@ -162,35 +178,84 @@ int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev) ...@@ -162,35 +178,84 @@ int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev)
break; break;
} }
} }
write_unlock(&smc_pnettable.lock); write_unlock(&pnettable->lock);
return rc; return rc;
} }
/* Append a pnetid to the end of the pnet table if not already on this list. /* Append a pnetid to the end of the pnet table if not already on this list.
*/ */
static int smc_pnet_enter(struct smc_pnetentry *new_pnetelem) static int smc_pnet_enter(struct smc_pnettable *pnettable,
struct smc_user_pnetentry *new_pnetelem)
{ {
u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
struct smc_pnetentry *tmp_pnetelem;
struct smc_pnetentry *pnetelem; struct smc_pnetentry *pnetelem;
int rc = -EEXIST; bool new_smcddev = false;
struct net_device *ndev;
write_lock(&smc_pnettable.lock); bool new_netdev = true;
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) { bool new_ibdev = false;
if (!strncmp(pnetelem->pnet_name, new_pnetelem->pnet_name,
sizeof(new_pnetelem->pnet_name)) || if (new_pnetelem->smcibdev) {
!strncmp(pnetelem->ndev->name, new_pnetelem->ndev->name, struct smc_ib_device *ib_dev = new_pnetelem->smcibdev;
sizeof(new_pnetelem->ndev->name)) || int ib_port = new_pnetelem->ib_port;
smc_pnet_same_ibname(pnetelem,
new_pnetelem->smcibdev->ibdev->name, spin_lock(&smc_ib_devices.lock);
new_pnetelem->ib_port)) { if (smc_pnet_match(ib_dev->pnetid[ib_port - 1], pnet_null)) {
dev_put(pnetelem->ndev); memcpy(ib_dev->pnetid[ib_port - 1],
goto found; new_pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
ib_dev->pnetid_by_user[ib_port - 1] = true;
new_ibdev = true;
} }
spin_unlock(&smc_ib_devices.lock);
} }
list_add_tail(&new_pnetelem->list, &smc_pnettable.pnetlist); if (new_pnetelem->smcd_dev) {
rc = 0; struct smcd_dev *smcd_dev = new_pnetelem->smcd_dev;
found:
write_unlock(&smc_pnettable.lock); spin_lock(&smcd_dev_list.lock);
return rc; if (smc_pnet_match(smcd_dev->pnetid, pnet_null)) {
memcpy(smcd_dev->pnetid, new_pnetelem->pnet_name,
SMC_MAX_PNETID_LEN);
smcd_dev->pnetid_by_user = true;
new_smcddev = true;
}
spin_unlock(&smcd_dev_list.lock);
}
if (!new_pnetelem->ndev)
return (new_ibdev || new_smcddev) ? 0 : -EEXIST;
/* check if (base) netdev already has a pnetid. If there is one, we do
* not want to add a pnet table entry
*/
ndev = pnet_find_base_ndev(new_pnetelem->ndev);
if (!smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
ndev_pnetid))
return (new_ibdev || new_smcddev) ? 0 : -EEXIST;
/* add a new netdev entry to the pnet table if there isn't one */
tmp_pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL);
if (!tmp_pnetelem)
return -ENOMEM;
memcpy(tmp_pnetelem->pnet_name, new_pnetelem->pnet_name,
SMC_MAX_PNETID_LEN);
tmp_pnetelem->ndev = new_pnetelem->ndev;
write_lock(&pnettable->lock);
list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetelem->ndev == new_pnetelem->ndev)
new_netdev = false;
}
if (new_netdev) {
dev_hold(tmp_pnetelem->ndev);
list_add_tail(&tmp_pnetelem->list, &pnettable->pnetlist);
write_unlock(&pnettable->lock);
} else {
write_unlock(&pnettable->lock);
kfree(tmp_pnetelem);
}
return (new_netdev || new_ibdev || new_smcddev) ? 0 : -EEXIST;
} }
/* The limit for pnetid is 16 characters. /* The limit for pnetid is 16 characters.
...@@ -228,7 +293,9 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name) ...@@ -228,7 +293,9 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
spin_lock(&smc_ib_devices.lock); spin_lock(&smc_ib_devices.lock);
list_for_each_entry(ibdev, &smc_ib_devices.list, list) { list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
if (!strncmp(ibdev->ibdev->name, ib_name, if (!strncmp(ibdev->ibdev->name, ib_name,
sizeof(ibdev->ibdev->name))) { sizeof(ibdev->ibdev->name)) ||
!strncmp(dev_name(ibdev->ibdev->dev.parent), ib_name,
IB_DEVICE_NAME_MAX - 1)) {
goto out; goto out;
} }
} }
...@@ -238,10 +305,28 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name) ...@@ -238,10 +305,28 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
return ibdev; return ibdev;
} }
/* Find an smcd device by a given name. The device might not exist. */
static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
{
struct smcd_dev *smcd_dev;
spin_lock(&smcd_dev_list.lock);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
if (!strncmp(dev_name(&smcd_dev->dev), smcd_name,
IB_DEVICE_NAME_MAX - 1))
goto out;
}
smcd_dev = NULL;
out:
spin_unlock(&smcd_dev_list.lock);
return smcd_dev;
}
/* Parse the supplied netlink attributes and fill a pnetentry structure. /* Parse the supplied netlink attributes and fill a pnetentry structure.
* For ethernet and infiniband device names verify that the devices exist. * For ethernet and infiniband device names verify that the devices exist.
*/ */
static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem, static int smc_pnet_fill_entry(struct net *net,
struct smc_user_pnetentry *pnetelem,
struct nlattr *tb[]) struct nlattr *tb[])
{ {
char *string, *ibname; char *string, *ibname;
...@@ -258,30 +343,34 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem, ...@@ -258,30 +343,34 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
goto error; goto error;
rc = -EINVAL; rc = -EINVAL;
if (!tb[SMC_PNETID_ETHNAME]) if (tb[SMC_PNETID_ETHNAME]) {
goto error; string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
rc = -ENOENT; pnetelem->ndev = dev_get_by_name(net, string);
string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]); if (!pnetelem->ndev)
pnetelem->ndev = dev_get_by_name(net, string); goto error;
if (!pnetelem->ndev) }
goto error;
rc = -EINVAL; /* if this is not the initial namespace, stop here */
if (!tb[SMC_PNETID_IBNAME]) if (net != &init_net)
goto error; return 0;
rc = -ENOENT;
ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
ibname = strim(ibname);
pnetelem->smcibdev = smc_pnet_find_ib(ibname);
if (!pnetelem->smcibdev)
goto error;
rc = -EINVAL; rc = -EINVAL;
if (!tb[SMC_PNETID_IBPORT]) if (tb[SMC_PNETID_IBNAME]) {
goto error; ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]); ibname = strim(ibname);
if (pnetelem->ib_port < 1 || pnetelem->ib_port > SMC_MAX_PORTS) pnetelem->smcibdev = smc_pnet_find_ib(ibname);
goto error; pnetelem->smcd_dev = smc_pnet_find_smcd(ibname);
if (!pnetelem->smcibdev && !pnetelem->smcd_dev)
goto error;
if (pnetelem->smcibdev) {
if (!tb[SMC_PNETID_IBPORT])
goto error;
pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
if (pnetelem->ib_port < 1 ||
pnetelem->ib_port > SMC_MAX_PORTS)
goto error;
}
}
return 0; return 0;
...@@ -292,79 +381,65 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem, ...@@ -292,79 +381,65 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
} }
/* Convert an smc_pnetentry to a netlink attribute sequence */ /* Convert an smc_pnetentry to a netlink attribute sequence */
static int smc_pnet_set_nla(struct sk_buff *msg, struct smc_pnetentry *pnetelem) static int smc_pnet_set_nla(struct sk_buff *msg,
struct smc_user_pnetentry *pnetelem)
{ {
if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name) || if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name))
nla_put_string(msg, SMC_PNETID_ETHNAME, pnetelem->ndev->name) ||
nla_put_string(msg, SMC_PNETID_IBNAME,
pnetelem->smcibdev->ibdev->name) ||
nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
return -1; return -1;
return 0; if (pnetelem->ndev) {
} if (nla_put_string(msg, SMC_PNETID_ETHNAME,
pnetelem->ndev->name))
/* Retrieve one PNETID entry */ return -1;
static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info) } else {
{ if (nla_put_string(msg, SMC_PNETID_ETHNAME, "n/a"))
struct smc_pnetentry *pnetelem; return -1;
struct sk_buff *msg;
void *hdr;
int rc;
if (!info->attrs[SMC_PNETID_NAME])
return -EINVAL;
pnetelem = smc_pnet_find_pnetid(
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
if (!pnetelem)
return -ENOENT;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
&smc_pnet_nl_family, 0, SMC_PNETID_GET);
if (!hdr) {
rc = -EMSGSIZE;
goto err_out;
} }
if (pnetelem->smcibdev) {
if (smc_pnet_set_nla(msg, pnetelem)) { if (nla_put_string(msg, SMC_PNETID_IBNAME,
rc = -ENOBUFS; dev_name(pnetelem->smcibdev->ibdev->dev.parent)) ||
goto err_out; nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
return -1;
} else if (pnetelem->smcd_dev) {
if (nla_put_string(msg, SMC_PNETID_IBNAME,
dev_name(&pnetelem->smcd_dev->dev)) ||
nla_put_u8(msg, SMC_PNETID_IBPORT, 1))
return -1;
} else {
if (nla_put_string(msg, SMC_PNETID_IBNAME, "n/a") ||
nla_put_u8(msg, SMC_PNETID_IBPORT, 0xff))
return -1;
} }
genlmsg_end(msg, hdr); return 0;
return genlmsg_reply(msg, info);
err_out:
nlmsg_free(msg);
return rc;
} }
static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info) static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
{ {
struct net *net = genl_info_net(info); struct net *net = genl_info_net(info);
struct smc_pnetentry *pnetelem; struct smc_user_pnetentry pnetelem;
struct smc_pnettable *pnettable;
struct smc_net *sn;
int rc; int rc;
pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL); /* get pnettable for namespace */
if (!pnetelem) sn = net_generic(net, smc_net_id);
return -ENOMEM; pnettable = &sn->pnettable;
rc = smc_pnet_fill_entry(net, pnetelem, info->attrs);
rc = smc_pnet_fill_entry(net, &pnetelem, info->attrs);
if (!rc) if (!rc)
rc = smc_pnet_enter(pnetelem); rc = smc_pnet_enter(pnettable, &pnetelem);
if (rc) { if (pnetelem.ndev)
kfree(pnetelem); dev_put(pnetelem.ndev);
return rc;
}
return rc; return rc;
} }
static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info) static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info)
{ {
struct net *net = genl_info_net(info);
if (!info->attrs[SMC_PNETID_NAME]) if (!info->attrs[SMC_PNETID_NAME])
return -EINVAL; return -EINVAL;
return smc_pnet_remove_by_pnetid( return smc_pnet_remove_by_pnetid(net,
(char *)nla_data(info->attrs[SMC_PNETID_NAME])); (char *)nla_data(info->attrs[SMC_PNETID_NAME]));
} }
...@@ -376,7 +451,7 @@ static int smc_pnet_dump_start(struct netlink_callback *cb) ...@@ -376,7 +451,7 @@ static int smc_pnet_dump_start(struct netlink_callback *cb)
static int smc_pnet_dumpinfo(struct sk_buff *skb, static int smc_pnet_dumpinfo(struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u32 portid, u32 seq, u32 flags,
struct smc_pnetentry *pnetelem) struct smc_user_pnetentry *pnetelem)
{ {
void *hdr; void *hdr;
...@@ -392,42 +467,143 @@ static int smc_pnet_dumpinfo(struct sk_buff *skb, ...@@ -392,42 +467,143 @@ static int smc_pnet_dumpinfo(struct sk_buff *skb,
return 0; return 0;
} }
static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb) static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
u32 seq, u8 *pnetid, int start_idx)
{ {
struct smc_user_pnetentry tmp_entry;
struct smc_pnettable *pnettable;
struct smc_pnetentry *pnetelem; struct smc_pnetentry *pnetelem;
struct smc_ib_device *ibdev;
struct smcd_dev *smcd_dev;
struct smc_net *sn;
int idx = 0; int idx = 0;
int ibport;
read_lock(&smc_pnettable.lock); /* get pnettable for namespace */
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) { sn = net_generic(net, smc_net_id);
if (idx++ < cb->args[0]) pnettable = &sn->pnettable;
/* dump netdevices */
read_lock(&pnettable->lock);
list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
continue;
if (idx++ < start_idx)
continue; continue;
if (smc_pnet_dumpinfo(skb, NETLINK_CB(cb->skb).portid, memset(&tmp_entry, 0, sizeof(tmp_entry));
cb->nlh->nlmsg_seq, NLM_F_MULTI, memcpy(&tmp_entry.pnet_name, pnetelem->pnet_name,
pnetelem)) { SMC_MAX_PNETID_LEN);
tmp_entry.ndev = pnetelem->ndev;
if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
&tmp_entry)) {
--idx; --idx;
break; break;
} }
} }
read_unlock(&pnettable->lock);
/* if this is not the initial namespace, stop here */
if (net != &init_net)
return idx;
/* dump ib devices */
spin_lock(&smc_ib_devices.lock);
list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
if (ibdev->pnetid_by_user[ibport]) {
if (pnetid &&
!smc_pnet_match(ibdev->pnetid[ibport],
pnetid))
continue;
if (idx++ < start_idx)
continue;
memset(&tmp_entry, 0, sizeof(tmp_entry));
memcpy(&tmp_entry.pnet_name,
ibdev->pnetid[ibport],
SMC_MAX_PNETID_LEN);
tmp_entry.smcibdev = ibdev;
tmp_entry.ib_port = ibport + 1;
if (smc_pnet_dumpinfo(skb, portid, seq,
NLM_F_MULTI,
&tmp_entry)) {
--idx;
break;
}
}
}
}
spin_unlock(&smc_ib_devices.lock);
/* dump smcd devices */
spin_lock(&smcd_dev_list.lock);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
if (smcd_dev->pnetid_by_user) {
if (pnetid && !smc_pnet_match(smcd_dev->pnetid, pnetid))
continue;
if (idx++ < start_idx)
continue;
memset(&tmp_entry, 0, sizeof(tmp_entry));
memcpy(&tmp_entry.pnet_name, smcd_dev->pnetid,
SMC_MAX_PNETID_LEN);
tmp_entry.smcd_dev = smcd_dev;
if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
&tmp_entry)) {
--idx;
break;
}
}
}
spin_unlock(&smcd_dev_list.lock);
return idx;
}
static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
int idx;
idx = _smc_pnet_dump(net, skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NULL, cb->args[0]);
cb->args[0] = idx; cb->args[0] = idx;
read_unlock(&smc_pnettable.lock);
return skb->len; return skb->len;
} }
/* Retrieve one PNETID entry */
static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
struct sk_buff *msg;
void *hdr;
if (!info->attrs[SMC_PNETID_NAME])
return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
_smc_pnet_dump(net, msg, info->snd_portid, info->snd_seq,
nla_data(info->attrs[SMC_PNETID_NAME]), 0);
/* finish multi part message and send it */
hdr = nlmsg_put(msg, info->snd_portid, info->snd_seq, NLMSG_DONE, 0,
NLM_F_MULTI);
if (!hdr) {
nlmsg_free(msg);
return -EMSGSIZE;
}
return genlmsg_reply(msg, info);
}
/* Remove and delete all pnetids from pnet table. /* Remove and delete all pnetids from pnet table.
*/ */
static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info) static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
{ {
struct smc_pnetentry *pnetelem, *tmp_pe; struct net *net = genl_info_net(info);
write_lock(&smc_pnettable.lock); return smc_pnet_remove_by_pnetid(net, NULL);
list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
list) {
list_del(&pnetelem->list);
dev_put(pnetelem->ndev);
kfree(pnetelem);
}
write_unlock(&smc_pnettable.lock);
return 0;
} }
/* SMC_PNETID generic netlink operation definition */ /* SMC_PNETID generic netlink operation definition */
...@@ -491,6 +667,18 @@ static struct notifier_block smc_netdev_notifier = { ...@@ -491,6 +667,18 @@ static struct notifier_block smc_netdev_notifier = {
.notifier_call = smc_pnet_netdev_event .notifier_call = smc_pnet_netdev_event
}; };
/* init network namespace */
int smc_pnet_net_init(struct net *net)
{
struct smc_net *sn = net_generic(net, smc_net_id);
struct smc_pnettable *pnettable = &sn->pnettable;
INIT_LIST_HEAD(&pnettable->pnetlist);
rwlock_init(&pnettable->lock);
return 0;
}
int __init smc_pnet_init(void) int __init smc_pnet_init(void)
{ {
int rc; int rc;
...@@ -504,9 +692,15 @@ int __init smc_pnet_init(void) ...@@ -504,9 +692,15 @@ int __init smc_pnet_init(void)
return rc; return rc;
} }
/* exit network namespace */
void smc_pnet_net_exit(struct net *net)
{
/* flush pnet table */
smc_pnet_remove_by_pnetid(net, NULL);
}
void smc_pnet_exit(void) void smc_pnet_exit(void)
{ {
smc_pnet_flush(NULL, NULL);
unregister_netdevice_notifier(&smc_netdev_notifier); unregister_netdevice_notifier(&smc_netdev_notifier);
genl_unregister_family(&smc_pnet_nl_family); genl_unregister_family(&smc_pnet_nl_family);
} }
...@@ -534,6 +728,32 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev) ...@@ -534,6 +728,32 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
return ndev; return ndev;
} }
static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
u8 *pnetid)
{
struct smc_pnettable *pnettable;
struct net *net = dev_net(ndev);
struct smc_pnetentry *pnetelem;
struct smc_net *sn;
int rc = -ENOENT;
/* get pnettable for namespace */
sn = net_generic(net, smc_net_id);
pnettable = &sn->pnettable;
read_lock(&pnettable->lock);
list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (ndev == pnetelem->ndev) {
/* get pnetid of netdev device */
memcpy(pnetid, pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
rc = 0;
break;
}
}
read_unlock(&pnettable->lock);
return rc;
}
/* Determine the corresponding IB device port based on the hardware PNETID. /* Determine the corresponding IB device port based on the hardware PNETID.
* Searching stops at the first matching active IB device port with vlan_id * Searching stops at the first matching active IB device port with vlan_id
* configured. * configured.
...@@ -549,7 +769,8 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev, ...@@ -549,7 +769,8 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
ndev = pnet_find_base_ndev(ndev); ndev = pnet_find_base_ndev(ndev);
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port, if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
ndev_pnetid)) ndev_pnetid) &&
smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
return; /* pnetid could not be determined */ return; /* pnetid could not be determined */
spin_lock(&smc_ib_devices.lock); spin_lock(&smc_ib_devices.lock);
...@@ -557,8 +778,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev, ...@@ -557,8 +778,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
for (i = 1; i <= SMC_MAX_PORTS; i++) { for (i = 1; i <= SMC_MAX_PORTS; i++) {
if (!rdma_is_port_valid(ibdev->ibdev, i)) if (!rdma_is_port_valid(ibdev->ibdev, i))
continue; continue;
if (!memcmp(ibdev->pnetid[i - 1], ndev_pnetid, if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) &&
SMC_MAX_PNETID_LEN) &&
smc_ib_port_active(ibdev, i) && smc_ib_port_active(ibdev, i) &&
!smc_ib_determine_gid(ibdev, i, vlan_id, gid, !smc_ib_determine_gid(ibdev, i, vlan_id, gid,
NULL)) { NULL)) {
...@@ -580,12 +800,13 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev, ...@@ -580,12 +800,13 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
ndev = pnet_find_base_ndev(ndev); ndev = pnet_find_base_ndev(ndev);
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port, if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
ndev_pnetid)) ndev_pnetid) &&
smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
return; /* pnetid could not be determined */ return; /* pnetid could not be determined */
spin_lock(&smcd_dev_list.lock); spin_lock(&smcd_dev_list.lock);
list_for_each_entry(ismdev, &smcd_dev_list.list, list) { list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
if (!memcmp(ismdev->pnetid, ndev_pnetid, SMC_MAX_PNETID_LEN)) { if (smc_pnet_match(ismdev->pnetid, ndev_pnetid)) {
*smcismdev = ismdev; *smcismdev = ismdev;
break; break;
} }
...@@ -593,31 +814,6 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev, ...@@ -593,31 +814,6 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
spin_unlock(&smcd_dev_list.lock); spin_unlock(&smcd_dev_list.lock);
} }
/* Lookup of coupled ib_device via SMC pnet table */
static void smc_pnet_find_roce_by_table(struct net_device *netdev,
struct smc_ib_device **smcibdev,
u8 *ibport, unsigned short vlan_id,
u8 gid[])
{
struct smc_pnetentry *pnetelem;
read_lock(&smc_pnettable.lock);
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
if (netdev == pnetelem->ndev) {
if (smc_ib_port_active(pnetelem->smcibdev,
pnetelem->ib_port) &&
!smc_ib_determine_gid(pnetelem->smcibdev,
pnetelem->ib_port, vlan_id,
gid, NULL)) {
*smcibdev = pnetelem->smcibdev;
*ibport = pnetelem->ib_port;
}
break;
}
}
read_unlock(&smc_pnettable.lock);
}
/* PNET table analysis for a given sock: /* PNET table analysis for a given sock:
* determine ib_device and port belonging to used internal TCP socket * determine ib_device and port belonging to used internal TCP socket
* ethernet interface. * ethernet interface.
...@@ -636,13 +832,7 @@ void smc_pnet_find_roce_resource(struct sock *sk, ...@@ -636,13 +832,7 @@ void smc_pnet_find_roce_resource(struct sock *sk,
if (!dst->dev) if (!dst->dev)
goto out_rel; goto out_rel;
/* if possible, lookup via hardware-defined pnetid */
smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport, vlan_id, gid); smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport, vlan_id, gid);
if (*smcibdev)
goto out_rel;
/* lookup via SMC PNET table */
smc_pnet_find_roce_by_table(dst->dev, smcibdev, ibport, vlan_id, gid);
out_rel: out_rel:
dst_release(dst); dst_release(dst);
...@@ -660,7 +850,6 @@ void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev) ...@@ -660,7 +850,6 @@ void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev)
if (!dst->dev) if (!dst->dev)
goto out_rel; goto out_rel;
/* if possible, lookup via hardware-defined pnetid */
smc_pnet_find_ism_by_pnetid(dst->dev, smcismdev); smc_pnet_find_ism_by_pnetid(dst->dev, smcismdev);
out_rel: out_rel:
......
...@@ -19,6 +19,16 @@ ...@@ -19,6 +19,16 @@
struct smc_ib_device; struct smc_ib_device;
struct smcd_dev; struct smcd_dev;
/**
* struct smc_pnettable - SMC PNET table anchor
* @lock: Lock for list action
* @pnetlist: List of PNETIDs
*/
struct smc_pnettable {
rwlock_t lock;
struct list_head pnetlist;
};
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)
{ {
...@@ -30,8 +40,9 @@ static inline int smc_pnetid_by_dev_port(struct device *dev, ...@@ -30,8 +40,9 @@ static inline int smc_pnetid_by_dev_port(struct device *dev,
} }
int smc_pnet_init(void) __init; int smc_pnet_init(void) __init;
int smc_pnet_net_init(struct net *net);
void smc_pnet_exit(void); void smc_pnet_exit(void);
int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev); void smc_pnet_net_exit(struct net *net);
void smc_pnet_find_roce_resource(struct sock *sk, void smc_pnet_find_roce_resource(struct sock *sk,
struct smc_ib_device **smcibdev, u8 *ibport, struct smc_ib_device **smcibdev, u8 *ibport,
unsigned short vlan_id, u8 gid[]); unsigned short vlan_id, u8 gid[]);
......
...@@ -483,7 +483,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn, ...@@ -483,7 +483,7 @@ static int smc_tx_rdma_writes(struct smc_connection *conn,
*/ */
static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn)
{ {
struct smc_cdc_producer_flags *pflags; struct smc_cdc_producer_flags *pflags = &conn->local_tx_ctrl.prod_flags;
struct smc_rdma_wr *wr_rdma_buf; struct smc_rdma_wr *wr_rdma_buf;
struct smc_cdc_tx_pend *pend; struct smc_cdc_tx_pend *pend;
struct smc_wr_buf *wr_buf; struct smc_wr_buf *wr_buf;
...@@ -506,7 +506,7 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) ...@@ -506,7 +506,7 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn)
} }
spin_lock_bh(&conn->send_lock); spin_lock_bh(&conn->send_lock);
if (!conn->local_tx_ctrl.prod_flags.urg_data_present) { if (!pflags->urg_data_present) {
rc = smc_tx_rdma_writes(conn, wr_rdma_buf); rc = smc_tx_rdma_writes(conn, wr_rdma_buf);
if (rc) { if (rc) {
smc_wr_tx_put_slot(&conn->lgr->lnk[SMC_SINGLE_LINK], smc_wr_tx_put_slot(&conn->lgr->lnk[SMC_SINGLE_LINK],
...@@ -516,7 +516,6 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn) ...@@ -516,7 +516,6 @@ static int smcr_tx_sndbuf_nonempty(struct smc_connection *conn)
} }
rc = smc_cdc_msg_send(conn, wr_buf, pend); rc = smc_cdc_msg_send(conn, wr_buf, pend);
pflags = &conn->local_tx_ctrl.prod_flags;
if (!rc && pflags->urg_data_present) { if (!rc && pflags->urg_data_present) {
pflags->urg_data_pending = 0; pflags->urg_data_pending = 0;
pflags->urg_data_present = 0; pflags->urg_data_present = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment