act_mirred.c revision 210d6de78c5d7c785fc532556cea340e517955e1
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/mirred.c	packet mirroring and redirect actions
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		This program is free software; you can redistribute it and/or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		modify it under the terms of the GNU General Public License
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		as published by the Free Software Foundation; either version
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		2 of the License, or (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors:	Jamal Hadi Salim (2002-4)
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: Add ingress support (and socket redirect support)
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
24881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman#include <net/net_namespace.h>
25dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tc_act/tc_mirred.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/tc_act/tc_mirred.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
32e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller#define MIRRED_TAB_MASK     7
33e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
34e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic u32 mirred_idx_gen;
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_RWLOCK(mirred_lock);
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
37e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic struct tcf_hashinfo mirred_hash_info = {
38e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	.htab	=	tcf_mirred_ht,
39e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	.hmask	=	MIRRED_TAB_MASK,
40e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	.lock	=	&mirred_lock,
41e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller};
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic inline int tcf_mirred_release(struct tcf_mirred *m, int bind)
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
45e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	if (m) {
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (bind)
47e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			m->tcf_bindcnt--;
48e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		m->tcf_refcnt--;
49e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
50e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			dev_put(m->tcfm_dev);
51e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			tcf_hash_destroy(&m->common, &mirred_hash_info);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 1;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5853b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardystatic const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
5953b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy	[TCA_MIRRED_PARMS]	= { .len = sizeof(struct tc_mirred) },
6053b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy};
6153b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy
627ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardystatic int tcf_mirred_init(struct nlattr *nla, struct nlattr *est,
63e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			   struct tc_action *a, int ovr, int bind)
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
657ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy	struct nlattr *tb[TCA_MIRRED_MAX + 1];
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_mirred *parm;
67e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	struct tcf_mirred *m;
68e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	struct tcf_common *pc;
69b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	struct net_device *dev;
70b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	int ret, ok_push = 0;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
72cee63723b358e594225e812d6e14a2a0abfd5c88Patrick McHardy	if (nla == NULL)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
74b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy);
75b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	if (ret < 0)
76b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		return ret;
7753b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy	if (tb[TCA_MIRRED_PARMS] == NULL)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
797ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy	parm = nla_data(tb[TCA_MIRRED_PARMS]);
80b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	switch (parm->eaction) {
81b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	case TCA_EGRESS_MIRROR:
82b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	case TCA_EGRESS_REDIR:
83b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		break;
84b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	default:
85b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		return -EINVAL;
86b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	}
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (parm->ifindex) {
88881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman		dev = __dev_get_by_index(&init_net, parm->ifindex);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (dev == NULL)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (dev->type) {
92b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_TUNNEL:
93b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_TUNNEL6:
94b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_SIT:
95b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_IPGRE:
96b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_VOID:
97b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		case ARPHRD_NONE:
98b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao			ok_push = 0;
99b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao			break;
100b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		default:
101b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao			ok_push = 1;
102b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao			break;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
104b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	} else {
105b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		dev = NULL;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info);
109e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	if (!pc) {
110b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		if (dev == NULL)
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
112e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
113e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller				     &mirred_idx_gen, &mirred_hash_info);
1140e991ec6a0340916d3f29bd5dcb35299069e7226Stephen Hemminger		if (IS_ERR(pc))
115b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao			return PTR_ERR(pc);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = ACT_P_CREATED;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ovr) {
119e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			tcf_mirred_release(to_mirred(pc), bind);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EEXIST;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
123e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	m = to_mirred(pc);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
125e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	spin_lock_bh(&m->tcf_lock);
126e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	m->tcf_action = parm->action;
127e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	m->tcfm_eaction = parm->eaction;
128b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao	if (dev != NULL) {
129e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		m->tcfm_ifindex = parm->ifindex;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret != ACT_P_CREATED)
131e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller			dev_put(m->tcfm_dev);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_hold(dev);
133b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao		m->tcfm_dev = dev;
134e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		m->tcfm_ok_push = ok_push;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
136e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	spin_unlock_bh(&m->tcf_lock);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret == ACT_P_CREATED)
138e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		tcf_hash_insert(pc, &mirred_hash_info);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
143e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int tcf_mirred_cleanup(struct tc_action *a, int bind)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	struct tcf_mirred *m = a->priv;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
147e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	if (m)
148e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		return tcf_mirred_release(m, bind);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
152e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
153e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		      struct tcf_result *res)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
155e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	struct tcf_mirred *m = a->priv;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
157feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	struct sk_buff *skb2;
158feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	u32 at;
159feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	int retval, err = 1;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	spin_lock(&m->tcf_lock);
162e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	m->tcf_tm.lastuse = jiffies;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	dev = m->tcfm_dev;
165feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	if (!(dev->flags & IFF_UP)) {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (net_ratelimit())
1676ff9c3644e72bfac20844e0155c2cc8108602820stephen hemminger			pr_notice("tc mirred to Houston: device %s is gone!\n",
1686ff9c3644e72bfac20844e0155c2cc8108602820stephen hemminger				  dev->name);
169feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		goto out;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
172210d6de78c5d7c785fc532556cea340e517955e1Changli Gao	at = G_TC_AT(skb->tc_verd);
173210d6de78c5d7c785fc532556cea340e517955e1Changli Gao	skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb2 == NULL)
175feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		goto out;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1770abf77e55a2459aa9905be4b226e4729d5b4f0cbJussi Kivilinna	m->tcf_bstats.bytes += qdisc_pkt_len(skb2);
178e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	m->tcf_bstats.packets++;
179feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	if (!(at & AT_EGRESS)) {
180e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller		if (m->tcfm_ok_push)
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_push(skb2, skb2->dev->hard_header_len);
182feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* mirror is always swallowed */
185e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1888964be4a9a5ca8cab1219bb046db2f6d1936227cEric Dumazet	skb2->skb_iif = skb->dev->ifindex;
189210d6de78c5d7c785fc532556cea340e517955e1Changli Gao	skb2->dev = dev;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_queue_xmit(skb2);
191feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	err = 0;
192feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao
193feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gaoout:
194feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	if (err) {
195feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		m->tcf_qstats.overlimits++;
196feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		m->tcf_bstats.bytes += qdisc_pkt_len(skb);
197feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		m->tcf_bstats.packets++;
198feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		/* should we be asking for packet to be dropped?
199feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		 * may make sense for redirect case only
200feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		 */
201feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		retval = TC_ACT_SHOT;
202feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	} else {
203feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao		retval = m->tcf_action;
204feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	}
205e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	spin_unlock(&m->tcf_lock);
206feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao
207feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao	return retval;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
210e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
21227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo	unsigned char *b = skb_tail_pointer(skb);
213e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	struct tcf_mirred *m = a->priv;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_mirred opt;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tcf_t t;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.index = m->tcf_index;
218e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.action = m->tcf_action;
219e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.refcnt = m->tcf_refcnt - ref;
220e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.bindcnt = m->tcf_bindcnt - bind;
221e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.eaction = m->tcfm_eaction;
222e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	opt.ifindex = m->tcfm_ifindex;
2237ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy	NLA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt);
224e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install);
225e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse);
226e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	t.expires = jiffies_to_clock_t(m->tcf_tm.expires);
2277ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy	NLA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2307ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardynla_put_failure:
231dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo	nlmsg_trim(skb, b);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tc_action_ops act_mirred_ops = {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.kind		=	"mirred",
237e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller	.hinfo		=	&mirred_hash_info,
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type		=	TCA_ACT_MIRRED,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.capab		=	TCA_CAP_NONE,
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		=	THIS_MODULE,
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.act		=	tcf_mirred,
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dump		=	tcf_mirred_dump,
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cleanup	=	tcf_mirred_cleanup,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lookup		=	tcf_hash_search,
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init		=	tcf_mirred_init,
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.walk		=	tcf_generic_walker
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jamal Hadi Salim(2002)");
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Device Mirror/redirect actions");
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
253e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int __init mirred_init_module(void)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2556ff9c3644e72bfac20844e0155c2cc8108602820stephen hemminger	pr_info("Mirror/redirect action on\n");
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return tcf_register_action(&act_mirred_ops);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
259e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic void __exit mirred_cleanup_module(void)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcf_unregister_action(&act_mirred_ops);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mirred_init_module);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mirred_cleanup_module);
266