diff options
Diffstat (limited to 'net/openvswitch/flow.c')
-rw-r--r-- | net/openvswitch/flow.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 2b78789ea7c5..90a21010fc8f 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/if_arp.h> | 32 | #include <linux/if_arp.h> |
33 | #include <linux/ip.h> | 33 | #include <linux/ip.h> |
34 | #include <linux/ipv6.h> | 34 | #include <linux/ipv6.h> |
35 | #include <linux/mpls.h> | ||
35 | #include <linux/sctp.h> | 36 | #include <linux/sctp.h> |
36 | #include <linux/smp.h> | 37 | #include <linux/smp.h> |
37 | #include <linux/tcp.h> | 38 | #include <linux/tcp.h> |
@@ -42,6 +43,7 @@ | |||
42 | #include <net/ip.h> | 43 | #include <net/ip.h> |
43 | #include <net/ip_tunnels.h> | 44 | #include <net/ip_tunnels.h> |
44 | #include <net/ipv6.h> | 45 | #include <net/ipv6.h> |
46 | #include <net/mpls.h> | ||
45 | #include <net/ndisc.h> | 47 | #include <net/ndisc.h> |
46 | 48 | ||
47 | #include "datapath.h" | 49 | #include "datapath.h" |
@@ -480,6 +482,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
480 | return -ENOMEM; | 482 | return -ENOMEM; |
481 | 483 | ||
482 | skb_reset_network_header(skb); | 484 | skb_reset_network_header(skb); |
485 | skb_reset_mac_len(skb); | ||
483 | __skb_push(skb, skb->data - skb_mac_header(skb)); | 486 | __skb_push(skb, skb->data - skb_mac_header(skb)); |
484 | 487 | ||
485 | /* Network layer. */ | 488 | /* Network layer. */ |
@@ -584,6 +587,33 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
584 | memset(&key->ip, 0, sizeof(key->ip)); | 587 | memset(&key->ip, 0, sizeof(key->ip)); |
585 | memset(&key->ipv4, 0, sizeof(key->ipv4)); | 588 | memset(&key->ipv4, 0, sizeof(key->ipv4)); |
586 | } | 589 | } |
590 | } else if (eth_p_mpls(key->eth.type)) { | ||
591 | size_t stack_len = MPLS_HLEN; | ||
592 | |||
593 | /* In the presence of an MPLS label stack the end of the L2 | ||
594 | * header and the beginning of the L3 header differ. | ||
595 | * | ||
596 | * Advance network_header to the beginning of the L3 | ||
597 | * header. mac_len corresponds to the end of the L2 header. | ||
598 | */ | ||
599 | while (1) { | ||
600 | __be32 lse; | ||
601 | |||
602 | error = check_header(skb, skb->mac_len + stack_len); | ||
603 | if (unlikely(error)) | ||
604 | return 0; | ||
605 | |||
606 | memcpy(&lse, skb_network_header(skb), MPLS_HLEN); | ||
607 | |||
608 | if (stack_len == MPLS_HLEN) | ||
609 | memcpy(&key->mpls.top_lse, &lse, MPLS_HLEN); | ||
610 | |||
611 | skb_set_network_header(skb, skb->mac_len + stack_len); | ||
612 | if (lse & htonl(MPLS_LS_S_MASK)) | ||
613 | break; | ||
614 | |||
615 | stack_len += MPLS_HLEN; | ||
616 | } | ||
587 | } else if (key->eth.type == htons(ETH_P_IPV6)) { | 617 | } else if (key->eth.type == htons(ETH_P_IPV6)) { |
588 | int nh_len; /* IPv6 Header + Extensions */ | 618 | int nh_len; /* IPv6 Header + Extensions */ |
589 | 619 | ||