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 333b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemmingerstatic LIST_HEAD(mirred_list); 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35a5b5c958ffd1610545d6b4b8290aa9c5266d10faWANG Congstatic void tcf_mirred_release(struct tc_action *a, int bind) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3786062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong struct tcf_mirred *m = to_mirred(a); 38a5b5c958ffd1610545d6b4b8290aa9c5266d10faWANG Cong list_del(&m->tcfm_list); 39a5b5c958ffd1610545d6b4b8290aa9c5266d10faWANG Cong if (m->tcfm_dev) 40a5b5c958ffd1610545d6b4b8290aa9c5266d10faWANG Cong dev_put(m->tcfm_dev); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4353b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardystatic const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { 4453b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) }, 4553b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy}; 4653b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy 47c1b52739e45f5969b208ebc377f52468280af11eBenjamin LaHaisestatic int tcf_mirred_init(struct net *net, struct nlattr *nla, 48c1b52739e45f5969b208ebc377f52468280af11eBenjamin LaHaise struct nlattr *est, struct tc_action *a, int ovr, 49c1b52739e45f5969b208ebc377f52468280af11eBenjamin LaHaise int bind) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 517ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy struct nlattr *tb[TCA_MIRRED_MAX + 1]; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_mirred *parm; 53e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller struct tcf_mirred *m; 54b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao struct net_device *dev; 55b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao int ret, ok_push = 0; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57cee63723b358e594225e812d6e14a2a0abfd5c88Patrick McHardy if (nla == NULL) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 59b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao ret = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); 60b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao if (ret < 0) 61b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao return ret; 6253b2bf3f8a652c9c8e86831f94ae2c5767ea54d7Patrick McHardy if (tb[TCA_MIRRED_PARMS] == NULL) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 647ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardy parm = nla_data(tb[TCA_MIRRED_PARMS]); 65b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao switch (parm->eaction) { 66b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case TCA_EGRESS_MIRROR: 67b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case TCA_EGRESS_REDIR: 68b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao break; 69b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao default: 70b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao return -EINVAL; 71b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao } 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (parm->ifindex) { 73c1b52739e45f5969b208ebc377f52468280af11eBenjamin LaHaise dev = __dev_get_by_index(net, parm->ifindex); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev == NULL) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dev->type) { 77b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_TUNNEL: 78b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_TUNNEL6: 79b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_SIT: 80b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_IPGRE: 81b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_VOID: 82b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao case ARPHRD_NONE: 83b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao ok_push = 0; 84b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao break; 85b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao default: 86b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao ok_push = 1; 87b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao break; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 89b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao } else { 90b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao dev = NULL; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9386062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong if (!tcf_hash_check(parm->index, a, bind)) { 94b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao if (dev == NULL) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9686062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong ret = tcf_hash_create(parm->index, est, a, sizeof(*m), bind); 9786062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong if (ret) 9886062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong return ret; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ACT_P_CREATED; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ovr) { 102a5b5c958ffd1610545d6b4b8290aa9c5266d10faWANG Cong tcf_hash_release(a, bind); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10686062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong m = to_mirred(a); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller spin_lock_bh(&m->tcf_lock); 109e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller m->tcf_action = parm->action; 110e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller m->tcfm_eaction = parm->eaction; 111b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao if (dev != NULL) { 112e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller m->tcfm_ifindex = parm->ifindex; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret != ACT_P_CREATED) 114e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller dev_put(m->tcfm_dev); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_hold(dev); 116b76965e02bfdd4164c00bf946ff6ca1818ed9fcdChangli Gao m->tcfm_dev = dev; 117e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller m->tcfm_ok_push = ok_push; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 119e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller spin_unlock_bh(&m->tcf_lock); 1203b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger if (ret == ACT_P_CREATED) { 1213b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger list_add(&m->tcfm_list, &mirred_list); 12286062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong tcf_hash_insert(a); 1233b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger } 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128dc7f9f6e8838556f226c2ebd1da7bb305cb25654Eric Dumazetstatic int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, 129e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller struct tcf_result *res) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 131e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller struct tcf_mirred *m = a->priv; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 133feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao struct sk_buff *skb2; 134feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao u32 at; 135feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao int retval, err = 1; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 137e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller spin_lock(&m->tcf_lock); 138e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller m->tcf_tm.lastuse = jiffies; 139bfe0d0298f2a67d94d58c39ea904a999aeeb7c3cEric Dumazet bstats_update(&m->tcf_bstats, skb); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao dev = m->tcfm_dev; 1423b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger if (!dev) { 1433b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); 1443b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger goto out; 1453b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger } 1463b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 147feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao if (!(dev->flags & IFF_UP)) { 148e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches net_notice_ratelimited("tc mirred to Houston: device %s is down\n", 149e87cc4728f0e2fb663e592a1141742b1d6c63256Joe Perches dev->name); 150feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao goto out; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 153210d6de78c5d7c785fc532556cea340e517955e1Changli Gao at = G_TC_AT(skb->tc_verd); 154210d6de78c5d7c785fc532556cea340e517955e1Changli Gao skb2 = skb_act_clone(skb, GFP_ATOMIC, m->tcf_action); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb2 == NULL) 156feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao goto out; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 158feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao if (!(at & AT_EGRESS)) { 159e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller if (m->tcfm_ok_push) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb2, skb2->dev->hard_header_len); 161feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* mirror is always swallowed */ 164e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller if (m->tcfm_eaction != TCA_EGRESS_MIRROR) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1678964be4a9a5ca8cab1219bb046db2f6d1936227cEric Dumazet skb2->skb_iif = skb->dev->ifindex; 168210d6de78c5d7c785fc532556cea340e517955e1Changli Gao skb2->dev = dev; 1698919bc13e8d92c5b082c5c0321567383a071f5bcJamal Hadi Salim err = dev_queue_xmit(skb2); 170feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao 171feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gaoout: 172feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao if (err) { 173feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao m->tcf_qstats.overlimits++; 17416c0b164bd24d44db137693a36b428ba28970c62Jason Wang if (m->tcfm_eaction != TCA_EGRESS_MIRROR) 17516c0b164bd24d44db137693a36b428ba28970c62Jason Wang retval = TC_ACT_SHOT; 17616c0b164bd24d44db137693a36b428ba28970c62Jason Wang else 17716c0b164bd24d44db137693a36b428ba28970c62Jason Wang retval = m->tcf_action; 17816c0b164bd24d44db137693a36b428ba28970c62Jason Wang } else 179feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao retval = m->tcf_action; 180e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller spin_unlock(&m->tcf_lock); 181feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao 182feed1f17241d26261e77ddb5f2fc2a91a3c16739Changli Gao return retval; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18727a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo unsigned char *b = skb_tail_pointer(skb); 188e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller struct tcf_mirred *m = a->priv; 1891c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet struct tc_mirred opt = { 1901c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .index = m->tcf_index, 1911c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .action = m->tcf_action, 1921c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .refcnt = m->tcf_refcnt - ref, 1931c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .bindcnt = m->tcf_bindcnt - bind, 1941c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .eaction = m->tcfm_eaction, 1951c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet .ifindex = m->tcfm_ifindex, 1961c40be12f7d8ca1d387510d39787b12e512a7ce8Eric Dumazet }; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tcf_t t; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt)) 2001b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 201e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller t.install = jiffies_to_clock_t(jiffies - m->tcf_tm.install); 202e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller t.lastuse = jiffies_to_clock_t(jiffies - m->tcf_tm.lastuse); 203e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Miller t.expires = jiffies_to_clock_t(m->tcf_tm.expires); 2041b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_MIRRED_TM, sizeof(t), &t)) 2051b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb->len; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2087ba699c604ab811972eee2e041fd6b07659a2e6ePatrick McHardynla_put_failure: 209dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo nlmsg_trim(skb, b); 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2133b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemmingerstatic int mirred_device_event(struct notifier_block *unused, 2143b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger unsigned long event, void *ptr) 2153b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger{ 216351638e7deeed2ec8ce451b53d33921b3da68f83Jiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 2173b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger struct tcf_mirred *m; 2183b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 2193b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger if (event == NETDEV_UNREGISTER) 2203b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger list_for_each_entry(m, &mirred_list, tcfm_list) { 221224e923cd9b001c612b7b68933264156271722f9Cong Wang spin_lock_bh(&m->tcf_lock); 2223b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger if (m->tcfm_dev == dev) { 2233b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger dev_put(dev); 2243b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger m->tcfm_dev = NULL; 2253b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger } 226224e923cd9b001c612b7b68933264156271722f9Cong Wang spin_unlock_bh(&m->tcf_lock); 2273b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger } 2283b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 2293b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger return NOTIFY_DONE; 2303b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger} 2313b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 2323b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemmingerstatic struct notifier_block mirred_device_notifier = { 2333b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger .notifier_call = mirred_device_event, 2343b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger}; 2353b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tc_action_ops act_mirred_ops = { 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .kind = "mirred", 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = TCA_ACT_MIRRED, 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .act = tcf_mirred, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dump = tcf_mirred_dump, 24286062033feb8a1692f7a3d570c652f1b4a4b4b52WANG Cong .cleanup = tcf_mirred_release, 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = tcf_mirred_init, 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jamal Hadi Salim(2002)"); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Device Mirror/redirect actions"); 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 250e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic int __init mirred_init_module(void) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2523b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger int err = register_netdevice_notifier(&mirred_device_notifier); 2533b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger if (err) 2543b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger return err; 2553b87956ea645fb4de7e59c7d0aa94de04be72615stephen hemminger 2566ff9c3644e72bfac20844e0155c2cc8108602820stephen hemminger pr_info("Mirror/redirect action on\n"); 2574f1e9d8949b438c7791993515fc164312e9080e2WANG Cong return tcf_register_action(&act_mirred_ops, MIRRED_TAB_MASK); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260e9ce1cd3cf6cf35b21d0ce990f2e738f35907386David S. Millerstatic void __exit mirred_cleanup_module(void) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tcf_unregister_action(&act_mirred_ops); 263568a153a22d8f338a5ebda70e6bd139f6d8bb2c3WANG Cong unregister_netdevice_notifier(&mirred_device_notifier); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mirred_init_module); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mirred_cleanup_module); 268