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