From: Pravin B Shelar Date: Sat, 8 Nov 2014 16:14:21 +0000 (-0800) Subject: datapath: Fix few mpls issues. X-Git-Tag: v2.4.0~1005 X-Git-Url: http://git.cascardo.eti.br/?p=cascardo%2Fovs.git;a=commitdiff_plain;h=2baf0e0c6cd2a96afd43cd7df2b94afe94dd1d4c datapath: Fix few mpls issues. Found during MPLS upstreaming. Also sync-up MPLS header files with upstream code. Signed-off-by: Pravin B Shelar --- diff --git a/datapath/Modules.mk b/datapath/Modules.mk index 72cb4dcbf..cca488727 100644 --- a/datapath/Modules.mk +++ b/datapath/Modules.mk @@ -27,7 +27,6 @@ openvswitch_headers = \ flow.h \ flow_netlink.h \ flow_table.h \ - mpls.h \ vlan.h \ vport.h \ vport-internal_dev.h \ diff --git a/datapath/actions.c b/datapath/actions.c index 3868e105f..b7cd58ed8 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -32,11 +32,11 @@ #include #include #include +#include #include #include "datapath.h" #include "gso.h" -#include "mpls.h" #include "vlan.h" #include "vport.h" @@ -133,25 +133,16 @@ static int make_writable(struct sk_buff *skb, int write_len) return pskb_expand_head(skb, 0, 0, GFP_ATOMIC); } -/* The end of the mac header. - * - * For non-MPLS skbs this will correspond to the network header. - * For MPLS skbs it will be before the network_header as the MPLS - * label stack lies between the end of the mac header and the network - * header. That is, for MPLS skbs the end of the mac header - * is the top of the MPLS label stack. - */ -static unsigned char *mac_header_end(const struct sk_buff *skb) -{ - return skb_mac_header(skb) + skb->mac_len; -} - static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_action_push_mpls *mpls) { __be32 *new_mpls_lse; struct ethhdr *hdr; + /* Networking stack do not allow simultaneous Tunnel and MPLS GSO. */ + if (skb_encapsulation(skb)) + return -ENOTSUPP; + if (skb_cow_head(skb, MPLS_HLEN) < 0) return -ENOMEM; @@ -160,7 +151,7 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, skb->mac_len); skb_reset_mac_header(skb); - new_mpls_lse = (__be32 *)mac_header_end(skb); + new_mpls_lse = (__be32 *)skb_mpls_header(skb); *new_mpls_lse = mpls->mpls_lse; if (skb->ip_summed == CHECKSUM_COMPLETE) @@ -172,6 +163,7 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key, if (!ovs_skb_get_inner_protocol(skb)) ovs_skb_set_inner_protocol(skb, skb->protocol); skb->protocol = mpls->mpls_ethertype; + invalidate_flow_key(key); return 0; } @@ -188,7 +180,7 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, if (skb->ip_summed == CHECKSUM_COMPLETE) skb->csum = csum_sub(skb->csum, - csum_partial(mac_header_end(skb), + csum_partial(skb_mpls_header(skb), MPLS_HLEN, 0)); memmove(skb_mac_header(skb) + MPLS_HLEN, skb_mac_header(skb), @@ -197,13 +189,14 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, __skb_pull(skb, MPLS_HLEN); skb_reset_mac_header(skb); - /* mac_header_end() is used to locate the ethertype + /* skb_mpls_header() is used to locate the ethertype * field correctly in the presence of VLAN tags. */ - hdr = (struct ethhdr *)(mac_header_end(skb) - ETH_HLEN); + hdr = (struct ethhdr *)(skb_mpls_header(skb) - ETH_HLEN); hdr->h_proto = ethertype; if (eth_p_mpls(skb->protocol)) skb->protocol = ethertype; + invalidate_flow_key(key); return 0; } @@ -211,13 +204,14 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, static int set_mpls(struct sk_buff *skb, struct sw_flow_key *key, const __be32 *mpls_lse) { - __be32 *stack = (__be32 *)mac_header_end(skb); + __be32 *stack; int err; err = make_writable(skb, skb->mac_len + MPLS_HLEN); if (unlikely(err)) return err; + stack = (__be32 *)skb_mpls_header(skb); if (skb->ip_summed == CHECKSUM_COMPLETE) { __be32 diff[] = { ~(*stack), *mpls_lse }; skb->csum = ~csum_partial((char *)diff, sizeof(diff), @@ -300,7 +294,6 @@ static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag)) return -ENOMEM; - /* Update mac_len for subsequent MPLS actions */ skb->mac_len += VLAN_HLEN; @@ -629,10 +622,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port) static int output_userspace(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr) { + struct ovs_tunnel_info info; struct dp_upcall_info upcall; const struct nlattr *a; int rem; - struct ovs_tunnel_info info; upcall.cmd = OVS_PACKET_CMD_ACTION; upcall.userdata = NULL; diff --git a/datapath/compat.h b/datapath/compat.h index 9632a6e60..5ef626fdb 100644 --- a/datapath/compat.h +++ b/datapath/compat.h @@ -76,4 +76,14 @@ static inline struct rtable *find_route(struct net *net, return rt; #endif } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +static inline bool skb_encapsulation(struct sk_buff *skb) +{ + return skb->encapsulation; +} +#else +#define skb_encapsulation(skb) false +#endif + #endif /* compat.h */ diff --git a/datapath/flow.c b/datapath/flow.c index a3c5d2f2b..5c25a5d32 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -41,13 +42,13 @@ #include #include #include +#include #include #include "datapath.h" #include "flow.h" #include "flow_netlink.h" -#include "mpls.h" #include "vlan.h" u64 ovs_flow_used_time(unsigned long flow_jiffies) @@ -609,7 +610,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) memcpy(&key->mpls.top_lse, &lse, MPLS_HLEN); skb_set_network_header(skb, skb->mac_len + stack_len); - if (lse & htonl(MPLS_BOS_MASK)) + if (lse & htonl(MPLS_LS_S_MASK)) break; stack_len += MPLS_HLEN; diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index 37b0bdd6c..0649d2caf 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -18,9 +18,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "flow.h" -#include "datapath.h" -#include "mpls.h" #include #include #include @@ -45,10 +42,12 @@ #include #include #include -#include #include #include +#include +#include "datapath.h" +#include "flow.h" #include "flow_netlink.h" static void update_range(struct sw_flow_match *match, @@ -1665,6 +1664,9 @@ static int validate_set(const struct nlattr *a, break; case OVS_KEY_ATTR_TUNNEL: + if (eth_p_mpls(eth_type)) + return -EINVAL; + *set_tun = true; err = validate_and_copy_set_tun(a, sfa, log); if (err) @@ -1778,6 +1780,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, __be16 eth_type, __be16 vlan_tci, bool log) { const struct nlattr *a; + bool out_tnl_port = false; int rem, err; if (depth >= SAMPLE_ACTION_DEPTH) @@ -1820,6 +1823,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_OUTPUT: if (nla_get_u32(a) >= DP_MAX_PORTS) return -EINVAL; + out_tnl_port = false; break; case OVS_ACTION_ATTR_HASH: { @@ -1854,6 +1858,12 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_PUSH_MPLS: { const struct ovs_action_push_mpls *mpls = nla_data(a); + /* Networking stack do not allow simultaneous Tunnel + * and MPLS GSO. + */ + if (out_tnl_port) + return -EINVAL; + if (!eth_p_mpls(mpls->mpls_ethertype)) return -EINVAL; /* Prohibit push MPLS other than to a white list @@ -1888,10 +1898,11 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, break; case OVS_ACTION_ATTR_SET: - err = validate_set(a, key, sfa, &skip_copy, eth_type, - log); + err = validate_set(a, key, sfa, + &out_tnl_port, eth_type, log); if (err) return err; + skip_copy = out_tnl_port; break; case OVS_ACTION_ATTR_SAMPLE: diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index 274b1f166..4b38fd57d 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -41,6 +41,7 @@ openvswitch_headers += \ linux/compat/include/linux/kernel.h \ linux/compat/include/linux/list.h \ linux/compat/include/linux/log2.h \ + linux/compat/include/linux/mpls.h \ linux/compat/include/linux/net.h \ linux/compat/include/linux/random.h \ linux/compat/include/linux/netdevice.h \ @@ -70,6 +71,7 @@ openvswitch_headers += \ linux/compat/include/net/ip.h \ linux/compat/include/net/ip_tunnels.h \ linux/compat/include/net/ipv6.h \ + linux/compat/include/net/mpls.h \ linux/compat/include/net/net_namespace.h \ linux/compat/include/net/netlink.h \ linux/compat/include/net/udp.h \ diff --git a/datapath/linux/compat/gso.c b/datapath/linux/compat/gso.c index 8344293bb..96b5d3d08 100644 --- a/datapath/linux/compat/gso.c +++ b/datapath/linux/compat/gso.c @@ -34,12 +34,12 @@ #include #include +#include #include #include #include #include "gso.h" -#include "mpls.h" #include "vlan.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \ diff --git a/datapath/linux/compat/gso.h b/datapath/linux/compat/gso.h index 20ec55cf0..fd1084871 100644 --- a/datapath/linux/compat/gso.h +++ b/datapath/linux/compat/gso.h @@ -102,11 +102,19 @@ static inline void ovs_skb_init_inner_protocol(struct sk_buff *skb) { */ } +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb, __be16 ethertype) { skb->inner_protocol = ethertype; } +#else +static inline void ovs_skb_set_inner_protocol(struct sk_buff *skb, + __be16 ethertype) +{ + skb_set_inner_protocol(skb, ethertype); +} +#endif static inline __be16 ovs_skb_get_inner_protocol(struct sk_buff *skb) { diff --git a/datapath/linux/compat/include/linux/mpls.h b/datapath/linux/compat/include/linux/mpls.h new file mode 100644 index 000000000..ab99ebc30 --- /dev/null +++ b/datapath/linux/compat/include/linux/mpls.h @@ -0,0 +1,40 @@ +#ifndef _UAPI_MPLS_WRAPPER_H +#define _UAPI_MPLS_WRAPPER_H + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,0) +#include_next +#else + +#include +#include + +/* Reference: RFC 5462, RFC 3032 + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Label | TC |S| TTL | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Label: Label Value, 20 bits + * TC: Traffic Class field, 3 bits + * S: Bottom of Stack, 1 bit + * TTL: Time to Live, 8 bits + */ + +struct mpls_label { + __be32 entry; +}; + +#define MPLS_LS_LABEL_MASK 0xFFFFF000 +#define MPLS_LS_LABEL_SHIFT 12 +#define MPLS_LS_TC_MASK 0x00000E00 +#define MPLS_LS_TC_SHIFT 9 +#define MPLS_LS_S_MASK 0x00000100 +#define MPLS_LS_S_SHIFT 8 +#define MPLS_LS_TTL_MASK 0x000000FF +#define MPLS_LS_TTL_SHIFT 0 +#endif + +#endif /* _UAPI_MPLS_WRAPPER_H */ diff --git a/datapath/linux/compat/include/net/mpls.h b/datapath/linux/compat/include/net/mpls.h new file mode 100644 index 000000000..73e48e37e --- /dev/null +++ b/datapath/linux/compat/include/net/mpls.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Nicira, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _NET_MPLS_WRAPPER_H +#define _NET_MPLS_WRAPPER_H 1 + +#include +#include + +#define MPLS_HLEN 4 + +static inline bool eth_p_mpls(__be16 eth_type) +{ + return eth_type == htons(ETH_P_MPLS_UC) || + eth_type == htons(ETH_P_MPLS_MC); +} + +/* + * For non-MPLS skbs this will correspond to the network header. + * For MPLS skbs it will be before the network_header as the MPLS + * label stack lies between the end of the mac header and the network + * header. That is, for MPLS skbs the end of the mac header + * is the top of the MPLS label stack. + */ +static inline unsigned char *skb_mpls_header(struct sk_buff *skb) +{ + return skb_mac_header(skb) + skb->mac_len; +} +#endif /* _NET_MPLS_WRAPPER_H */ diff --git a/datapath/linux/compat/netdevice.c b/datapath/linux/compat/netdevice.c index 72bdec5f4..79308238b 100644 --- a/datapath/linux/compat/netdevice.c +++ b/datapath/linux/compat/netdevice.c @@ -1,7 +1,7 @@ #include #include +#include -#include "mpls.h" #include "gso.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) diff --git a/datapath/mpls.h b/datapath/mpls.h deleted file mode 100644 index 7eab104be..000000000 --- a/datapath/mpls.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef MPLS_H -#define MPLS_H 1 - -#include - -#define MPLS_BOS_MASK 0x00000100 -#define MPLS_HLEN 4 - -static inline bool eth_p_mpls(__be16 eth_type) -{ - return eth_type == htons(ETH_P_MPLS_UC) || - eth_type == htons(ETH_P_MPLS_MC); -} - -#endif