#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL)
-static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */
-
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
static struct kmem_cache *mrt_cachep __read_mostly;
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache);
+static int ip6_mr_forward(struct net *net, struct sk_buff *skb,
+ struct mfc6_cache *cache);
static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt,
mifi_t mifi, int assert);
-static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
+static int ip6mr_fill_mroute(struct net *net, struct sk_buff *skb,
+ struct mfc6_cache *c, struct rtmsg *rtm);
static void mroute_clean_tables(struct net *net);
-static struct timer_list ipmr_expire_timer;
-
#ifdef CONFIG_PROC_FS
return mfc;
read_unlock(&mrt_lock);
- it->cache = &mfc_unres_queue;
+ it->cache = &net->ipv6.mfc6_unres_queue;
spin_lock_bh(&mfc_unres_lock);
- for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
- if (net_eq(mfc6_net(mfc), net) &&
- pos-- == 0)
+ for (mfc = net->ipv6.mfc6_unres_queue; mfc; mfc = mfc->next)
+ if (pos-- == 0)
return mfc;
spin_unlock_bh(&mfc_unres_lock);
if (mfc->next)
return mfc->next;
- if (it->cache == &mfc_unres_queue)
+ if (it->cache == &net->ipv6.mfc6_unres_queue)
goto end_of_list;
BUG_ON(it->cache != net->ipv6.mfc6_cache_array);
/* exhausted cache_array, show unresolved */
read_unlock(&mrt_lock);
- it->cache = &mfc_unres_queue;
+ it->cache = &net->ipv6.mfc6_unres_queue;
it->ct = 0;
spin_lock_bh(&mfc_unres_lock);
- mfc = mfc_unres_queue;
+ mfc = net->ipv6.mfc6_unres_queue;
if (mfc)
return mfc;
struct ipmr_mfc_iter *it = seq->private;
struct net *net = seq_file_net(seq);
- if (it->cache == &mfc_unres_queue)
+ if (it->cache == &net->ipv6.mfc6_unres_queue)
spin_unlock_bh(&mfc_unres_lock);
else if (it->cache == net->ipv6.mfc6_cache_array)
read_unlock(&mrt_lock);
&mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
mfc->mf6c_parent);
- if (it->cache != &mfc_unres_queue) {
+ if (it->cache != &net->ipv6.mfc6_unres_queue) {
seq_printf(seq, " %8lu %8lu %8lu",
mfc->mfc_un.res.pkt,
mfc->mfc_un.res.bytes,
static inline void ip6mr_cache_free(struct mfc6_cache *c)
{
- release_net(mfc6_net(c));
kmem_cache_free(mrt_cachep, c);
}
and reporting error to netlink readers.
*/
-static void ip6mr_destroy_unres(struct mfc6_cache *c)
+static void ip6mr_destroy_unres(struct net *net, struct mfc6_cache *c)
{
struct sk_buff *skb;
- struct net *net = mfc6_net(c);
atomic_dec(&net->ipv6.cache_resolve_queue_len);
}
-/* Single timer process for all the unresolved queue. */
+/* Timer process for all the unresolved queue. */
-static void ipmr_do_expire_process(unsigned long dummy)
+static void ipmr_do_expire_process(struct net *net)
{
unsigned long now = jiffies;
unsigned long expires = 10 * HZ;
struct mfc6_cache *c, **cp;
- cp = &mfc_unres_queue;
+ cp = &net->ipv6.mfc6_unres_queue;
while ((c = *cp) != NULL) {
if (time_after(c->mfc_un.unres.expires, now)) {
}
*cp = c->next;
- ip6mr_destroy_unres(c);
+ ip6mr_destroy_unres(net, c);
}
- if (mfc_unres_queue != NULL)
- mod_timer(&ipmr_expire_timer, jiffies + expires);
+ if (net->ipv6.mfc6_unres_queue != NULL)
+ mod_timer(&net->ipv6.ipmr_expire_timer, jiffies + expires);
}
-static void ipmr_expire_process(unsigned long dummy)
+static void ipmr_expire_process(unsigned long arg)
{
+ struct net *net = (struct net *)arg;
+
if (!spin_trylock(&mfc_unres_lock)) {
- mod_timer(&ipmr_expire_timer, jiffies + 1);
+ mod_timer(&net->ipv6.ipmr_expire_timer, jiffies + 1);
return;
}
- if (mfc_unres_queue != NULL)
- ipmr_do_expire_process(dummy);
+ if (net->ipv6.mfc6_unres_queue != NULL)
+ ipmr_do_expire_process(net);
spin_unlock(&mfc_unres_lock);
}
/* Fill oifs list. It is called under write locked mrt_lock. */
-static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls)
+static void ip6mr_update_thresholds(struct net *net, struct mfc6_cache *cache,
+ unsigned char *ttls)
{
int vifi;
- struct net *net = mfc6_net(cache);
cache->mfc_un.res.minvif = MAXMIFS;
cache->mfc_un.res.maxvif = 0;
/*
* Allocate a multicast cache entry
*/
-static struct mfc6_cache *ip6mr_cache_alloc(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc(void)
{
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
if (c == NULL)
return NULL;
c->mfc_un.res.minvif = MAXMIFS;
- mfc6_net_set(c, net);
return c;
}
-static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
{
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
if (c == NULL)
return NULL;
skb_queue_head_init(&c->mfc_un.unres.unresolved);
c->mfc_un.unres.expires = jiffies + 10 * HZ;
- mfc6_net_set(c, net);
return c;
}
* A cache entry has gone into a resolved state from queued
*/
-static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
+static void ip6mr_cache_resolve(struct net *net, struct mfc6_cache *uc,
+ struct mfc6_cache *c)
{
struct sk_buff *skb;
int err;
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
- if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+ if (ip6mr_fill_mroute(net, skb, c, NLMSG_DATA(nlh)) > 0) {
nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
} else {
nlh->nlmsg_type = NLMSG_ERROR;
skb_trim(skb, nlh->nlmsg_len);
((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
}
- err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
} else
- ip6_mr_forward(skb, c);
+ ip6_mr_forward(net, skb, c);
}
}
struct mfc6_cache *c;
spin_lock_bh(&mfc_unres_lock);
- for (c = mfc_unres_queue; c; c = c->next) {
- if (net_eq(mfc6_net(c), net) &&
- ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
+ for (c = net->ipv6.mfc6_unres_queue; c; c = c->next) {
+ if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr))
break;
}
*/
if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 ||
- (c = ip6mr_cache_alloc_unres(net)) == NULL) {
+ (c = ip6mr_cache_alloc_unres()) == NULL) {
spin_unlock_bh(&mfc_unres_lock);
kfree_skb(skb);
}
atomic_inc(&net->ipv6.cache_resolve_queue_len);
- c->next = mfc_unres_queue;
- mfc_unres_queue = c;
+ c->next = net->ipv6.mfc6_unres_queue;
+ net->ipv6.mfc6_unres_queue = c;
- ipmr_do_expire_process(1);
+ ipmr_do_expire_process(net);
}
/*
goto fail_mfc6_cache;
}
+ setup_timer(&net->ipv6.ipmr_expire_timer, ipmr_expire_process,
+ (unsigned long)net);
+
#ifdef CONFIG_IPV6_PIMSM_V2
net->ipv6.mroute_reg_vif_num = -1;
#endif
proc_net_remove(net, "ip6_mr_cache");
proc_net_remove(net, "ip6_mr_vif");
#endif
+ del_timer(&net->ipv6.ipmr_expire_timer);
mroute_clean_tables(net);
kfree(net->ipv6.mfc6_cache_array);
kfree(net->ipv6.vif6_table);
if (err)
goto reg_pernet_fail;
- setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
err = register_netdevice_notifier(&ip6_mr_notifier);
if (err)
goto reg_notif_fail;
unregister_netdevice_notifier(&ip6_mr_notifier);
#endif
reg_notif_fail:
- del_timer(&ipmr_expire_timer);
unregister_pernet_subsys(&ip6mr_net_ops);
reg_pernet_fail:
kmem_cache_destroy(mrt_cachep);
void ip6_mr_cleanup(void)
{
unregister_netdevice_notifier(&ip6_mr_notifier);
- del_timer(&ipmr_expire_timer);
unregister_pernet_subsys(&ip6mr_net_ops);
kmem_cache_destroy(mrt_cachep);
}
if (c != NULL) {
write_lock_bh(&mrt_lock);
c->mf6c_parent = mfc->mf6cc_parent;
- ip6mr_update_thresholds(c, ttls);
+ ip6mr_update_thresholds(net, c, ttls);
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
write_unlock_bh(&mrt_lock);
if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
return -EINVAL;
- c = ip6mr_cache_alloc(net);
+ c = ip6mr_cache_alloc();
if (c == NULL)
return -ENOMEM;
c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
c->mf6c_parent = mfc->mf6cc_parent;
- ip6mr_update_thresholds(c, ttls);
+ ip6mr_update_thresholds(net, c, ttls);
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
* need to send on the frames and tidy up.
*/
spin_lock_bh(&mfc_unres_lock);
- for (cp = &mfc_unres_queue; (uc = *cp) != NULL;
+ for (cp = &net->ipv6.mfc6_unres_queue; (uc = *cp) != NULL;
cp = &uc->next) {
- if (net_eq(mfc6_net(uc), net) &&
- ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
+ if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
*cp = uc->next;
atomic_dec(&net->ipv6.cache_resolve_queue_len);
break;
}
}
- if (mfc_unres_queue == NULL)
- del_timer(&ipmr_expire_timer);
+ if (net->ipv6.mfc6_unres_queue == NULL)
+ del_timer(&net->ipv6.ipmr_expire_timer);
spin_unlock_bh(&mfc_unres_lock);
if (uc) {
- ip6mr_cache_resolve(uc, c);
+ ip6mr_cache_resolve(net, uc, c);
ip6mr_cache_free(uc);
}
return 0;
struct mfc6_cache *c, **cp;
spin_lock_bh(&mfc_unres_lock);
- cp = &mfc_unres_queue;
+ cp = &net->ipv6.mfc6_unres_queue;
while ((c = *cp) != NULL) {
- if (!net_eq(mfc6_net(c), net)) {
- cp = &c->next;
- continue;
- }
*cp = c->next;
- ip6mr_destroy_unres(c);
+ ip6mr_destroy_unres(net, c);
}
spin_unlock_bh(&mfc_unres_lock);
}
* Processing handlers for ip6mr_forward
*/
-static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
+static int ip6mr_forward2(struct net *net, struct sk_buff *skb,
+ struct mfc6_cache *c, int vifi)
{
struct ipv6hdr *ipv6h;
- struct net *net = mfc6_net(c);
struct mif_device *vif = &net->ipv6.vif6_table[vifi];
struct net_device *dev;
struct dst_entry *dst;
IP6CB(skb)->flags |= IP6SKB_FORWARDED;
- return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev,
+ return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
ip6mr_forward2_finish);
out_free:
return ct;
}
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
+static int ip6_mr_forward(struct net *net, struct sk_buff *skb,
+ struct mfc6_cache *cache)
{
int psend = -1;
int vif, ct;
- struct net *net = mfc6_net(cache);
vif = cache->mf6c_parent;
cache->mfc_un.res.pkt++;
if (psend != -1) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2)
- ip6mr_forward2(skb2, cache, psend);
+ ip6mr_forward2(net, skb2, cache, psend);
}
psend = ct;
}
}
if (psend != -1) {
- ip6mr_forward2(skb, cache, psend);
+ ip6mr_forward2(net, skb, cache, psend);
return 0;
}
return -ENODEV;
}
- ip6_mr_forward(skb, cache);
+ ip6_mr_forward(net, skb, cache);
read_unlock(&mrt_lock);
static int
-ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
+ip6mr_fill_mroute(struct net *net, struct sk_buff *skb, struct mfc6_cache *c,
+ struct rtmsg *rtm)
{
int ct;
struct rtnexthop *nhp;
- struct net *net = mfc6_net(c);
u8 *b = skb_tail_pointer(skb);
struct rtattr *mp_head;
if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
cache->mfc_flags |= MFC_NOTIFY;
- err = ip6mr_fill_mroute(skb, cache, rtm);
+ err = ip6mr_fill_mroute(net, skb, cache, rtm);
read_unlock(&mrt_lock);
return err;
}