Release 4.7 net/sched/act_mirred.c
/*
* net/sched/act_mirred.c packet mirroring and redirect actions
*
* 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.
*
* Authors: Jamal Hadi Salim (2002-4)
*
* TODO: Add ingress support (and socket redirect support)
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <linux/tc_act/tc_mirred.h>
#include <net/tc_act/tc_mirred.h>
#include <linux/if_arp.h>
#define MIRRED_TAB_MASK 7
static LIST_HEAD(mirred_list);
static DEFINE_SPINLOCK(mirred_list_lock);
static void tcf_mirred_release(struct tc_action *a, int bind)
{
struct tcf_mirred *m = to_mirred(a);
struct net_device *dev;
/* We could be called either in a RCU callback or with RTNL lock held. */
spin_lock_bh(&mirred_list_lock);
list_del(&m->tcfm_list);
dev = rcu_dereference_protected(m->tcfm_dev, 1);
if (dev)
dev_put(dev);
spin_unlock_bh(&mirred_list_lock);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
americo wang | americo wang | 37 | 52.86% | 4 | 57.14% |
jamal hadi salim | jamal hadi salim | 15 | 21.43% | 1 | 14.29% |
stephen hemminger | stephen hemminger | 11 | 15.71% | 1 | 14.29% |
eric dumazet | eric dumazet | 7 | 10.00% | 1 | 14.29% |
| Total | 70 | 100.00% | 7 | 100.00% |
static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
[TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) },
};
static int mirred_net_id;
static int tcf_mirred_init(struct net *net, struct nlattr *nla,
struct nlattr *est, struct tc_action *a, int ovr,
int bind)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
struct nlattr *tb[TCA_MIRRED_MAX + 1];
struct tc_mirred *parm;
struct tcf_mirred *m;
struct net_device *dev;
int ret, ok_push = 0, exists = 0;
if (nla == NULL)
return -EINVAL;
ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
if (ret < 0)
return ret;
if (tb[TCA_MIRRED_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_MIRRED_PARMS]);
exists = tcf_hash_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
switch (parm->eaction) {
case TCA_EGRESS_MIRROR:
case TCA_EGRESS_REDIR:
break;
default:
if (exists)
tcf_hash_release(a, bind);
return -EINVAL;
}
if (parm->ifindex) {
dev = __dev_get_by_index(net, parm->ifindex);
if (dev == NULL) {
if (exists)
tcf_hash_release(a, bind);
return -ENODEV;
}
switch (dev->type) {
case ARPHRD_TUNNEL:
case ARPHRD_TUNNEL6:
case ARPHRD_SIT:
case ARPHRD_IPGRE:
case ARPHRD_VOID:
case ARPHRD_NONE:
ok_push = 0;
break;
default:
ok_push = 1;
break;
}
} else {
dev = NULL;
}
if (!exists) {
if (dev == NULL)
return -EINVAL;
ret = tcf_hash_create(tn, parm->index, est, a,
sizeof(*m), bind, true);
if (ret)
return ret;
ret = ACT_P_CREATED;
} else {
tcf_hash_release(a, bind);
if (!ovr)
return -EEXIST;
}
m = to_mirred(a);
ASSERT_RTNL();
m->tcf_action = parm->action;
m->tcfm_eaction = parm->eaction;
if (dev != NULL) {
m->tcfm_ifindex = parm->ifindex;
if (ret != ACT_P_CREATED)
dev_put(rcu_dereference_protected(m->tcfm_dev, 1));
dev_hold(dev);
rcu_assign_pointer(m->tcfm_dev, dev);
m->tcfm_ok_push = ok_push;
}
if (ret == ACT_P_CREATED) {
spin_lock_bh(&mirred_list_lock);
list_add(&m->tcfm_list, &mirred_list);
spin_unlock_bh(&mirred_list_lock);
tcf_hash_insert(tn, a);
}
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 222 | 47.33% | 2 | 9.09% |
patrick mchardy | patrick mchardy | 108 | 23.03% | 7 | 31.82% |
americo wang | americo wang | 43 | 9.17% | 6 | 27.27% |
changli gao | changli gao | 41 | 8.74% | 1 | 4.55% |
david s. miller | david s. miller | 22 | 4.69% | 1 | 4.55% |
stephen hemminger | stephen hemminger | 13 | 2.77% | 1 | 4.55% |
eric dumazet | eric dumazet | 13 | 2.77% | 2 | 9.09% |
benjamin lahaise | benjamin lahaise | 6 | 1.28% | 1 | 4.55% |
eric w. biederman | eric w. biederman | 1 | 0.21% | 1 | 4.55% |
| Total | 469 | 100.00% | 22 | 100.00% |
static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
struct tcf_result *res)
{
struct tcf_mirred *m = a->priv;
struct net_device *dev;
struct sk_buff *skb2;
int retval, err;
u32 at;
tcf_lastuse_update(&m->tcf_tm);
bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb);
rcu_read_lock();
retval = READ_ONCE(m->tcf_action);
dev = rcu_dereference(m->tcfm_dev);
if (unlikely(!dev)) {
pr_notice_once("tc mirred: target device is gone\n");
goto out;
}
if (unlikely(!(dev->flags & IFF_UP))) {
net_notice_ratelimited("tc mirred to Houston: device %s is down\n",
dev->name);
goto out;
}
at = G_TC_AT(skb->tc_verd);
skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2)
goto out;
if (!(at & AT_EGRESS)) {
if (m->tcfm_ok_push)
skb_push_rcsum(skb2, skb->mac_len);
}
/* mirror is always swallowed */
if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
skb2->skb_iif = skb->dev->ifindex;
skb2->dev = dev;
err = dev_queue_xmit(skb2);
if (err) {
out:
qstats_overlimit_inc(this_cpu_ptr(m->common.cpu_qstats));
if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
retval = TC_ACT_SHOT;
}
rcu_read_unlock();
return retval;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 123 | 45.05% | 2 | 9.52% |
changli gao | changli gao | 52 | 19.05% | 3 | 14.29% |
eric dumazet | eric dumazet | 48 | 17.58% | 4 | 19.05% |
stephen hemminger | stephen hemminger | 15 | 5.49% | 1 | 4.76% |
patrick mchardy | patrick mchardy | 13 | 4.76% | 5 | 23.81% |
david s. miller | david s. miller | 9 | 3.30% | 1 | 4.76% |
jason wang | jason wang | 8 | 2.93% | 1 | 4.76% |
herbert xu | herbert xu | 2 | 0.73% | 1 | 4.76% |
americo wang | americo wang | 1 | 0.37% | 1 | 4.76% |
joe perches | joe perches | 1 | 0.37% | 1 | 4.76% |
florian westphal | florian westphal | 1 | 0.37% | 1 | 4.76% |
| Total | 273 | 100.00% | 21 | 100.00% |
static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
{
unsigned char *b = skb_tail_pointer(skb);
struct tcf_mirred *m = a->priv;
struct tc_mirred opt = {
.index = m->tcf_index,
.action = m->tcf_action,
.refcnt = m->tcf_refcnt - ref,
.bindcnt = m->tcf_bindcnt - bind,
.eaction = m->tcfm_eaction,
.ifindex = m->tcfm_ifindex,
};
struct tcf_t t;
if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt))
goto nla_put_failure;
t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD))
goto nla_put_failure;
return skb->len;
nla_put_failure:
nlmsg_trim(skb, b);
return -1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 130 | 65.00% | 1 | 9.09% |
david s. miller | david s. miller | 38 | 19.00% | 2 | 18.18% |
eric dumazet | eric dumazet | 13 | 6.50% | 1 | 9.09% |
patrick mchardy | patrick mchardy | 12 | 6.00% | 4 | 36.36% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 4 | 2.00% | 2 | 18.18% |
nicolas dichtel | nicolas dichtel | 3 | 1.50% | 1 | 9.09% |
| Total | 200 | 100.00% | 11 | 100.00% |
static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
struct netlink_callback *cb, int type,
struct tc_action *a)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tcf_generic_walker(tn, skb, cb, type, a);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
americo wang | americo wang | 55 | 100.00% | 1 | 100.00% |
| Total | 55 | 100.00% | 1 | 100.00% |
static int tcf_mirred_search(struct net *net, struct tc_action *a, u32 index)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tcf_hash_search(tn, a, index);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
americo wang | americo wang | 41 | 100.00% | 1 | 100.00% |
| Total | 41 | 100.00% | 1 | 100.00% |
static int mirred_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct tcf_mirred *m;
ASSERT_RTNL();
if (event == NETDEV_UNREGISTER) {
spin_lock_bh(&mirred_list_lock);
list_for_each_entry(m, &mirred_list, tcfm_list) {
if (rcu_access_pointer(m->tcfm_dev) == dev) {
dev_put(dev);
/* Note : no rcu grace period necessary, as
* net_device are already rcu protected.
*/
RCU_INIT_POINTER(m->tcfm_dev, NULL);
}
}
spin_unlock_bh(&mirred_list_lock);
}
return NOTIFY_DONE;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
stephen hemminger | stephen hemminger | 68 | 69.39% | 1 | 20.00% |
americo wang | americo wang | 14 | 14.29% | 1 | 20.00% |
eric dumazet | eric dumazet | 11 | 11.22% | 1 | 20.00% |
jiri pirko | jiri pirko | 3 | 3.06% | 1 | 20.00% |
cong wang | cong wang | 2 | 2.04% | 1 | 20.00% |
| Total | 98 | 100.00% | 5 | 100.00% |
static struct notifier_block mirred_device_notifier = {
.notifier_call = mirred_device_event,
};
static struct tc_action_ops act_mirred_ops = {
.kind = "mirred",
.type = TCA_ACT_MIRRED,
.owner = THIS_MODULE,
.act = tcf_mirred,
.dump = tcf_mirred_dump,
.cleanup = tcf_mirred_release,
.init = tcf_mirred_init,
.walk = tcf_mirred_walker,
.lookup = tcf_mirred_search,
};
static __net_init int mirred_init_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
americo wang | americo wang | 35 | 100.00% | 1 | 100.00% |
| Total | 35 | 100.00% | 1 | 100.00% |
static void __net_exit mirred_exit_net(struct net *net)
{
struct tc_action_net *tn = net_generic(net, mirred_net_id);
tc_action_net_exit(tn);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
americo wang | americo wang | 29 | 100.00% | 1 | 100.00% |
| Total | 29 | 100.00% | 1 | 100.00% |
static struct pernet_operations mirred_net_ops = {
.init = mirred_init_net,
.exit = mirred_exit_net,
.id = &mirred_net_id,
.size = sizeof(struct tc_action_net),
};
MODULE_AUTHOR("Jamal Hadi Salim(2002)");
MODULE_DESCRIPTION("Device Mirror/redirect actions");
MODULE_LICENSE("GPL");
static int __init mirred_init_module(void)
{
int err = register_netdevice_notifier(&mirred_device_notifier);
if (err)
return err;
pr_info("Mirror/redirect action on\n");
return tcf_register_action(&act_mirred_ops, &mirred_net_ops);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 20 | 50.00% | 1 | 20.00% |
stephen hemminger | stephen hemminger | 17 | 42.50% | 2 | 40.00% |
americo wang | americo wang | 3 | 7.50% | 2 | 40.00% |
| Total | 40 | 100.00% | 5 | 100.00% |
static void __exit mirred_cleanup_module(void)
{
tcf_unregister_action(&act_mirred_ops, &mirred_net_ops);
unregister_netdevice_notifier(&mirred_device_notifier);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 13 | 54.17% | 1 | 25.00% |
americo wang | americo wang | 7 | 29.17% | 2 | 50.00% |
stephen hemminger | stephen hemminger | 4 | 16.67% | 1 | 25.00% |
| Total | 24 | 100.00% | 4 | 100.00% |
module_init(mirred_init_module);
module_exit(mirred_cleanup_module);
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jamal hadi salim | jamal hadi salim | 628 | 40.54% | 4 | 7.69% |
americo wang | americo wang | 318 | 20.53% | 10 | 19.23% |
patrick mchardy | patrick mchardy | 161 | 10.39% | 11 | 21.15% |
stephen hemminger | stephen hemminger | 145 | 9.36% | 2 | 3.85% |
changli gao | changli gao | 93 | 6.00% | 4 | 7.69% |
eric dumazet | eric dumazet | 92 | 5.94% | 6 | 11.54% |
david s. miller | david s. miller | 71 | 4.58% | 2 | 3.85% |
jason wang | jason wang | 8 | 0.52% | 1 | 1.92% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 7 | 0.45% | 2 | 3.85% |
benjamin lahaise | benjamin lahaise | 6 | 0.39% | 1 | 1.92% |
eric w. biederman | eric w. biederman | 4 | 0.26% | 1 | 1.92% |
jiri pirko | jiri pirko | 4 | 0.26% | 2 | 3.85% |
nicolas dichtel | nicolas dichtel | 3 | 0.19% | 1 | 1.92% |
tejun heo | tejun heo | 3 | 0.19% | 1 | 1.92% |
cong wang | cong wang | 2 | 0.13% | 1 | 1.92% |
herbert xu | herbert xu | 2 | 0.13% | 1 | 1.92% |
joe perches | joe perches | 1 | 0.06% | 1 | 1.92% |
florian westphal | florian westphal | 1 | 0.06% | 1 | 1.92% |
| Total | 1549 | 100.00% | 52 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.