ipmr, ip6mr: Unite mfc seq logic
With the exception of the final dump, ipmr and ip6mr have the exact same seq logic for traversing a given mr_table. Refactor that code and make it common. Signed-off-by: Yuval Mintz <yuvalm@mellanox.com> Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
845c9a7ae7
Коммит
c8d6196803
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/rhashtable.h>
|
#include <linux/rhashtable.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
|
||||||
|
@ -203,4 +204,72 @@ static inline void *mr_mfc_find(struct mr_table *mrt, void *hasharg)
|
||||||
{
|
{
|
||||||
return mr_mfc_find_parent(mrt, hasharg, -1);
|
return mr_mfc_find_parent(mrt, hasharg, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
struct mr_mfc_iter {
|
||||||
|
struct seq_net_private p;
|
||||||
|
struct mr_table *mrt;
|
||||||
|
struct list_head *cache;
|
||||||
|
|
||||||
|
/* Lock protecting the mr_table's unresolved queue */
|
||||||
|
spinlock_t *lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IP_MROUTE_COMMON
|
||||||
|
/* These actually return 'struct mr_mfc *', but to avoid need for explicit
|
||||||
|
* castings they simply return void.
|
||||||
|
*/
|
||||||
|
void *mr_mfc_seq_idx(struct net *net,
|
||||||
|
struct mr_mfc_iter *it, loff_t pos);
|
||||||
|
void *mr_mfc_seq_next(struct seq_file *seq, void *v,
|
||||||
|
loff_t *pos);
|
||||||
|
|
||||||
|
static inline void *mr_mfc_seq_start(struct seq_file *seq, loff_t *pos,
|
||||||
|
struct mr_table *mrt, spinlock_t *lock)
|
||||||
|
{
|
||||||
|
struct mr_mfc_iter *it = seq->private;
|
||||||
|
|
||||||
|
it->mrt = mrt;
|
||||||
|
it->cache = NULL;
|
||||||
|
it->lock = lock;
|
||||||
|
|
||||||
|
return *pos ? mr_mfc_seq_idx(seq_file_net(seq),
|
||||||
|
seq->private, *pos - 1)
|
||||||
|
: SEQ_START_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mr_mfc_seq_stop(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
struct mr_mfc_iter *it = seq->private;
|
||||||
|
struct mr_table *mrt = it->mrt;
|
||||||
|
|
||||||
|
if (it->cache == &mrt->mfc_unres_queue)
|
||||||
|
spin_unlock_bh(it->lock);
|
||||||
|
else if (it->cache == &mrt->mfc_cache_list)
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void *mr_mfc_seq_idx(struct net *net,
|
||||||
|
struct mr_mfc_iter *it, loff_t pos)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *mr_mfc_seq_next(struct seq_file *seq, void *v,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *mr_mfc_seq_start(struct seq_file *seq, loff_t *pos,
|
||||||
|
struct mr_table *mrt, spinlock_t *lock)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mr_mfc_seq_stop(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3014,41 +3014,8 @@ static const struct file_operations ipmr_vif_fops = {
|
||||||
.release = seq_release_net,
|
.release = seq_release_net,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ipmr_mfc_iter {
|
|
||||||
struct seq_net_private p;
|
|
||||||
struct mr_table *mrt;
|
|
||||||
struct list_head *cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
|
|
||||||
struct ipmr_mfc_iter *it, loff_t pos)
|
|
||||||
{
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
struct mr_mfc *mfc;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
it->cache = &mrt->mfc_cache_list;
|
|
||||||
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
|
|
||||||
if (pos-- == 0)
|
|
||||||
return (struct mfc_cache *)mfc;
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
|
||||||
it->cache = &mrt->mfc_unres_queue;
|
|
||||||
list_for_each_entry(mfc, it->cache, list)
|
|
||||||
if (pos-- == 0)
|
|
||||||
return (struct mfc_cache *)mfc;
|
|
||||||
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
|
|
||||||
it->cache = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct net *net = seq_file_net(seq);
|
struct net *net = seq_file_net(seq);
|
||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
|
|
||||||
|
@ -3056,57 +3023,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
if (!mrt)
|
if (!mrt)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
it->mrt = mrt;
|
return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
|
||||||
it->cache = NULL;
|
|
||||||
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
|
|
||||||
: SEQ_START_TOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
||||||
{
|
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct net *net = seq_file_net(seq);
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
struct mfc_cache *mfc = v;
|
|
||||||
|
|
||||||
++*pos;
|
|
||||||
|
|
||||||
if (v == SEQ_START_TOKEN)
|
|
||||||
return ipmr_mfc_seq_idx(net, seq->private, 0);
|
|
||||||
|
|
||||||
if (mfc->_c.list.next != it->cache)
|
|
||||||
return (struct mfc_cache *)(list_entry(mfc->_c.list.next,
|
|
||||||
struct mr_mfc, list));
|
|
||||||
|
|
||||||
if (it->cache == &mrt->mfc_unres_queue)
|
|
||||||
goto end_of_list;
|
|
||||||
|
|
||||||
/* exhausted cache_array, show unresolved */
|
|
||||||
rcu_read_unlock();
|
|
||||||
it->cache = &mrt->mfc_unres_queue;
|
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
|
||||||
if (!list_empty(it->cache))
|
|
||||||
return (struct mfc_cache *)(list_first_entry(it->cache,
|
|
||||||
struct mr_mfc,
|
|
||||||
list));
|
|
||||||
|
|
||||||
end_of_list:
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
it->cache = NULL;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
|
|
||||||
{
|
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
|
|
||||||
if (it->cache == &mrt->mfc_unres_queue)
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
else if (it->cache == &mrt->mfc_cache_list)
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
|
@ -3118,7 +3035,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
"Group Origin Iif Pkts Bytes Wrong Oifs\n");
|
"Group Origin Iif Pkts Bytes Wrong Oifs\n");
|
||||||
} else {
|
} else {
|
||||||
const struct mfc_cache *mfc = v;
|
const struct mfc_cache *mfc = v;
|
||||||
const struct ipmr_mfc_iter *it = seq->private;
|
const struct mr_mfc_iter *it = seq->private;
|
||||||
const struct mr_table *mrt = it->mrt;
|
const struct mr_table *mrt = it->mrt;
|
||||||
|
|
||||||
seq_printf(seq, "%08X %08X %-3hd",
|
seq_printf(seq, "%08X %08X %-3hd",
|
||||||
|
@ -3152,15 +3069,15 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
|
|
||||||
static const struct seq_operations ipmr_mfc_seq_ops = {
|
static const struct seq_operations ipmr_mfc_seq_ops = {
|
||||||
.start = ipmr_mfc_seq_start,
|
.start = ipmr_mfc_seq_start,
|
||||||
.next = ipmr_mfc_seq_next,
|
.next = mr_mfc_seq_next,
|
||||||
.stop = ipmr_mfc_seq_stop,
|
.stop = mr_mfc_seq_stop,
|
||||||
.show = ipmr_mfc_seq_show,
|
.show = ipmr_mfc_seq_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ipmr_mfc_open(struct inode *inode, struct file *file)
|
static int ipmr_mfc_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
|
return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
|
||||||
sizeof(struct ipmr_mfc_iter));
|
sizeof(struct mr_mfc_iter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations ipmr_mfc_fops = {
|
static const struct file_operations ipmr_mfc_fops = {
|
||||||
|
|
|
@ -103,3 +103,65 @@ void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg)
|
||||||
return mr_mfc_find_any_parent(mrt, vifi);
|
return mr_mfc_find_any_parent(mrt, vifi);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mr_mfc_find_any);
|
EXPORT_SYMBOL(mr_mfc_find_any);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
|
void *mr_mfc_seq_idx(struct net *net,
|
||||||
|
struct mr_mfc_iter *it, loff_t pos)
|
||||||
|
{
|
||||||
|
struct mr_table *mrt = it->mrt;
|
||||||
|
struct mr_mfc *mfc;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
it->cache = &mrt->mfc_cache_list;
|
||||||
|
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
|
||||||
|
if (pos-- == 0)
|
||||||
|
return mfc;
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
spin_lock_bh(it->lock);
|
||||||
|
it->cache = &mrt->mfc_unres_queue;
|
||||||
|
list_for_each_entry(mfc, it->cache, list)
|
||||||
|
if (pos-- == 0)
|
||||||
|
return mfc;
|
||||||
|
spin_unlock_bh(it->lock);
|
||||||
|
|
||||||
|
it->cache = NULL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mr_mfc_seq_idx);
|
||||||
|
|
||||||
|
void *mr_mfc_seq_next(struct seq_file *seq, void *v,
|
||||||
|
loff_t *pos)
|
||||||
|
{
|
||||||
|
struct mr_mfc_iter *it = seq->private;
|
||||||
|
struct net *net = seq_file_net(seq);
|
||||||
|
struct mr_table *mrt = it->mrt;
|
||||||
|
struct mr_mfc *c = v;
|
||||||
|
|
||||||
|
++*pos;
|
||||||
|
|
||||||
|
if (v == SEQ_START_TOKEN)
|
||||||
|
return mr_mfc_seq_idx(net, seq->private, 0);
|
||||||
|
|
||||||
|
if (c->list.next != it->cache)
|
||||||
|
return list_entry(c->list.next, struct mr_mfc, list);
|
||||||
|
|
||||||
|
if (it->cache == &mrt->mfc_unres_queue)
|
||||||
|
goto end_of_list;
|
||||||
|
|
||||||
|
/* exhausted cache_array, show unresolved */
|
||||||
|
rcu_read_unlock();
|
||||||
|
it->cache = &mrt->mfc_unres_queue;
|
||||||
|
|
||||||
|
spin_lock_bh(it->lock);
|
||||||
|
if (!list_empty(it->cache))
|
||||||
|
return list_first_entry(it->cache, struct mr_mfc, list);
|
||||||
|
|
||||||
|
end_of_list:
|
||||||
|
spin_unlock_bh(it->lock);
|
||||||
|
it->cache = NULL;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mr_mfc_seq_next);
|
||||||
|
#endif
|
||||||
|
|
|
@ -333,40 +333,8 @@ static void ip6mr_free_table(struct mr_table *mrt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
/* The /proc interfaces to multicast routing
|
||||||
struct ipmr_mfc_iter {
|
* /proc/ip6_mr_cache /proc/ip6_mr_vif
|
||||||
struct seq_net_private p;
|
|
||||||
struct mr_table *mrt;
|
|
||||||
struct list_head *cache;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
|
|
||||||
struct ipmr_mfc_iter *it, loff_t pos)
|
|
||||||
{
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
struct mr_mfc *mfc;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
it->cache = &mrt->mfc_cache_list;
|
|
||||||
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
|
|
||||||
if (pos-- == 0)
|
|
||||||
return (struct mfc6_cache *)mfc;
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
|
||||||
it->cache = &mrt->mfc_unres_queue;
|
|
||||||
list_for_each_entry(mfc, it->cache, list)
|
|
||||||
if (pos-- == 0)
|
|
||||||
return (struct mfc6_cache *)mfc;
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
|
|
||||||
it->cache = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ipmr_vif_iter {
|
struct ipmr_vif_iter {
|
||||||
|
@ -476,7 +444,6 @@ static const struct file_operations ip6mr_vif_fops = {
|
||||||
|
|
||||||
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct net *net = seq_file_net(seq);
|
struct net *net = seq_file_net(seq);
|
||||||
struct mr_table *mrt;
|
struct mr_table *mrt;
|
||||||
|
|
||||||
|
@ -484,57 +451,7 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||||
if (!mrt)
|
if (!mrt)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
it->mrt = mrt;
|
return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
|
||||||
it->cache = NULL;
|
|
||||||
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
|
|
||||||
: SEQ_START_TOKEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
||||||
{
|
|
||||||
struct mfc6_cache *mfc = v;
|
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct net *net = seq_file_net(seq);
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
|
|
||||||
++*pos;
|
|
||||||
|
|
||||||
if (v == SEQ_START_TOKEN)
|
|
||||||
return ipmr_mfc_seq_idx(net, seq->private, 0);
|
|
||||||
|
|
||||||
if (mfc->_c.list.next != it->cache)
|
|
||||||
return (struct mfc6_cache *)(list_entry(mfc->_c.list.next,
|
|
||||||
struct mr_mfc, list));
|
|
||||||
|
|
||||||
if (it->cache == &mrt->mfc_unres_queue)
|
|
||||||
goto end_of_list;
|
|
||||||
|
|
||||||
/* exhausted cache_array, show unresolved */
|
|
||||||
rcu_read_unlock();
|
|
||||||
it->cache = &mrt->mfc_unres_queue;
|
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
|
||||||
if (!list_empty(it->cache))
|
|
||||||
return (struct mfc6_cache *)(list_first_entry(it->cache,
|
|
||||||
struct mr_mfc,
|
|
||||||
list));
|
|
||||||
|
|
||||||
end_of_list:
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
it->cache = NULL;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
|
|
||||||
{
|
|
||||||
struct ipmr_mfc_iter *it = seq->private;
|
|
||||||
struct mr_table *mrt = it->mrt;
|
|
||||||
|
|
||||||
if (it->cache == &mrt->mfc_unres_queue)
|
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
|
||||||
else if (it->cache == &mrt->mfc_cache_list)
|
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
|
@ -548,7 +465,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
"Iif Pkts Bytes Wrong Oifs\n");
|
"Iif Pkts Bytes Wrong Oifs\n");
|
||||||
} else {
|
} else {
|
||||||
const struct mfc6_cache *mfc = v;
|
const struct mfc6_cache *mfc = v;
|
||||||
const struct ipmr_mfc_iter *it = seq->private;
|
const struct mr_mfc_iter *it = seq->private;
|
||||||
struct mr_table *mrt = it->mrt;
|
struct mr_table *mrt = it->mrt;
|
||||||
|
|
||||||
seq_printf(seq, "%pI6 %pI6 %-3hd",
|
seq_printf(seq, "%pI6 %pI6 %-3hd",
|
||||||
|
@ -581,15 +498,15 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
|
||||||
|
|
||||||
static const struct seq_operations ipmr_mfc_seq_ops = {
|
static const struct seq_operations ipmr_mfc_seq_ops = {
|
||||||
.start = ipmr_mfc_seq_start,
|
.start = ipmr_mfc_seq_start,
|
||||||
.next = ipmr_mfc_seq_next,
|
.next = mr_mfc_seq_next,
|
||||||
.stop = ipmr_mfc_seq_stop,
|
.stop = mr_mfc_seq_stop,
|
||||||
.show = ipmr_mfc_seq_show,
|
.show = ipmr_mfc_seq_show,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ipmr_mfc_open(struct inode *inode, struct file *file)
|
static int ipmr_mfc_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
|
return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
|
||||||
sizeof(struct ipmr_mfc_iter));
|
sizeof(struct mr_mfc_iter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations ip6mr_mfc_fops = {
|
static const struct file_operations ip6mr_mfc_fops = {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче