diff options
-rw-r--r-- | net/sched/act_mirred.c | 59 |
1 files changed, 33 insertions, 26 deletions
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index b9aaab4e0354..b812c20b66c6 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -148,47 +148,39 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
148 | { | 148 | { |
149 | struct tcf_mirred *m = a->priv; | 149 | struct tcf_mirred *m = a->priv; |
150 | struct net_device *dev; | 150 | struct net_device *dev; |
151 | struct sk_buff *skb2 = NULL; | 151 | struct sk_buff *skb2; |
152 | u32 at = G_TC_AT(skb->tc_verd); | 152 | u32 at; |
153 | int retval, err = 1; | ||
153 | 154 | ||
154 | spin_lock(&m->tcf_lock); | 155 | spin_lock(&m->tcf_lock); |
155 | |||
156 | dev = m->tcfm_dev; | ||
157 | m->tcf_tm.lastuse = jiffies; | 156 | m->tcf_tm.lastuse = jiffies; |
157 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR && | ||
158 | m->tcfm_eaction != TCA_EGRESS_REDIR) { | ||
159 | if (net_ratelimit()) | ||
160 | printk("tcf_mirred unknown action %d\n", | ||
161 | m->tcfm_eaction); | ||
162 | goto out; | ||
163 | } | ||
158 | 164 | ||
159 | if (!(dev->flags&IFF_UP) ) { | 165 | dev = m->tcfm_dev; |
166 | if (!(dev->flags & IFF_UP)) { | ||
160 | if (net_ratelimit()) | 167 | if (net_ratelimit()) |
161 | printk("mirred to Houston: device %s is gone!\n", | 168 | printk("mirred to Houston: device %s is gone!\n", |
162 | dev->name); | 169 | dev->name); |
163 | bad_mirred: | 170 | goto out; |
164 | if (skb2 != NULL) | ||
165 | kfree_skb(skb2); | ||
166 | m->tcf_qstats.overlimits++; | ||
167 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
168 | m->tcf_bstats.packets++; | ||
169 | spin_unlock(&m->tcf_lock); | ||
170 | /* should we be asking for packet to be dropped? | ||
171 | * may make sense for redirect case only | ||
172 | */ | ||
173 | return TC_ACT_SHOT; | ||
174 | } | 171 | } |
175 | 172 | ||
176 | skb2 = skb_act_clone(skb, GFP_ATOMIC); | 173 | skb2 = skb_act_clone(skb, GFP_ATOMIC); |
177 | if (skb2 == NULL) | 174 | if (skb2 == NULL) |
178 | goto bad_mirred; | 175 | goto out; |
179 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR && | ||
180 | m->tcfm_eaction != TCA_EGRESS_REDIR) { | ||
181 | if (net_ratelimit()) | ||
182 | printk("tcf_mirred unknown action %d\n", | ||
183 | m->tcfm_eaction); | ||
184 | goto bad_mirred; | ||
185 | } | ||
186 | 176 | ||
187 | m->tcf_bstats.bytes += qdisc_pkt_len(skb2); | 177 | m->tcf_bstats.bytes += qdisc_pkt_len(skb2); |
188 | m->tcf_bstats.packets++; | 178 | m->tcf_bstats.packets++; |
189 | if (!(at & AT_EGRESS)) | 179 | at = G_TC_AT(skb->tc_verd); |
180 | if (!(at & AT_EGRESS)) { | ||
190 | if (m->tcfm_ok_push) | 181 | if (m->tcfm_ok_push) |
191 | skb_push(skb2, skb2->dev->hard_header_len); | 182 | skb_push(skb2, skb2->dev->hard_header_len); |
183 | } | ||
192 | 184 | ||
193 | /* mirror is always swallowed */ | 185 | /* mirror is always swallowed */ |
194 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) | 186 | if (m->tcfm_eaction != TCA_EGRESS_MIRROR) |
@@ -197,8 +189,23 @@ bad_mirred: | |||
197 | skb2->dev = dev; | 189 | skb2->dev = dev; |
198 | skb2->iif = skb->dev->ifindex; | 190 | skb2->iif = skb->dev->ifindex; |
199 | dev_queue_xmit(skb2); | 191 | dev_queue_xmit(skb2); |
192 | err = 0; | ||
193 | |||
194 | out: | ||
195 | if (err) { | ||
196 | m->tcf_qstats.overlimits++; | ||
197 | m->tcf_bstats.bytes += qdisc_pkt_len(skb); | ||
198 | m->tcf_bstats.packets++; | ||
199 | /* should we be asking for packet to be dropped? | ||
200 | * may make sense for redirect case only | ||
201 | */ | ||
202 | retval = TC_ACT_SHOT; | ||
203 | } else { | ||
204 | retval = m->tcf_action; | ||
205 | } | ||
200 | spin_unlock(&m->tcf_lock); | 206 | spin_unlock(&m->tcf_lock); |
201 | return m->tcf_action; | 207 | |
208 | return retval; | ||
202 | } | 209 | } |
203 | 210 | ||
204 | static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) | 211 | static int tcf_mirred_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |