Blame view
net/sched/act_mirred.c
12 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
0c6965dd3 sched: fix act fi... |
3 |
* net/sched/act_mirred.c packet mirroring and redirect actions |
1da177e4c Linux-2.6.12-rc2 |
4 |
* |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 |
* Authors: Jamal Hadi Salim (2002-4) * * TODO: Add ingress support (and socket redirect support) |
1da177e4c Linux-2.6.12-rc2 |
8 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
9 10 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
11 |
#include <linux/string.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include <linux/errno.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 |
#include <linux/skbuff.h> #include <linux/rtnetlink.h> #include <linux/module.h> #include <linux/init.h> |
5a0e3ad6a include cleanup: ... |
17 |
#include <linux/gfp.h> |
c491680f8 bpf: reuse dev_is... |
18 |
#include <linux/if_arp.h> |
881d966b4 [NET]: Make the d... |
19 |
#include <net/net_namespace.h> |
dc5fc579b [NETLINK]: Use nl... |
20 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <net/pkt_sched.h> |
e5cf1baf9 act_mirred: use T... |
22 |
#include <net/pkt_cls.h> |
1da177e4c Linux-2.6.12-rc2 |
23 24 |
#include <linux/tc_act/tc_mirred.h> #include <net/tc_act/tc_mirred.h> |
3b87956ea net sched: fix ra... |
25 |
static LIST_HEAD(mirred_list); |
4e232818b net: sched: act_m... |
26 |
static DEFINE_SPINLOCK(mirred_list_lock); |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
e2ca070f8 net: sched: prote... |
28 29 |
#define MIRRED_RECURSION_LIMIT 4 static DEFINE_PER_CPU(unsigned int, mirred_rec_level); |
53592b364 net/sched: act_mi... |
30 31 32 33 |
static bool tcf_mirred_is_act_redirect(int action) { return action == TCA_EGRESS_REDIR || action == TCA_INGRESS_REDIR; } |
8dc07fdbf net-tc: convert t... |
34 |
static bool tcf_mirred_act_wants_ingress(int action) |
53592b364 net/sched: act_mi... |
35 36 37 38 |
{ switch (action) { case TCA_EGRESS_REDIR: case TCA_EGRESS_MIRROR: |
8dc07fdbf net-tc: convert t... |
39 |
return false; |
53592b364 net/sched: act_mi... |
40 41 |
case TCA_INGRESS_REDIR: case TCA_INGRESS_MIRROR: |
8dc07fdbf net-tc: convert t... |
42 |
return true; |
53592b364 net/sched: act_mi... |
43 44 45 46 |
default: BUG(); } } |
e5cf1baf9 act_mirred: use T... |
47 48 49 50 51 52 53 54 55 56 57 |
static bool tcf_mirred_can_reinsert(int action) { switch (action) { case TC_ACT_SHOT: case TC_ACT_STOLEN: case TC_ACT_QUEUED: case TC_ACT_TRAP: return true; } return false; } |
4e232818b net: sched: act_m... |
58 59 60 61 62 |
static struct net_device *tcf_mirred_dev_dereference(struct tcf_mirred *m) { return rcu_dereference_protected(m->tcfm_dev, lockdep_is_held(&m->tcf_lock)); } |
9a63b255d net_sched: remove... |
63 |
static void tcf_mirred_release(struct tc_action *a) |
1da177e4c Linux-2.6.12-rc2 |
64 |
{ |
86062033f net_sched: act: h... |
65 |
struct tcf_mirred *m = to_mirred(a); |
dc327f893 net_sched: close ... |
66 |
struct net_device *dev; |
2ee22a90c net_sched: act_mi... |
67 |
|
4e232818b net: sched: act_m... |
68 |
spin_lock(&mirred_list_lock); |
a5b5c958f net_sched: act: r... |
69 |
list_del(&m->tcfm_list); |
4e232818b net: sched: act_m... |
70 71 72 73 |
spin_unlock(&mirred_list_lock); /* last reference to action, no need to lock */ dev = rcu_dereference_protected(m->tcfm_dev, 1); |
2ee22a90c net_sched: act_mi... |
74 75 |
if (dev) dev_put(dev); |
1da177e4c Linux-2.6.12-rc2 |
76 |
} |
53b2bf3f8 [NET_SCHED]: Use ... |
77 78 79 |
static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { [TCA_MIRRED_PARMS] = { .len = sizeof(struct tc_mirred) }, }; |
c7d03a00b netns: make struc... |
80 |
static unsigned int mirred_net_id; |
a85a970af net_sched: move t... |
81 |
static struct tc_action_ops act_mirred_ops; |
ddf97ccdd net_sched: add ne... |
82 |
|
c1b52739e pkt_sched: namesp... |
83 |
static int tcf_mirred_init(struct net *net, struct nlattr *nla, |
789871bb2 net: sched: imple... |
84 85 |
struct nlattr *est, struct tc_action **a, int ovr, int bind, bool rtnl_held, |
85d0966fa net/sched: prepar... |
86 |
struct tcf_proto *tp, |
abbb0d336 net: sched: exten... |
87 |
u32 flags, struct netlink_ext_ack *extack) |
1da177e4c Linux-2.6.12-rc2 |
88 |
{ |
ddf97ccdd net_sched: add ne... |
89 |
struct tc_action_net *tn = net_generic(net, mirred_net_id); |
7ba699c60 [NET_SCHED]: Conv... |
90 |
struct nlattr *tb[TCA_MIRRED_MAX + 1]; |
ff9721d32 net/sched: act_mi... |
91 |
struct tcf_chain *goto_ch = NULL; |
165779231 net/sched: act_mi... |
92 |
bool mac_header_xmit = false; |
1da177e4c Linux-2.6.12-rc2 |
93 |
struct tc_mirred *parm; |
e9ce1cd3c [PKT_SCHED]: Kill... |
94 |
struct tcf_mirred *m; |
b76965e02 act_mirred: optim... |
95 |
struct net_device *dev; |
b2313077e net_sched: make t... |
96 |
bool exists = false; |
0190c1d45 net: sched: atomi... |
97 |
int ret, err; |
7be8ef2cd net: sched: use t... |
98 |
u32 index; |
1da177e4c Linux-2.6.12-rc2 |
99 |
|
1d4760c75 net: sched: act: ... |
100 101 |
if (!nla) { NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed"); |
1da177e4c Linux-2.6.12-rc2 |
102 |
return -EINVAL; |
1d4760c75 net: sched: act: ... |
103 |
} |
8cb081746 netlink: make val... |
104 105 |
ret = nla_parse_nested_deprecated(tb, TCA_MIRRED_MAX, nla, mirred_policy, extack); |
b76965e02 act_mirred: optim... |
106 107 |
if (ret < 0) return ret; |
1d4760c75 net: sched: act: ... |
108 109 |
if (!tb[TCA_MIRRED_PARMS]) { NL_SET_ERR_MSG_MOD(extack, "Missing required mirred parameters"); |
1da177e4c Linux-2.6.12-rc2 |
110 |
return -EINVAL; |
1d4760c75 net: sched: act: ... |
111 |
} |
7ba699c60 [NET_SCHED]: Conv... |
112 |
parm = nla_data(tb[TCA_MIRRED_PARMS]); |
7be8ef2cd net: sched: use t... |
113 114 |
index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); |
0190c1d45 net: sched: atomi... |
115 116 117 |
if (err < 0) return err; exists = err; |
87dfbdc6c net sched: mirred... |
118 119 |
if (exists && bind) return 0; |
b76965e02 act_mirred: optim... |
120 121 122 |
switch (parm->eaction) { case TCA_EGRESS_MIRROR: case TCA_EGRESS_REDIR: |
53592b364 net/sched: act_mi... |
123 124 |
case TCA_INGRESS_REDIR: case TCA_INGRESS_MIRROR: |
b76965e02 act_mirred: optim... |
125 126 |
break; default: |
87dfbdc6c net sched: mirred... |
127 |
if (exists) |
65a206c01 net/sched: Change... |
128 |
tcf_idr_release(*a, bind); |
0190c1d45 net: sched: atomi... |
129 |
else |
7be8ef2cd net: sched: use t... |
130 |
tcf_idr_cleanup(tn, index); |
1d4760c75 net: sched: act: ... |
131 |
NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option"); |
b76965e02 act_mirred: optim... |
132 133 |
return -EINVAL; } |
1da177e4c Linux-2.6.12-rc2 |
134 |
|
87dfbdc6c net sched: mirred... |
135 |
if (!exists) { |
4e232818b net: sched: act_m... |
136 |
if (!parm->ifindex) { |
7be8ef2cd net: sched: use t... |
137 |
tcf_idr_cleanup(tn, index); |
1d4760c75 net: sched: act: ... |
138 |
NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist"); |
1da177e4c Linux-2.6.12-rc2 |
139 |
return -EINVAL; |
1d4760c75 net: sched: act: ... |
140 |
} |
e38226786 net: sched: updat... |
141 142 |
ret = tcf_idr_create_from_flags(tn, index, est, a, &act_mirred_ops, bind, flags); |
0190c1d45 net: sched: atomi... |
143 |
if (ret) { |
7be8ef2cd net: sched: use t... |
144 |
tcf_idr_cleanup(tn, index); |
86062033f net_sched: act: h... |
145 |
return ret; |
0190c1d45 net: sched: atomi... |
146 |
} |
1da177e4c Linux-2.6.12-rc2 |
147 |
ret = ACT_P_CREATED; |
4e8ddd7f1 net: sched: don't... |
148 |
} else if (!ovr) { |
65a206c01 net/sched: Change... |
149 |
tcf_idr_release(*a, bind); |
4e8ddd7f1 net: sched: don't... |
150 |
return -EEXIST; |
1da177e4c Linux-2.6.12-rc2 |
151 |
} |
064c5d688 net: sched: fix c... |
152 153 154 155 |
m = to_mirred(*a); if (ret == ACT_P_CREATED) INIT_LIST_HEAD(&m->tcfm_list); |
ff9721d32 net/sched: act_mi... |
156 157 158 |
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) goto release_idr; |
653cd284a net: sched: alway... |
159 |
spin_lock_bh(&m->tcf_lock); |
4e232818b net: sched: act_m... |
160 161 162 163 |
if (parm->ifindex) { dev = dev_get_by_index(net, parm->ifindex); if (!dev) { |
653cd284a net: sched: alway... |
164 |
spin_unlock_bh(&m->tcf_lock); |
ff9721d32 net/sched: act_mi... |
165 166 |
err = -ENODEV; goto put_chain; |
4e232818b net: sched: act_m... |
167 168 |
} mac_header_xmit = dev_is_mac_header_xmit(dev); |
445d37493 net/sched: Replac... |
169 170 |
dev = rcu_replace_pointer(m->tcfm_dev, dev, lockdep_is_held(&m->tcf_lock)); |
4e232818b net: sched: act_m... |
171 172 |
if (dev) dev_put(dev); |
165779231 net/sched: act_mi... |
173 |
m->tcfm_mac_header_xmit = mac_header_xmit; |
1da177e4c Linux-2.6.12-rc2 |
174 |
} |
ff9721d32 net/sched: act_mi... |
175 176 |
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); m->tcfm_eaction = parm->eaction; |
653cd284a net: sched: alway... |
177 |
spin_unlock_bh(&m->tcf_lock); |
ff9721d32 net/sched: act_mi... |
178 179 |
if (goto_ch) tcf_chain_put_by_act(goto_ch); |
2ee22a90c net_sched: act_mi... |
180 |
|
3b87956ea net sched: fix ra... |
181 |
if (ret == ACT_P_CREATED) { |
4e232818b net: sched: act_m... |
182 |
spin_lock(&mirred_list_lock); |
3b87956ea net sched: fix ra... |
183 |
list_add(&m->tcfm_list, &mirred_list); |
4e232818b net: sched: act_m... |
184 |
spin_unlock(&mirred_list_lock); |
3b87956ea net sched: fix ra... |
185 |
} |
1da177e4c Linux-2.6.12-rc2 |
186 |
|
1da177e4c Linux-2.6.12-rc2 |
187 |
return ret; |
ff9721d32 net/sched: act_mi... |
188 189 190 191 192 193 |
put_chain: if (goto_ch) tcf_chain_put_by_act(goto_ch); release_idr: tcf_idr_release(*a, bind); return err; |
1da177e4c Linux-2.6.12-rc2 |
194 |
} |
7c5790c4d net: sched: act_m... |
195 196 |
static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) |
1da177e4c Linux-2.6.12-rc2 |
197 |
{ |
a85a970af net_sched: move t... |
198 |
struct tcf_mirred *m = to_mirred(a); |
e5cf1baf9 act_mirred: use T... |
199 |
struct sk_buff *skb2 = skb; |
53592b364 net/sched: act_mi... |
200 |
bool m_mac_header_xmit; |
1da177e4c Linux-2.6.12-rc2 |
201 |
struct net_device *dev; |
e2ca070f8 net: sched: prote... |
202 |
unsigned int rec_level; |
53592b364 net/sched: act_mi... |
203 |
int retval, err = 0; |
e5cf1baf9 act_mirred: use T... |
204 205 206 |
bool use_reinsert; bool want_ingress; bool is_redirect; |
70cf3dc73 net/sched: act_mi... |
207 |
bool expects_nh; |
53592b364 net/sched: act_mi... |
208 209 |
int m_eaction; int mac_len; |
70cf3dc73 net/sched: act_mi... |
210 |
bool at_nh; |
1da177e4c Linux-2.6.12-rc2 |
211 |
|
e2ca070f8 net: sched: prote... |
212 213 214 215 216 217 218 219 |
rec_level = __this_cpu_inc_return(mirred_rec_level); if (unlikely(rec_level > MIRRED_RECURSION_LIMIT)) { net_warn_ratelimited("Packet exceeded mirred recursion limit on dev %s ", netdev_name(skb->dev)); __this_cpu_dec(mirred_rec_level); return TC_ACT_SHOT; } |
2ee22a90c net_sched: act_mi... |
220 |
tcf_lastuse_update(&m->tcf_tm); |
5e1ad95b6 net: sched: extra... |
221 |
tcf_action_update_bstats(&m->common, skb); |
1da177e4c Linux-2.6.12-rc2 |
222 |
|
53592b364 net/sched: act_mi... |
223 224 |
m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); m_eaction = READ_ONCE(m->tcfm_eaction); |
2ee22a90c net_sched: act_mi... |
225 |
retval = READ_ONCE(m->tcf_action); |
7fd4b288e tc/act: remove un... |
226 |
dev = rcu_dereference_bh(m->tcfm_dev); |
2ee22a90c net_sched: act_mi... |
227 228 229 |
if (unlikely(!dev)) { pr_notice_once("tc mirred: target device is gone "); |
3b87956ea net sched: fix ra... |
230 231 |
goto out; } |
2ee22a90c net_sched: act_mi... |
232 |
if (unlikely(!(dev->flags & IFF_UP))) { |
e87cc4728 net: Convert net_... |
233 234 235 |
net_notice_ratelimited("tc mirred to Houston: device %s is down ", dev->name); |
feed1f172 act_mirred: cleanup |
236 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
237 |
} |
e5cf1baf9 act_mirred: use T... |
238 239 240 241 242 243 244 245 246 247 248 249 |
/* we could easily avoid the clone only if called by ingress and clsact; * since we can't easily detect the clsact caller, skip clone only for * ingress - that covers the TC S/W datapath. */ is_redirect = tcf_mirred_is_act_redirect(m_eaction); use_reinsert = skb_at_tc_ingress(skb) && is_redirect && tcf_mirred_can_reinsert(retval); if (!use_reinsert) { skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) goto out; } |
1da177e4c Linux-2.6.12-rc2 |
250 |
|
e5cf1baf9 act_mirred: use T... |
251 |
want_ingress = tcf_mirred_act_wants_ingress(m_eaction); |
70cf3dc73 net/sched: act_mi... |
252 253 254 255 256 257 258 259 |
expects_nh = want_ingress || !m_mac_header_xmit; at_nh = skb->data == skb_network_header(skb); if (at_nh != expects_nh) { mac_len = skb_at_tc_ingress(skb) ? skb->mac_len : skb_network_header(skb) - skb_mac_header(skb); if (expects_nh) { /* target device/action expect data at nh */ |
53592b364 net/sched: act_mi... |
260 261 |
skb_pull_rcsum(skb2, mac_len); } else { |
70cf3dc73 net/sched: act_mi... |
262 263 |
/* target device/action expect data at mac */ skb_push_rcsum(skb2, mac_len); |
53592b364 net/sched: act_mi... |
264 |
} |
feed1f172 act_mirred: cleanup |
265 |
} |
1da177e4c Linux-2.6.12-rc2 |
266 |
|
e5cf1baf9 act_mirred: use T... |
267 268 |
skb2->skb_iif = skb->dev->ifindex; skb2->dev = dev; |
1da177e4c Linux-2.6.12-rc2 |
269 |
/* mirror is always swallowed */ |
e5cf1baf9 act_mirred: use T... |
270 |
if (is_redirect) { |
2c64605b5 net: Fix CONFIG_N... |
271 |
skb_set_redirected(skb2, skb2->tc_at_ingress); |
e5cf1baf9 act_mirred: use T... |
272 273 274 |
/* let's the caller reinsert the packet, if possible */ if (use_reinsert) { res->ingress = want_ingress; |
ef816f3c4 net: sched: don't... |
275 276 |
if (skb_tc_reinsert(skb, res)) tcf_action_inc_overlimit_qstats(&m->common); |
e2ca070f8 net: sched: prote... |
277 |
__this_cpu_dec(mirred_rec_level); |
720f22fed net: sched: refac... |
278 |
return TC_ACT_CONSUMED; |
e5cf1baf9 act_mirred: use T... |
279 |
} |
bc31c905e net-tc: convert t... |
280 |
} |
1da177e4c Linux-2.6.12-rc2 |
281 |
|
e5cf1baf9 act_mirred: use T... |
282 |
if (!want_ingress) |
53592b364 net/sched: act_mi... |
283 284 285 |
err = dev_queue_xmit(skb2); else err = netif_receive_skb(skb2); |
feed1f172 act_mirred: cleanup |
286 |
|
feed1f172 act_mirred: cleanup |
287 |
if (err) { |
2ee22a90c net_sched: act_mi... |
288 |
out: |
26b537a88 net: sched: extra... |
289 |
tcf_action_inc_overlimit_qstats(&m->common); |
53592b364 net/sched: act_mi... |
290 |
if (tcf_mirred_is_act_redirect(m_eaction)) |
16c0b164b act_mirred: do no... |
291 |
retval = TC_ACT_SHOT; |
2ee22a90c net_sched: act_mi... |
292 |
} |
e2ca070f8 net: sched: prote... |
293 |
__this_cpu_dec(mirred_rec_level); |
feed1f172 act_mirred: cleanup |
294 295 |
return retval; |
1da177e4c Linux-2.6.12-rc2 |
296 |
} |
4b61d3e8d net: qos offload ... |
297 298 |
static void tcf_stats_update(struct tc_action *a, u64 bytes, u64 packets, u64 drops, u64 lastuse, bool hw) |
9798e6fe4 net: act_mirred: ... |
299 |
{ |
5712bf9c5 net/sched: act_mi... |
300 301 |
struct tcf_mirred *m = to_mirred(a); struct tcf_t *tm = &m->tcf_tm; |
4b61d3e8d net: qos offload ... |
302 |
tcf_action_update_stats(a, bytes, packets, drops, hw); |
3bb23421a net/sched: Fix up... |
303 |
tm->lastuse = max_t(u64, tm->lastuse, lastuse); |
9798e6fe4 net: act_mirred: ... |
304 |
} |
5a7a5555a net sched: stylis... |
305 306 |
static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
1da177e4c Linux-2.6.12-rc2 |
307 |
{ |
27a884dc3 [SK_BUFF]: Conver... |
308 |
unsigned char *b = skb_tail_pointer(skb); |
a85a970af net_sched: move t... |
309 |
struct tcf_mirred *m = to_mirred(a); |
1c40be12f net sched: fix so... |
310 311 |
struct tc_mirred opt = { .index = m->tcf_index, |
036bb4432 net: sched: chang... |
312 313 |
.refcnt = refcount_read(&m->tcf_refcnt) - ref, .bindcnt = atomic_read(&m->tcf_bindcnt) - bind, |
1c40be12f net sched: fix so... |
314 |
}; |
4e232818b net: sched: act_m... |
315 |
struct net_device *dev; |
1da177e4c Linux-2.6.12-rc2 |
316 |
struct tcf_t t; |
653cd284a net: sched: alway... |
317 |
spin_lock_bh(&m->tcf_lock); |
4e232818b net: sched: act_m... |
318 319 320 321 322 |
opt.action = m->tcf_action; opt.eaction = m->tcfm_eaction; dev = tcf_mirred_dev_dereference(m); if (dev) opt.ifindex = dev->ifindex; |
1b34ec43c pkt_sched: Stop u... |
323 324 |
if (nla_put(skb, TCA_MIRRED_PARMS, sizeof(opt), &opt)) goto nla_put_failure; |
48d8ee169 net sched actions... |
325 326 |
tcf_tm_dump(&t, &m->tcf_tm); |
9854518ea sched: align nlat... |
327 |
if (nla_put_64bit(skb, TCA_MIRRED_TM, sizeof(t), &t, TCA_MIRRED_PAD)) |
1b34ec43c pkt_sched: Stop u... |
328 |
goto nla_put_failure; |
653cd284a net: sched: alway... |
329 |
spin_unlock_bh(&m->tcf_lock); |
4e232818b net: sched: act_m... |
330 |
|
1da177e4c Linux-2.6.12-rc2 |
331 |
return skb->len; |
7ba699c60 [NET_SCHED]: Conv... |
332 |
nla_put_failure: |
653cd284a net: sched: alway... |
333 |
spin_unlock_bh(&m->tcf_lock); |
dc5fc579b [NETLINK]: Use nl... |
334 |
nlmsg_trim(skb, b); |
1da177e4c Linux-2.6.12-rc2 |
335 336 |
return -1; } |
ddf97ccdd net_sched: add ne... |
337 338 |
static int tcf_mirred_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, |
417801055 net: sched: act: ... |
339 340 |
const struct tc_action_ops *ops, struct netlink_ext_ack *extack) |
ddf97ccdd net_sched: add ne... |
341 342 |
{ struct tc_action_net *tn = net_generic(net, mirred_net_id); |
b36201455 net: sched: act: ... |
343 |
return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
ddf97ccdd net_sched: add ne... |
344 |
} |
f061b48c1 Revert "net: sche... |
345 |
static int tcf_mirred_search(struct net *net, struct tc_action **a, u32 index) |
ddf97ccdd net_sched: add ne... |
346 347 |
{ struct tc_action_net *tn = net_generic(net, mirred_net_id); |
65a206c01 net/sched: Change... |
348 |
return tcf_idr_search(tn, a, index); |
ddf97ccdd net_sched: add ne... |
349 |
} |
3b87956ea net sched: fix ra... |
350 351 352 |
static int mirred_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { |
351638e7d net: pass info st... |
353 |
struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
3b87956ea net sched: fix ra... |
354 |
struct tcf_mirred *m; |
2ee22a90c net_sched: act_mi... |
355 |
ASSERT_RTNL(); |
6bd00b850 act_mirred: fix a... |
356 |
if (event == NETDEV_UNREGISTER) { |
4e232818b net: sched: act_m... |
357 |
spin_lock(&mirred_list_lock); |
3b87956ea net sched: fix ra... |
358 |
list_for_each_entry(m, &mirred_list, tcfm_list) { |
653cd284a net: sched: alway... |
359 |
spin_lock_bh(&m->tcf_lock); |
4e232818b net: sched: act_m... |
360 |
if (tcf_mirred_dev_dereference(m) == dev) { |
3b87956ea net sched: fix ra... |
361 |
dev_put(dev); |
2ee22a90c net_sched: act_mi... |
362 363 364 365 |
/* Note : no rcu grace period necessary, as * net_device are already rcu protected. */ RCU_INIT_POINTER(m->tcfm_dev, NULL); |
3b87956ea net sched: fix ra... |
366 |
} |
653cd284a net: sched: alway... |
367 |
spin_unlock_bh(&m->tcf_lock); |
3b87956ea net sched: fix ra... |
368 |
} |
4e232818b net: sched: act_m... |
369 |
spin_unlock(&mirred_list_lock); |
6bd00b850 act_mirred: fix a... |
370 |
} |
3b87956ea net sched: fix ra... |
371 372 373 374 375 376 377 |
return NOTIFY_DONE; } static struct notifier_block mirred_device_notifier = { .notifier_call = mirred_device_event, }; |
470d5060e net: sched: use g... |
378 379 380 381 382 383 384 385 386 387 |
static void tcf_mirred_dev_put(void *priv) { struct net_device *dev = priv; dev_put(dev); } static struct net_device * tcf_mirred_get_dev(const struct tc_action *a, tc_action_priv_destructor *destructor) |
255cb3042 net/sched: act_mi... |
388 |
{ |
843e79d05 net: sched: make ... |
389 |
struct tcf_mirred *m = to_mirred(a); |
4e232818b net: sched: act_m... |
390 |
struct net_device *dev; |
84a75b329 net: sched: exten... |
391 |
|
4e232818b net: sched: act_m... |
392 393 |
rcu_read_lock(); dev = rcu_dereference(m->tcfm_dev); |
470d5060e net: sched: use g... |
394 |
if (dev) { |
84a75b329 net: sched: exten... |
395 |
dev_hold(dev); |
470d5060e net: sched: use g... |
396 397 |
*destructor = tcf_mirred_dev_put; } |
4e232818b net: sched: act_m... |
398 |
rcu_read_unlock(); |
255cb3042 net/sched: act_mi... |
399 |
|
84a75b329 net: sched: exten... |
400 401 |
return dev; } |
b84b2d4e3 net sched: update... |
402 403 404 405 |
static size_t tcf_mirred_get_fill_size(const struct tc_action *act) { return nla_total_size(sizeof(struct tc_mirred)); } |
1da177e4c Linux-2.6.12-rc2 |
406 407 |
static struct tc_action_ops act_mirred_ops = { .kind = "mirred", |
eddd2cf19 net: Change TCA_A... |
408 |
.id = TCA_ID_MIRRED, |
1da177e4c Linux-2.6.12-rc2 |
409 |
.owner = THIS_MODULE, |
7c5790c4d net: sched: act_m... |
410 |
.act = tcf_mirred_act, |
9798e6fe4 net: act_mirred: ... |
411 |
.stats_update = tcf_stats_update, |
1da177e4c Linux-2.6.12-rc2 |
412 |
.dump = tcf_mirred_dump, |
86062033f net_sched: act: h... |
413 |
.cleanup = tcf_mirred_release, |
1da177e4c Linux-2.6.12-rc2 |
414 |
.init = tcf_mirred_init, |
ddf97ccdd net_sched: add ne... |
415 416 |
.walk = tcf_mirred_walker, .lookup = tcf_mirred_search, |
b84b2d4e3 net sched: update... |
417 |
.get_fill_size = tcf_mirred_get_fill_size, |
a85a970af net_sched: move t... |
418 |
.size = sizeof(struct tcf_mirred), |
843e79d05 net: sched: make ... |
419 |
.get_dev = tcf_mirred_get_dev, |
ddf97ccdd net_sched: add ne... |
420 421 422 423 424 |
}; static __net_init int mirred_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, mirred_net_id); |
981471bd3 net_sched: fix a ... |
425 |
return tc_action_net_init(net, tn, &act_mirred_ops); |
ddf97ccdd net_sched: add ne... |
426 |
} |
039af9c66 net_sched: switch... |
427 |
static void __net_exit mirred_exit_net(struct list_head *net_list) |
ddf97ccdd net_sched: add ne... |
428 |
{ |
039af9c66 net_sched: switch... |
429 |
tc_action_net_exit(net_list, mirred_net_id); |
ddf97ccdd net_sched: add ne... |
430 431 432 433 |
} static struct pernet_operations mirred_net_ops = { .init = mirred_init_net, |
039af9c66 net_sched: switch... |
434 |
.exit_batch = mirred_exit_net, |
ddf97ccdd net_sched: add ne... |
435 436 |
.id = &mirred_net_id, .size = sizeof(struct tc_action_net), |
1da177e4c Linux-2.6.12-rc2 |
437 438 439 440 441 |
}; MODULE_AUTHOR("Jamal Hadi Salim(2002)"); MODULE_DESCRIPTION("Device Mirror/redirect actions"); MODULE_LICENSE("GPL"); |
e9ce1cd3c [PKT_SCHED]: Kill... |
442 |
static int __init mirred_init_module(void) |
1da177e4c Linux-2.6.12-rc2 |
443 |
{ |
3b87956ea net sched: fix ra... |
444 445 446 |
int err = register_netdevice_notifier(&mirred_device_notifier); if (err) return err; |
6ff9c3644 net sched: printk... |
447 448 |
pr_info("Mirror/redirect action on "); |
11c9a7d38 act_mirred: Fix m... |
449 450 451 452 453 |
err = tcf_register_action(&act_mirred_ops, &mirred_net_ops); if (err) unregister_netdevice_notifier(&mirred_device_notifier); return err; |
1da177e4c Linux-2.6.12-rc2 |
454 |
} |
e9ce1cd3c [PKT_SCHED]: Kill... |
455 |
static void __exit mirred_cleanup_module(void) |
1da177e4c Linux-2.6.12-rc2 |
456 |
{ |
ddf97ccdd net_sched: add ne... |
457 |
tcf_unregister_action(&act_mirred_ops, &mirred_net_ops); |
568a153a2 net_sched: fix a ... |
458 |
unregister_netdevice_notifier(&mirred_device_notifier); |
1da177e4c Linux-2.6.12-rc2 |
459 460 461 462 |
} module_init(mirred_init_module); module_exit(mirred_cleanup_module); |