aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-01-28 01:01:53 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-28 01:01:53 -0500
commita4daad6b0923030fbd3b00a01f570e4c3eef446b (patch)
treeb8e5b9a2110628503e57149f0bb2a4bb1bf3f027
parent8571a19c4ac140f1a507f3e7eb716892afa27109 (diff)
net: Pre-COW metrics for TCP.
TCP is going to record metrics for the connection, so pre-COW the route metrics at route cache entry creation time. This avoids several atomic operations that have to occur if we COW the metrics after the entry reaches global visibility. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/flow.h3
-rw-r--r--include/net/inet_sock.h8
-rw-r--r--include/net/route.h4
-rw-r--r--net/ipv4/route.c26
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
220static inline __u8 inet_sk_flowi_flags(const struct sock *sk) 220static 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
1860static 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
1860static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) 1882static 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