diff options
Diffstat (limited to 'net/mpls/af_mpls.c')
-rw-r--r-- | net/mpls/af_mpls.c | 48 |
1 files changed, 25 insertions, 23 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 15fe97644ffe..5b77377e5a15 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c | |||
@@ -98,18 +98,19 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) | |||
98 | } | 98 | } |
99 | EXPORT_SYMBOL_GPL(mpls_pkt_too_big); | 99 | EXPORT_SYMBOL_GPL(mpls_pkt_too_big); |
100 | 100 | ||
101 | static u32 mpls_multipath_hash(struct mpls_route *rt, | 101 | static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb) |
102 | struct sk_buff *skb, bool bos) | ||
103 | { | 102 | { |
104 | struct mpls_entry_decoded dec; | 103 | struct mpls_entry_decoded dec; |
104 | unsigned int mpls_hdr_len = 0; | ||
105 | struct mpls_shim_hdr *hdr; | 105 | struct mpls_shim_hdr *hdr; |
106 | bool eli_seen = false; | 106 | bool eli_seen = false; |
107 | int label_index; | 107 | int label_index; |
108 | u32 hash = 0; | 108 | u32 hash = 0; |
109 | 109 | ||
110 | for (label_index = 0; label_index < MAX_MP_SELECT_LABELS && !bos; | 110 | for (label_index = 0; label_index < MAX_MP_SELECT_LABELS; |
111 | label_index++) { | 111 | label_index++) { |
112 | if (!pskb_may_pull(skb, sizeof(*hdr) * label_index)) | 112 | mpls_hdr_len += sizeof(*hdr); |
113 | if (!pskb_may_pull(skb, mpls_hdr_len)) | ||
113 | break; | 114 | break; |
114 | 115 | ||
115 | /* Read and decode the current label */ | 116 | /* Read and decode the current label */ |
@@ -134,37 +135,38 @@ static u32 mpls_multipath_hash(struct mpls_route *rt, | |||
134 | eli_seen = true; | 135 | eli_seen = true; |
135 | } | 136 | } |
136 | 137 | ||
137 | bos = dec.bos; | 138 | if (!dec.bos) |
138 | if (bos && pskb_may_pull(skb, sizeof(*hdr) * label_index + | 139 | continue; |
139 | sizeof(struct iphdr))) { | 140 | |
141 | /* found bottom label; does skb have room for a header? */ | ||
142 | if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) { | ||
140 | const struct iphdr *v4hdr; | 143 | const struct iphdr *v4hdr; |
141 | 144 | ||
142 | v4hdr = (const struct iphdr *)(mpls_hdr(skb) + | 145 | v4hdr = (const struct iphdr *)(hdr + 1); |
143 | label_index); | ||
144 | if (v4hdr->version == 4) { | 146 | if (v4hdr->version == 4) { |
145 | hash = jhash_3words(ntohl(v4hdr->saddr), | 147 | hash = jhash_3words(ntohl(v4hdr->saddr), |
146 | ntohl(v4hdr->daddr), | 148 | ntohl(v4hdr->daddr), |
147 | v4hdr->protocol, hash); | 149 | v4hdr->protocol, hash); |
148 | } else if (v4hdr->version == 6 && | 150 | } else if (v4hdr->version == 6 && |
149 | pskb_may_pull(skb, sizeof(*hdr) * label_index + | 151 | pskb_may_pull(skb, mpls_hdr_len + |
150 | sizeof(struct ipv6hdr))) { | 152 | sizeof(struct ipv6hdr))) { |
151 | const struct ipv6hdr *v6hdr; | 153 | const struct ipv6hdr *v6hdr; |
152 | 154 | ||
153 | v6hdr = (const struct ipv6hdr *)(mpls_hdr(skb) + | 155 | v6hdr = (const struct ipv6hdr *)(hdr + 1); |
154 | label_index); | ||
155 | |||
156 | hash = __ipv6_addr_jhash(&v6hdr->saddr, hash); | 156 | hash = __ipv6_addr_jhash(&v6hdr->saddr, hash); |
157 | hash = __ipv6_addr_jhash(&v6hdr->daddr, hash); | 157 | hash = __ipv6_addr_jhash(&v6hdr->daddr, hash); |
158 | hash = jhash_1word(v6hdr->nexthdr, hash); | 158 | hash = jhash_1word(v6hdr->nexthdr, hash); |
159 | } | 159 | } |
160 | } | 160 | } |
161 | |||
162 | break; | ||
161 | } | 163 | } |
162 | 164 | ||
163 | return hash; | 165 | return hash; |
164 | } | 166 | } |
165 | 167 | ||
166 | static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt, | 168 | static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt, |
167 | struct sk_buff *skb, bool bos) | 169 | struct sk_buff *skb) |
168 | { | 170 | { |
169 | int alive = ACCESS_ONCE(rt->rt_nhn_alive); | 171 | int alive = ACCESS_ONCE(rt->rt_nhn_alive); |
170 | u32 hash = 0; | 172 | u32 hash = 0; |
@@ -180,7 +182,7 @@ static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt, | |||
180 | if (alive <= 0) | 182 | if (alive <= 0) |
181 | return NULL; | 183 | return NULL; |
182 | 184 | ||
183 | hash = mpls_multipath_hash(rt, skb, bos); | 185 | hash = mpls_multipath_hash(rt, skb); |
184 | nh_index = hash % alive; | 186 | nh_index = hash % alive; |
185 | if (alive == rt->rt_nhn) | 187 | if (alive == rt->rt_nhn) |
186 | goto out; | 188 | goto out; |
@@ -278,17 +280,11 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, | |||
278 | hdr = mpls_hdr(skb); | 280 | hdr = mpls_hdr(skb); |
279 | dec = mpls_entry_decode(hdr); | 281 | dec = mpls_entry_decode(hdr); |
280 | 282 | ||
281 | /* Pop the label */ | ||
282 | skb_pull(skb, sizeof(*hdr)); | ||
283 | skb_reset_network_header(skb); | ||
284 | |||
285 | skb_orphan(skb); | ||
286 | |||
287 | rt = mpls_route_input_rcu(net, dec.label); | 283 | rt = mpls_route_input_rcu(net, dec.label); |
288 | if (!rt) | 284 | if (!rt) |
289 | goto drop; | 285 | goto drop; |
290 | 286 | ||
291 | nh = mpls_select_multipath(rt, skb, dec.bos); | 287 | nh = mpls_select_multipath(rt, skb); |
292 | if (!nh) | 288 | if (!nh) |
293 | goto drop; | 289 | goto drop; |
294 | 290 | ||
@@ -297,6 +293,12 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, | |||
297 | if (!mpls_output_possible(out_dev)) | 293 | if (!mpls_output_possible(out_dev)) |
298 | goto drop; | 294 | goto drop; |
299 | 295 | ||
296 | /* Pop the label */ | ||
297 | skb_pull(skb, sizeof(*hdr)); | ||
298 | skb_reset_network_header(skb); | ||
299 | |||
300 | skb_orphan(skb); | ||
301 | |||
300 | if (skb_warn_if_lro(skb)) | 302 | if (skb_warn_if_lro(skb)) |
301 | goto drop; | 303 | goto drop; |
302 | 304 | ||