|
@@ -98,18 +98,19 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(mpls_pkt_too_big);
|
|
|
|
|
|
-static u32 mpls_multipath_hash(struct mpls_route *rt,
|
|
|
- struct sk_buff *skb, bool bos)
|
|
|
+static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
|
|
|
{
|
|
|
struct mpls_entry_decoded dec;
|
|
|
+ unsigned int mpls_hdr_len = 0;
|
|
|
struct mpls_shim_hdr *hdr;
|
|
|
bool eli_seen = false;
|
|
|
int label_index;
|
|
|
u32 hash = 0;
|
|
|
|
|
|
- for (label_index = 0; label_index < MAX_MP_SELECT_LABELS && !bos;
|
|
|
+ for (label_index = 0; label_index < MAX_MP_SELECT_LABELS;
|
|
|
label_index++) {
|
|
|
- if (!pskb_may_pull(skb, sizeof(*hdr) * label_index))
|
|
|
+ mpls_hdr_len += sizeof(*hdr);
|
|
|
+ if (!pskb_may_pull(skb, mpls_hdr_len))
|
|
|
break;
|
|
|
|
|
|
/* Read and decode the current label */
|
|
@@ -134,37 +135,38 @@ static u32 mpls_multipath_hash(struct mpls_route *rt,
|
|
|
eli_seen = true;
|
|
|
}
|
|
|
|
|
|
- bos = dec.bos;
|
|
|
- if (bos && pskb_may_pull(skb, sizeof(*hdr) * label_index +
|
|
|
- sizeof(struct iphdr))) {
|
|
|
+ if (!dec.bos)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* found bottom label; does skb have room for a header? */
|
|
|
+ if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) {
|
|
|
const struct iphdr *v4hdr;
|
|
|
|
|
|
- v4hdr = (const struct iphdr *)(mpls_hdr(skb) +
|
|
|
- label_index);
|
|
|
+ v4hdr = (const struct iphdr *)(hdr + 1);
|
|
|
if (v4hdr->version == 4) {
|
|
|
hash = jhash_3words(ntohl(v4hdr->saddr),
|
|
|
ntohl(v4hdr->daddr),
|
|
|
v4hdr->protocol, hash);
|
|
|
} else if (v4hdr->version == 6 &&
|
|
|
- pskb_may_pull(skb, sizeof(*hdr) * label_index +
|
|
|
- sizeof(struct ipv6hdr))) {
|
|
|
+ pskb_may_pull(skb, mpls_hdr_len +
|
|
|
+ sizeof(struct ipv6hdr))) {
|
|
|
const struct ipv6hdr *v6hdr;
|
|
|
|
|
|
- v6hdr = (const struct ipv6hdr *)(mpls_hdr(skb) +
|
|
|
- label_index);
|
|
|
-
|
|
|
+ v6hdr = (const struct ipv6hdr *)(hdr + 1);
|
|
|
hash = __ipv6_addr_jhash(&v6hdr->saddr, hash);
|
|
|
hash = __ipv6_addr_jhash(&v6hdr->daddr, hash);
|
|
|
hash = jhash_1word(v6hdr->nexthdr, hash);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
return hash;
|
|
|
}
|
|
|
|
|
|
static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
|
|
|
- struct sk_buff *skb, bool bos)
|
|
|
+ struct sk_buff *skb)
|
|
|
{
|
|
|
int alive = ACCESS_ONCE(rt->rt_nhn_alive);
|
|
|
u32 hash = 0;
|
|
@@ -180,7 +182,7 @@ static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
|
|
|
if (alive <= 0)
|
|
|
return NULL;
|
|
|
|
|
|
- hash = mpls_multipath_hash(rt, skb, bos);
|
|
|
+ hash = mpls_multipath_hash(rt, skb);
|
|
|
nh_index = hash % alive;
|
|
|
if (alive == rt->rt_nhn)
|
|
|
goto out;
|
|
@@ -278,17 +280,11 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
|
|
|
hdr = mpls_hdr(skb);
|
|
|
dec = mpls_entry_decode(hdr);
|
|
|
|
|
|
- /* Pop the label */
|
|
|
- skb_pull(skb, sizeof(*hdr));
|
|
|
- skb_reset_network_header(skb);
|
|
|
-
|
|
|
- skb_orphan(skb);
|
|
|
-
|
|
|
rt = mpls_route_input_rcu(net, dec.label);
|
|
|
if (!rt)
|
|
|
goto drop;
|
|
|
|
|
|
- nh = mpls_select_multipath(rt, skb, dec.bos);
|
|
|
+ nh = mpls_select_multipath(rt, skb);
|
|
|
if (!nh)
|
|
|
goto drop;
|
|
|
|
|
@@ -297,6 +293,12 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
|
|
|
if (!mpls_output_possible(out_dev))
|
|
|
goto drop;
|
|
|
|
|
|
+ /* Pop the label */
|
|
|
+ skb_pull(skb, sizeof(*hdr));
|
|
|
+ skb_reset_network_header(skb);
|
|
|
+
|
|
|
+ skb_orphan(skb);
|
|
|
+
|
|
|
if (skb_warn_if_lro(skb))
|
|
|
goto drop;
|
|
|
|