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>
This commit is contained in:
Родитель
8571a19c4a
Коммит
a4daad6b09
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче