aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-02-07 23:38:06 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-10 16:33:41 -0500
commit6431cbc25fa21635ee04eb0516ba6c51389fbfac (patch)
tree515deede7292fce41c019e7bd72b58cab34ecb9c
parentddd4aa424b866a08ceba7ddf38e61542c91b93a0 (diff)
inet: Create a mechanism for upward inetpeer propagation into routes.
If we didn't have a routing cache, we would not be able to properly propagate certain kinds of dynamic path attributes, for example PMTU information and redirects. The reason is that if we didn't have a routing cache, then there would be no way to lookup all of the active cached routes hanging off of sockets, tunnels, IPSEC bundles, etc. Consider the case where we created a cached route, but no inetpeer entry existed and also we were not asked to pre-COW the route metrics and therefore did not force the creation a new inetpeer entry. If we later get a PMTU message, or a redirect, and store this information in a new inetpeer entry, there is no way to teach that cached route about the newly existing inetpeer entry. The facilities implemented here handle this problem. First we create a generation ID. When we create a cached route of any kind, we remember the generation ID at the time of attachment. Any time we force-create an inetpeer entry in response to new path information, we bump that generation ID. The dst_ops->check() callback is where the knowledge of this event is propagated. If the global generation ID does not equal the one stored in the cached route, and the cached route has not attached to an inetpeer yet, we look it up and attach if one is found. Now that we've updated the cached route's information, we update the route's generation ID too. This clears the way for implementing PMTU and redirects directly in the inetpeer cache. There is absolutely no need to consult cached route information in order to maintain this information. At this point nothing bumps the inetpeer genids, that comes in the later changes which handle PMTUs and redirects using inetpeers. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip6_fib.h1
-rw-r--r--include/net/route.h1
-rw-r--r--net/ipv4/route.c19
-rw-r--r--net/ipv6/route.c18
4 files changed, 36 insertions, 3 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 708ff7cb8806..46a6e8ae232c 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -108,6 +108,7 @@ struct rt6_info {
108 u32 rt6i_flags; 108 u32 rt6i_flags;
109 struct rt6key rt6i_src; 109 struct rt6key rt6i_src;
110 u32 rt6i_metric; 110 u32 rt6i_metric;
111 u32 rt6i_peer_genid;
111 112
112 struct inet6_dev *rt6i_idev; 113 struct inet6_dev *rt6i_idev;
113 struct inet_peer *rt6i_peer; 114 struct inet_peer *rt6i_peer;
diff --git a/include/net/route.h b/include/net/route.h
index e5864658dc76..bf790c1c6ac8 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -69,6 +69,7 @@ struct rtable {
69 69
70 /* Miscellaneous cached information */ 70 /* Miscellaneous cached information */
71 __be32 rt_spec_dst; /* RFC1122 specific destination */ 71 __be32 rt_spec_dst; /* RFC1122 specific destination */
72 u32 rt_peer_genid;
72 struct inet_peer *peer; /* long-living peer info */ 73 struct inet_peer *peer; /* long-living peer info */
73 struct fib_info *fi; /* for client ref to shared metrics */ 74 struct fib_info *fi; /* for client ref to shared metrics */
74}; 75};
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 0455af851751..0979e039104a 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1308,6 +1308,13 @@ skip_hashing:
1308 return 0; 1308 return 0;
1309} 1309}
1310 1310
1311static atomic_t __rt_peer_genid = ATOMIC_INIT(0);
1312
1313static u32 rt_peer_genid(void)
1314{
1315 return atomic_read(&__rt_peer_genid);
1316}
1317
1311void rt_bind_peer(struct rtable *rt, int create) 1318void rt_bind_peer(struct rtable *rt, int create)
1312{ 1319{
1313 struct inet_peer *peer; 1320 struct inet_peer *peer;
@@ -1316,6 +1323,8 @@ void rt_bind_peer(struct rtable *rt, int create)
1316 1323
1317 if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL) 1324 if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
1318 inet_putpeer(peer); 1325 inet_putpeer(peer);
1326 else
1327 rt->rt_peer_genid = rt_peer_genid();
1319} 1328}
1320 1329
1321/* 1330/*
@@ -1767,8 +1776,16 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
1767 1776
1768static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) 1777static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
1769{ 1778{
1770 if (rt_is_expired((struct rtable *)dst)) 1779 struct rtable *rt = (struct rtable *) dst;
1780
1781 if (rt_is_expired(rt))
1771 return NULL; 1782 return NULL;
1783 if (rt->rt_peer_genid != rt_peer_genid()) {
1784 if (!rt->peer)
1785 rt_bind_peer(rt, 0);
1786
1787 rt->rt_peer_genid = rt_peer_genid();
1788 }
1772 return dst; 1789 return dst;
1773} 1790}
1774 1791
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 12ec83d48806..ad8556e6fd41 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -240,6 +240,13 @@ static void ip6_dst_destroy(struct dst_entry *dst)
240 } 240 }
241} 241}
242 242
243static atomic_t __rt6_peer_genid = ATOMIC_INIT(0);
244
245static u32 rt6_peer_genid(void)
246{
247 return atomic_read(&__rt6_peer_genid);
248}
249
243void rt6_bind_peer(struct rt6_info *rt, int create) 250void rt6_bind_peer(struct rt6_info *rt, int create)
244{ 251{
245 struct inet_peer *peer; 252 struct inet_peer *peer;
@@ -247,6 +254,8 @@ void rt6_bind_peer(struct rt6_info *rt, int create)
247 peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create); 254 peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
248 if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL) 255 if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
249 inet_putpeer(peer); 256 inet_putpeer(peer);
257 else
258 rt->rt6i_peer_genid = rt6_peer_genid();
250} 259}
251 260
252static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 261static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
@@ -912,9 +921,14 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
912 921
913 rt = (struct rt6_info *) dst; 922 rt = (struct rt6_info *) dst;
914 923
915 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) 924 if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
925 if (rt->rt6i_peer_genid != rt6_peer_genid()) {
926 if (!rt->rt6i_peer)
927 rt6_bind_peer(rt, 0);
928 rt->rt6i_peer_genid = rt6_peer_genid();
929 }
916 return dst; 930 return dst;
917 931 }
918 return NULL; 932 return NULL;
919} 933}
920 934