Skip to content

Commit

Permalink
net: Abstract away all dst_entry metrics accesses.
Browse files Browse the repository at this point in the history
Use helper functions to hide all direct accesses, especially writes,
to dst_entry metrics values.

This will allow us to:

1) More easily change how the metrics are stored.

2) Implement COW for metrics.

In particular this will help us put metrics into the inetpeer
cache if that is what we end up doing.  We can make the _metrics
member a pointer instead of an array, initially have it point
at the read-only metrics in the FIB, and then on the first set
grab an inetpeer entry and point the _metrics member there.

Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
  • Loading branch information
David S. Miller committed Dec 9, 2010
1 parent 84b3cdc commit defb351
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 81 deletions.
26 changes: 23 additions & 3 deletions include/net/dst.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct dst_entry {

struct dst_ops *ops;

u32 metrics[RTAX_MAX];
u32 _metrics[RTAX_MAX];

#ifdef CONFIG_NET_CLS_ROUTE
__u32 tclassid;
Expand Down Expand Up @@ -106,7 +106,27 @@ struct dst_entry {
static inline u32
dst_metric(const struct dst_entry *dst, int metric)
{
return dst->metrics[metric-1];
return dst->_metrics[metric-1];
}

static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val)
{
dst->_metrics[metric-1] = val;
}

static inline void dst_import_metrics(struct dst_entry *dst, const u32 *src_metrics)
{
memcpy(dst->_metrics, src_metrics, RTAX_MAX * sizeof(u32));
}

static inline void dst_copy_metrics(struct dst_entry *dest, const struct dst_entry *src)
{
dst_import_metrics(dest, src->_metrics);
}

static inline u32 *dst_metrics_ptr(struct dst_entry *dst)
{
return dst->_metrics;
}

static inline u32
Expand Down Expand Up @@ -134,7 +154,7 @@ static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metr
static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric,
unsigned long rtt)
{
dst->metrics[metric-1] = jiffies_to_msecs(rtt);
dst_metric_set(dst, metric, jiffies_to_msecs(rtt));
}

static inline u32
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/br_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)

#ifdef CONFIG_BRIDGE_NETFILTER
/* remember the MTU in the rtable for PMTU */
br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu;
dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
#endif

return 0;
Expand Down
2 changes: 1 addition & 1 deletion net/bridge/br_netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
atomic_set(&rt->dst.__refcnt, 1);
rt->dst.dev = br->dev;
rt->dst.path = &rt->dst;
rt->dst.metrics[RTAX_MTU - 1] = 1500;
dst_metric_set(&rt->dst, RTAX_MTU, 1500);
rt->dst.flags = DST_NOXFRM;
rt->dst.ops = &fake_dst_ops;
}
Expand Down
13 changes: 6 additions & 7 deletions net/decnet/dn_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,13 +240,13 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)

if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) {
if (!(dst_metric_locked(dst, RTAX_MTU))) {
dst->metrics[RTAX_MTU-1] = mtu;
dst_metric_set(dst, RTAX_MTU, mtu);
dst_set_expires(dst, dn_rt_mtu_expires);
}
if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
if (dst_metric(dst, RTAX_ADVMSS) > mss)
dst->metrics[RTAX_ADVMSS-1] = mss;
dst_metric_set(dst, RTAX_ADVMSS, mss);
}
}
}
Expand Down Expand Up @@ -806,8 +806,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
if (DN_FIB_RES_GW(*res) &&
DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = DN_FIB_RES_GW(*res);
memcpy(rt->dst.metrics, fi->fib_metrics,
sizeof(rt->dst.metrics));
dst_import_metrics(&rt->dst, fi->fib_metrics);
}
rt->rt_type = res->type;

Expand All @@ -820,11 +819,11 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)

if (dst_metric(&rt->dst, RTAX_MTU) == 0 ||
dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu);
mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst));
if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0 ||
dst_metric(&rt->dst, RTAX_ADVMSS) > mss)
rt->dst.metrics[RTAX_ADVMSS-1] = mss;
dst_metric_set(&rt->dst, RTAX_ADVMSS, mss);
return 0;
}

Expand Down Expand Up @@ -1502,7 +1501,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
if (rt->rt_daddr != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
goto rtattr_failure;
expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires,
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/ip_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
!ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
rt6->rt6i_dst.plen == 128) {
rt6->rt6i_flags |= RTF_MODIFIED;
skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
}
}

Expand Down
55 changes: 30 additions & 25 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1686,11 +1686,14 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
if (mtu < dst_mtu(&rth->dst)) {
dst_confirm(&rth->dst);
if (mtu < ip_rt_min_pmtu) {
u32 lock = dst_metric(&rth->dst,
RTAX_LOCK);
mtu = ip_rt_min_pmtu;
rth->dst.metrics[RTAX_LOCK-1] |=
(1 << RTAX_MTU);
lock |= (1 << RTAX_MTU);
dst_metric_set(&rth->dst, RTAX_LOCK,
lock);
}
rth->dst.metrics[RTAX_MTU-1] = mtu;
dst_metric_set(&rth->dst, RTAX_MTU, mtu);
dst_set_expires(&rth->dst,
ip_rt_mtu_expires);
}
Expand All @@ -1708,10 +1711,11 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
if (dst_mtu(dst) > mtu && mtu >= 68 &&
!(dst_metric_locked(dst, RTAX_MTU))) {
if (mtu < ip_rt_min_pmtu) {
u32 lock = dst_metric(dst, RTAX_LOCK);
mtu = ip_rt_min_pmtu;
dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU);
dst_metric_set(dst, RTAX_LOCK, lock | (1 << RTAX_MTU));
}
dst->metrics[RTAX_MTU-1] = mtu;
dst_metric_set(dst, RTAX_MTU, mtu);
dst_set_expires(dst, ip_rt_mtu_expires);
call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
}
Expand Down Expand Up @@ -1796,36 +1800,37 @@ static void set_class_tag(struct rtable *rt, u32 tag)

static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
{
struct dst_entry *dst = &rt->dst;
struct fib_info *fi = res->fi;

if (fi) {
if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res);
memcpy(rt->dst.metrics, fi->fib_metrics,
sizeof(rt->dst.metrics));
dst_import_metrics(dst, fi->fib_metrics);
if (fi->fib_mtu == 0) {
rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);
if (dst_metric_locked(dst, RTAX_MTU) &&
rt->rt_gateway != rt->rt_dst &&
rt->dst.dev->mtu > 576)
rt->dst.metrics[RTAX_MTU-1] = 576;
dst->dev->mtu > 576)
dst_metric_set(dst, RTAX_MTU, 576);
}
#ifdef CONFIG_NET_CLS_ROUTE
rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif
} else
rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;

if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
if (dst_mtu(&rt->dst) > IP_MAX_MTU)
rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
ip_rt_min_advmss);
if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);

if (dst_metric(dst, RTAX_HOPLIMIT) == 0)
dst_metric_set(dst, RTAX_HOPLIMIT, sysctl_ip_default_ttl);
if (dst_mtu(dst) > IP_MAX_MTU)
dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
if (dst_metric(dst, RTAX_ADVMSS) == 0)
dst_metric_set(dst, RTAX_ADVMSS,
max_t(unsigned int, dst->dev->mtu - 40,
ip_rt_min_advmss));
if (dst_metric(dst, RTAX_ADVMSS) > 65535 - 40)
dst_metric_set(dst, RTAX_ADVMSS, 65535 - 40);

#ifdef CONFIG_NET_CLS_ROUTE
#ifdef CONFIG_IP_MULTIPLE_TABLES
Expand Down Expand Up @@ -2720,7 +2725,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
new->__use = 1;
new->input = dst_discard;
new->output = dst_discard;
memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
dst_copy_metrics(new, &ort->dst);

new->dev = ort->dst.dev;
if (new->dev)
Expand Down Expand Up @@ -2827,7 +2832,7 @@ static int rt_fill_info(struct net *net,
if (rt->rt_dst != rt->rt_gateway)
NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);

if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
goto nla_put_failure;

if (rt->fl.mark)
Expand Down
22 changes: 13 additions & 9 deletions net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ void tcp_update_metrics(struct sock *sk)
* Reset our results.
*/
if (!(dst_metric_locked(dst, RTAX_RTT)))
dst->metrics[RTAX_RTT - 1] = 0;
dst_metric_set(dst, RTAX_RTT, 0);
return;
}

Expand Down Expand Up @@ -776,34 +776,38 @@ void tcp_update_metrics(struct sock *sk)
if (dst_metric(dst, RTAX_SSTHRESH) &&
!dst_metric_locked(dst, RTAX_SSTHRESH) &&
(tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH))
dst->metrics[RTAX_SSTHRESH-1] = tp->snd_cwnd >> 1;
dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_cwnd >> 1);
if (!dst_metric_locked(dst, RTAX_CWND) &&
tp->snd_cwnd > dst_metric(dst, RTAX_CWND))
dst->metrics[RTAX_CWND - 1] = tp->snd_cwnd;
dst_metric_set(dst, RTAX_CWND, tp->snd_cwnd);
} else if (tp->snd_cwnd > tp->snd_ssthresh &&
icsk->icsk_ca_state == TCP_CA_Open) {
/* Cong. avoidance phase, cwnd is reliable. */
if (!dst_metric_locked(dst, RTAX_SSTHRESH))
dst->metrics[RTAX_SSTHRESH-1] =
max(tp->snd_cwnd >> 1, tp->snd_ssthresh);
dst_metric_set(dst, RTAX_SSTHRESH,
max(tp->snd_cwnd >> 1, tp->snd_ssthresh));
if (!dst_metric_locked(dst, RTAX_CWND))
dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_cwnd) >> 1;
dst_metric_set(dst, RTAX_CWND,
(dst_metric(dst, RTAX_CWND) +
tp->snd_cwnd) >> 1);
} else {
/* Else slow start did not finish, cwnd is non-sense,
ssthresh may be also invalid.
*/
if (!dst_metric_locked(dst, RTAX_CWND))
dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_ssthresh) >> 1;
dst_metric_set(dst, RTAX_CWND,
(dst_metric(dst, RTAX_CWND) +
tp->snd_ssthresh) >> 1);
if (dst_metric(dst, RTAX_SSTHRESH) &&
!dst_metric_locked(dst, RTAX_SSTHRESH) &&
tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH))
dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh;
dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_ssthresh);
}

if (!dst_metric_locked(dst, RTAX_REORDERING)) {
if (dst_metric(dst, RTAX_REORDERING) < tp->reordering &&
tp->reordering != sysctl_tcp_reordering)
dst->metrics[RTAX_REORDERING-1] = tp->reordering;
dst_metric_set(dst, RTAX_REORDERING, tp->reordering);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
if (ra_msg->icmph.icmp6_hop_limit) {
in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
if (rt)
rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
ra_msg->icmph.icmp6_hop_limit);
}

skip_defrtr:
Expand Down Expand Up @@ -1377,7 +1378,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
in6_dev->cnf.mtu6 = mtu;

if (rt)
rt->dst.metrics[RTAX_MTU-1] = mtu;
dst_metric_set(&rt->dst, RTAX_MTU, mtu);

rt6_mtu_change(skb->dev, mtu);
}
Expand Down
Loading

0 comments on commit defb351

Please sign in to comment.