diff options
Diffstat (limited to 'net/sched/act_mirred.c')
| -rw-r--r-- | net/sched/act_mirred.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index c0b6863e3b87..1980b71c283f 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; | 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; |
| 34 | static u32 mirred_idx_gen; | 34 | static u32 mirred_idx_gen; |
| 35 | static DEFINE_RWLOCK(mirred_lock); | 35 | static DEFINE_RWLOCK(mirred_lock); |
| 36 | static LIST_HEAD(mirred_list); | ||
| 36 | 37 | ||
| 37 | static struct tcf_hashinfo mirred_hash_info = { | 38 | static struct tcf_hashinfo mirred_hash_info = { |
| 38 | .htab = tcf_mirred_ht, | 39 | .htab = tcf_mirred_ht, |
| @@ -47,7 +48,9 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) | |||
| 47 | m->tcf_bindcnt--; | 48 | m->tcf_bindcnt--; |
| 48 | m->tcf_refcnt--; | 49 | m->tcf_refcnt--; |
| 49 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { | 50 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { |
| 50 | dev_put(m->tcfm_dev); | 51 | list_del(&m->tcfm_list); |
| 52 | if (m->tcfm_dev) | ||
| 53 | dev_put(m->tcfm_dev); | ||
| 51 | tcf_hash_destroy(&m->common, &mirred_hash_info); | 54 | tcf_hash_destroy(&m->common, &mirred_hash_info); |
| 52 | return 1; | 55 | return 1; |
| 53 | } | 56 | } |
| @@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, | |||
| 134 | m->tcfm_ok_push = ok_push; | 137 | m->tcfm_ok_push = ok_push; |
| 135 | } | 138 | } |
| 136 | spin_unlock_bh(&m->tcf_lock); | 139 | spin_unlock_bh(&m->tcf_lock); |
| 137 | if (ret == ACT_P_CREATED) | 140 | if (ret == ACT_P_CREATED) { |
| 141 | list_add(&m->tcfm_list, &mirred_list); | ||
| 138 | tcf_hash_insert(pc, &mirred_hash_info); | 142 | tcf_hash_insert(pc, &mirred_hash_info); |
| 143 | } | ||
| 139 | 144 | ||
| 140 | return ret; | 145 | return ret; |
| 141 | } | 146 | } |
| @@ -162,9 +167,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
| 162 | m->tcf_tm.lastuse = jiffies; | 167 | m->tcf_tm.lastuse = jiffies; |
| 163 | 168 | ||
| 164 | dev = m->tcfm_dev; | 169 | dev = m->tcfm_dev; |
| 170 | if (!dev) { | ||
| 171 | printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); | ||
| 172 | goto out; | ||
| 173 | } | ||
| 174 | |||
| 165 | if (!(dev->flags & IFF_UP)) { | 175 | if (!(dev->flags & IFF_UP)) { |
| 166 | if (net_ratelimit()) | 176 | if (net_ratelimit()) |
| 167 | pr_notice("tc mirred to Houston: device %s is gone!\n", | 177 | pr_notice("tc mirred to Houston: device %s is down\n", |
| 168 | dev->name); | 178 | dev->name); |
| 169 | goto out; | 179 | goto out; |
| 170 | } | 180 | } |
| @@ -232,6 +242,28 @@ nla_put_failure: | |||
| 232 | return -1; | 242 | return -1; |
| 233 | } | 243 | } |
| 234 | 244 | ||
| 245 | static int mirred_device_event(struct notifier_block *unused, | ||
| 246 | unsigned long event, void *ptr) | ||
| 247 | { | ||
| 248 | struct net_device *dev = ptr; | ||
| 249 | struct tcf_mirred *m; | ||
| 250 | |||
| 251 | if (event == NETDEV_UNREGISTER) | ||
| 252 | list_for_each_entry(m, &mirred_list, tcfm_list) { | ||
| 253 | if (m->tcfm_dev == dev) { | ||
| 254 | dev_put(dev); | ||
| 255 | m->tcfm_dev = NULL; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | return NOTIFY_DONE; | ||
| 260 | } | ||
| 261 | |||
| 262 | static struct notifier_block mirred_device_notifier = { | ||
| 263 | .notifier_call = mirred_device_event, | ||
| 264 | }; | ||
| 265 | |||
| 266 | |||
| 235 | static struct tc_action_ops act_mirred_ops = { | 267 | static struct tc_action_ops act_mirred_ops = { |
| 236 | .kind = "mirred", | 268 | .kind = "mirred", |
| 237 | .hinfo = &mirred_hash_info, | 269 | .hinfo = &mirred_hash_info, |
| @@ -252,12 +284,17 @@ MODULE_LICENSE("GPL"); | |||
| 252 | 284 | ||
| 253 | static int __init mirred_init_module(void) | 285 | static int __init mirred_init_module(void) |
| 254 | { | 286 | { |
| 287 | int err = register_netdevice_notifier(&mirred_device_notifier); | ||
| 288 | if (err) | ||
| 289 | return err; | ||
| 290 | |||
| 255 | pr_info("Mirror/redirect action on\n"); | 291 | pr_info("Mirror/redirect action on\n"); |
| 256 | return tcf_register_action(&act_mirred_ops); | 292 | return tcf_register_action(&act_mirred_ops); |
| 257 | } | 293 | } |
| 258 | 294 | ||
| 259 | static void __exit mirred_cleanup_module(void) | 295 | static void __exit mirred_cleanup_module(void) |
| 260 | { | 296 | { |
| 297 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
| 261 | tcf_unregister_action(&act_mirred_ops); | 298 | tcf_unregister_action(&act_mirred_ops); |
| 262 | } | 299 | } |
| 263 | 300 | ||
