Skip to content

Commit

Permalink
net: Pre-COW metrics for TCP.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David S. Miller committed Jan 28, 2011
1 parent 8571a19 commit a4daad6
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 5 deletions.
3 changes: 2 additions & 1 deletion include/net/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ struct flowi {

__u8 proto;
__u8 flags;
#define FLOWI_FLAG_ANYSRC 0x01
#define FLOWI_FLAG_ANYSRC 0x01
#define FLOWI_FLAG_PRECOW_METRICS 0x02
union {
struct {
__be16 sport;
Expand Down
8 changes: 7 additions & 1 deletion include/net/inet_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,13 @@ static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops

static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
{
return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0;
__u8 flags = 0;

if (inet_sk(sk)->transparent)
flags |= FLOWI_FLAG_ANYSRC;
if (sk->sk_protocol == IPPROTO_TCP)
flags |= FLOWI_FLAG_PRECOW_METRICS;
return flags;
}

#endif /* _INET_SOCK_H */
4 changes: 4 additions & 0 deletions include/net/route.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst,

if (inet_sk(sk)->transparent)
fl.flags |= FLOWI_FLAG_ANYSRC;
if (protocol == IPPROTO_TCP)
fl.flags |= FLOWI_FLAG_PRECOW_METRICS;

if (!dst || !src) {
err = __ip_route_output_key(net, rp, &fl);
Expand Down Expand Up @@ -209,6 +211,8 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol,
fl.proto = protocol;
if (inet_sk(sk)->transparent)
fl.flags |= FLOWI_FLAG_ANYSRC;
if (protocol == IPPROTO_TCP)
fl.flags |= FLOWI_FLAG_PRECOW_METRICS;
ip_rt_put(*rp);
*rp = NULL;
security_sk_classify_flow(sk, &fl);
Expand Down
26 changes: 23 additions & 3 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1857,6 +1857,28 @@ static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
return mtu;
}

static void rt_init_metrics(struct rtable *rt, struct fib_info *fi)
{
if (!(rt->fl.flags & FLOWI_FLAG_PRECOW_METRICS)) {
no_cow:
rt->fi = fi;
atomic_inc(&fi->fib_clntref);
dst_init_metrics(&rt->dst, fi->fib_metrics, true);
} else {
struct inet_peer *peer;

if (!rt->peer)
rt_bind_peer(rt, 1);
peer = rt->peer;
if (!peer)
goto no_cow;
if (inet_metrics_new(peer))
memcpy(peer->metrics, fi->fib_metrics,
sizeof(u32) * RTAX_MAX);
dst_init_metrics(&rt->dst, peer->metrics, false);
}
}

static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
{
struct dst_entry *dst = &rt->dst;
Expand All @@ -1866,9 +1888,7 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res);
rt->fi = fi;
atomic_inc(&fi->fib_clntref);
dst_init_metrics(dst, fi->fib_metrics, true);
rt_init_metrics(rt, fi);
#ifdef CONFIG_IP_ROUTE_CLASSID
dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif
Expand Down

0 comments on commit a4daad6

Please sign in to comment.