- return (void *)cache + ALIGN(sizeof(struct tnl_cache), CACHE_DATA_ALIGN);
-}
-
-static inline bool check_cache_valid(const struct tnl_cache *cache,
- const struct tnl_mutable_config *mutable)
-{
- return cache &&
-#ifdef NEED_CACHE_TIMEOUT
- time_before(jiffies, cache->expiration) &&
-#endif
-#ifdef HAVE_RT_GENID
- 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 &&
-#endif
- mutable->seq == cache->mutable_seq &&
- (!is_internal_dev(rt_dst(cache->rt).dev) ||
- (cache->flow && !cache->flow->dead));
-}
-
-static int cache_cleaner_cb(struct tbl_node *tbl_node, void *aux)
-{
- struct tnl_vport *tnl_vport = tnl_vport_table_cast(tbl_node);
- const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable);
- const struct tnl_cache *cache = rcu_dereference(tnl_vport->cache);
-
- if (cache && !check_cache_valid(cache, mutable) &&
- spin_trylock_bh(&tnl_vport->cache_lock)) {
- assign_cache_rcu(tnl_vport_to_vport(tnl_vport), NULL);
- spin_unlock_bh(&tnl_vport->cache_lock);
- }
-
- return 0;
-}
-
-static void cache_cleaner(struct work_struct *work)
-{
- schedule_cache_cleaner();
-
- rcu_read_lock();
- tbl_foreach(rcu_dereference(port_table), cache_cleaner_cb, NULL);
- rcu_read_unlock();
-}
-
-static inline void create_eth_hdr(struct tnl_cache *cache,
- const 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;
-
-#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));
-
- cache->hh_seq = hh_seq;
+ struct rtable *rt;
+ /* 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 = daddr,
+ .saddr = *saddr,
+ .tos = RT_TOS(tos) } },
+ .proto = ipproto };
+
+ if (unlikely(ip_route_output_key(net, &rt, &fl)))
+ return ERR_PTR(-EADDRNOTAVAIL);
+ *saddr = fl.nl_u.ip4_u.saddr;
+ return rt;