>From 3.1 kernel, struct dst_entry no longer has direct ref to hh_cache. Following patch handles this case.
Signed-off-by: Pravin Shelar <[email protected]> --- datapath/tunnel.c | 45 ++++++++++++++++++++++++++++++--------------- 1 files changed, 30 insertions(+), 15 deletions(-) diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 8edff06..c7e9814 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -93,6 +93,12 @@ static unsigned int remote_ports __read_mostly; #define rt_dst(rt) (rt->u.dst) #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#define rt_hh(rt) (&dst_get_neighbour(&rt_dst(rt))->hh) +#else +#define rt_hh(rt) (rt_dst(rt).hh) +#endif + static inline struct vport *tnl_vport_to_vport(const struct tnl_vport *tnl_vport) { return vport_from_priv(tnl_vport); @@ -751,7 +757,7 @@ static inline bool check_cache_valid(const struct tnl_cache *cache, atomic_read(&init_net.ipv4.rt_genid) == cache->rt->rt_genid && #endif #ifdef HAVE_HH_SEQ - rt_dst(cache->rt).hh->hh_lock.sequence == cache->hh_seq && + rt_hh(cache->rt)->hh_lock.sequence == cache->hh_seq && #endif mutable->seq == cache->mutable_seq && (!is_internal_dev(rt_dst(cache->rt).dev) || @@ -791,25 +797,26 @@ static void cache_cleaner(struct work_struct *work) } static inline void create_eth_hdr(struct tnl_cache *cache, - const struct rtable *rt) + struct rtable *rt) { void *cache_data = get_cached_header(cache); - int hh_len = rt_dst(rt).hh->hh_len; - int hh_off = HH_DATA_ALIGN(rt_dst(rt).hh->hh_len) - hh_len; + struct hh_cache *hh = rt_hh(rt); + int hh_len = hh->hh_len; + int hh_off = HH_DATA_ALIGN(hh_len) - hh_len; #ifdef HAVE_HH_SEQ unsigned hh_seq; do { - hh_seq = read_seqbegin(&rt_dst(rt).hh->hh_lock); - memcpy(cache_data, (void *)rt_dst(rt).hh->hh_data + hh_off, hh_len); - } while (read_seqretry(&rt_dst(rt).hh->hh_lock, hh_seq)); + hh_seq = read_seqbegin(&hh->hh_lock); + memcpy(cache_data, (void *)hh->hh_data + hh_off, hh_len); + } while (read_seqretry(&hh->hh_lock, hh_seq)); cache->hh_seq = hh_seq; #else - read_lock(&rt_dst(rt).hh->hh_lock); - memcpy(cache_data, (void *)rt_dst(rt).hh->hh_data + hh_off, hh_len); - read_unlock(&rt_dst(rt).hh->hh_lock); + read_lock(&hh->hh_lock); + memcpy(cache_data, (void *)hh->hh_data + hh_off, hh_len); + read_unlock(&hh->hh_lock); #endif } @@ -829,9 +836,17 @@ static struct tnl_cache *build_cache(struct vport *vport, * If there is no entry in the ARP cache or if this device does not * support hard header caching just fall back to the IP stack. */ - if (!rt_dst(rt).hh) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) + { + struct neighbour *neigh = dst_get_neighbour(&rt->dst); + if (!neigh || !(neigh->nud_state & NUD_CONNECTED) || + !neigh->hh.hh_len) + return NULL; + } +#else + if (!rt_hh(rt)) return NULL; - +#endif /* * If lock is contended fall back to directly building the header. * We're not going to help performance by sitting here spinning. @@ -845,7 +860,7 @@ static struct tnl_cache *build_cache(struct vport *vport, else cache = NULL; - cache_len = rt_dst(rt).hh->hh_len + mutable->tunnel_hlen; + cache_len = rt_hh(rt)->hh_len + mutable->tunnel_hlen; cache = kzalloc(ALIGN(sizeof(struct tnl_cache), CACHE_DATA_ALIGN) + cache_len, GFP_ATOMIC); @@ -855,7 +870,7 @@ static struct tnl_cache *build_cache(struct vport *vport, cache->len = cache_len; create_eth_hdr(cache, rt); - cache_data = get_cached_header(cache) + rt_dst(rt).hh->hh_len; + cache_data = get_cached_header(cache) + rt_hh(rt)->hh_len; create_tunnel_header(vport, mutable, rt, cache_data); @@ -1181,7 +1196,7 @@ int tnl_send(struct vport *vport, struct sk_buff *skb) skb_push(skb, cache->len); memcpy(skb->data, get_cached_header(cache), cache->len); skb_reset_mac_header(skb); - skb_set_network_header(skb, rt_dst(rt).hh->hh_len); + skb_set_network_header(skb, rt_hh(rt)->hh_len); } else { skb_push(skb, mutable->tunnel_hlen); -- 1.7.1 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
