This is a first pass at providing a tun_key which can be used as the basis for flow-based tunnelling. The tun_key includes and replaces the tun_id in both struct ovs_skb_cb and struct sw_tun_key.
This patch allows all existing tun_id behaviour to still work. Existing users of tun_id are redirected to tun_key->tun_id to retain compatibility. However, when the userspace code is updated to make use of the new tun_key, the old behaviour will be deprecated and removed. NOTE: With these changes, the tunneling code no longer assumes input and output keys are symmetric. If they are not, PMTUD needs to be disabled for tunneling to work. Signed-off-by: Kyle Mestery <kmest...@cisco.com> Cc: Simon Horman <ho...@verge.net.au> Cc: Jesse Gross <je...@nicira.com> --- V3: - Fix issues found during review by Jesse. - Add a NEWS entry around tunnel code no longer assuming symmetric input and output tunnel keys. V2: - Fix blank line addition/removal found by Simon. - Fix hex printing output found by Simon. --- NEWS | 2 ++ datapath/actions.c | 8 +++-- datapath/datapath.c | 10 +++++- datapath/datapath.h | 5 +-- datapath/flow.c | 51 +++++++++++++++++++++++++---- datapath/flow.h | 10 +++--- datapath/tunnel.c | 80 +++++++++++++++++++++++++-------------------- datapath/tunnel.h | 14 ++++++-- datapath/vport-capwap.c | 12 +++---- datapath/vport-gre.c | 15 +++++---- datapath/vport.c | 2 +- include/linux/openvswitch.h | 13 +++++++- lib/dpif-netdev.c | 1 + lib/odp-util.c | 17 ++++++++-- lib/odp-util.h | 5 +-- 15 files changed, 173 insertions(+), 72 deletions(-) diff --git a/NEWS b/NEWS index 872f8d0..389b4c0 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ post-v1.8.0 ------------------------ + - The tunneling code no longer assumes input and output keys are symmetric. + If they are not, PMTUD needs to be disabled for tunneling to work. - FreeBSD is now a supported platform, thanks to code contributions from Gaetano Catalli, Ed Maste, and Giuseppe Lettieri. - ovs-bugtool: New --ovs option to report only OVS related information. diff --git a/datapath/actions.c b/datapath/actions.c index ec9b595..9ce5a0b 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -343,7 +343,11 @@ static int execute_set_action(struct sk_buff *skb, break; case OVS_KEY_ATTR_TUN_ID: - OVS_CB(skb)->tun_id = nla_get_be64(nested_attr); + OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr); + break; + + case OVS_KEY_ATTR_IPV4_TUNNEL: + OVS_CB(skb)->tun_key = nla_data(nested_attr); break; case OVS_KEY_ATTR_ETHERNET: @@ -469,7 +473,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb) goto out_loop; } - OVS_CB(skb)->tun_id = 0; + OVS_CB(skb)->tun_key = NULL; error = do_execute_actions(dp, skb, acts->actions, acts->actions_len, false); diff --git a/datapath/datapath.c b/datapath/datapath.c index c83ce16..83622a4 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -587,12 +587,20 @@ static int validate_set(const struct nlattr *a, switch (key_type) { const struct ovs_key_ipv4 *ipv4_key; + const struct ovs_key_ipv4_tunnel *tun_key; case OVS_KEY_ATTR_PRIORITY: case OVS_KEY_ATTR_TUN_ID: case OVS_KEY_ATTR_ETHERNET: break; + case OVS_KEY_ATTR_IPV4_TUNNEL: + tun_key = nla_data(ovs_key); + if (!tun_key->ipv4_dst) { + return -EINVAL; + } + break; + case OVS_KEY_ATTR_IPV4: if (flow_key->eth.type != htons(ETH_P_IP)) return -EINVAL; @@ -785,7 +793,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority, &flow->key.phy.in_port, - &flow->key.phy.tun_id, + &flow->key.phy.tun_key, a[OVS_PACKET_ATTR_KEY]); if (err) goto err_flow_put; diff --git a/datapath/datapath.h b/datapath/datapath.h index affbf0e..c5df12d 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -96,7 +96,8 @@ struct datapath { /** * struct ovs_skb_cb - OVS data in skb CB * @flow: The flow associated with this packet. May be %NULL if no flow. - * @tun_id: ID of the tunnel that encapsulated this packet. It is 0 if the + * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the + * packet is not being tunneled. * @ip_summed: Consistently stores L4 checksumming status across different * kernel versions. * @csum_start: Stores the offset from which to start checksumming independent @@ -107,7 +108,7 @@ struct datapath { */ struct ovs_skb_cb { struct sw_flow *flow; - __be64 tun_id; + struct ovs_key_ipv4_tunnel *tun_key; #ifdef NEED_CSUM_NORMALIZE enum csum_type ip_summed; u16 csum_start; diff --git a/datapath/flow.c b/datapath/flow.c index d07337c..c250315 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -629,7 +629,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, memset(key, 0, sizeof(*key)); key->phy.priority = skb->priority; - key->phy.tun_id = OVS_CB(skb)->tun_id; + if (OVS_CB(skb)->tun_key) + key->phy.tun_key = *OVS_CB(skb)->tun_key; key->phy.in_port = in_port; skb_reset_mac_header(skb); @@ -847,6 +848,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { /* Not upstream. */ [OVS_KEY_ATTR_TUN_ID] = sizeof(__be64), + [OVS_KEY_ATTR_IPV4_TUNNEL] = sizeof(struct ovs_key_ipv4_tunnel), }; static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, @@ -996,6 +998,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, { const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; const struct ovs_key_ethernet *eth_key; + __be64 tun_id = 0; int key_len; u64 attrs; int err; @@ -1023,10 +1026,28 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, } if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) { - swkey->phy.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]); + tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]); attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID); } + if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) { + struct ovs_key_ipv4_tunnel *tun_key; + tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]); + + /* + * If both OVS_KEY_ATTR_TUN_ID and OVS_KEY_ATTR_IPV4_TUNNEL are + * present, ensure they are consistent or error out. + */ + if (tun_id != 0) { + /* Verify they match */ + if (tun_id != tun_key->tun_id) + return -EINVAL; + } + + swkey->phy.tun_key = *tun_key; + attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL); + } + /* Data attributes. */ if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) return -EINVAL; @@ -1162,14 +1183,15 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, * get the metadata, that is, the parts of the flow key that cannot be * extracted from the packet itself. */ -int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id, +int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, + struct ovs_key_ipv4_tunnel *tun_key, const struct nlattr *attr) { const struct nlattr *nla; int rem; *in_port = DP_MAX_PORTS; - *tun_id = 0; + memset(tun_key, 0, sizeof(struct ovs_key_ipv4_tunnel)); *priority = 0; nla_for_each_nested(nla, attr, rem) { @@ -1185,7 +1207,12 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id, break; case OVS_KEY_ATTR_TUN_ID: - *tun_id = nla_get_be64(nla); + tun_key->tun_id = nla_get_be64(nla); + break; + + case OVS_KEY_ATTR_IPV4_TUNNEL: + memcpy(tun_key, nla_data(nla), + sizeof(*tun_key)); break; case OVS_KEY_ATTR_IN_PORT: @@ -1210,10 +1237,20 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority)) goto nla_put_failure; - if (swkey->phy.tun_id != cpu_to_be64(0) && - nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun_id)) + if (swkey->phy.tun_key.tun_id != cpu_to_be64(0) && + nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun_key.tun_id)) goto nla_put_failure; + if (swkey->phy.tun_key.ipv4_dst) { + struct ovs_key_ipv4_tunnel *tun_key; + nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, + sizeof(*tun_key)); + if (!nla) + goto nla_put_failure; + tun_key = nla_data(nla); + *tun_key = swkey->phy.tun_key; + } + if (swkey->phy.in_port != DP_MAX_PORTS && nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) goto nla_put_failure; diff --git a/datapath/flow.h b/datapath/flow.h index 02c563a..ffa047a 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -42,7 +42,7 @@ struct sw_flow_actions { struct sw_flow_key { struct { - __be64 tun_id; /* Encapsulating tunnel ID. */ + struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ u32 priority; /* Packet QoS priority. */ u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ } phy; @@ -150,6 +150,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); * ------ --- ------ ----- * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 * OVS_KEY_ATTR_TUN_ID 8 -- 4 12 + * OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) @@ -160,14 +161,15 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); * OVS_KEY_ATTR_ICMPV6 2 2 4 8 * OVS_KEY_ATTR_ND 28 -- 4 32 * ------------------------------------------------- - * total 156 + * total 184 */ -#define FLOW_BUFSIZE 156 +#define FLOW_BUFSIZE 184 int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, const struct nlattr *); -int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id, +int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, + struct ovs_key_ipv4_tunnel *tun_key, const struct nlattr *); #define MAX_ACTIONS_BUFSIZE (16 * 1024) diff --git a/datapath/tunnel.c b/datapath/tunnel.c index d651c11..0687f80 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -367,9 +367,9 @@ struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr, return NULL; } -static void ecn_decapsulate(struct sk_buff *skb, u8 tos) +static void ecn_decapsulate(struct sk_buff *skb) { - if (unlikely(INET_ECN_is_ce(tos))) { + if (unlikely(INET_ECN_is_ce(OVS_CB(skb)->tun_key->ipv4_tos))) { __be16 protocol = skb->protocol; skb_set_network_header(skb, ETH_HLEN); @@ -416,7 +416,7 @@ static void ecn_decapsulate(struct sk_buff *skb, u8 tos) * - skb->csum does not include the inner Ethernet header. * - The layer pointers are undefined. */ -void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos) +void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb) { struct ethhdr *eh; @@ -433,7 +433,7 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos) skb_clear_rxhash(skb); secpath_reset(skb); - ecn_decapsulate(skb, tos); + ecn_decapsulate(skb); vlan_set_tci(skb, 0); if (unlikely(compute_ip_summed(skb, false))) { @@ -613,7 +613,7 @@ static void ipv6_build_icmp(struct sk_buff *skb, struct sk_buff *nskb, bool ovs_tnl_frag_needed(struct vport *vport, const struct tnl_mutable_config *mutable, - struct sk_buff *skb, unsigned int mtu, __be64 flow_key) + struct sk_buff *skb, unsigned int mtu) { unsigned int eth_hdr_len = ETH_HLEN; unsigned int total_length = 0, header_length = 0, payload_length; @@ -697,17 +697,6 @@ bool ovs_tnl_frag_needed(struct vport *vport, ipv6_build_icmp(skb, nskb, mtu, payload_length); #endif - /* - * Assume that flow based keys are symmetric with respect to input - * and output and use the key that we were going to put on the - * outgoing packet for the fake received packet. If the keys are - * not symmetric then PMTUD needs to be disabled since we won't have - * any way of synthesizing packets. - */ - if ((mutable->flags & (TNL_F_IN_KEY_MATCH | TNL_F_OUT_KEY_ACTION)) == - (TNL_F_IN_KEY_MATCH | TNL_F_OUT_KEY_ACTION)) - OVS_CB(nskb)->tun_id = flow_key; - if (unlikely(compute_ip_summed(nskb, false))) { kfree_skb(nskb); return false; @@ -760,8 +749,7 @@ static bool check_mtu(struct sk_buff *skb, mtu = max(mtu, IP_MIN_MTU); if (packet_length > mtu && - ovs_tnl_frag_needed(vport, mutable, skb, mtu, - OVS_CB(skb)->tun_id)) + ovs_tnl_frag_needed(vport, mutable, skb, mtu)) return false; } } @@ -777,8 +765,7 @@ static bool check_mtu(struct sk_buff *skb, mtu = max(mtu, IPV6_MIN_MTU); if (packet_length > mtu && - ovs_tnl_frag_needed(vport, mutable, skb, mtu, - OVS_CB(skb)->tun_id)) + ovs_tnl_frag_needed(vport, mutable, skb, mtu)) return false; } } @@ -799,10 +786,10 @@ static void create_tunnel_header(const struct vport *vport, iph->ihl = sizeof(struct iphdr) >> 2; iph->frag_off = htons(IP_DF); iph->protocol = tnl_vport->tnl_ops->ipproto; - iph->tos = mutable->tos; + iph->tos = mutable->tos; iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; - iph->ttl = mutable->ttl; + iph->ttl = mutable->ttl; if (!iph->ttl) iph->ttl = ip4_dst_hoplimit(&rt_dst(rt)); @@ -1000,15 +987,16 @@ unlock: } static struct rtable *__find_route(const struct tnl_mutable_config *mutable, - u8 ipproto, u8 tos) + __be32 saddr, __be32 daddr, u8 ipproto, + u8 tos) { /* Tunnel configuration keeps DSCP part of TOS bits, But Linux * router expect RT_TOS bits only. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) struct flowi fl = { .nl_u = { .ip4_u = { - .daddr = mutable->key.daddr, - .saddr = mutable->key.saddr, + .daddr = daddr, + .saddr = saddr, .tos = RT_TOS(tos) } }, .proto = ipproto }; struct rtable *rt; @@ -1018,8 +1006,8 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable, return rt; #else - struct flowi4 fl = { .daddr = mutable->key.daddr, - .saddr = mutable->key.saddr, + struct flowi4 fl = { .daddr = daddr, + .saddr = saddr, .flowi4_tos = RT_TOS(tos), .flowi4_proto = ipproto }; @@ -1029,7 +1017,8 @@ static struct rtable *__find_route(const struct tnl_mutable_config *mutable, static struct rtable *find_route(struct vport *vport, const struct tnl_mutable_config *mutable, - u8 tos, struct tnl_cache **cache) + u8 tos, __be32 daddr, __be32 saddr, + struct tnl_cache **cache) { struct tnl_vport *tnl_vport = tnl_vport_priv(vport); struct tnl_cache *cur_cache = rcu_dereference(tnl_vport->cache); @@ -1037,18 +1026,21 @@ static struct rtable *find_route(struct vport *vport, *cache = NULL; tos = RT_TOS(tos); - if (likely(tos == RT_TOS(mutable->tos) && - check_cache_valid(cur_cache, mutable))) { + if (daddr == mutable->key.daddr && saddr == mutable->key.saddr && + tos == RT_TOS(mutable->tos) && + check_cache_valid(cur_cache, mutable)) { *cache = cur_cache; return cur_cache->rt; } else { struct rtable *rt; - rt = __find_route(mutable, tnl_vport->tnl_ops->ipproto, tos); + rt = __find_route(mutable, saddr, daddr, + tnl_vport->tnl_ops->ipproto, tos); if (IS_ERR(rt)) return NULL; - if (likely(tos == RT_TOS(mutable->tos))) + if (daddr == mutable->key.daddr && saddr == mutable->key.saddr && + tos == RT_TOS(mutable->tos)) *cache = build_cache(vport, mutable, rt); return rt; @@ -1180,6 +1172,8 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) struct tnl_cache *cache; int sent_len = 0; __be16 frag_off = 0; + __be32 daddr; + __be32 saddr; u8 ttl; u8 inner_tos; u8 tos; @@ -1219,11 +1213,23 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) if (mutable->flags & TNL_F_TOS_INHERIT) tos = inner_tos; + else if (OVS_CB(skb)->tun_key && OVS_CB(skb)->tun_key->ipv4_tos != 0) + tos = OVS_CB(skb)->tun_key->ipv4_tos; else tos = mutable->tos; + if (OVS_CB(skb)->tun_key && OVS_CB(skb)->tun_key->ipv4_dst != 0) + daddr = OVS_CB(skb)->tun_key->ipv4_dst; + else + daddr = mutable->key.daddr; + + if (OVS_CB(skb)->tun_key && OVS_CB(skb)->tun_key->ipv4_src != 0) + saddr = OVS_CB(skb)->tun_key->ipv4_src; + else + saddr = mutable->key.saddr; + /* Route lookup */ - rt = find_route(vport, mutable, tos, &cache); + rt = find_route(vport, mutable, tos, daddr, saddr, &cache); if (unlikely(!rt)) goto error_free; if (unlikely(!cache)) @@ -1260,7 +1266,10 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb) } /* TTL */ - ttl = mutable->ttl; + if (OVS_CB(skb)->tun_key && OVS_CB(skb)->tun_key->ipv4_ttl != 0) + ttl = OVS_CB(skb)->tun_key->ipv4_ttl; + else + ttl = mutable->ttl; if (!ttl) ttl = ip4_dst_hoplimit(&rt_dst(rt)); @@ -1442,7 +1451,8 @@ static int tnl_set_config(struct net *net, struct nlattr *options, struct net_device *dev; struct rtable *rt; - rt = __find_route(mutable, tnl_ops->ipproto, mutable->tos); + rt = __find_route(mutable, mutable->key.saddr, mutable->key.daddr, + tnl_ops->ipproto, mutable->tos); if (IS_ERR(rt)) return -EADDRNOTAVAIL; dev = rt_dst(rt).dev; diff --git a/datapath/tunnel.h b/datapath/tunnel.h index 1924017..78a4d14 100644 --- a/datapath/tunnel.h +++ b/datapath/tunnel.h @@ -269,14 +269,14 @@ int ovs_tnl_set_addr(struct vport *vport, const unsigned char *addr); const char *ovs_tnl_get_name(const struct vport *vport); const unsigned char *ovs_tnl_get_addr(const struct vport *vport); int ovs_tnl_send(struct vport *vport, struct sk_buff *skb); -void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb, u8 tos); +void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb); struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr, __be64 key, int tunnel_type, const struct tnl_mutable_config **mutable); bool ovs_tnl_frag_needed(struct vport *vport, const struct tnl_mutable_config *mutable, - struct sk_buff *skb, unsigned int mtu, __be64 flow_key); + struct sk_buff *skb, unsigned int mtu); void ovs_tnl_free_linked_skbs(struct sk_buff *skb); int ovs_tnl_init(void); @@ -286,4 +286,14 @@ static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport) return vport_priv(vport); } +static inline void tun_key_init(struct ovs_key_ipv4_tunnel *tun_key, + const struct iphdr *iph, __be64 tun_id) +{ + tun_key->tun_id = tun_id; + tun_key->ipv4_src = iph->saddr; + tun_key->ipv4_dst = iph->daddr; + tun_key->ipv4_tos = iph->tos; + tun_key->ipv4_ttl = iph->ttl; +} + #endif /* tunnel.h */ diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c index 05a099d..1e08d5a 100644 --- a/datapath/vport-capwap.c +++ b/datapath/vport-capwap.c @@ -220,7 +220,7 @@ static struct sk_buff *capwap_update_header(const struct vport *vport, struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1); struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1); - opt->key = OVS_CB(skb)->tun_id; + opt->key = OVS_CB(skb)->tun_key->tun_id; } udph->len = htons(skb->len - skb_transport_offset(skb)); @@ -316,6 +316,7 @@ static int capwap_rcv(struct sock *sk, struct sk_buff *skb) struct vport *vport; const struct tnl_mutable_config *mutable; struct iphdr *iph; + struct ovs_key_ipv4_tunnel tun_key; __be64 key = 0; if (unlikely(!pskb_may_pull(skb, CAPWAP_MIN_HLEN + ETH_HLEN))) @@ -333,12 +334,11 @@ static int capwap_rcv(struct sock *sk, struct sk_buff *skb) goto error; } - if (mutable->flags & TNL_F_IN_KEY_MATCH) - OVS_CB(skb)->tun_id = key; - else - OVS_CB(skb)->tun_id = 0; + tun_key_init(&tun_key, iph, + mutable->flags & TNL_F_IN_KEY_MATCH ? key : 0); + OVS_CB(skb)->tun_key = &tun_key; - ovs_tnl_rcv(vport, skb, iph->tos); + ovs_tnl_rcv(vport, skb); goto out; error: diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index ab89c5b..beb8c04 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -103,7 +103,7 @@ static struct sk_buff *gre_update_header(const struct vport *vport, /* Work backwards over the options so the checksum is last. */ if (mutable->flags & TNL_F_OUT_KEY_ACTION) - *options = be64_get_low32(OVS_CB(skb)->tun_id); + *options = be64_get_low32(OVS_CB(skb)->tun_key->tun_id); if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION) options--; @@ -285,7 +285,7 @@ static void gre_err(struct sk_buff *skb, u32 info) #endif __skb_pull(skb, tunnel_hdr_len); - ovs_tnl_frag_needed(vport, mutable, skb, mtu, key); + ovs_tnl_frag_needed(vport, mutable, skb, mtu); __skb_push(skb, tunnel_hdr_len); out: @@ -327,6 +327,7 @@ static int gre_rcv(struct sk_buff *skb) const struct tnl_mutable_config *mutable; int hdr_len; struct iphdr *iph; + struct ovs_key_ipv4_tunnel tun_key; __be16 flags; __be64 key; @@ -351,15 +352,15 @@ static int gre_rcv(struct sk_buff *skb) goto error; } - if (mutable->flags & TNL_F_IN_KEY_MATCH) - OVS_CB(skb)->tun_id = key; - else - OVS_CB(skb)->tun_id = 0; + + tun_key_init(&tun_key, iph, + mutable->flags & TNL_F_IN_KEY_MATCH ? key : 0); + OVS_CB(skb)->tun_key = &tun_key; __skb_pull(skb, hdr_len); skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN); - ovs_tnl_rcv(vport, skb, iph->tos); + ovs_tnl_rcv(vport, skb); return 0; error: diff --git a/datapath/vport.c b/datapath/vport.c index 172261a..0c77a1b 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -462,7 +462,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb) OVS_CB(skb)->flow = NULL; if (!(vport->ops->flags & VPORT_F_TUN_ID)) - OVS_CB(skb)->tun_id = 0; + OVS_CB(skb)->tun_key = NULL; ovs_dp_process_received_packet(vport, skb); } diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index f5c9cca..f9f0c66 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -278,7 +278,8 @@ enum ovs_key_attr { OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */ OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */ OVS_KEY_ATTR_ND, /* struct ovs_key_nd */ - OVS_KEY_ATTR_TUN_ID = 63, /* be64 tunnel ID */ + OVS_KEY_ATTR_IPV4_TUNNEL, /* struct ovs_key_ipv4_tunnel */ + OVS_KEY_ATTR_TUN_ID = 63, /* be64 tunnel ID */ __OVS_KEY_ATTR_MAX }; @@ -360,6 +361,16 @@ struct ovs_key_nd { __u8 nd_tll[6]; }; +struct ovs_key_ipv4_tunnel { + __be64 tun_id; + __u32 tun_flags; + __be32 ipv4_src; + __be32 ipv4_dst; + __u8 ipv4_tos; + __u8 ipv4_ttl; + __u8 pad[2]; +}; + /** * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands. * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 144b6b6..c105a3f 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1180,6 +1180,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a) case OVS_KEY_ATTR_TUN_ID: case OVS_KEY_ATTR_PRIORITY: case OVS_KEY_ATTR_IPV6: + case OVS_KEY_ATTR_IPV4_TUNNEL: /* not implemented */ break; diff --git a/lib/odp-util.c b/lib/odp-util.c index 901dac3..5a17e11 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -99,13 +99,14 @@ ovs_key_attr_to_string(enum ovs_key_attr attr) case OVS_KEY_ATTR_ETHERTYPE: return "eth_type"; case OVS_KEY_ATTR_IPV4: return "ipv4"; case OVS_KEY_ATTR_IPV6: return "ipv6"; + case OVS_KEY_ATTR_TUN_ID: return "tun_id"; + case OVS_KEY_ATTR_IPV4_TUNNEL: return "ipv4_tunnel"; case OVS_KEY_ATTR_TCP: return "tcp"; case OVS_KEY_ATTR_UDP: return "udp"; case OVS_KEY_ATTR_ICMP: return "icmp"; case OVS_KEY_ATTR_ICMPV6: return "icmpv6"; case OVS_KEY_ATTR_ARP: return "arp"; case OVS_KEY_ATTR_ND: return "nd"; - case OVS_KEY_ATTR_TUN_ID: return "tun_id"; case __OVS_KEY_ATTR_MAX: default: @@ -601,13 +602,14 @@ odp_flow_key_attr_len(uint16_t type) switch ((enum ovs_key_attr) type) { case OVS_KEY_ATTR_ENCAP: return -2; case OVS_KEY_ATTR_PRIORITY: return 4; - case OVS_KEY_ATTR_TUN_ID: return 8; case OVS_KEY_ATTR_IN_PORT: return 4; case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet); case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16); case OVS_KEY_ATTR_ETHERTYPE: return 2; case OVS_KEY_ATTR_IPV4: return sizeof(struct ovs_key_ipv4); case OVS_KEY_ATTR_IPV6: return sizeof(struct ovs_key_ipv6); + case OVS_KEY_ATTR_TUN_ID: return 8; + case OVS_KEY_ATTR_IPV4_TUNNEL: return sizeof(struct ovs_key_ipv4_tunnel); case OVS_KEY_ATTR_TCP: return sizeof(struct ovs_key_tcp); case OVS_KEY_ATTR_UDP: return sizeof(struct ovs_key_udp); case OVS_KEY_ATTR_ICMP: return sizeof(struct ovs_key_icmp); @@ -668,6 +670,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) const struct ovs_key_icmpv6 *icmpv6_key; const struct ovs_key_arp *arp_key; const struct ovs_key_nd *nd_key; + const struct ovs_key_ipv4_tunnel *ipv4_tun_key; enum ovs_key_attr attr = nl_attr_type(a); int expected_len; @@ -698,6 +701,16 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a))); break; + case OVS_KEY_ATTR_IPV4_TUNNEL: + ipv4_tun_key = nl_attr_get(a); + ds_put_format(ds, "(tun_id=0x%"PRIx64",flags=0x%"PRIx32 + ",src="IP_FMT",dst="IP_FMT",tos=0x%"PRIx8",ttl=%"PRIu8")", + ntohll(ipv4_tun_key->tun_id), ipv4_tun_key->tun_flags, + IP_ARGS(&ipv4_tun_key->ipv4_src), + IP_ARGS(&ipv4_tun_key->ipv4_dst), + ipv4_tun_key->ipv4_tos, ipv4_tun_key->ipv4_ttl); + break; + case OVS_KEY_ATTR_IN_PORT: ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a)); break; diff --git a/lib/odp-util.h b/lib/odp-util.h index 16f2b15..250302e 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -80,6 +80,7 @@ int odp_actions_from_string(const char *, const struct simap *port_names, * ------ --- ------ ----- * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 * OVS_KEY_ATTR_TUN_ID 8 -- 4 12 + * OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) @@ -90,12 +91,12 @@ int odp_actions_from_string(const char *, const struct simap *port_names, * OVS_KEY_ATTR_ICMPV6 2 2 4 8 * OVS_KEY_ATTR_ND 28 -- 4 32 * ------------------------------------------------- - * total 156 + * total 184 * * We include some slack space in case the calculation isn't quite right or we * add another field and forget to adjust this value. */ -#define ODPUTIL_FLOW_KEY_BYTES 200 +#define ODPUTIL_FLOW_KEY_BYTES 204 /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow * key. An array of "struct nlattr" might not, in theory, be sufficiently -- 1.7.11.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev