ipv4: ipmr: convert struct mfc_cache to struct list_head
Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d658f8a0e6
commit
862465f2e7
|
@ -191,7 +191,7 @@ struct vif_device {
|
||||||
#define VIFF_STATIC 0x8000
|
#define VIFF_STATIC 0x8000
|
||||||
|
|
||||||
struct mfc_cache {
|
struct mfc_cache {
|
||||||
struct mfc_cache *next; /* Next entry on cache line */
|
struct list_head list;
|
||||||
__be32 mfc_mcastgrp; /* Group the entry belongs to */
|
__be32 mfc_mcastgrp; /* Group the entry belongs to */
|
||||||
__be32 mfc_origin; /* Source of packet */
|
__be32 mfc_origin; /* Source of packet */
|
||||||
vifi_t mfc_parent; /* Source interface */
|
vifi_t mfc_parent; /* Source interface */
|
||||||
|
|
|
@ -61,8 +61,8 @@ struct netns_ipv4 {
|
||||||
#ifdef CONFIG_IP_MROUTE
|
#ifdef CONFIG_IP_MROUTE
|
||||||
struct sock *mroute_sk;
|
struct sock *mroute_sk;
|
||||||
struct timer_list ipmr_expire_timer;
|
struct timer_list ipmr_expire_timer;
|
||||||
struct mfc_cache *mfc_unres_queue;
|
struct list_head mfc_unres_queue;
|
||||||
struct mfc_cache **mfc_cache_array;
|
struct list_head *mfc_cache_array;
|
||||||
struct vif_device *vif_table;
|
struct vif_device *vif_table;
|
||||||
int maxvif;
|
int maxvif;
|
||||||
atomic_t cache_resolve_queue_len;
|
atomic_t cache_resolve_queue_len;
|
||||||
|
|
121
net/ipv4/ipmr.c
121
net/ipv4/ipmr.c
|
@ -367,35 +367,32 @@ static void ipmr_expire_process(unsigned long arg)
|
||||||
struct net *net = (struct net *)arg;
|
struct net *net = (struct net *)arg;
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
unsigned long expires;
|
unsigned long expires;
|
||||||
struct mfc_cache *c, **cp;
|
struct mfc_cache *c, *next;
|
||||||
|
|
||||||
if (!spin_trylock(&mfc_unres_lock)) {
|
if (!spin_trylock(&mfc_unres_lock)) {
|
||||||
mod_timer(&net->ipv4.ipmr_expire_timer, jiffies+HZ/10);
|
mod_timer(&net->ipv4.ipmr_expire_timer, jiffies+HZ/10);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (net->ipv4.mfc_unres_queue == NULL)
|
if (list_empty(&net->ipv4.mfc_unres_queue))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
now = jiffies;
|
now = jiffies;
|
||||||
expires = 10*HZ;
|
expires = 10*HZ;
|
||||||
cp = &net->ipv4.mfc_unres_queue;
|
|
||||||
|
|
||||||
while ((c=*cp) != NULL) {
|
list_for_each_entry_safe(c, next, &net->ipv4.mfc_unres_queue, list) {
|
||||||
if (time_after(c->mfc_un.unres.expires, now)) {
|
if (time_after(c->mfc_un.unres.expires, now)) {
|
||||||
unsigned long interval = c->mfc_un.unres.expires - now;
|
unsigned long interval = c->mfc_un.unres.expires - now;
|
||||||
if (interval < expires)
|
if (interval < expires)
|
||||||
expires = interval;
|
expires = interval;
|
||||||
cp = &c->next;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*cp = c->next;
|
list_del(&c->list);
|
||||||
|
|
||||||
ipmr_destroy_unres(net, c);
|
ipmr_destroy_unres(net, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (net->ipv4.mfc_unres_queue != NULL)
|
if (!list_empty(&net->ipv4.mfc_unres_queue))
|
||||||
mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires);
|
mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -537,12 +534,12 @@ static struct mfc_cache *ipmr_cache_find(struct net *net,
|
||||||
int line = MFC_HASH(mcastgrp, origin);
|
int line = MFC_HASH(mcastgrp, origin);
|
||||||
struct mfc_cache *c;
|
struct mfc_cache *c;
|
||||||
|
|
||||||
for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
|
list_for_each_entry(c, &net->ipv4.mfc_cache_array[line], list) {
|
||||||
if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
|
if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
|
||||||
break;
|
|
||||||
}
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a multicast cache entry
|
* Allocate a multicast cache entry
|
||||||
|
@ -699,18 +696,21 @@ static int ipmr_cache_report(struct net *net,
|
||||||
static int
|
static int
|
||||||
ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
|
ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
bool found = false;
|
||||||
int err;
|
int err;
|
||||||
struct mfc_cache *c;
|
struct mfc_cache *c;
|
||||||
const struct iphdr *iph = ip_hdr(skb);
|
const struct iphdr *iph = ip_hdr(skb);
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
spin_lock_bh(&mfc_unres_lock);
|
||||||
for (c=net->ipv4.mfc_unres_queue; c; c=c->next) {
|
list_for_each_entry(c, &net->ipv4.mfc_unres_queue, list) {
|
||||||
if (c->mfc_mcastgrp == iph->daddr &&
|
if (c->mfc_mcastgrp == iph->daddr &&
|
||||||
c->mfc_origin == iph->saddr)
|
c->mfc_origin == iph->saddr) {
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c == NULL) {
|
if (!found) {
|
||||||
/*
|
/*
|
||||||
* Create a new entry if allowable
|
* Create a new entry if allowable
|
||||||
*/
|
*/
|
||||||
|
@ -746,8 +746,7 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_inc(&net->ipv4.cache_resolve_queue_len);
|
atomic_inc(&net->ipv4.cache_resolve_queue_len);
|
||||||
c->next = net->ipv4.mfc_unres_queue;
|
list_add(&c->list, &net->ipv4.mfc_unres_queue);
|
||||||
net->ipv4.mfc_unres_queue = c;
|
|
||||||
|
|
||||||
mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires);
|
mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires);
|
||||||
}
|
}
|
||||||
|
@ -774,16 +773,15 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
|
||||||
static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
|
static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
|
||||||
{
|
{
|
||||||
int line;
|
int line;
|
||||||
struct mfc_cache *c, **cp;
|
struct mfc_cache *c, *next;
|
||||||
|
|
||||||
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
|
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
|
||||||
|
|
||||||
for (cp = &net->ipv4.mfc_cache_array[line];
|
list_for_each_entry_safe(c, next, &net->ipv4.mfc_cache_array[line], list) {
|
||||||
(c = *cp) != NULL; cp = &c->next) {
|
|
||||||
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
|
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
|
||||||
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
|
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
|
||||||
write_lock_bh(&mrt_lock);
|
write_lock_bh(&mrt_lock);
|
||||||
*cp = c->next;
|
list_del(&c->list);
|
||||||
write_unlock_bh(&mrt_lock);
|
write_unlock_bh(&mrt_lock);
|
||||||
|
|
||||||
ipmr_cache_free(c);
|
ipmr_cache_free(c);
|
||||||
|
@ -795,22 +793,24 @@ static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
|
||||||
|
|
||||||
static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
|
static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
|
||||||
{
|
{
|
||||||
|
bool found = false;
|
||||||
int line;
|
int line;
|
||||||
struct mfc_cache *uc, *c, **cp;
|
struct mfc_cache *uc, *c;
|
||||||
|
|
||||||
if (mfc->mfcc_parent >= MAXVIFS)
|
if (mfc->mfcc_parent >= MAXVIFS)
|
||||||
return -ENFILE;
|
return -ENFILE;
|
||||||
|
|
||||||
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
|
line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
|
||||||
|
|
||||||
for (cp = &net->ipv4.mfc_cache_array[line];
|
list_for_each_entry(c, &net->ipv4.mfc_cache_array[line], list) {
|
||||||
(c = *cp) != NULL; cp = &c->next) {
|
|
||||||
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
|
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
|
||||||
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
|
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
|
||||||
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (c != NULL) {
|
if (found) {
|
||||||
write_lock_bh(&mrt_lock);
|
write_lock_bh(&mrt_lock);
|
||||||
c->mfc_parent = mfc->mfcc_parent;
|
c->mfc_parent = mfc->mfcc_parent;
|
||||||
ipmr_update_thresholds(net, c, mfc->mfcc_ttls);
|
ipmr_update_thresholds(net, c, mfc->mfcc_ttls);
|
||||||
|
@ -835,8 +835,7 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
|
||||||
c->mfc_flags |= MFC_STATIC;
|
c->mfc_flags |= MFC_STATIC;
|
||||||
|
|
||||||
write_lock_bh(&mrt_lock);
|
write_lock_bh(&mrt_lock);
|
||||||
c->next = net->ipv4.mfc_cache_array[line];
|
list_add(&c->list, &net->ipv4.mfc_cache_array[line]);
|
||||||
net->ipv4.mfc_cache_array[line] = c;
|
|
||||||
write_unlock_bh(&mrt_lock);
|
write_unlock_bh(&mrt_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -844,16 +843,15 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
|
||||||
* need to send on the frames and tidy up.
|
* need to send on the frames and tidy up.
|
||||||
*/
|
*/
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
spin_lock_bh(&mfc_unres_lock);
|
||||||
for (cp = &net->ipv4.mfc_unres_queue; (uc=*cp) != NULL;
|
list_for_each_entry(uc, &net->ipv4.mfc_unres_queue, list) {
|
||||||
cp = &uc->next) {
|
|
||||||
if (uc->mfc_origin == c->mfc_origin &&
|
if (uc->mfc_origin == c->mfc_origin &&
|
||||||
uc->mfc_mcastgrp == c->mfc_mcastgrp) {
|
uc->mfc_mcastgrp == c->mfc_mcastgrp) {
|
||||||
*cp = uc->next;
|
list_del(&uc->list);
|
||||||
atomic_dec(&net->ipv4.cache_resolve_queue_len);
|
atomic_dec(&net->ipv4.cache_resolve_queue_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (net->ipv4.mfc_unres_queue == NULL)
|
if (list_empty(&net->ipv4.mfc_unres_queue))
|
||||||
del_timer(&net->ipv4.ipmr_expire_timer);
|
del_timer(&net->ipv4.ipmr_expire_timer);
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
spin_unlock_bh(&mfc_unres_lock);
|
||||||
|
|
||||||
|
@ -872,6 +870,7 @@ static void mroute_clean_tables(struct net *net)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
|
struct mfc_cache *c, *next;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shut down all active vif entries
|
* Shut down all active vif entries
|
||||||
|
@ -886,16 +885,11 @@ static void mroute_clean_tables(struct net *net)
|
||||||
* Wipe the cache
|
* Wipe the cache
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < MFC_LINES; i++) {
|
for (i = 0; i < MFC_LINES; i++) {
|
||||||
struct mfc_cache *c, **cp;
|
list_for_each_entry_safe(c, next, &net->ipv4.mfc_cache_array[i], list) {
|
||||||
|
if (c->mfc_flags&MFC_STATIC)
|
||||||
cp = &net->ipv4.mfc_cache_array[i];
|
|
||||||
while ((c = *cp) != NULL) {
|
|
||||||
if (c->mfc_flags&MFC_STATIC) {
|
|
||||||
cp = &c->next;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
write_lock_bh(&mrt_lock);
|
write_lock_bh(&mrt_lock);
|
||||||
*cp = c->next;
|
list_del(&c->list);
|
||||||
write_unlock_bh(&mrt_lock);
|
write_unlock_bh(&mrt_lock);
|
||||||
|
|
||||||
ipmr_cache_free(c);
|
ipmr_cache_free(c);
|
||||||
|
@ -903,12 +897,9 @@ static void mroute_clean_tables(struct net *net)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
|
if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
|
||||||
struct mfc_cache *c, **cp;
|
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
spin_lock_bh(&mfc_unres_lock);
|
||||||
cp = &net->ipv4.mfc_unres_queue;
|
list_for_each_entry_safe(c, next, &net->ipv4.mfc_unres_queue, list) {
|
||||||
while ((c = *cp) != NULL) {
|
list_del(&c->list);
|
||||||
*cp = c->next;
|
|
||||||
ipmr_destroy_unres(net, c);
|
ipmr_destroy_unres(net, c);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
spin_unlock_bh(&mfc_unres_lock);
|
||||||
|
@ -1789,7 +1780,7 @@ static const struct file_operations ipmr_vif_fops = {
|
||||||
|
|
||||||
struct ipmr_mfc_iter {
|
struct ipmr_mfc_iter {
|
||||||
struct seq_net_private p;
|
struct seq_net_private p;
|
||||||
struct mfc_cache **cache;
|
struct list_head *cache;
|
||||||
int ct;
|
int ct;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1799,18 +1790,18 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
|
||||||
{
|
{
|
||||||
struct mfc_cache *mfc;
|
struct mfc_cache *mfc;
|
||||||
|
|
||||||
it->cache = net->ipv4.mfc_cache_array;
|
|
||||||
read_lock(&mrt_lock);
|
read_lock(&mrt_lock);
|
||||||
for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
|
for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
|
||||||
for (mfc = net->ipv4.mfc_cache_array[it->ct];
|
it->cache = &net->ipv4.mfc_cache_array[it->ct];
|
||||||
mfc; mfc = mfc->next)
|
list_for_each_entry(mfc, it->cache, list)
|
||||||
if (pos-- == 0)
|
if (pos-- == 0)
|
||||||
return mfc;
|
return mfc;
|
||||||
|
}
|
||||||
read_unlock(&mrt_lock);
|
read_unlock(&mrt_lock);
|
||||||
|
|
||||||
it->cache = &net->ipv4.mfc_unres_queue;
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
spin_lock_bh(&mfc_unres_lock);
|
||||||
for (mfc = net->ipv4.mfc_unres_queue; mfc; mfc = mfc->next)
|
it->cache = &net->ipv4.mfc_unres_queue;
|
||||||
|
list_for_each_entry(mfc, it->cache, list)
|
||||||
if (pos-- == 0)
|
if (pos-- == 0)
|
||||||
return mfc;
|
return mfc;
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
spin_unlock_bh(&mfc_unres_lock);
|
||||||
|
@ -1842,18 +1833,19 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||||
if (v == SEQ_START_TOKEN)
|
if (v == SEQ_START_TOKEN)
|
||||||
return ipmr_mfc_seq_idx(net, seq->private, 0);
|
return ipmr_mfc_seq_idx(net, seq->private, 0);
|
||||||
|
|
||||||
if (mfc->next)
|
if (mfc->list.next != it->cache)
|
||||||
return mfc->next;
|
return list_entry(mfc->list.next, struct mfc_cache, list);
|
||||||
|
|
||||||
if (it->cache == &net->ipv4.mfc_unres_queue)
|
if (it->cache == &net->ipv4.mfc_unres_queue)
|
||||||
goto end_of_list;
|
goto end_of_list;
|
||||||
|
|
||||||
BUG_ON(it->cache != net->ipv4.mfc_cache_array);
|
BUG_ON(it->cache != &net->ipv4.mfc_cache_array[it->ct]);
|
||||||
|
|
||||||
while (++it->ct < MFC_LINES) {
|
while (++it->ct < MFC_LINES) {
|
||||||
mfc = net->ipv4.mfc_cache_array[it->ct];
|
it->cache = &net->ipv4.mfc_cache_array[it->ct];
|
||||||
if (mfc)
|
if (list_empty(it->cache))
|
||||||
return mfc;
|
continue;
|
||||||
|
return list_first_entry(it->cache, struct mfc_cache, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exhausted cache_array, show unresolved */
|
/* exhausted cache_array, show unresolved */
|
||||||
|
@ -1862,9 +1854,8 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||||
it->ct = 0;
|
it->ct = 0;
|
||||||
|
|
||||||
spin_lock_bh(&mfc_unres_lock);
|
spin_lock_bh(&mfc_unres_lock);
|
||||||
mfc = net->ipv4.mfc_unres_queue;
|
if (!list_empty(it->cache))
|
||||||
if (mfc)
|
return list_first_entry(it->cache, struct mfc_cache, list);
|
||||||
return mfc;
|
|
||||||
|
|
||||||
end_of_list:
|
end_of_list:
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
spin_unlock_bh(&mfc_unres_lock);
|
||||||
|
@ -1880,7 +1871,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
|
||||||
|
|
||||||
if (it->cache == &net->ipv4.mfc_unres_queue)
|
if (it->cache == &net->ipv4.mfc_unres_queue)
|
||||||
spin_unlock_bh(&mfc_unres_lock);
|
spin_unlock_bh(&mfc_unres_lock);
|
||||||
else if (it->cache == net->ipv4.mfc_cache_array)
|
else if (it->cache == &net->ipv4.mfc_cache_array[it->ct])
|
||||||
read_unlock(&mrt_lock);
|
read_unlock(&mrt_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1960,6 +1951,7 @@ static const struct net_protocol pim_protocol = {
|
||||||
*/
|
*/
|
||||||
static int __net_init ipmr_net_init(struct net *net)
|
static int __net_init ipmr_net_init(struct net *net)
|
||||||
{
|
{
|
||||||
|
unsigned int i;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
|
net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
|
||||||
|
@ -1971,13 +1963,18 @@ static int __net_init ipmr_net_init(struct net *net)
|
||||||
|
|
||||||
/* Forwarding cache */
|
/* Forwarding cache */
|
||||||
net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
|
net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
|
||||||
sizeof(struct mfc_cache *),
|
sizeof(struct list_head),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!net->ipv4.mfc_cache_array) {
|
if (!net->ipv4.mfc_cache_array) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto fail_mfc_cache;
|
goto fail_mfc_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < MFC_LINES; i++)
|
||||||
|
INIT_LIST_HEAD(&net->ipv4.mfc_cache_array[i]);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&net->ipv4.mfc_unres_queue);
|
||||||
|
|
||||||
setup_timer(&net->ipv4.ipmr_expire_timer, ipmr_expire_process,
|
setup_timer(&net->ipv4.ipmr_expire_timer, ipmr_expire_process,
|
||||||
(unsigned long)net);
|
(unsigned long)net);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue