[IPoIB] add path record information in debugfs
Add ibX_path files to debugfs that contain information about the IPoIB path cache. IPoIB ARP only gives GIDs, which the IPoIB driver must resolve to real IB paths through the ib_sa module. For debugging, when the ARP table looks OK but traffic isn't flowing, it's useful to be able to see if the resolution from GID to path worked. Also clean up the formatting of the existing _mcg debugfs files. Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
8b37b94721
commit
1732b0ef3b
|
@ -179,6 +179,7 @@ struct ipoib_dev_priv {
|
|||
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
|
||||
struct list_head fs_list;
|
||||
struct dentry *mcg_dentry;
|
||||
struct dentry *path_dentry;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -270,7 +271,6 @@ void ipoib_mcast_dev_flush(struct net_device *dev);
|
|||
|
||||
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
|
||||
struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev);
|
||||
void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter);
|
||||
int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter);
|
||||
void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter,
|
||||
union ib_gid *gid,
|
||||
|
@ -278,6 +278,11 @@ void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter,
|
|||
unsigned int *queuelen,
|
||||
unsigned int *complete,
|
||||
unsigned int *send_only);
|
||||
|
||||
struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev);
|
||||
int ipoib_path_iter_next(struct ipoib_path_iter *iter);
|
||||
void ipoib_path_iter_read(struct ipoib_path_iter *iter,
|
||||
struct ipoib_path *path);
|
||||
#endif
|
||||
|
||||
int ipoib_mcast_attach(struct net_device *dev, u16 mlid,
|
||||
|
@ -299,13 +304,13 @@ void ipoib_pkey_poll(void *dev);
|
|||
int ipoib_pkey_dev_delay_open(struct net_device *dev);
|
||||
|
||||
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
|
||||
int ipoib_create_debug_file(struct net_device *dev);
|
||||
void ipoib_delete_debug_file(struct net_device *dev);
|
||||
void ipoib_create_debug_files(struct net_device *dev);
|
||||
void ipoib_delete_debug_files(struct net_device *dev);
|
||||
int ipoib_register_debugfs(void);
|
||||
void ipoib_unregister_debugfs(void);
|
||||
#else
|
||||
static inline int ipoib_create_debug_file(struct net_device *dev) { return 0; }
|
||||
static inline void ipoib_delete_debug_file(struct net_device *dev) { }
|
||||
static inline void ipoib_create_debug_files(struct net_device *dev) { }
|
||||
static inline void ipoib_delete_debug_files(struct net_device *dev) { }
|
||||
static inline int ipoib_register_debugfs(void) { return 0; }
|
||||
static inline void ipoib_unregister_debugfs(void) { }
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,18 @@ struct file_operations;
|
|||
|
||||
static struct dentry *ipoib_root;
|
||||
|
||||
static void format_gid(union ib_gid *gid, char *buf)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
for (n = 0, i = 0; i < 8; ++i) {
|
||||
n += sprintf(buf + n, "%x",
|
||||
be16_to_cpu(((__be16 *) gid->raw)[i]));
|
||||
if (i < 7)
|
||||
buf[n++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
|
||||
{
|
||||
struct ipoib_mcast_iter *iter;
|
||||
|
@ -54,7 +66,7 @@ static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos)
|
|||
|
||||
while (n--) {
|
||||
if (ipoib_mcast_iter_next(iter)) {
|
||||
ipoib_mcast_iter_free(iter);
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +82,7 @@ static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr,
|
|||
(*pos)++;
|
||||
|
||||
if (ipoib_mcast_iter_next(iter)) {
|
||||
ipoib_mcast_iter_free(iter);
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -87,32 +99,32 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
|
|||
struct ipoib_mcast_iter *iter = iter_ptr;
|
||||
char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
|
||||
union ib_gid mgid;
|
||||
int i, n;
|
||||
unsigned long created;
|
||||
unsigned int queuelen, complete, send_only;
|
||||
|
||||
if (iter) {
|
||||
ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
|
||||
&complete, &send_only);
|
||||
if (!iter)
|
||||
return 0;
|
||||
|
||||
for (n = 0, i = 0; i < sizeof mgid / 2; ++i) {
|
||||
n += sprintf(gid_buf + n, "%x",
|
||||
be16_to_cpu(((__be16 *) mgid.raw)[i]));
|
||||
if (i < sizeof mgid / 2 - 1)
|
||||
gid_buf[n++] = ':';
|
||||
}
|
||||
}
|
||||
ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen,
|
||||
&complete, &send_only);
|
||||
|
||||
seq_printf(file, "GID: %*s", -(1 + (int) sizeof gid_buf), gid_buf);
|
||||
format_gid(&mgid, gid_buf);
|
||||
|
||||
seq_printf(file,
|
||||
" created: %10ld queuelen: %4d complete: %d send_only: %d\n",
|
||||
created, queuelen, complete, send_only);
|
||||
"GID: %s\n"
|
||||
" created: %10ld\n"
|
||||
" queuelen: %9d\n"
|
||||
" complete: %9s\n"
|
||||
" send_only: %8s\n"
|
||||
"\n",
|
||||
gid_buf, created, queuelen,
|
||||
complete ? "yes" : "no",
|
||||
send_only ? "yes" : "no");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations ipoib_seq_ops = {
|
||||
static struct seq_operations ipoib_mcg_seq_ops = {
|
||||
.start = ipoib_mcg_seq_start,
|
||||
.next = ipoib_mcg_seq_next,
|
||||
.stop = ipoib_mcg_seq_stop,
|
||||
|
@ -124,7 +136,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file)
|
|||
struct seq_file *seq;
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &ipoib_seq_ops);
|
||||
ret = seq_open(file, &ipoib_mcg_seq_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -134,7 +146,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations ipoib_fops = {
|
||||
static struct file_operations ipoib_mcg_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ipoib_mcg_open,
|
||||
.read = seq_read,
|
||||
|
@ -142,25 +154,138 @@ static struct file_operations ipoib_fops = {
|
|||
.release = seq_release
|
||||
};
|
||||
|
||||
int ipoib_create_debug_file(struct net_device *dev)
|
||||
static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
char name[IFNAMSIZ + sizeof "_mcg"];
|
||||
struct ipoib_path_iter *iter;
|
||||
loff_t n = *pos;
|
||||
|
||||
snprintf(name, sizeof name, "%s_mcg", dev->name);
|
||||
iter = ipoib_path_iter_init(file->private);
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
|
||||
ipoib_root, dev, &ipoib_fops);
|
||||
while (n--) {
|
||||
if (ipoib_path_iter_next(iter)) {
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return priv->mcg_dentry ? 0 : -ENOMEM;
|
||||
return iter;
|
||||
}
|
||||
|
||||
void ipoib_delete_debug_file(struct net_device *dev)
|
||||
static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr,
|
||||
loff_t *pos)
|
||||
{
|
||||
struct ipoib_path_iter *iter = iter_ptr;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
if (ipoib_path_iter_next(iter)) {
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
/* nothing for now */
|
||||
}
|
||||
|
||||
static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
|
||||
{
|
||||
struct ipoib_path_iter *iter = iter_ptr;
|
||||
char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
|
||||
struct ipoib_path path;
|
||||
int rate;
|
||||
|
||||
if (!iter)
|
||||
return 0;
|
||||
|
||||
ipoib_path_iter_read(iter, &path);
|
||||
|
||||
format_gid(&path.pathrec.dgid, gid_buf);
|
||||
|
||||
seq_printf(file,
|
||||
"GID: %s\n"
|
||||
" complete: %6s\n",
|
||||
gid_buf, path.pathrec.dlid ? "yes" : "no");
|
||||
|
||||
if (path.pathrec.dlid) {
|
||||
rate = ib_sa_rate_enum_to_int(path.pathrec.rate) * 25;
|
||||
|
||||
seq_printf(file,
|
||||
" DLID: 0x%04x\n"
|
||||
" SL: %12d\n"
|
||||
" rate: %*d%s Gb/sec\n",
|
||||
be16_to_cpu(path.pathrec.dlid),
|
||||
path.pathrec.sl,
|
||||
10 - ((rate % 10) ? 2 : 0),
|
||||
rate / 10, rate % 10 ? ".5" : "");
|
||||
}
|
||||
|
||||
seq_putc(file, '\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations ipoib_path_seq_ops = {
|
||||
.start = ipoib_path_seq_start,
|
||||
.next = ipoib_path_seq_next,
|
||||
.stop = ipoib_path_seq_stop,
|
||||
.show = ipoib_path_seq_show,
|
||||
};
|
||||
|
||||
static int ipoib_path_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq;
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &ipoib_path_seq_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
seq = file->private_data;
|
||||
seq->private = inode->u.generic_ip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations ipoib_path_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ipoib_path_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
void ipoib_create_debug_files(struct net_device *dev)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
char name[IFNAMSIZ + sizeof "_path"];
|
||||
|
||||
snprintf(name, sizeof name, "%s_mcg", dev->name);
|
||||
priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
|
||||
ipoib_root, dev, &ipoib_mcg_fops);
|
||||
if (!priv->mcg_dentry)
|
||||
ipoib_warn(priv, "failed to create mcg debug file\n");
|
||||
|
||||
snprintf(name, sizeof name, "%s_path", dev->name);
|
||||
priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
|
||||
ipoib_root, dev, &ipoib_path_fops);
|
||||
if (!priv->path_dentry)
|
||||
ipoib_warn(priv, "failed to create path debug file\n");
|
||||
}
|
||||
|
||||
void ipoib_delete_debug_files(struct net_device *dev)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->mcg_dentry)
|
||||
debugfs_remove(priv->mcg_dentry);
|
||||
if (priv->path_dentry)
|
||||
debugfs_remove(priv->path_dentry);
|
||||
}
|
||||
|
||||
int ipoib_register_debugfs(void)
|
||||
|
|
|
@ -58,6 +58,11 @@ module_param_named(debug_level, ipoib_debug_level, int, 0644);
|
|||
MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
|
||||
#endif
|
||||
|
||||
struct ipoib_path_iter {
|
||||
struct net_device *dev;
|
||||
struct ipoib_path path;
|
||||
};
|
||||
|
||||
static const u8 ipv4_bcast_addr[] = {
|
||||
0x00, 0xff, 0xff, 0xff,
|
||||
0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -250,6 +255,64 @@ static void path_free(struct net_device *dev, struct ipoib_path *path)
|
|||
kfree(path);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
|
||||
|
||||
struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev)
|
||||
{
|
||||
struct ipoib_path_iter *iter;
|
||||
|
||||
iter = kmalloc(sizeof *iter, GFP_KERNEL);
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
iter->dev = dev;
|
||||
memset(iter->path.pathrec.dgid.raw, 0, 16);
|
||||
|
||||
if (ipoib_path_iter_next(iter)) {
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
int ipoib_path_iter_next(struct ipoib_path_iter *iter)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(iter->dev);
|
||||
struct rb_node *n;
|
||||
struct ipoib_path *path;
|
||||
int ret = 1;
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
|
||||
n = rb_first(&priv->path_tree);
|
||||
|
||||
while (n) {
|
||||
path = rb_entry(n, struct ipoib_path, rb_node);
|
||||
|
||||
if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw,
|
||||
sizeof (union ib_gid)) < 0) {
|
||||
iter->path = *path;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
n = rb_next(n);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ipoib_path_iter_read(struct ipoib_path_iter *iter,
|
||||
struct ipoib_path *path)
|
||||
{
|
||||
*path = iter->path;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */
|
||||
|
||||
void ipoib_flush_paths(struct net_device *dev)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev);
|
||||
|
@ -763,7 +826,7 @@ void ipoib_dev_cleanup(struct net_device *dev)
|
|||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv;
|
||||
|
||||
ipoib_delete_debug_file(dev);
|
||||
ipoib_delete_debug_files(dev);
|
||||
|
||||
/* Delete any child interfaces first */
|
||||
list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) {
|
||||
|
@ -972,8 +1035,7 @@ static struct net_device *ipoib_add_port(const char *format,
|
|||
goto register_failed;
|
||||
}
|
||||
|
||||
if (ipoib_create_debug_file(priv->dev))
|
||||
goto debug_failed;
|
||||
ipoib_create_debug_files(priv->dev);
|
||||
|
||||
if (ipoib_add_pkey_attr(priv->dev))
|
||||
goto sysfs_failed;
|
||||
|
@ -987,9 +1049,7 @@ static struct net_device *ipoib_add_port(const char *format,
|
|||
return priv->dev;
|
||||
|
||||
sysfs_failed:
|
||||
ipoib_delete_debug_file(priv->dev);
|
||||
|
||||
debug_failed:
|
||||
ipoib_delete_debug_files(priv->dev);
|
||||
unregister_netdev(priv->dev);
|
||||
|
||||
register_failed:
|
||||
|
|
|
@ -928,21 +928,16 @@ struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev)
|
|||
return NULL;
|
||||
|
||||
iter->dev = dev;
|
||||
memset(iter->mgid.raw, 0, sizeof iter->mgid);
|
||||
memset(iter->mgid.raw, 0, 16);
|
||||
|
||||
if (ipoib_mcast_iter_next(iter)) {
|
||||
ipoib_mcast_iter_free(iter);
|
||||
kfree(iter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void ipoib_mcast_iter_free(struct ipoib_mcast_iter *iter)
|
||||
{
|
||||
kfree(iter);
|
||||
}
|
||||
|
||||
int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter)
|
||||
{
|
||||
struct ipoib_dev_priv *priv = netdev_priv(iter->dev);
|
||||
|
|
|
@ -113,8 +113,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
|
|||
|
||||
priv->parent = ppriv->dev;
|
||||
|
||||
if (ipoib_create_debug_file(priv->dev))
|
||||
goto debug_failed;
|
||||
ipoib_create_debug_files(priv->dev);
|
||||
|
||||
if (ipoib_add_pkey_attr(priv->dev))
|
||||
goto sysfs_failed;
|
||||
|
@ -130,9 +129,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
|
|||
return 0;
|
||||
|
||||
sysfs_failed:
|
||||
ipoib_delete_debug_file(priv->dev);
|
||||
|
||||
debug_failed:
|
||||
ipoib_delete_debug_files(priv->dev);
|
||||
unregister_netdev(priv->dev);
|
||||
|
||||
register_failed:
|
||||
|
|
Loading…
Reference in New Issue