Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.15-rc7 276 lines 6.6 kB view raw
1/* 2 * net/sched/mirred.c packet mirroring and redirect actions 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Jamal Hadi Salim (2002-4) 10 * 11 * TODO: Add ingress support (and socket redirect support) 12 * 13 */ 14 15#include <asm/uaccess.h> 16#include <asm/system.h> 17#include <asm/bitops.h> 18#include <linux/config.h> 19#include <linux/types.h> 20#include <linux/kernel.h> 21#include <linux/sched.h> 22#include <linux/string.h> 23#include <linux/mm.h> 24#include <linux/socket.h> 25#include <linux/sockios.h> 26#include <linux/in.h> 27#include <linux/errno.h> 28#include <linux/interrupt.h> 29#include <linux/netdevice.h> 30#include <linux/skbuff.h> 31#include <linux/rtnetlink.h> 32#include <linux/module.h> 33#include <linux/init.h> 34#include <linux/proc_fs.h> 35#include <net/sock.h> 36#include <net/pkt_sched.h> 37#include <linux/tc_act/tc_mirred.h> 38#include <net/tc_act/tc_mirred.h> 39 40#include <linux/etherdevice.h> 41#include <linux/if_arp.h> 42 43 44/* use generic hash table */ 45#define MY_TAB_SIZE 8 46#define MY_TAB_MASK (MY_TAB_SIZE - 1) 47static u32 idx_gen; 48static struct tcf_mirred *tcf_mirred_ht[MY_TAB_SIZE]; 49static DEFINE_RWLOCK(mirred_lock); 50 51/* ovewrride the defaults */ 52#define tcf_st tcf_mirred 53#define tc_st tc_mirred 54#define tcf_t_lock mirred_lock 55#define tcf_ht tcf_mirred_ht 56 57#define CONFIG_NET_ACT_INIT 1 58#include <net/pkt_act.h> 59 60static inline int 61tcf_mirred_release(struct tcf_mirred *p, int bind) 62{ 63 if (p) { 64 if (bind) 65 p->bindcnt--; 66 p->refcnt--; 67 if(!p->bindcnt && p->refcnt <= 0) { 68 dev_put(p->dev); 69 tcf_hash_destroy(p); 70 return 1; 71 } 72 } 73 return 0; 74} 75 76static int 77tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, 78 int ovr, int bind) 79{ 80 struct rtattr *tb[TCA_MIRRED_MAX]; 81 struct tc_mirred *parm; 82 struct tcf_mirred *p; 83 struct net_device *dev = NULL; 84 int ret = 0; 85 int ok_push = 0; 86 87 if (rta == NULL || rtattr_parse_nested(tb, TCA_MIRRED_MAX, rta) < 0) 88 return -EINVAL; 89 90 if (tb[TCA_MIRRED_PARMS-1] == NULL || 91 RTA_PAYLOAD(tb[TCA_MIRRED_PARMS-1]) < sizeof(*parm)) 92 return -EINVAL; 93 parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]); 94 95 if (parm->ifindex) { 96 dev = __dev_get_by_index(parm->ifindex); 97 if (dev == NULL) 98 return -ENODEV; 99 switch (dev->type) { 100 case ARPHRD_TUNNEL: 101 case ARPHRD_TUNNEL6: 102 case ARPHRD_SIT: 103 case ARPHRD_IPGRE: 104 case ARPHRD_VOID: 105 case ARPHRD_NONE: 106 ok_push = 0; 107 break; 108 default: 109 ok_push = 1; 110 break; 111 } 112 } 113 114 p = tcf_hash_check(parm->index, a, ovr, bind); 115 if (p == NULL) { 116 if (!parm->ifindex) 117 return -EINVAL; 118 p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); 119 if (p == NULL) 120 return -ENOMEM; 121 ret = ACT_P_CREATED; 122 } else { 123 if (!ovr) { 124 tcf_mirred_release(p, bind); 125 return -EEXIST; 126 } 127 } 128 129 spin_lock_bh(&p->lock); 130 p->action = parm->action; 131 p->eaction = parm->eaction; 132 if (parm->ifindex) { 133 p->ifindex = parm->ifindex; 134 if (ret != ACT_P_CREATED) 135 dev_put(p->dev); 136 p->dev = dev; 137 dev_hold(dev); 138 p->ok_push = ok_push; 139 } 140 spin_unlock_bh(&p->lock); 141 if (ret == ACT_P_CREATED) 142 tcf_hash_insert(p); 143 144 DPRINTK("tcf_mirred_init index %d action %d eaction %d device %s " 145 "ifindex %d\n", parm->index, parm->action, parm->eaction, 146 dev->name, parm->ifindex); 147 return ret; 148} 149 150static int 151tcf_mirred_cleanup(struct tc_action *a, int bind) 152{ 153 struct tcf_mirred *p = PRIV(a, mirred); 154 155 if (p != NULL) 156 return tcf_mirred_release(p, bind); 157 return 0; 158} 159 160static int 161tcf_mirred(struct sk_buff **pskb, struct tc_action *a, struct tcf_result *res) 162{ 163 struct tcf_mirred *p = PRIV(a, mirred); 164 struct net_device *dev; 165 struct sk_buff *skb2 = NULL; 166 struct sk_buff *skb = *pskb; 167 u32 at = G_TC_AT(skb->tc_verd); 168 169 spin_lock(&p->lock); 170 171 dev = p->dev; 172 p->tm.lastuse = jiffies; 173 174 if (!(dev->flags&IFF_UP) ) { 175 if (net_ratelimit()) 176 printk("mirred to Houston: device %s is gone!\n", 177 dev->name); 178bad_mirred: 179 if (skb2 != NULL) 180 kfree_skb(skb2); 181 p->qstats.overlimits++; 182 p->bstats.bytes += skb->len; 183 p->bstats.packets++; 184 spin_unlock(&p->lock); 185 /* should we be asking for packet to be dropped? 186 * may make sense for redirect case only 187 */ 188 return TC_ACT_SHOT; 189 } 190 191 skb2 = skb_clone(skb, GFP_ATOMIC); 192 if (skb2 == NULL) 193 goto bad_mirred; 194 if (p->eaction != TCA_EGRESS_MIRROR && p->eaction != TCA_EGRESS_REDIR) { 195 if (net_ratelimit()) 196 printk("tcf_mirred unknown action %d\n", p->eaction); 197 goto bad_mirred; 198 } 199 200 p->bstats.bytes += skb2->len; 201 p->bstats.packets++; 202 if (!(at & AT_EGRESS)) 203 if (p->ok_push) 204 skb_push(skb2, skb2->dev->hard_header_len); 205 206 /* mirror is always swallowed */ 207 if (p->eaction != TCA_EGRESS_MIRROR) 208 skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); 209 210 skb2->dev = dev; 211 skb2->input_dev = skb->dev; 212 dev_queue_xmit(skb2); 213 spin_unlock(&p->lock); 214 return p->action; 215} 216 217static int 218tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) 219{ 220 unsigned char *b = skb->tail; 221 struct tc_mirred opt; 222 struct tcf_mirred *p = PRIV(a, mirred); 223 struct tcf_t t; 224 225 opt.index = p->index; 226 opt.action = p->action; 227 opt.refcnt = p->refcnt - ref; 228 opt.bindcnt = p->bindcnt - bind; 229 opt.eaction = p->eaction; 230 opt.ifindex = p->ifindex; 231 DPRINTK("tcf_mirred_dump index %d action %d eaction %d ifindex %d\n", 232 p->index, p->action, p->eaction, p->ifindex); 233 RTA_PUT(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt); 234 t.install = jiffies_to_clock_t(jiffies - p->tm.install); 235 t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse); 236 t.expires = jiffies_to_clock_t(p->tm.expires); 237 RTA_PUT(skb, TCA_MIRRED_TM, sizeof(t), &t); 238 return skb->len; 239 240 rtattr_failure: 241 skb_trim(skb, b - skb->data); 242 return -1; 243} 244 245static struct tc_action_ops act_mirred_ops = { 246 .kind = "mirred", 247 .type = TCA_ACT_MIRRED, 248 .capab = TCA_CAP_NONE, 249 .owner = THIS_MODULE, 250 .act = tcf_mirred, 251 .dump = tcf_mirred_dump, 252 .cleanup = tcf_mirred_cleanup, 253 .lookup = tcf_hash_search, 254 .init = tcf_mirred_init, 255 .walk = tcf_generic_walker 256}; 257 258MODULE_AUTHOR("Jamal Hadi Salim(2002)"); 259MODULE_DESCRIPTION("Device Mirror/redirect actions"); 260MODULE_LICENSE("GPL"); 261 262static int __init 263mirred_init_module(void) 264{ 265 printk("Mirror/redirect action on\n"); 266 return tcf_register_action(&act_mirred_ops); 267} 268 269static void __exit 270mirred_cleanup_module(void) 271{ 272 tcf_unregister_action(&act_mirred_ops); 273} 274 275module_init(mirred_init_module); 276module_exit(mirred_cleanup_module);