diff options
-rw-r--r-- | include/net/flow.h | 3 | ||||
-rw-r--r-- | include/net/inet_sock.h | 8 | ||||
-rw-r--r-- | include/net/route.h | 4 | ||||
-rw-r--r-- | net/ipv4/route.c | 26 |
4 files changed, 36 insertions, 5 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index 240b7f356c71..1ae901f24436 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -48,7 +48,8 @@ struct flowi { | |||
48 | 48 | ||
49 | __u8 proto; | 49 | __u8 proto; |
50 | __u8 flags; | 50 | __u8 flags; |
51 | #define FLOWI_FLAG_ANYSRC 0x01 | 51 | #define FLOWI_FLAG_ANYSRC 0x01 |
52 | #define FLOWI_FLAG_PRECOW_METRICS 0x02 | ||
52 | union { | 53 | union { |
53 | struct { | 54 | struct { |
54 | __be16 sport; | 55 | __be16 sport; |
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 8181498fa96c..6e6dfd757682 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h | |||
@@ -219,7 +219,13 @@ static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops | |||
219 | 219 | ||
220 | static inline __u8 inet_sk_flowi_flags(const struct sock *sk) | 220 | static inline __u8 inet_sk_flowi_flags(const struct sock *sk) |
221 | { | 221 | { |
222 | return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0; | 222 | __u8 flags = 0; |
223 | |||
224 | if (inet_sk(sk)->transparent) | ||
225 | flags |= FLOWI_FLAG_ANYSRC; | ||
226 | if (sk->sk_protocol == IPPROTO_TCP) | ||
227 | flags |= FLOWI_FLAG_PRECOW_METRICS; | ||
228 | return flags; | ||
223 | } | 229 | } |
224 | 230 | ||
225 | #endif /* _INET_SOCK_H */ | 231 | #endif /* _INET_SOCK_H */ |
diff --git a/include/net/route.h b/include/net/route.h index 5677cbf0c6e6..e5864658dc76 100644 --- a/include/net/route.h +++ b/include/net/route.h | |||
@@ -182,6 +182,8 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, | |||
182 | 182 | ||
183 | if (inet_sk(sk)->transparent) | 183 | if (inet_sk(sk)->transparent) |
184 | fl.flags |= FLOWI_FLAG_ANYSRC; | 184 | fl.flags |= FLOWI_FLAG_ANYSRC; |
185 | if (protocol == IPPROTO_TCP) | ||
186 | fl.flags |= FLOWI_FLAG_PRECOW_METRICS; | ||
185 | 187 | ||
186 | if (!dst || !src) { | 188 | if (!dst || !src) { |
187 | err = __ip_route_output_key(net, rp, &fl); | 189 | err = __ip_route_output_key(net, rp, &fl); |
@@ -209,6 +211,8 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol, | |||
209 | fl.proto = protocol; | 211 | fl.proto = protocol; |
210 | if (inet_sk(sk)->transparent) | 212 | if (inet_sk(sk)->transparent) |
211 | fl.flags |= FLOWI_FLAG_ANYSRC; | 213 | fl.flags |= FLOWI_FLAG_ANYSRC; |
214 | if (protocol == IPPROTO_TCP) | ||
215 | fl.flags |= FLOWI_FLAG_PRECOW_METRICS; | ||
212 | ip_rt_put(*rp); | 216 | ip_rt_put(*rp); |
213 | *rp = NULL; | 217 | *rp = NULL; |
214 | security_sk_classify_flow(sk, &fl); | 218 | security_sk_classify_flow(sk, &fl); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 68cee358d9a3..dd57f4896736 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1857,6 +1857,28 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst) | |||
1857 | return mtu; | 1857 | return mtu; |
1858 | } | 1858 | } |
1859 | 1859 | ||
1860 | static void rt_init_metrics(struct rtable *rt, struct fib_info *fi) | ||
1861 | { | ||
1862 | if (!(rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)) { | ||
1863 | no_cow: | ||
1864 | rt->fi = fi; | ||
1865 | atomic_inc(&fi->fib_clntref); | ||
1866 | dst_init_metrics(&rt->dst, fi->fib_metrics, true); | ||
1867 | } else { | ||
1868 | struct inet_peer *peer; | ||
1869 | |||
1870 | if (!rt->peer) | ||
1871 | rt_bind_peer(rt, 1); | ||
1872 | peer = rt->peer; | ||
1873 | if (!peer) | ||
1874 | goto no_cow; | ||
1875 | if (inet_metrics_new(peer)) | ||
1876 | memcpy(peer->metrics, fi->fib_metrics, | ||
1877 | sizeof(u32) * RTAX_MAX); | ||
1878 | dst_init_metrics(&rt->dst, peer->metrics, false); | ||
1879 | } | ||
1880 | } | ||
1881 | |||
1860 | static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) | 1882 | static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) |
1861 | { | 1883 | { |
1862 | struct dst_entry *dst = &rt->dst; | 1884 | struct dst_entry *dst = &rt->dst; |
@@ -1866,9 +1888,7 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) | |||
1866 | if (FIB_RES_GW(*res) && | 1888 | if (FIB_RES_GW(*res) && |
1867 | FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) | 1889 | FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) |
1868 | rt->rt_gateway = FIB_RES_GW(*res); | 1890 | rt->rt_gateway = FIB_RES_GW(*res); |
1869 | rt->fi = fi; | 1891 | rt_init_metrics(rt, fi); |
1870 | atomic_inc(&fi->fib_clntref); | ||
1871 | dst_init_metrics(dst, fi->fib_metrics, true); | ||
1872 | #ifdef CONFIG_IP_ROUTE_CLASSID | 1892 | #ifdef CONFIG_IP_ROUTE_CLASSID |
1873 | dst->tclassid = FIB_RES_NH(*res).nh_tclassid; | 1893 | dst->tclassid = FIB_RES_NH(*res).nh_tclassid; |
1874 | #endif | 1894 | #endif |