Release 4.11 net/ipv6/ip6mr.c
/*
* Linux IPv6 multicast routing support for BSD pim6sd
* Based on net/ipv4/ipmr.c.
*
* (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr>
* LSIIT Laboratory, Strasbourg, France
* (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com>
* 6WIND, Paris, France
* Copyright (C)2007,2008 USAGI/WIDE Project
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <net/protocol.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/raw.h>
#include <linux/notifier.h>
#include <linux/if_arp.h>
#include <net/checksum.h>
#include <net/netlink.h>
#include <net/fib_rules.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <linux/mroute6.h>
#include <linux/pim.h>
#include <net/addrconf.h>
#include <linux/netfilter_ipv6.h>
#include <linux/export.h>
#include <net/ip6_checksum.h>
#include <linux/netconf.h>
struct mr6_table {
struct list_head list;
possible_net_t net;
u32 id;
struct sock *mroute6_sk;
struct timer_list ipmr_expire_timer;
struct list_head mfc6_unres_queue;
struct list_head mfc6_cache_array[MFC6_LINES];
struct mif_device vif6_table[MAXMIFS];
int maxvif;
atomic_t cache_resolve_queue_len;
bool mroute_do_assert;
bool mroute_do_pim;
#ifdef CONFIG_IPV6_PIMSM_V2
int mroute_reg_vif_num;
#endif
};
struct ip6mr_rule {
struct fib_rule common;
};
struct ip6mr_result {
struct mr6_table *mrt;
};
/* Big lock, protecting vif table, mrt cache and mroute socket state.
Note that the changes are semaphored via rtnl_lock.
*/
static DEFINE_RWLOCK(mrt_lock);
/*
* Multicast router control variables
*/
#define MIF_EXISTS(_mrt, _idx) ((_mrt)->vif6_table[_idx].dev != NULL)
/* Special spinlock for queue of unresolved entries */
static DEFINE_SPINLOCK(mfc_unres_lock);
/* We return to original Alan's scheme. Hash table of resolved
entries is changed only in process context and protected
with weak lock mrt_lock. Queue of unresolved entries is protected
with strong spinlock mfc_unres_lock.
In this case data path is free of exclusive locks at all.
*/
static struct kmem_cache *mrt_cachep __read_mostly;
static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
static void ip6mr_free_table(struct mr6_table *mrt);
static void ip6_mr_forward(struct net *net, struct mr6_table *mrt,
struct sk_buff *skb, struct mfc6_cache *cache);
static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
mifi_t mifi, int assert);
static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
struct mfc6_cache *c, struct rtmsg *rtm);
static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
int cmd);
static int ip6mr_rtm_dumproute(struct sk_buff *skb,
struct netlink_callback *cb);
static void mroute_clean_tables(struct mr6_table *mrt, bool all);
static void ipmr_expire_process(unsigned long arg);
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
#define ip6mr_for_each_table(mrt, net) \
list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
{
struct mr6_table *mrt;
ip6mr_for_each_table(mrt, net) {
if (mrt->id == id)
return mrt;
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 43 | 100.00% | 1 | 100.00% |
Total | 43 | 100.00% | 1 | 100.00% |
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
struct mr6_table **mrt)
{
int err;
struct ip6mr_result res;
struct fib_lookup_arg arg = {
.result = &res,
.flags = FIB_LOOKUP_NOREF,
};
err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
flowi6_to_flowi(flp6), 0, &arg);
if (err < 0)
return err;
*mrt = res.mrt;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 71 | 82.56% | 1 | 33.33% |
Hannes Frederic Sowa | 9 | 10.47% | 1 | 33.33% |
David S. Miller | 6 | 6.98% | 1 | 33.33% |
Total | 86 | 100.00% | 3 | 100.00% |
static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
int flags, struct fib_lookup_arg *arg)
{
struct ip6mr_result *res = arg->result;
struct mr6_table *mrt;
switch (rule->action) {
case FR_ACT_TO_TBL:
break;
case FR_ACT_UNREACHABLE:
return -ENETUNREACH;
case FR_ACT_PROHIBIT:
return -EACCES;
case FR_ACT_BLACKHOLE:
default:
return -EINVAL;
}
mrt = ip6mr_get_table(rule->fr_net, rule->table);
if (!mrt)
return -EAGAIN;
res->mrt = mrt;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 102 | 99.03% | 1 | 50.00% |
Ian Morris | 1 | 0.97% | 1 | 50.00% |
Total | 103 | 100.00% | 2 | 100.00% |
static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
{
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
FRA_GENERIC_POLICY,
};
static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh, struct nlattr **tb)
{
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 30 | 100.00% | 1 | 100.00% |
Total | 30 | 100.00% | 1 | 100.00% |
static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
struct nlattr **tb)
{
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 25 | 100.00% | 1 | 100.00% |
Total | 25 | 100.00% | 1 | 100.00% |
static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
struct fib_rule_hdr *frh)
{
frh->dst_len = 0;
frh->src_len = 0;
frh->tos = 0;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 42 | 100.00% | 1 | 100.00% |
Total | 42 | 100.00% | 1 | 100.00% |
static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = {
.family = RTNL_FAMILY_IP6MR,
.rule_size = sizeof(struct ip6mr_rule),
.addr_size = sizeof(struct in6_addr),
.action = ip6mr_rule_action,
.match = ip6mr_rule_match,
.configure = ip6mr_rule_configure,
.compare = ip6mr_rule_compare,
.fill = ip6mr_rule_fill,
.nlgroup = RTNLGRP_IPV6_RULE,
.policy = ip6mr_rule_policy,
.owner = THIS_MODULE,
};
static int __net_init ip6mr_rules_init(struct net *net)
{
struct fib_rules_ops *ops;
struct mr6_table *mrt;
int err;
ops = fib_rules_register(&ip6mr_rules_ops_template, net);
if (IS_ERR(ops))
return PTR_ERR(ops);
INIT_LIST_HEAD(&net->ipv6.mr6_tables);
mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
if (!mrt) {
err = -ENOMEM;
goto err1;
}
err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
if (err < 0)
goto err2;
net->ipv6.mr6_rules_ops = ops;
return 0;
err2:
ip6mr_free_table(mrt);
err1:
fib_rules_unregister(ops);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 130 | 98.48% | 1 | 33.33% |
Ian Morris | 1 | 0.76% | 1 | 33.33% |
Américo Wang | 1 | 0.76% | 1 | 33.33% |
Total | 132 | 100.00% | 3 | 100.00% |
static void __net_exit ip6mr_rules_exit(struct net *net)
{
struct mr6_table *mrt, *next;
rtnl_lock();
list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
list_del(&mrt->list);
ip6mr_free_table(mrt);
}
fib_rules_unregister(net->ipv6.mr6_rules_ops);
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 44 | 73.33% | 1 | 25.00% |
Eric Dumazet | 10 | 16.67% | 1 | 25.00% |
Américo Wang | 3 | 5.00% | 1 | 25.00% |
Hannes Frederic Sowa | 3 | 5.00% | 1 | 25.00% |
Total | 60 | 100.00% | 4 | 100.00% |
#else
#define ip6mr_for_each_table(mrt, net) \
for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
{
return net->ipv6.mrt6;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
struct mr6_table **mrt)
{
*mrt = net->ipv6.mrt6;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 32 | 94.12% | 1 | 50.00% |
David S. Miller | 2 | 5.88% | 1 | 50.00% |
Total | 34 | 100.00% | 2 | 100.00% |
static int __net_init ip6mr_rules_init(struct net *net)
{
net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
return net->ipv6.mrt6 ? 0 : -ENOMEM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 37 | 100.00% | 1 | 100.00% |
Total | 37 | 100.00% | 1 | 100.00% |
static void __net_exit ip6mr_rules_exit(struct net *net)
{
rtnl_lock();
ip6mr_free_table(net->ipv6.mrt6);
net->ipv6.mrt6 = NULL;
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 21 | 60.00% | 1 | 50.00% |
Hannes Frederic Sowa | 14 | 40.00% | 1 | 50.00% |
Total | 35 | 100.00% | 2 | 100.00% |
#endif
static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
{
struct mr6_table *mrt;
unsigned int i;
mrt = ip6mr_get_table(net, id);
if (mrt)
return mrt;
mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
if (!mrt)
return NULL;
mrt->id = id;
write_pnet(&mrt->net, net);
/* Forwarding cache */
for (i = 0; i < MFC6_LINES; i++)
INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
(unsigned long)mrt);
#ifdef CONFIG_IPV6_PIMSM_V2
mrt->mroute_reg_vif_num = -1;
#endif
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
#endif
return mrt;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 161 | 99.38% | 1 | 50.00% |
Ian Morris | 1 | 0.62% | 1 | 50.00% |
Total | 162 | 100.00% | 2 | 100.00% |
static void ip6mr_free_table(struct mr6_table *mrt)
{
del_timer_sync(&mrt->ipmr_expire_timer);
mroute_clean_tables(mrt, true);
kfree(mrt);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 28 | 90.32% | 2 | 50.00% |
Nikolay Aleksandrov | 2 | 6.45% | 1 | 25.00% |
Américo Wang | 1 | 3.23% | 1 | 25.00% |
Total | 31 | 100.00% | 4 | 100.00% |
#ifdef CONFIG_PROC_FS
struct ipmr_mfc_iter {
struct seq_net_private p;
struct mr6_table *mrt;
struct list_head *cache;
int ct;
};
static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
struct ipmr_mfc_iter *it, loff_t pos)
{
struct mr6_table *mrt = it->mrt;
struct mfc6_cache *mfc;
read_lock(&mrt_lock);
for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
it->cache = &mrt->mfc6_cache_array[it->ct];
list_for_each_entry(mfc, it->cache, list)
if (pos-- == 0)
return mfc;
}
read_unlock(&mrt_lock);
spin_lock_bh(&mfc_unres_lock);
it->cache = &mrt->mfc6_unres_queue;
list_for_each_entry(mfc, it->cache, list)
if (pos-- == 0)
return mfc;
spin_unlock_bh(&mfc_unres_lock);
it->cache = NULL;
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 101 | 68.24% | 1 | 14.29% |
Patrick McHardy | 40 | 27.03% | 4 | 57.14% |
Benjamin Thery | 7 | 4.73% | 2 | 28.57% |
Total | 148 | 100.00% | 7 | 100.00% |
/*
* The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
*/
struct ipmr_vif_iter {
struct seq_net_private p;
struct mr6_table *mrt;
int ct;
};
static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
struct ipmr_vif_iter *iter,
loff_t pos)
{
struct mr6_table *mrt = iter->mrt;
for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
if (!MIF_EXISTS(mrt, iter->ct))
continue;
if (pos-- == 0)
return &mrt->vif6_table[iter->ct];
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 67 | 77.01% | 1 | 20.00% |
Patrick McHardy | 12 | 13.79% | 2 | 40.00% |
Benjamin Thery | 8 | 9.20% | 2 | 40.00% |
Total | 87 | 100.00% | 5 | 100.00% |
static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
__acquires
(mrt_lock)
{
struct ipmr_vif_iter *iter = seq->private;
struct net *net = seq_file_net(seq);
struct mr6_table *mrt;
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
if (!mrt)
return ERR_PTR(-ENOENT);
iter->mrt = mrt;
read_lock(&mrt_lock);
return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 44 | 45.36% | 1 | 25.00% |
Patrick McHardy | 40 | 41.24% | 1 | 25.00% |
Benjamin Thery | 12 | 12.37% | 1 | 25.00% |
Ian Morris | 1 | 1.03% | 1 | 25.00% |
Total | 97 | 100.00% | 4 | 100.00% |
static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ipmr_vif_iter *iter = seq->private;
struct net *net = seq_file_net(seq);
struct mr6_table *mrt = iter->mrt;
++*pos;
if (v == SEQ_START_TOKEN)
return ip6mr_vif_seq_idx(net, iter, 0);
while (++iter->ct < mrt->maxvif) {
if (!MIF_EXISTS(mrt, iter->ct))
continue;
return &mrt->vif6_table[iter->ct];
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 81 | 75.00% | 1 | 20.00% |
Benjamin Thery | 15 | 13.89% | 2 | 40.00% |
Patrick McHardy | 12 | 11.11% | 2 | 40.00% |
Total | 108 | 100.00% | 5 | 100.00% |
static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
__releases
(mrt_lock)
{
read_unlock(&mrt_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 25 | 100.00% | 1 | 100.00% |
Total | 25 | 100.00% | 1 | 100.00% |
static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
{
struct ipmr_vif_iter *iter = seq->private;
struct mr6_table *mrt = iter->mrt;
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
"Interface BytesIn PktsIn BytesOut PktsOut Flags\n");
} else {
const struct mif_device *vif = v;
const char *name = vif->dev ? vif->dev->name : "none";
seq_printf(seq,
"%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
vif - mrt->vif6_table,
name, vif->bytes_in, vif->pkt_in,
vif->bytes_out, vif->pkt_out,
vif->flags);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 93 | 81.58% | 1 | 20.00% |
Patrick McHardy | 14 | 12.28% | 2 | 40.00% |
Benjamin Thery | 6 | 5.26% | 1 | 20.00% |
Al Viro | 1 | 0.88% | 1 | 20.00% |
Total | 114 | 100.00% | 5 | 100.00% |
static const struct seq_operations ip6mr_vif_seq_ops = {
.start = ip6mr_vif_seq_start,
.next = ip6mr_vif_seq_next,
.stop = ip6mr_vif_seq_stop,
.show = ip6mr_vif_seq_show,
};
static int ip6mr_vif_open(struct inode *inode, struct file *file)
{
return seq_open_net(inode, file, &ip6mr_vif_seq_ops,
sizeof(struct ipmr_vif_iter));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 30 | 90.91% | 1 | 50.00% |
Benjamin Thery | 3 | 9.09% | 1 | 50.00% |
Total | 33 | 100.00% | 2 | 100.00% |
static const struct file_operations ip6mr_vif_fops = {
.owner = THIS_MODULE,
.open = ip6mr_vif_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_net,
};
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 mr6_table *mrt;
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
if (!mrt)
return ERR_PTR(-ENOENT);
it->mrt = mrt;
return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
: SEQ_START_TOKEN;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick McHardy | 40 | 45.98% | 1 | 25.00% |
Hideaki Yoshifuji / 吉藤英明 | 34 | 39.08% | 1 | 25.00% |
Benjamin Thery | 12 | 13.79% | 1 | 25.00% |
Ian Morris | 1 | 1.15% | 1 | 25.00% |
Total | 87 | 100.00% | 4 | 100.00% |
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 mr6_table *mrt = it->mrt;
++*pos;
if (v == SEQ_START_TOKEN)
return ipmr_mfc_seq_idx(net, seq->private, 0);
if (mfc->list.next != it->cache)
return list_entry(mfc->list.next, struct mfc6_cache, list);
if (it->cache == &mrt->mfc6_unres_queue)
goto end_of_list;
BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
while (++it->ct < MFC6_LINES) {
it->cache = &mrt->mfc6_cache_array[it->ct];
if (list_empty(it->cache))
continue;
return list_first_entry(it->cache, struct mfc6_cache, list);
}
/* exhausted cache_array, show unresolved */
read_unlock(&mrt_lock);
it->cache = &mrt->mfc6_unres_queue;
it->ct = 0;
spin_lock_bh(&mfc_unres_lock);
if (!list_empty(it->cache))
return list_first_entry(it->cache, struct mfc6_cache, list);
end_of_list:
spin_unlock_bh(&mfc_unres_lock);
it->cache = NULL;
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 157 | 62.55% | 1 | 14.29% |
Patrick McHardy | 79 | 31.47% | 4 | 57.14% |
Benjamin Thery | 15 | 5.98% | 2 | 28.57% |
Total | 251 | 100.00% | 7 | 100.00% |
static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
{
struct ipmr_mfc_iter *it = seq->private;
struct mr6_table *mrt = it->mrt;
if (it->cache == &mrt->mfc6_unres_queue)
spin_unlock_bh(&mfc_unres_lock);
else if (it->cache == &mrt->mfc6_cache_array[it->ct])
read_unlock(&mrt_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 53 | 72.60% | 1 | 16.67% |
Patrick McHardy | 12 | 16.44% | 3 | 50.00% |
Richard Laing | 6 | 8.22% | 1 | 16.67% |
Benjamin Thery | 2 | 2.74% | 1 | 16.67% |
Total | 73 | 100.00% | 6 | 100.00% |
static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
{
int n;
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
"Group "
"Origin "
"Iif Pkts Bytes Wrong Oifs\n");
} else {
const struct mfc6_cache *mfc = v;
const struct ipmr_mfc_iter *it = seq->private;
struct mr6_table *mrt = it->mrt;
seq_printf(seq, "%pI6 %pI6 %-3hd",
&mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
mfc->mf6c_parent);
if (it->cache != &mrt->mfc6_unres_queue) {
seq_printf(seq, " %8lu %8lu %8lu",
mfc->mfc_un.res.pkt,
mfc->mfc_un.res.bytes,
mfc->mfc_un.res.wrong_if);
for (n = mfc->mfc_un.res.minvif;
n < mfc->mfc_un.res.maxvif; n++) {
if (MIF_EXISTS(mrt, n) &&
mfc->mfc_un.res.ttls[n] < 255)
seq_printf(seq,
" %2d:%-3d",
n, mfc->mfc_un.res.ttls[n]);
}
} else {
/* unresolved mfc_caches don't contain
* pkt, bytes and wrong_if values
*/
seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
}
seq_putc(seq, '\n');
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 176 | 77.88% | 1 | 12.50% |
Benjamin Thery | 35 | 15.49% | 3 | 37.50% |
Patrick McHardy | 13 | 5.75% | 3 | 37.50% |
Harvey Harrison | 2 | 0.88% | 1 | 12.50% |
Total | 226 | 100.00% | 8 | 100.00% |
static const struct seq_operations ipmr_mfc_seq_ops = {
.start = ipmr_mfc_seq_start,
.next = ipmr_mfc_seq_next,
.stop = ipmr_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));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Hideaki Yoshifuji / 吉藤英明 | 30 | 90.91% | 1 | 50.00% |
Benjamin Thery | 3 | 9.09% | 1 | 50.00% |
Total | 33 | 100.00% | 2 | 100.00% |
static const struct file_operations ip6mr_mfc_fops = {
.owner = THIS_MODULE,
.open = ipmr_mfc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_net,
};
#endif
#ifdef CONFIG_IPV6_PIMSM_V2
static int pim6_rcv(struct sk_buff *skb)
{
struct pimreghdr *pim;
struct ipv6hdr *encap;
struct net_device *reg_dev = NULL;
struct net *net = dev_net(skb->dev);
struct mr6_table *mrt;
struct flowi6 fl6 = {
.flowi6_iif = skb->dev->ifindex,
.flowi6_mark = skb->mark,
};
int reg_vif_num;
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
goto drop;
pim = (struct pimreghdr *)skb_transport_header(skb);
if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER)