Skip to content

Commit

Permalink
ipmr, ip6mr: Unite mfc seq logic
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Yuval Mintz authored and David S. Miller committed Mar 1, 2018
1 parent 845c9a7 commit c8d6196
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 178 deletions.
69 changes: 69 additions & 0 deletions include/linux/mroute_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/netdevice.h>
#include <linux/rhashtable.h>
#include <linux/spinlock.h>
#include <net/net_namespace.h>
#include <net/sock.h>

Expand Down Expand Up @@ -203,4 +204,72 @@ static inline void *mr_mfc_find(struct mr_table *mrt, void *hasharg)
{
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
93 changes: 5 additions & 88 deletions net/ipv4/ipmr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3014,99 +3014,16 @@ static const struct file_operations ipmr_vif_fops = {
.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)
{
struct ipmr_mfc_iter *it = seq->private;
struct net *net = seq_file_net(seq);
struct mr_table *mrt;

mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
if (!mrt)
return ERR_PTR(-ENOENT);

it->mrt = mrt;
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();
return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock);
}

static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
Expand All @@ -3118,7 +3035,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
"Group Origin Iif Pkts Bytes Wrong Oifs\n");
} else {
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;

seq_printf(seq, "%08X %08X %-3hd",
Expand Down Expand Up @@ -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 = {
.start = ipmr_mfc_seq_start,
.next = ipmr_mfc_seq_next,
.stop = ipmr_mfc_seq_stop,
.next = mr_mfc_seq_next,
.stop = mr_mfc_seq_stop,
.show = ipmr_mfc_seq_show,
};

static int ipmr_mfc_open(struct inode *inode, struct file *file)
{
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 = {
Expand Down
62 changes: 62 additions & 0 deletions net/ipv4/ipmr_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
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
Loading

0 comments on commit c8d6196

Please sign in to comment.