aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-12-14 16:01:14 -0500
committerDavid S. Miller <davem@davemloft.net>2010-12-14 16:01:14 -0500
commitd33e455337ea2c71d09d7f4367d6ad6dd32b6965 (patch)
treed1b35b1be5ab73df6f7e57b86a2e68fad2990adf
parent9fe146aef44afe5ec677d8150b6ae94e09b773f7 (diff)
net: Abstract default MTU metric calculation behind an accessor.
Like RTAX_ADVMSS, make the default calculation go through a dst_ops method rather than caching the computation in the routing cache entries. Now dst metrics are pretty much left as-is when new entries are created, thus optimizing metric sharing becomes a real possibility. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/dst.h15
-rw-r--r--include/net/dst_ops.h1
-rw-r--r--net/decnet/dn_route.c10
-rw-r--r--net/ipv4/route.c29
-rw-r--r--net/ipv6/route.c37
-rw-r--r--net/xfrm/xfrm_policy.c7
6 files changed, 60 insertions, 39 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index 03a1c3d52d80..93b0310317be 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -113,7 +113,8 @@ static inline u32
113dst_metric(const struct dst_entry *dst, const int metric) 113dst_metric(const struct dst_entry *dst, const int metric)
114{ 114{
115 WARN_ON_ONCE(metric == RTAX_HOPLIMIT || 115 WARN_ON_ONCE(metric == RTAX_HOPLIMIT ||
116 metric == RTAX_ADVMSS); 116 metric == RTAX_ADVMSS ||
117 metric == RTAX_MTU);
117 return dst_metric_raw(dst, metric); 118 return dst_metric_raw(dst, metric);
118} 119}
119 120
@@ -156,11 +157,11 @@ dst_feature(const struct dst_entry *dst, u32 feature)
156 157
157static inline u32 dst_mtu(const struct dst_entry *dst) 158static inline u32 dst_mtu(const struct dst_entry *dst)
158{ 159{
159 u32 mtu = dst_metric(dst, RTAX_MTU); 160 u32 mtu = dst_metric_raw(dst, RTAX_MTU);
160 /* 161
161 * Alexey put it here, so ask him about it :) 162 if (!mtu)
162 */ 163 mtu = dst->ops->default_mtu(dst);
163 barrier(); 164
164 return mtu; 165 return mtu;
165} 166}
166 167
@@ -186,7 +187,7 @@ dst_allfrag(const struct dst_entry *dst)
186} 187}
187 188
188static inline int 189static inline int
189dst_metric_locked(struct dst_entry *dst, int metric) 190dst_metric_locked(const struct dst_entry *dst, int metric)
190{ 191{
191 return dst_metric(dst, RTAX_LOCK) & (1<<metric); 192 return dst_metric(dst, RTAX_LOCK) & (1<<metric);
192} 193}
diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h
index 15fb7af08c42..21a320b8708e 100644
--- a/include/net/dst_ops.h
+++ b/include/net/dst_ops.h
@@ -17,6 +17,7 @@ struct dst_ops {
17 int (*gc)(struct dst_ops *ops); 17 int (*gc)(struct dst_ops *ops);
18 struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); 18 struct dst_entry * (*check)(struct dst_entry *, __u32 cookie);
19 unsigned int (*default_advmss)(const struct dst_entry *); 19 unsigned int (*default_advmss)(const struct dst_entry *);
20 unsigned int (*default_mtu)(const struct dst_entry *);
20 void (*destroy)(struct dst_entry *); 21 void (*destroy)(struct dst_entry *);
21 void (*ifdown)(struct dst_entry *, 22 void (*ifdown)(struct dst_entry *,
22 struct net_device *dev, int how); 23 struct net_device *dev, int how);
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index b8a5c0515be8..5e636365d33c 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -111,6 +111,7 @@ static unsigned long dn_rt_deadline;
111static int dn_dst_gc(struct dst_ops *ops); 111static int dn_dst_gc(struct dst_ops *ops);
112static struct dst_entry *dn_dst_check(struct dst_entry *, __u32); 112static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
113static unsigned int dn_dst_default_advmss(const struct dst_entry *dst); 113static unsigned int dn_dst_default_advmss(const struct dst_entry *dst);
114static unsigned int dn_dst_default_mtu(const struct dst_entry *dst);
114static struct dst_entry *dn_dst_negative_advice(struct dst_entry *); 115static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
115static void dn_dst_link_failure(struct sk_buff *); 116static void dn_dst_link_failure(struct sk_buff *);
116static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu); 117static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu);
@@ -131,6 +132,7 @@ static struct dst_ops dn_dst_ops = {
131 .gc = dn_dst_gc, 132 .gc = dn_dst_gc,
132 .check = dn_dst_check, 133 .check = dn_dst_check,
133 .default_advmss = dn_dst_default_advmss, 134 .default_advmss = dn_dst_default_advmss,
135 .default_mtu = dn_dst_default_mtu,
134 .negative_advice = dn_dst_negative_advice, 136 .negative_advice = dn_dst_negative_advice,
135 .link_failure = dn_dst_link_failure, 137 .link_failure = dn_dst_link_failure,
136 .update_pmtu = dn_dst_update_pmtu, 138 .update_pmtu = dn_dst_update_pmtu,
@@ -803,6 +805,11 @@ static unsigned int dn_dst_default_advmss(const struct dst_entry *dst)
803 return dn_mss_from_pmtu(dst->dev, dst_mtu(dst)); 805 return dn_mss_from_pmtu(dst->dev, dst_mtu(dst));
804} 806}
805 807
808static unsigned int dn_dst_default_mtu(const struct dst_entry *dst)
809{
810 return dst->dev->mtu;
811}
812
806static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) 813static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
807{ 814{
808 struct dn_fib_info *fi = res->fi; 815 struct dn_fib_info *fi = res->fi;
@@ -825,8 +832,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
825 rt->dst.neighbour = n; 832 rt->dst.neighbour = n;
826 } 833 }
827 834
828 if (dst_metric(&rt->dst, RTAX_MTU) == 0 || 835 if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
829 dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
830 dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu); 836 dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu);
831 metric = dst_metric_raw(&rt->dst, RTAX_ADVMSS); 837 metric = dst_metric_raw(&rt->dst, RTAX_ADVMSS);
832 if (metric) { 838 if (metric) {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 80997333db0c..ae520963540f 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -140,6 +140,7 @@ static unsigned long expires_ljiffies;
140 140
141static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); 141static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie);
142static unsigned int ipv4_default_advmss(const struct dst_entry *dst); 142static unsigned int ipv4_default_advmss(const struct dst_entry *dst);
143static unsigned int ipv4_default_mtu(const struct dst_entry *dst);
143static void ipv4_dst_destroy(struct dst_entry *dst); 144static void ipv4_dst_destroy(struct dst_entry *dst);
144static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); 145static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
145static void ipv4_link_failure(struct sk_buff *skb); 146static void ipv4_link_failure(struct sk_buff *skb);
@@ -157,6 +158,7 @@ static struct dst_ops ipv4_dst_ops = {
157 .gc = rt_garbage_collect, 158 .gc = rt_garbage_collect,
158 .check = ipv4_dst_check, 159 .check = ipv4_dst_check,
159 .default_advmss = ipv4_default_advmss, 160 .default_advmss = ipv4_default_advmss,
161 .default_mtu = ipv4_default_mtu,
160 .destroy = ipv4_dst_destroy, 162 .destroy = ipv4_dst_destroy,
161 .ifdown = ipv4_dst_ifdown, 163 .ifdown = ipv4_dst_ifdown,
162 .negative_advice = ipv4_negative_advice, 164 .negative_advice = ipv4_negative_advice,
@@ -1812,6 +1814,23 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst)
1812 return advmss; 1814 return advmss;
1813} 1815}
1814 1816
1817static unsigned int ipv4_default_mtu(const struct dst_entry *dst)
1818{
1819 unsigned int mtu = dst->dev->mtu;
1820
1821 if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
1822 const struct rtable *rt = (const struct rtable *) dst;
1823
1824 if (rt->rt_gateway != rt->rt_dst && mtu > 576)
1825 mtu = 576;
1826 }
1827
1828 if (mtu > IP_MAX_MTU)
1829 mtu = IP_MAX_MTU;
1830
1831 return mtu;
1832}
1833
1815static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) 1834static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
1816{ 1835{
1817 struct dst_entry *dst = &rt->dst; 1836 struct dst_entry *dst = &rt->dst;
@@ -1822,18 +1841,10 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
1822 FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) 1841 FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
1823 rt->rt_gateway = FIB_RES_GW(*res); 1842 rt->rt_gateway = FIB_RES_GW(*res);
1824 dst_import_metrics(dst, fi->fib_metrics); 1843 dst_import_metrics(dst, fi->fib_metrics);
1825 if (fi->fib_mtu == 0) {
1826 dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);
1827 if (dst_metric_locked(dst, RTAX_MTU) &&
1828 rt->rt_gateway != rt->rt_dst &&
1829 dst->dev->mtu > 576)
1830 dst_metric_set(dst, RTAX_MTU, 576);
1831 }
1832#ifdef CONFIG_NET_CLS_ROUTE 1844#ifdef CONFIG_NET_CLS_ROUTE
1833 dst->tclassid = FIB_RES_NH(*res).nh_tclassid; 1845 dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
1834#endif 1846#endif
1835 } else 1847 }
1836 dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);
1837 1848
1838 if (dst_mtu(dst) > IP_MAX_MTU) 1849 if (dst_mtu(dst) > IP_MAX_MTU)
1839 dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU); 1850 dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d9cb832be529..e7efb269a6e9 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -77,6 +77,7 @@
77static struct rt6_info * ip6_rt_copy(struct rt6_info *ort); 77static struct rt6_info * ip6_rt_copy(struct rt6_info *ort);
78static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); 78static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie);
79static unsigned int ip6_default_advmss(const struct dst_entry *dst); 79static unsigned int ip6_default_advmss(const struct dst_entry *dst);
80static unsigned int ip6_default_mtu(const struct dst_entry *dst);
80static struct dst_entry *ip6_negative_advice(struct dst_entry *); 81static struct dst_entry *ip6_negative_advice(struct dst_entry *);
81static void ip6_dst_destroy(struct dst_entry *); 82static void ip6_dst_destroy(struct dst_entry *);
82static void ip6_dst_ifdown(struct dst_entry *, 83static void ip6_dst_ifdown(struct dst_entry *,
@@ -105,6 +106,7 @@ static struct dst_ops ip6_dst_ops_template = {
105 .gc_thresh = 1024, 106 .gc_thresh = 1024,
106 .check = ip6_dst_check, 107 .check = ip6_dst_check,
107 .default_advmss = ip6_default_advmss, 108 .default_advmss = ip6_default_advmss,
109 .default_mtu = ip6_default_mtu,
108 .destroy = ip6_dst_destroy, 110 .destroy = ip6_dst_destroy,
109 .ifdown = ip6_dst_ifdown, 111 .ifdown = ip6_dst_ifdown,
110 .negative_advice = ip6_negative_advice, 112 .negative_advice = ip6_negative_advice,
@@ -937,8 +939,6 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
937 } 939 }
938} 940}
939 941
940static int ipv6_get_mtu(struct net_device *dev);
941
942static unsigned int ip6_default_advmss(const struct dst_entry *dst) 942static unsigned int ip6_default_advmss(const struct dst_entry *dst)
943{ 943{
944 struct net_device *dev = dst->dev; 944 struct net_device *dev = dst->dev;
@@ -961,6 +961,20 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
961 return mtu; 961 return mtu;
962} 962}
963 963
964static unsigned int ip6_default_mtu(const struct dst_entry *dst)
965{
966 unsigned int mtu = IPV6_MIN_MTU;
967 struct inet6_dev *idev;
968
969 rcu_read_lock();
970 idev = __in6_dev_get(dst->dev);
971 if (idev)
972 mtu = idev->cnf.mtu6;
973 rcu_read_unlock();
974
975 return mtu;
976}
977
964static struct dst_entry *icmp6_dst_gc_list; 978static struct dst_entry *icmp6_dst_gc_list;
965static DEFINE_SPINLOCK(icmp6_dst_lock); 979static DEFINE_SPINLOCK(icmp6_dst_lock);
966 980
@@ -995,7 +1009,6 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
995 rt->rt6i_nexthop = neigh; 1009 rt->rt6i_nexthop = neigh;
996 atomic_set(&rt->dst.__refcnt, 1); 1010 atomic_set(&rt->dst.__refcnt, 1);
997 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); 1011 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
998 dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(rt->rt6i_dev));
999 rt->dst.output = ip6_output; 1012 rt->dst.output = ip6_output;
1000 1013
1001#if 0 /* there's no chance to use these for ndisc */ 1014#if 0 /* there's no chance to use these for ndisc */
@@ -1094,19 +1107,6 @@ out:
1094 Remove it only when all the things will work! 1107 Remove it only when all the things will work!
1095 */ 1108 */
1096 1109
1097static int ipv6_get_mtu(struct net_device *dev)
1098{
1099 int mtu = IPV6_MIN_MTU;
1100 struct inet6_dev *idev;
1101
1102 rcu_read_lock();
1103 idev = __in6_dev_get(dev);
1104 if (idev)
1105 mtu = idev->cnf.mtu6;
1106 rcu_read_unlock();
1107 return mtu;
1108}
1109
1110int ip6_dst_hoplimit(struct dst_entry *dst) 1110int ip6_dst_hoplimit(struct dst_entry *dst)
1111{ 1111{
1112 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); 1112 int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
@@ -1315,8 +1315,6 @@ install_route:
1315 } 1315 }
1316 } 1316 }
1317 1317
1318 if (!dst_mtu(&rt->dst))
1319 dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(dev));
1320 rt->dst.dev = dev; 1318 rt->dst.dev = dev;
1321 rt->rt6i_idev = idev; 1319 rt->rt6i_idev = idev;
1322 rt->rt6i_table = table; 1320 rt->rt6i_table = table;
@@ -1541,8 +1539,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
1541 1539
1542 ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); 1540 ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
1543 nrt->rt6i_nexthop = neigh_clone(neigh); 1541 nrt->rt6i_nexthop = neigh_clone(neigh);
1544 /* Reset pmtu, it may be better */
1545 dst_metric_set(&nrt->dst, RTAX_MTU, ipv6_get_mtu(neigh->dev));
1546 1542
1547 if (ip6_ins_rt(nrt)) 1543 if (ip6_ins_rt(nrt))
1548 goto out; 1544 goto out;
@@ -1971,7 +1967,6 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1971 rt->dst.output = ip6_output; 1967 rt->dst.output = ip6_output;
1972 rt->rt6i_dev = net->loopback_dev; 1968 rt->rt6i_dev = net->loopback_dev;
1973 rt->rt6i_idev = idev; 1969 rt->rt6i_idev = idev;
1974 dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(rt->rt6i_dev));
1975 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1); 1970 dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1);
1976 rt->dst.obsolete = -1; 1971 rt->dst.obsolete = -1;
1977 1972
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 36936c8ae961..8b3ef404c794 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2366,6 +2366,11 @@ static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
2366 return dst_metric_advmss(dst->path); 2366 return dst_metric_advmss(dst->path);
2367} 2367}
2368 2368
2369static unsigned int xfrm_default_mtu(const struct dst_entry *dst)
2370{
2371 return dst_mtu(dst->path);
2372}
2373
2369int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) 2374int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
2370{ 2375{
2371 struct net *net; 2376 struct net *net;
@@ -2385,6 +2390,8 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
2385 dst_ops->check = xfrm_dst_check; 2390 dst_ops->check = xfrm_dst_check;
2386 if (likely(dst_ops->default_advmss == NULL)) 2391 if (likely(dst_ops->default_advmss == NULL))
2387 dst_ops->default_advmss = xfrm_default_advmss; 2392 dst_ops->default_advmss = xfrm_default_advmss;
2393 if (likely(dst_ops->default_mtu == NULL))
2394 dst_ops->default_mtu = xfrm_default_mtu;
2388 if (likely(dst_ops->negative_advice == NULL)) 2395 if (likely(dst_ops->negative_advice == NULL))
2389 dst_ops->negative_advice = xfrm_negative_advice; 2396 dst_ops->negative_advice = xfrm_negative_advice;
2390 if (likely(dst_ops->link_failure == NULL)) 2397 if (likely(dst_ops->link_failure == NULL))