/* 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)
{
- int low;
- int high;
+ u32 hash = skb_get_hash(skb);
unsigned int range;
- struct sw_flow_key *pkt_key = OVS_CB(skb)->pkt_key;
- u32 hash = jhash2((const u32 *)pkt_key,
- sizeof(*pkt_key) / sizeof(u32), 0);
+ int high;
+ int low;
+
+ 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);
+ }
- 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;
}
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;
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));
return ERR_PTR(err);
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
+
static void lisp_fix_segment(struct sk_buff *skb)
{
struct udphdr *udph = udp_hdr(skb);
udph->len = htons(skb->len - skb_transport_offset(skb));
}
-static void handle_offloads(struct sk_buff *skb)
+static int handle_offloads(struct sk_buff *skb)
{
if (skb_is_gso(skb))
OVS_GSO_CB(skb)->fix_segment = lisp_fix_segment;
else if (skb->ip_summed != CHECKSUM_PARTIAL)
skb->ip_summed = CHECKSUM_NONE;
+ return 0;
}
+#else
+static int handle_offloads(struct sk_buff *skb)
+{
+ if (skb_is_gso(skb)) {
+ int err = skb_unclone(skb, GFP_ATOMIC);
+ if (unlikely(err))
+ return err;
+
+ skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL;
+ } else if (skb->ip_summed != CHECKSUM_PARTIAL)
+ skb->ip_summed = CHECKSUM_NONE;
+
+ skb->encapsulation = 1;
+ return 0;
+}
+#endif
static int lisp_send(struct vport *vport, struct sk_buff *skb)
{
- struct net *net = ovs_dp_get_net(vport->dp);
int network_offset = skb_network_offset(skb);
struct rtable *rt;
int min_headroom;
goto err_free_rt;
}
+ /* Reset l2 headers. */
skb_pull(skb, network_offset);
skb_reset_mac_header(skb);
+ vlan_set_tci(skb, 0);
+
skb_reset_inner_headers(skb);
__skb_push(skb, LISP_HLEN);
lisp_build_header(vport, skb);
/* Offloading */
- handle_offloads(skb);
+ err = handle_offloads(skb);
+ if (err)
+ goto err_free_rt;
+
skb->local_df = 1;
df = OVS_CB(skb)->tun_key->tun_flags &
TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
- sent_len = iptunnel_xmit(net, rt, skb,
+ 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);
+ OVS_CB(skb)->tun_key->ipv4_ttl, df, false);
return sent_len > 0 ? sent_len + network_offset : sent_len;