11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * net/dst.h Protocol independent destination cache definitions. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #ifndef _NET_DST_H 91da177e4SLinus Torvalds #define _NET_DST_H 101da177e4SLinus Torvalds 1114c85021SArnaldo Carvalho de Melo #include <linux/netdevice.h> 121da177e4SLinus Torvalds #include <linux/rtnetlink.h> 131da177e4SLinus Torvalds #include <linux/rcupdate.h> 141da177e4SLinus Torvalds #include <linux/jiffies.h> 151da177e4SLinus Torvalds #include <net/neighbour.h> 161da177e4SLinus Torvalds #include <asm/processor.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* 191da177e4SLinus Torvalds * 0 - no debugging messages 201da177e4SLinus Torvalds * 1 - rare events and bugs (default) 211da177e4SLinus Torvalds * 2 - trace mode. 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds #define RT_CACHE_DEBUG 0 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define DST_GC_MIN (HZ/10) 261da177e4SLinus Torvalds #define DST_GC_INC (HZ/2) 271da177e4SLinus Torvalds #define DST_GC_MAX (120*HZ) 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* Each dst_entry has reference count and sits in some parent list(s). 301da177e4SLinus Torvalds * When it is removed from parent list, it is "freed" (dst_free). 311da177e4SLinus Torvalds * After this it enters dead state (dst->obsolete > 0) and if its refcnt 321da177e4SLinus Torvalds * is zero, it can be destroyed immediately, otherwise it is added 331da177e4SLinus Torvalds * to gc list and garbage collector periodically checks the refcnt. 341da177e4SLinus Torvalds */ 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds struct sk_buff; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds struct dst_entry 391da177e4SLinus Torvalds { 401e19e02cSEric Dumazet struct rcu_head rcu_head; 411da177e4SLinus Torvalds struct dst_entry *child; 421da177e4SLinus Torvalds struct net_device *dev; 43c4d54110SHerbert Xu short error; 44c4d54110SHerbert Xu short obsolete; 451da177e4SLinus Torvalds int flags; 461da177e4SLinus Torvalds #define DST_HOST 1 471da177e4SLinus Torvalds #define DST_NOXFRM 2 481da177e4SLinus Torvalds #define DST_NOPOLICY 4 491da177e4SLinus Torvalds #define DST_NOHASH 8 501da177e4SLinus Torvalds unsigned long expires; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds unsigned short header_len; /* more space at head required */ 531da177e4SLinus Torvalds unsigned short trailer_len; /* space to reserve at tail */ 541da177e4SLinus Torvalds 5569a73829SEric Dumazet unsigned int rate_tokens; 56f1dd9c37SZhang Yanmin unsigned long rate_last; /* rate limiting for ICMP */ 5769a73829SEric Dumazet 58f1dd9c37SZhang Yanmin struct dst_entry *path; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds struct neighbour *neighbour; 611da177e4SLinus Torvalds struct hh_cache *hh; 621da177e4SLinus Torvalds struct xfrm_state *xfrm; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds int (*input)(struct sk_buff*); 651da177e4SLinus Torvalds int (*output)(struct sk_buff*); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds struct dst_ops *ops; 681da177e4SLinus Torvalds 69f1dd9c37SZhang Yanmin u32 metrics[RTAX_MAX]; 70f1dd9c37SZhang Yanmin 71f1dd9c37SZhang Yanmin #ifdef CONFIG_NET_CLS_ROUTE 72f1dd9c37SZhang Yanmin __u32 tclassid; 73f1dd9c37SZhang Yanmin #endif 74f1dd9c37SZhang Yanmin 75f1dd9c37SZhang Yanmin /* 76f1dd9c37SZhang Yanmin * __refcnt wants to be on a different cache line from 77f1dd9c37SZhang Yanmin * input/output/ops or performance tanks badly 78f1dd9c37SZhang Yanmin */ 791e19e02cSEric Dumazet atomic_t __refcnt; /* client references */ 801e19e02cSEric Dumazet int __use; 81f1dd9c37SZhang Yanmin unsigned long lastuse; 821e19e02cSEric Dumazet union { 831e19e02cSEric Dumazet struct dst_entry *next; 841e19e02cSEric Dumazet struct rtable *rt_next; 851e19e02cSEric Dumazet struct rt6_info *rt6_next; 861e19e02cSEric Dumazet struct dn_route *dn_next; 871e19e02cSEric Dumazet }; 881da177e4SLinus Torvalds }; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds struct dst_ops 921da177e4SLinus Torvalds { 931da177e4SLinus Torvalds unsigned short family; 94d77072ecSAl Viro __be16 protocol; 951da177e4SLinus Torvalds unsigned gc_thresh; 961da177e4SLinus Torvalds 97569d3645SDaniel Lezcano int (*gc)(struct dst_ops *ops); 981da177e4SLinus Torvalds struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); 991da177e4SLinus Torvalds void (*destroy)(struct dst_entry *); 1001da177e4SLinus Torvalds void (*ifdown)(struct dst_entry *, 1011da177e4SLinus Torvalds struct net_device *dev, int how); 1021da177e4SLinus Torvalds struct dst_entry * (*negative_advice)(struct dst_entry *); 1031da177e4SLinus Torvalds void (*link_failure)(struct sk_buff *); 1041da177e4SLinus Torvalds void (*update_pmtu)(struct dst_entry *dst, u32 mtu); 105862b82c6SHerbert Xu int (*local_out)(struct sk_buff *skb); 1061da177e4SLinus Torvalds int entry_size; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds atomic_t entries; 109e18b890bSChristoph Lameter struct kmem_cache *kmem_cachep; 110d4fa26ffSDaniel Lezcano struct net *dst_net; 1111da177e4SLinus Torvalds }; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds #ifdef __KERNEL__ 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static inline u32 1161da177e4SLinus Torvalds dst_metric(const struct dst_entry *dst, int metric) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds return dst->metrics[metric-1]; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds static inline u32 dst_mtu(const struct dst_entry *dst) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds u32 mtu = dst_metric(dst, RTAX_MTU); 1241da177e4SLinus Torvalds /* 1251da177e4SLinus Torvalds * Alexey put it here, so ask him about it :) 1261da177e4SLinus Torvalds */ 1271da177e4SLinus Torvalds barrier(); 1281da177e4SLinus Torvalds return mtu; 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static inline u32 1321da177e4SLinus Torvalds dst_allfrag(const struct dst_entry *dst) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds int ret = dst_metric(dst, RTAX_FEATURES) & RTAX_FEATURE_ALLFRAG; 1351da177e4SLinus Torvalds /* Yes, _exactly_. This is paranoia. */ 1361da177e4SLinus Torvalds barrier(); 1371da177e4SLinus Torvalds return ret; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds static inline int 1411da177e4SLinus Torvalds dst_metric_locked(struct dst_entry *dst, int metric) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds return dst_metric(dst, RTAX_LOCK) & (1<<metric); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static inline void dst_hold(struct dst_entry * dst) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds atomic_inc(&dst->__refcnt); 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 15103f49f34SPavel Emelyanov static inline void dst_use(struct dst_entry *dst, unsigned long time) 15203f49f34SPavel Emelyanov { 15303f49f34SPavel Emelyanov dst_hold(dst); 15403f49f34SPavel Emelyanov dst->__use++; 15503f49f34SPavel Emelyanov dst->lastuse = time; 15603f49f34SPavel Emelyanov } 15703f49f34SPavel Emelyanov 1581da177e4SLinus Torvalds static inline 1591da177e4SLinus Torvalds struct dst_entry * dst_clone(struct dst_entry * dst) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds if (dst) 1621da177e4SLinus Torvalds atomic_inc(&dst->__refcnt); 1631da177e4SLinus Torvalds return dst; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 166*8d330868SIlpo Järvinen extern void dst_release(struct dst_entry *dst); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /* Children define the path of the packet through the 1691da177e4SLinus Torvalds * Linux networking. Thus, destinations are stackable. 1701da177e4SLinus Torvalds */ 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds static inline struct dst_entry *dst_pop(struct dst_entry *dst) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds struct dst_entry *child = dst_clone(dst->child); 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds dst_release(dst); 1771da177e4SLinus Torvalds return child; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 180352e512cSHerbert Xu extern int dst_discard(struct sk_buff *skb); 1811da177e4SLinus Torvalds extern void * dst_alloc(struct dst_ops * ops); 1821da177e4SLinus Torvalds extern void __dst_free(struct dst_entry * dst); 1831da177e4SLinus Torvalds extern struct dst_entry *dst_destroy(struct dst_entry * dst); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static inline void dst_free(struct dst_entry * dst) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds if (dst->obsolete > 1) 1881da177e4SLinus Torvalds return; 1891da177e4SLinus Torvalds if (!atomic_read(&dst->__refcnt)) { 1901da177e4SLinus Torvalds dst = dst_destroy(dst); 1911da177e4SLinus Torvalds if (!dst) 1921da177e4SLinus Torvalds return; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds __dst_free(dst); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds static inline void dst_rcu_free(struct rcu_head *head) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); 2001da177e4SLinus Torvalds dst_free(dst); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds static inline void dst_confirm(struct dst_entry *dst) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds if (dst) 2061da177e4SLinus Torvalds neigh_confirm(dst->neighbour); 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds static inline void dst_negative_advice(struct dst_entry **dst_p) 2101da177e4SLinus Torvalds { 2111da177e4SLinus Torvalds struct dst_entry * dst = *dst_p; 2121da177e4SLinus Torvalds if (dst && dst->ops->negative_advice) 2131da177e4SLinus Torvalds *dst_p = dst->ops->negative_advice(dst); 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static inline void dst_link_failure(struct sk_buff *skb) 2171da177e4SLinus Torvalds { 2181da177e4SLinus Torvalds struct dst_entry * dst = skb->dst; 2191da177e4SLinus Torvalds if (dst && dst->ops && dst->ops->link_failure) 2201da177e4SLinus Torvalds dst->ops->link_failure(skb); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds static inline void dst_set_expires(struct dst_entry *dst, int timeout) 2241da177e4SLinus Torvalds { 2251da177e4SLinus Torvalds unsigned long expires = jiffies + timeout; 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds if (expires == 0) 2281da177e4SLinus Torvalds expires = 1; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds if (dst->expires == 0 || time_before(expires, dst->expires)) 2311da177e4SLinus Torvalds dst->expires = expires; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* Output packet to network from transport. */ 2351da177e4SLinus Torvalds static inline int dst_output(struct sk_buff *skb) 2361da177e4SLinus Torvalds { 23716a6677fSPatrick McHardy return skb->dst->output(skb); 2381da177e4SLinus Torvalds } 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* Input packet from network to transport. */ 2411da177e4SLinus Torvalds static inline int dst_input(struct sk_buff *skb) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds int err; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds for (;;) { 2461da177e4SLinus Torvalds err = skb->dst->input(skb); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds if (likely(err == 0)) 2491da177e4SLinus Torvalds return err; 2501da177e4SLinus Torvalds /* Oh, Jamal... Seems, I will not forgive you this mess. :-) */ 2511da177e4SLinus Torvalds if (unlikely(err != NET_XMIT_BYPASS)) 2521da177e4SLinus Torvalds return err; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds if (dst->obsolete) 2591da177e4SLinus Torvalds dst = dst->ops->check(dst, cookie); 2601da177e4SLinus Torvalds return dst; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds extern void dst_init(void); 2641da177e4SLinus Torvalds 265815f4e57SHerbert Xu /* Flags for xfrm_lookup flags argument. */ 266815f4e57SHerbert Xu enum { 267815f4e57SHerbert Xu XFRM_LOOKUP_WAIT = 1 << 0, 2688b7817f3SHerbert Xu XFRM_LOOKUP_ICMP = 1 << 1, 269815f4e57SHerbert Xu }; 270815f4e57SHerbert Xu 2711da177e4SLinus Torvalds struct flowi; 2721da177e4SLinus Torvalds #ifndef CONFIG_XFRM 2731da177e4SLinus Torvalds static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, 2741da177e4SLinus Torvalds struct sock *sk, int flags) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds return 0; 2771da177e4SLinus Torvalds } 27814e50e57SDavid S. Miller static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, 27914e50e57SDavid S. Miller struct sock *sk, int flags) 28014e50e57SDavid S. Miller { 28114e50e57SDavid S. Miller return 0; 28214e50e57SDavid S. Miller } 2831da177e4SLinus Torvalds #else 2841da177e4SLinus Torvalds extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, 2851da177e4SLinus Torvalds struct sock *sk, int flags); 28614e50e57SDavid S. Miller extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, 28714e50e57SDavid S. Miller struct sock *sk, int flags); 2881da177e4SLinus Torvalds #endif 2891da177e4SLinus Torvalds #endif 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds #endif /* _NET_DST_H */ 292