| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * net/dst.h	Protocol independent destination cache definitions. | 
|  | 3 | * | 
|  | 4 | * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | 
|  | 5 | * | 
|  | 6 | */ | 
|  | 7 |  | 
|  | 8 | #ifndef _NET_DST_H | 
|  | 9 | #define _NET_DST_H | 
|  | 10 |  | 
| Alexey Dobriyan | 86393e5 | 2009-08-29 01:34:49 +0000 | [diff] [blame] | 11 | #include <net/dst_ops.h> | 
| Arnaldo Carvalho de Melo | 14c8502 | 2005-12-27 02:43:12 -0200 | [diff] [blame] | 12 | #include <linux/netdevice.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 | #include <linux/rtnetlink.h> | 
|  | 14 | #include <linux/rcupdate.h> | 
| Paul Gortmaker | 187f188 | 2011-11-23 20:12:59 -0500 | [diff] [blame] | 15 | #include <linux/bug.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 | #include <linux/jiffies.h> | 
|  | 17 | #include <net/neighbour.h> | 
|  | 18 | #include <asm/processor.h> | 
|  | 19 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | #define DST_GC_MIN	(HZ/10) | 
|  | 21 | #define DST_GC_INC	(HZ/2) | 
|  | 22 | #define DST_GC_MAX	(120*HZ) | 
|  | 23 |  | 
|  | 24 | /* Each dst_entry has reference count and sits in some parent list(s). | 
|  | 25 | * When it is removed from parent list, it is "freed" (dst_free). | 
|  | 26 | * After this it enters dead state (dst->obsolete > 0) and if its refcnt | 
|  | 27 | * is zero, it can be destroyed immediately, otherwise it is added | 
|  | 28 | * to gc list and garbage collector periodically checks the refcnt. | 
|  | 29 | */ | 
|  | 30 |  | 
|  | 31 | struct sk_buff; | 
|  | 32 |  | 
| Eric Dumazet | fd2c3ef | 2009-11-03 03:26:03 +0000 | [diff] [blame] | 33 | struct dst_entry { | 
| Eric Dumazet | 1e19e02 | 2007-02-09 16:26:55 -0800 | [diff] [blame] | 34 | struct rcu_head		rcu_head; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | struct dst_entry	*child; | 
|  | 36 | struct net_device       *dev; | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 37 | struct  dst_ops	        *ops; | 
|  | 38 | unsigned long		_metrics; | 
| Gao feng | 1716a96 | 2012-04-06 00:13:10 +0000 | [diff] [blame] | 39 | union { | 
|  | 40 | unsigned long           expires; | 
|  | 41 | /* point to where the dst_entry copied from */ | 
|  | 42 | struct dst_entry        *from; | 
|  | 43 | }; | 
| Zhang Yanmin | f1dd9c3 | 2008-03-12 22:52:37 -0700 | [diff] [blame] | 44 | struct dst_entry	*path; | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 45 | struct neighbour __rcu	*_neighbour; | 
| Alexey Dobriyan | def8b4f | 2008-10-28 13:24:06 -0700 | [diff] [blame] | 46 | #ifdef CONFIG_XFRM | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | struct xfrm_state	*xfrm; | 
| Eric Dumazet | 5635c10 | 2008-11-16 19:46:36 -0800 | [diff] [blame] | 48 | #else | 
|  | 49 | void			*__pad1; | 
| Alexey Dobriyan | def8b4f | 2008-10-28 13:24:06 -0700 | [diff] [blame] | 50 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | int			(*input)(struct sk_buff*); | 
|  | 52 | int			(*output)(struct sk_buff*); | 
|  | 53 |  | 
| David S. Miller | f6b72b6 | 2011-07-14 07:53:20 -0700 | [diff] [blame] | 54 | int			flags; | 
|  | 55 | #define DST_HOST		0x0001 | 
|  | 56 | #define DST_NOXFRM		0x0002 | 
|  | 57 | #define DST_NOPOLICY		0x0004 | 
|  | 58 | #define DST_NOHASH		0x0008 | 
|  | 59 | #define DST_NOCACHE		0x0010 | 
|  | 60 | #define DST_NOCOUNT		0x0020 | 
| Eric Dumazet | e688a60 | 2011-12-22 04:15:53 +0000 | [diff] [blame] | 61 | #define DST_NOPEER		0x0040 | 
| Peter Huang (Peng) | a881e96 | 2012-04-19 20:12:51 +0000 | [diff] [blame] | 62 | #define DST_FAKE_RTABLE		0x0080 | 
| Gao feng | 0c18337 | 2012-05-26 01:30:53 +0000 | [diff] [blame] | 63 | #define DST_XFRM_TUNNEL		0x0100 | 
| David S. Miller | f6b72b6 | 2011-07-14 07:53:20 -0700 | [diff] [blame] | 64 |  | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 65 | short			error; | 
|  | 66 | short			obsolete; | 
|  | 67 | unsigned short		header_len;	/* more space at head required */ | 
|  | 68 | unsigned short		trailer_len;	/* space to reserve at tail */ | 
| Patrick McHardy | c7066f7 | 2011-01-14 13:36:42 +0100 | [diff] [blame] | 69 | #ifdef CONFIG_IP_ROUTE_CLASSID | 
| Zhang Yanmin | f1dd9c3 | 2008-03-12 22:52:37 -0700 | [diff] [blame] | 70 | __u32			tclassid; | 
| Eric Dumazet | 5635c10 | 2008-11-16 19:46:36 -0800 | [diff] [blame] | 71 | #else | 
|  | 72 | __u32			__pad2; | 
| Zhang Yanmin | f1dd9c3 | 2008-03-12 22:52:37 -0700 | [diff] [blame] | 73 | #endif | 
|  | 74 |  | 
| Eric Dumazet | 5635c10 | 2008-11-16 19:46:36 -0800 | [diff] [blame] | 75 | /* | 
|  | 76 | * Align __refcnt to a 64 bytes alignment | 
|  | 77 | * (L1_CACHE_SIZE would be too much) | 
|  | 78 | */ | 
|  | 79 | #ifdef CONFIG_64BIT | 
| David S. Miller | f6b72b6 | 2011-07-14 07:53:20 -0700 | [diff] [blame] | 80 | long			__pad_to_align_refcnt[2]; | 
| Eric Dumazet | 5635c10 | 2008-11-16 19:46:36 -0800 | [diff] [blame] | 81 | #endif | 
| Zhang Yanmin | f1dd9c3 | 2008-03-12 22:52:37 -0700 | [diff] [blame] | 82 | /* | 
|  | 83 | * __refcnt wants to be on a different cache line from | 
|  | 84 | * input/output/ops or performance tanks badly | 
|  | 85 | */ | 
| Eric Dumazet | 1e19e02 | 2007-02-09 16:26:55 -0800 | [diff] [blame] | 86 | atomic_t		__refcnt;	/* client references	*/ | 
|  | 87 | int			__use; | 
| Zhang Yanmin | f1dd9c3 | 2008-03-12 22:52:37 -0700 | [diff] [blame] | 88 | unsigned long		lastuse; | 
| Eric Dumazet | 1e19e02 | 2007-02-09 16:26:55 -0800 | [diff] [blame] | 89 | union { | 
| Eric Dumazet | fc766e4 | 2010-10-29 03:09:24 +0000 | [diff] [blame] | 90 | struct dst_entry	*next; | 
|  | 91 | struct rtable __rcu	*rt_next; | 
|  | 92 | struct rt6_info		*rt6_next; | 
|  | 93 | struct dn_route __rcu	*dn_next; | 
| Eric Dumazet | 1e19e02 | 2007-02-09 16:26:55 -0800 | [diff] [blame] | 94 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | }; | 
|  | 96 |  | 
| David Miller | 2721745 | 2011-12-02 16:52:08 +0000 | [diff] [blame] | 97 | static inline struct neighbour *dst_get_neighbour_noref(struct dst_entry *dst) | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 98 | { | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 99 | return rcu_dereference(dst->_neighbour); | 
|  | 100 | } | 
|  | 101 |  | 
| David Miller | 2721745 | 2011-12-02 16:52:08 +0000 | [diff] [blame] | 102 | static inline struct neighbour *dst_get_neighbour_noref_raw(struct dst_entry *dst) | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 103 | { | 
|  | 104 | return rcu_dereference_raw(dst->_neighbour); | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 105 | } | 
|  | 106 |  | 
|  | 107 | static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh) | 
|  | 108 | { | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 109 | rcu_assign_pointer(dst->_neighbour, neigh); | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 110 | } | 
|  | 111 |  | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 112 | extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); | 
| David S. Miller | 725d1e1 | 2011-01-28 14:05:05 -0800 | [diff] [blame] | 113 | extern const u32 dst_default_metrics[RTAX_MAX]; | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 114 |  | 
|  | 115 | #define DST_METRICS_READ_ONLY	0x1UL | 
|  | 116 | #define __DST_METRICS_PTR(Y)	\ | 
|  | 117 | ((u32 *)((Y) & ~DST_METRICS_READ_ONLY)) | 
|  | 118 | #define DST_METRICS_PTR(X)	__DST_METRICS_PTR((X)->_metrics) | 
|  | 119 |  | 
|  | 120 | static inline bool dst_metrics_read_only(const struct dst_entry *dst) | 
|  | 121 | { | 
|  | 122 | return dst->_metrics & DST_METRICS_READ_ONLY; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | extern void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old); | 
|  | 126 |  | 
|  | 127 | static inline void dst_destroy_metrics_generic(struct dst_entry *dst) | 
|  | 128 | { | 
|  | 129 | unsigned long val = dst->_metrics; | 
|  | 130 | if (!(val & DST_METRICS_READ_ONLY)) | 
|  | 131 | __dst_destroy_metrics_generic(dst, val); | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | static inline u32 *dst_metrics_write_ptr(struct dst_entry *dst) | 
|  | 135 | { | 
|  | 136 | unsigned long p = dst->_metrics; | 
|  | 137 |  | 
| Stephen Hemminger | 1f37070 | 2011-05-24 13:50:52 -0400 | [diff] [blame] | 138 | BUG_ON(!p); | 
|  | 139 |  | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 140 | if (p & DST_METRICS_READ_ONLY) | 
|  | 141 | return dst->ops->cow_metrics(dst, p); | 
|  | 142 | return __DST_METRICS_PTR(p); | 
|  | 143 | } | 
|  | 144 |  | 
|  | 145 | /* This may only be invoked before the entry has reached global | 
|  | 146 | * visibility. | 
|  | 147 | */ | 
|  | 148 | static inline void dst_init_metrics(struct dst_entry *dst, | 
|  | 149 | const u32 *src_metrics, | 
|  | 150 | bool read_only) | 
|  | 151 | { | 
|  | 152 | dst->_metrics = ((unsigned long) src_metrics) | | 
|  | 153 | (read_only ? DST_METRICS_READ_ONLY : 0); | 
|  | 154 | } | 
|  | 155 |  | 
|  | 156 | static inline void dst_copy_metrics(struct dst_entry *dest, const struct dst_entry *src) | 
|  | 157 | { | 
|  | 158 | u32 *dst_metrics = dst_metrics_write_ptr(dest); | 
|  | 159 |  | 
|  | 160 | if (dst_metrics) { | 
|  | 161 | u32 *src_metrics = DST_METRICS_PTR(src); | 
|  | 162 |  | 
|  | 163 | memcpy(dst_metrics, src_metrics, RTAX_MAX * sizeof(u32)); | 
|  | 164 | } | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | static inline u32 *dst_metrics_ptr(struct dst_entry *dst) | 
|  | 168 | { | 
|  | 169 | return DST_METRICS_PTR(dst); | 
|  | 170 | } | 
|  | 171 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 | static inline u32 | 
| David S. Miller | 5170ae8 | 2010-12-12 21:35:57 -0800 | [diff] [blame] | 173 | dst_metric_raw(const struct dst_entry *dst, const int metric) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | { | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 175 | u32 *p = DST_METRICS_PTR(dst); | 
|  | 176 |  | 
|  | 177 | return p[metric-1]; | 
| David S. Miller | defb351 | 2010-12-08 21:16:57 -0800 | [diff] [blame] | 178 | } | 
|  | 179 |  | 
| David S. Miller | 5170ae8 | 2010-12-12 21:35:57 -0800 | [diff] [blame] | 180 | static inline u32 | 
|  | 181 | dst_metric(const struct dst_entry *dst, const int metric) | 
|  | 182 | { | 
| David S. Miller | 0dbaee3 | 2010-12-13 12:52:14 -0800 | [diff] [blame] | 183 | WARN_ON_ONCE(metric == RTAX_HOPLIMIT || | 
| David S. Miller | d33e455 | 2010-12-14 13:01:14 -0800 | [diff] [blame] | 184 | metric == RTAX_ADVMSS || | 
|  | 185 | metric == RTAX_MTU); | 
| David S. Miller | 5170ae8 | 2010-12-12 21:35:57 -0800 | [diff] [blame] | 186 | return dst_metric_raw(dst, metric); | 
|  | 187 | } | 
|  | 188 |  | 
| David S. Miller | 0dbaee3 | 2010-12-13 12:52:14 -0800 | [diff] [blame] | 189 | static inline u32 | 
|  | 190 | dst_metric_advmss(const struct dst_entry *dst) | 
|  | 191 | { | 
|  | 192 | u32 advmss = dst_metric_raw(dst, RTAX_ADVMSS); | 
|  | 193 |  | 
|  | 194 | if (!advmss) | 
|  | 195 | advmss = dst->ops->default_advmss(dst); | 
|  | 196 |  | 
|  | 197 | return advmss; | 
|  | 198 | } | 
|  | 199 |  | 
| David S. Miller | defb351 | 2010-12-08 21:16:57 -0800 | [diff] [blame] | 200 | static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val) | 
|  | 201 | { | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 202 | u32 *p = dst_metrics_write_ptr(dst); | 
| David S. Miller | defb351 | 2010-12-08 21:16:57 -0800 | [diff] [blame] | 203 |  | 
| David S. Miller | 62fa8a8 | 2011-01-26 20:51:05 -0800 | [diff] [blame] | 204 | if (p) | 
|  | 205 | p[metric-1] = val; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | } | 
|  | 207 |  | 
| Gilad Ben-Yossef | 0c3adfb | 2009-10-28 04:15:23 +0000 | [diff] [blame] | 208 | static inline u32 | 
|  | 209 | dst_feature(const struct dst_entry *dst, u32 feature) | 
|  | 210 | { | 
| David S. Miller | bb5b7c1 | 2009-12-15 20:56:42 -0800 | [diff] [blame] | 211 | return dst_metric(dst, RTAX_FEATURES) & feature; | 
| Gilad Ben-Yossef | 0c3adfb | 2009-10-28 04:15:23 +0000 | [diff] [blame] | 212 | } | 
|  | 213 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | static inline u32 dst_mtu(const struct dst_entry *dst) | 
|  | 215 | { | 
| Steffen Klassert | 618f9bc | 2011-11-23 02:13:31 +0000 | [diff] [blame] | 216 | return dst->ops->mtu(dst); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 217 | } | 
|  | 218 |  | 
| Stephen Hemminger | c1e20f7 | 2008-07-18 23:02:15 -0700 | [diff] [blame] | 219 | /* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ | 
|  | 220 | static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metric) | 
|  | 221 | { | 
|  | 222 | return msecs_to_jiffies(dst_metric(dst, metric)); | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric, | 
|  | 226 | unsigned long rtt) | 
|  | 227 | { | 
| David S. Miller | defb351 | 2010-12-08 21:16:57 -0800 | [diff] [blame] | 228 | dst_metric_set(dst, metric, jiffies_to_msecs(rtt)); | 
| Stephen Hemminger | c1e20f7 | 2008-07-18 23:02:15 -0700 | [diff] [blame] | 229 | } | 
|  | 230 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | static inline u32 | 
|  | 232 | dst_allfrag(const struct dst_entry *dst) | 
|  | 233 | { | 
| Gilad Ben-Yossef | 0c3adfb | 2009-10-28 04:15:23 +0000 | [diff] [blame] | 234 | int ret = dst_feature(dst,  RTAX_FEATURE_ALLFRAG); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | return ret; | 
|  | 236 | } | 
|  | 237 |  | 
|  | 238 | static inline int | 
| David S. Miller | d33e455 | 2010-12-14 13:01:14 -0800 | [diff] [blame] | 239 | dst_metric_locked(const struct dst_entry *dst, int metric) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 | { | 
|  | 241 | return dst_metric(dst, RTAX_LOCK) & (1<<metric); | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | static inline void dst_hold(struct dst_entry * dst) | 
|  | 245 | { | 
| Eric Dumazet | 5635c10 | 2008-11-16 19:46:36 -0800 | [diff] [blame] | 246 | /* | 
|  | 247 | * If your kernel compilation stops here, please check | 
|  | 248 | * __pad_to_align_refcnt declaration in struct dst_entry | 
|  | 249 | */ | 
|  | 250 | BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 | atomic_inc(&dst->__refcnt); | 
|  | 252 | } | 
|  | 253 |  | 
| Pavel Emelyanov | 03f49f3 | 2007-11-10 21:28:34 -0800 | [diff] [blame] | 254 | static inline void dst_use(struct dst_entry *dst, unsigned long time) | 
|  | 255 | { | 
|  | 256 | dst_hold(dst); | 
|  | 257 | dst->__use++; | 
|  | 258 | dst->lastuse = time; | 
|  | 259 | } | 
|  | 260 |  | 
| Eric Dumazet | 7fee226 | 2010-05-11 23:19:48 +0000 | [diff] [blame] | 261 | static inline void dst_use_noref(struct dst_entry *dst, unsigned long time) | 
|  | 262 | { | 
|  | 263 | dst->__use++; | 
|  | 264 | dst->lastuse = time; | 
|  | 265 | } | 
|  | 266 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 267 | static inline | 
|  | 268 | struct dst_entry * dst_clone(struct dst_entry * dst) | 
|  | 269 | { | 
|  | 270 | if (dst) | 
|  | 271 | atomic_inc(&dst->__refcnt); | 
|  | 272 | return dst; | 
|  | 273 | } | 
|  | 274 |  | 
| Ilpo Järvinen | 8d33086 | 2008-03-27 17:53:31 -0700 | [diff] [blame] | 275 | extern void dst_release(struct dst_entry *dst); | 
| Eric Dumazet | 7fee226 | 2010-05-11 23:19:48 +0000 | [diff] [blame] | 276 |  | 
|  | 277 | static inline void refdst_drop(unsigned long refdst) | 
|  | 278 | { | 
|  | 279 | if (!(refdst & SKB_DST_NOREF)) | 
|  | 280 | dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK)); | 
|  | 281 | } | 
|  | 282 |  | 
|  | 283 | /** | 
|  | 284 | * skb_dst_drop - drops skb dst | 
|  | 285 | * @skb: buffer | 
|  | 286 | * | 
|  | 287 | * Drops dst reference count if a reference was taken. | 
|  | 288 | */ | 
| Eric Dumazet | adf3090 | 2009-06-02 05:19:30 +0000 | [diff] [blame] | 289 | static inline void skb_dst_drop(struct sk_buff *skb) | 
|  | 290 | { | 
| Eric Dumazet | 7fee226 | 2010-05-11 23:19:48 +0000 | [diff] [blame] | 291 | if (skb->_skb_refdst) { | 
|  | 292 | refdst_drop(skb->_skb_refdst); | 
|  | 293 | skb->_skb_refdst = 0UL; | 
|  | 294 | } | 
|  | 295 | } | 
|  | 296 |  | 
|  | 297 | static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb) | 
|  | 298 | { | 
|  | 299 | nskb->_skb_refdst = oskb->_skb_refdst; | 
|  | 300 | if (!(nskb->_skb_refdst & SKB_DST_NOREF)) | 
|  | 301 | dst_clone(skb_dst(nskb)); | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | /** | 
|  | 305 | * skb_dst_force - makes sure skb dst is refcounted | 
|  | 306 | * @skb: buffer | 
|  | 307 | * | 
|  | 308 | * If dst is not yet refcounted, let's do it | 
|  | 309 | */ | 
|  | 310 | static inline void skb_dst_force(struct sk_buff *skb) | 
|  | 311 | { | 
|  | 312 | if (skb_dst_is_noref(skb)) { | 
|  | 313 | WARN_ON(!rcu_read_lock_held()); | 
|  | 314 | skb->_skb_refdst &= ~SKB_DST_NOREF; | 
|  | 315 | dst_clone(skb_dst(skb)); | 
|  | 316 | } | 
| Eric Dumazet | adf3090 | 2009-06-02 05:19:30 +0000 | [diff] [blame] | 317 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 |  | 
| Eric Dumazet | d19d56d | 2010-05-17 22:36:55 -0700 | [diff] [blame] | 319 |  | 
|  | 320 | /** | 
| Eric Dumazet | 290b895 | 2010-09-27 00:33:35 +0000 | [diff] [blame] | 321 | *	__skb_tunnel_rx - prepare skb for rx reinsert | 
|  | 322 | *	@skb: buffer | 
|  | 323 | *	@dev: tunnel device | 
|  | 324 | * | 
|  | 325 | *	After decapsulation, packet is going to re-enter (netif_rx()) our stack, | 
|  | 326 | *	so make some cleanups. (no accounting done) | 
|  | 327 | */ | 
|  | 328 | static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev) | 
|  | 329 | { | 
|  | 330 | skb->dev = dev; | 
| Tom Herbert | bdeab99 | 2011-08-14 19:45:55 +0000 | [diff] [blame] | 331 |  | 
|  | 332 | /* | 
|  | 333 | * Clear rxhash so that we can recalulate the hash for the | 
|  | 334 | * encapsulated packet, unless we have already determine the hash | 
|  | 335 | * over the L4 4-tuple. | 
|  | 336 | */ | 
|  | 337 | if (!skb->l4_rxhash) | 
|  | 338 | skb->rxhash = 0; | 
| Eric Dumazet | 290b895 | 2010-09-27 00:33:35 +0000 | [diff] [blame] | 339 | skb_set_queue_mapping(skb, 0); | 
|  | 340 | skb_dst_drop(skb); | 
|  | 341 | nf_reset(skb); | 
|  | 342 | } | 
|  | 343 |  | 
|  | 344 | /** | 
| Eric Dumazet | d19d56d | 2010-05-17 22:36:55 -0700 | [diff] [blame] | 345 | *	skb_tunnel_rx - prepare skb for rx reinsert | 
|  | 346 | *	@skb: buffer | 
|  | 347 | *	@dev: tunnel device | 
|  | 348 | * | 
|  | 349 | *	After decapsulation, packet is going to re-enter (netif_rx()) our stack, | 
|  | 350 | *	so make some cleanups, and perform accounting. | 
| Eric Dumazet | 290b895 | 2010-09-27 00:33:35 +0000 | [diff] [blame] | 351 | *	Note: this accounting is not SMP safe. | 
| Eric Dumazet | d19d56d | 2010-05-17 22:36:55 -0700 | [diff] [blame] | 352 | */ | 
|  | 353 | static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev) | 
|  | 354 | { | 
| Eric Dumazet | d19d56d | 2010-05-17 22:36:55 -0700 | [diff] [blame] | 355 | /* TODO : stats should be SMP safe */ | 
|  | 356 | dev->stats.rx_packets++; | 
|  | 357 | dev->stats.rx_bytes += skb->len; | 
| Eric Dumazet | 290b895 | 2010-09-27 00:33:35 +0000 | [diff] [blame] | 358 | __skb_tunnel_rx(skb, dev); | 
| Eric Dumazet | d19d56d | 2010-05-17 22:36:55 -0700 | [diff] [blame] | 359 | } | 
|  | 360 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 | /* Children define the path of the packet through the | 
|  | 362 | * Linux networking.  Thus, destinations are stackable. | 
|  | 363 | */ | 
|  | 364 |  | 
| Steffen Klassert | 8764ab2 | 2010-06-04 01:57:38 +0000 | [diff] [blame] | 365 | static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 366 | { | 
| Steffen Klassert | e433430 | 2011-03-15 21:09:32 +0000 | [diff] [blame] | 367 | struct dst_entry *child = dst_clone(skb_dst(skb)->child); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 |  | 
| Steffen Klassert | 8764ab2 | 2010-06-04 01:57:38 +0000 | [diff] [blame] | 369 | skb_dst_drop(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 | return child; | 
|  | 371 | } | 
|  | 372 |  | 
| Herbert Xu | 352e512 | 2007-11-13 21:34:06 -0800 | [diff] [blame] | 373 | extern int dst_discard(struct sk_buff *skb); | 
| David S. Miller | 5c1e6aa | 2011-04-28 14:13:38 -0700 | [diff] [blame] | 374 | extern void *dst_alloc(struct dst_ops * ops, struct net_device *dev, | 
|  | 375 | int initial_ref, int initial_obsolete, int flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 376 | extern void __dst_free(struct dst_entry * dst); | 
|  | 377 | extern struct dst_entry *dst_destroy(struct dst_entry * dst); | 
|  | 378 |  | 
|  | 379 | static inline void dst_free(struct dst_entry * dst) | 
|  | 380 | { | 
|  | 381 | if (dst->obsolete > 1) | 
|  | 382 | return; | 
|  | 383 | if (!atomic_read(&dst->__refcnt)) { | 
|  | 384 | dst = dst_destroy(dst); | 
|  | 385 | if (!dst) | 
|  | 386 | return; | 
|  | 387 | } | 
|  | 388 | __dst_free(dst); | 
|  | 389 | } | 
|  | 390 |  | 
|  | 391 | static inline void dst_rcu_free(struct rcu_head *head) | 
|  | 392 | { | 
|  | 393 | struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); | 
|  | 394 | dst_free(dst); | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | static inline void dst_confirm(struct dst_entry *dst) | 
|  | 398 | { | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 399 | if (dst) { | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 400 | struct neighbour *n; | 
|  | 401 |  | 
|  | 402 | rcu_read_lock(); | 
| David Miller | 2721745 | 2011-12-02 16:52:08 +0000 | [diff] [blame] | 403 | n = dst_get_neighbour_noref(dst); | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 404 | neigh_confirm(n); | 
| Eric Dumazet | f2c31e3 | 2011-07-29 19:00:53 +0000 | [diff] [blame] | 405 | rcu_read_unlock(); | 
| David S. Miller | 69cce1d | 2011-07-17 23:09:49 -0700 | [diff] [blame] | 406 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 407 | } | 
|  | 408 |  | 
| David S. Miller | d3aaeb3 | 2011-07-18 00:40:17 -0700 | [diff] [blame] | 409 | static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr) | 
|  | 410 | { | 
|  | 411 | return dst->ops->neigh_lookup(dst, daddr); | 
|  | 412 | } | 
|  | 413 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 414 | static inline void dst_link_failure(struct sk_buff *skb) | 
|  | 415 | { | 
| Eric Dumazet | adf3090 | 2009-06-02 05:19:30 +0000 | [diff] [blame] | 416 | struct dst_entry *dst = skb_dst(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 417 | if (dst && dst->ops && dst->ops->link_failure) | 
|  | 418 | dst->ops->link_failure(skb); | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | static inline void dst_set_expires(struct dst_entry *dst, int timeout) | 
|  | 422 | { | 
|  | 423 | unsigned long expires = jiffies + timeout; | 
|  | 424 |  | 
|  | 425 | if (expires == 0) | 
|  | 426 | expires = 1; | 
|  | 427 |  | 
|  | 428 | if (dst->expires == 0 || time_before(expires, dst->expires)) | 
|  | 429 | dst->expires = expires; | 
|  | 430 | } | 
|  | 431 |  | 
|  | 432 | /* Output packet to network from transport.  */ | 
|  | 433 | static inline int dst_output(struct sk_buff *skb) | 
|  | 434 | { | 
| Eric Dumazet | adf3090 | 2009-06-02 05:19:30 +0000 | [diff] [blame] | 435 | return skb_dst(skb)->output(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 436 | } | 
|  | 437 |  | 
|  | 438 | /* Input packet from network to transport.  */ | 
|  | 439 | static inline int dst_input(struct sk_buff *skb) | 
|  | 440 | { | 
| Eric Dumazet | adf3090 | 2009-06-02 05:19:30 +0000 | [diff] [blame] | 441 | return skb_dst(skb)->input(skb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 442 | } | 
|  | 443 |  | 
|  | 444 | static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) | 
|  | 445 | { | 
|  | 446 | if (dst->obsolete) | 
|  | 447 | dst = dst->ops->check(dst, cookie); | 
|  | 448 | return dst; | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 | extern void		dst_init(void); | 
|  | 452 |  | 
| Herbert Xu | 815f4e5 | 2007-12-12 10:36:59 -0800 | [diff] [blame] | 453 | /* Flags for xfrm_lookup flags argument. */ | 
|  | 454 | enum { | 
| David S. Miller | 80c0bc9 | 2011-03-01 14:36:37 -0800 | [diff] [blame] | 455 | XFRM_LOOKUP_ICMP = 1 << 0, | 
| Herbert Xu | 815f4e5 | 2007-12-12 10:36:59 -0800 | [diff] [blame] | 456 | }; | 
|  | 457 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 458 | struct flowi; | 
|  | 459 | #ifndef CONFIG_XFRM | 
| David S. Miller | 452edd5 | 2011-03-02 13:27:41 -0800 | [diff] [blame] | 460 | static inline struct dst_entry *xfrm_lookup(struct net *net, | 
|  | 461 | struct dst_entry *dst_orig, | 
|  | 462 | const struct flowi *fl, struct sock *sk, | 
|  | 463 | int flags) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 464 | { | 
| David S. Miller | 452edd5 | 2011-03-02 13:27:41 -0800 | [diff] [blame] | 465 | return dst_orig; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 466 | } | 
|  | 467 | #else | 
| David S. Miller | 452edd5 | 2011-03-02 13:27:41 -0800 | [diff] [blame] | 468 | extern struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, | 
|  | 469 | const struct flowi *fl, struct sock *sk, | 
|  | 470 | int flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 471 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 472 |  | 
|  | 473 | #endif /* _NET_DST_H */ |