diff options
-rw-r--r-- | net/sched/sch_teql.c | 47 |
1 files changed, 22 insertions, 25 deletions
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index ca0c29695d51..474167162947 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
@@ -67,7 +67,6 @@ struct teql_master { | |||
67 | struct teql_sched_data { | 67 | struct teql_sched_data { |
68 | struct Qdisc *next; | 68 | struct Qdisc *next; |
69 | struct teql_master *m; | 69 | struct teql_master *m; |
70 | struct neighbour *ncache; | ||
71 | struct sk_buff_head q; | 70 | struct sk_buff_head q; |
72 | }; | 71 | }; |
73 | 72 | ||
@@ -134,7 +133,6 @@ teql_reset(struct Qdisc *sch) | |||
134 | 133 | ||
135 | skb_queue_purge(&dat->q); | 134 | skb_queue_purge(&dat->q); |
136 | sch->q.qlen = 0; | 135 | sch->q.qlen = 0; |
137 | teql_neigh_release(xchg(&dat->ncache, NULL)); | ||
138 | } | 136 | } |
139 | 137 | ||
140 | static void | 138 | static void |
@@ -166,7 +164,6 @@ teql_destroy(struct Qdisc *sch) | |||
166 | } | 164 | } |
167 | } | 165 | } |
168 | skb_queue_purge(&dat->q); | 166 | skb_queue_purge(&dat->q); |
169 | teql_neigh_release(xchg(&dat->ncache, NULL)); | ||
170 | break; | 167 | break; |
171 | } | 168 | } |
172 | 169 | ||
@@ -225,21 +222,25 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) | |||
225 | static int | 222 | static int |
226 | __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, | 223 | __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, |
227 | struct net_device *dev, struct netdev_queue *txq, | 224 | struct net_device *dev, struct netdev_queue *txq, |
228 | struct neighbour *mn) | 225 | struct dst_entry *dst) |
229 | { | 226 | { |
230 | struct teql_sched_data *q = qdisc_priv(txq->qdisc); | 227 | struct neighbour *n; |
231 | struct neighbour *n = q->ncache; | 228 | int err = 0; |
232 | 229 | ||
233 | if (mn->tbl == NULL) | 230 | n = dst_neigh_lookup_skb(dst, skb); |
234 | return -EINVAL; | 231 | if (!n) |
235 | if (n && n->tbl == mn->tbl && | 232 | return -ENOENT; |
236 | memcmp(n->primary_key, mn->primary_key, mn->tbl->key_len) == 0) { | 233 | |
237 | atomic_inc(&n->refcnt); | 234 | if (dst->dev != dev) { |
238 | } else { | 235 | struct neighbour *mn; |
239 | n = __neigh_lookup_errno(mn->tbl, mn->primary_key, dev); | 236 | |
240 | if (IS_ERR(n)) | 237 | mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev); |
241 | return PTR_ERR(n); | 238 | neigh_release(n); |
239 | if (IS_ERR(mn)) | ||
240 | return PTR_ERR(mn); | ||
241 | n = mn; | ||
242 | } | 242 | } |
243 | |||
243 | if (neigh_event_send(n, skb_res) == 0) { | 244 | if (neigh_event_send(n, skb_res) == 0) { |
244 | int err; | 245 | int err; |
245 | char haddr[MAX_ADDR_LEN]; | 246 | char haddr[MAX_ADDR_LEN]; |
@@ -248,15 +249,13 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, | |||
248 | err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr, | 249 | err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr, |
249 | NULL, skb->len); | 250 | NULL, skb->len); |
250 | 251 | ||
251 | if (err < 0) { | 252 | if (err < 0) |
252 | neigh_release(n); | 253 | err = -EINVAL; |
253 | return -EINVAL; | 254 | } else { |
254 | } | 255 | err = (skb_res == NULL) ? -EAGAIN : 1; |
255 | teql_neigh_release(xchg(&q->ncache, n)); | ||
256 | return 0; | ||
257 | } | 256 | } |
258 | neigh_release(n); | 257 | neigh_release(n); |
259 | return (skb_res == NULL) ? -EAGAIN : 1; | 258 | return err; |
260 | } | 259 | } |
261 | 260 | ||
262 | static inline int teql_resolve(struct sk_buff *skb, | 261 | static inline int teql_resolve(struct sk_buff *skb, |
@@ -265,7 +264,6 @@ static inline int teql_resolve(struct sk_buff *skb, | |||
265 | struct netdev_queue *txq) | 264 | struct netdev_queue *txq) |
266 | { | 265 | { |
267 | struct dst_entry *dst = skb_dst(skb); | 266 | struct dst_entry *dst = skb_dst(skb); |
268 | struct neighbour *mn; | ||
269 | int res; | 267 | int res; |
270 | 268 | ||
271 | if (txq->qdisc == &noop_qdisc) | 269 | if (txq->qdisc == &noop_qdisc) |
@@ -275,8 +273,7 @@ static inline int teql_resolve(struct sk_buff *skb, | |||
275 | return 0; | 273 | return 0; |
276 | 274 | ||
277 | rcu_read_lock(); | 275 | rcu_read_lock(); |
278 | mn = dst_get_neighbour_noref(dst); | 276 | res = __teql_resolve(skb, skb_res, dev, txq, dst); |
279 | res = mn ? __teql_resolve(skb, skb_res, dev, txq, mn) : 0; | ||
280 | rcu_read_unlock(); | 277 | rcu_read_unlock(); |
281 | 278 | ||
282 | return res; | 279 | return res; |