datapath: Use tun_info only for egress tunnel path.
[cascardo/ovs.git] / datapath / vport-lisp.c
index e33cffe..cdd325e 100644 (file)
@@ -163,9 +163,9 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid)
 /* Compute source UDP port for outgoing packet.
  * Currently we use the flow hash.
  */
-static u16 get_src_port(struct sk_buff *skb)
+static u16 get_src_port(struct net *net, struct sk_buff *skb)
 {
-       u32 hash = skb_get_rxhash(skb);
+       u32 hash = skb_get_hash(skb);
        unsigned int range;
        int high;
        int low;
@@ -173,11 +173,18 @@ static u16 get_src_port(struct sk_buff *skb)
        if (!hash) {
                struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
 
-               hash = jhash2((const u32 *)pkt_key,
-                           sizeof(*pkt_key) / sizeof(u32), 0);
+               if (skb->protocol == htons(ETH_P_IP))
+                       hash = jhash2((const u32 *)&pkt_key->ipv4.addr,
+                                  sizeof(pkt_key->ipv4.addr) / sizeof(u32), 0);
+               else if (skb->protocol == htons(ETH_P_IPV6))
+                       hash = jhash2((const u32 *)&pkt_key->ipv6.addr,
+                                  sizeof(pkt_key->ipv6.addr) / sizeof(u32), 0);
+               else
+                       pr_warn_once("LISP inner protocol is not IP when "
+                                    "calculating hash.\n");
        }
 
-       inet_get_local_port_range(&low, &high);
+       inet_get_local_port_range(net, &low, &high);
        range = (high - low) + 1;
        return (((u64) hash * range) >> 32) + low;
 }
@@ -185,13 +192,15 @@ static u16 get_src_port(struct sk_buff *skb)
 static void lisp_build_header(const struct vport *vport,
                              struct sk_buff *skb)
 {
+       struct net *net = ovs_dp_get_net(vport->dp);
        struct lisp_port *lisp_port = lisp_vport(vport);
        struct udphdr *udph = udp_hdr(skb);
        struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
-       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
+       const struct ovs_key_ipv4_tunnel *tun_key;
 
+       tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
        udph->dest = lisp_port->dst_port;
-       udph->source = htons(get_src_port(skb));
+       udph->source = htons(get_src_port(net, skb));
        udph->check = 0;
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
@@ -216,7 +225,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
        struct lisp_port *lisp_port;
        struct lisphdr *lisph;
        struct iphdr *iph, *inner_iph;
-       struct ovs_key_ipv4_tunnel tun_key;
+       struct ovs_tunnel_info tun_info;
        __be64 key;
        struct ethhdr *ethh;
        __be16 protocol;
@@ -237,7 +246,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
 
        /* Save outer tunnel values */
        iph = ip_hdr(skb);
-       ovs_flow_tun_key_init(&tun_key, iph, key, TUNNEL_KEY);
+       ovs_flow_tun_info_init(&tun_info, iph, key, TUNNEL_KEY, NULL, 0);
 
        /* Drop non-IP inner packets */
        inner_iph = (struct iphdr *)(lisph + 1);
@@ -262,7 +271,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
 
        ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
 
-       ovs_vport_receive(vport_from_priv(lisp_port), skb, &tun_key);
+       ovs_vport_receive(vport_from_priv(lisp_port), skb, &tun_info);
        goto out;
 
 error:
@@ -401,6 +410,11 @@ static int handle_offloads(struct sk_buff *skb)
 #else
 static int handle_offloads(struct sk_buff *skb)
 {
+       if (skb->encapsulation && skb_is_gso(skb)) {
+               kfree_skb(skb);
+               return -ENOSYS;
+       }
+
        if (skb_is_gso(skb)) {
                int err = skb_unclone(skb, GFP_ATOMIC);
                if (unlikely(err))
@@ -417,6 +431,7 @@ static int handle_offloads(struct sk_buff *skb)
 
 static int lisp_send(struct vport *vport, struct sk_buff *skb)
 {
+       struct ovs_key_ipv4_tunnel *tun_key;
        int network_offset = skb_network_offset(skb);
        struct rtable *rt;
        int min_headroom;
@@ -425,9 +440,11 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb)
        int sent_len;
        int err;
 
-       if (unlikely(!OVS_CB(skb)->tun_key))
+       if (unlikely(!OVS_CB(skb)->egress_tun_info))
                return -EINVAL;
 
+       tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
+
        if (skb->protocol != htons(ETH_P_IP) &&
            skb->protocol != htons(ETH_P_IPV6)) {
                kfree_skb(skb);
@@ -435,12 +452,10 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb)
        }
 
        /* Route lookup */
-       saddr = OVS_CB(skb)->tun_key->ipv4_src;
+       saddr = tun_key->ipv4_src;
        rt = find_route(ovs_dp_get_net(vport->dp),
-                       &saddr,
-                       OVS_CB(skb)->tun_key->ipv4_dst,
-                       IPPROTO_UDP,
-                       OVS_CB(skb)->tun_key->ipv4_tos,
+                       &saddr, tun_key->ipv4_dst,
+                       IPPROTO_UDP, tun_key->ipv4_tos,
                        skb->mark);
        if (IS_ERR(rt)) {
                err = PTR_ERR(rt);
@@ -480,12 +495,11 @@ static int lisp_send(struct vport *vport, struct sk_buff *skb)
 
        skb->local_df = 1;
 
-       df = OVS_CB(skb)->tun_key->tun_flags &
-                                 TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
+       df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
        sent_len = iptunnel_xmit(rt, skb,
-                            saddr, OVS_CB(skb)->tun_key->ipv4_dst,
-                            IPPROTO_UDP, OVS_CB(skb)->tun_key->ipv4_tos,
-                            OVS_CB(skb)->tun_key->ipv4_ttl, df, false);
+                            saddr, tun_key->ipv4_dst,
+                            IPPROTO_UDP, tun_key->ipv4_tos,
+                            tun_key->ipv4_ttl, df, false);
 
        return sent_len > 0 ? sent_len + network_offset : sent_len;