aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-17 15:58:50 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-20 16:36:40 -0400
commitd2d68ba9fe8b38eb03124b3176a013bb8aa2b5e5 (patch)
treec523a0448a1feca0ebfa57983ff9ff58a898b768 /net
parentf2bb4bedf35d5167a073dcdddf16543f351ef3ae (diff)
ipv4: Cache input routes in fib_info nexthops.
Caching input routes is slightly simpler than output routes, since we don't need to be concerned with nexthop exceptions. (locally destined, and routed packets, never trigger PMTU events or redirects that will be processed by us). However, we have to elide caching for the DIRECTSRC and non-zero itag cases. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_semantics.c2
-rw-r--r--net/ipv4/route.c55
2 files changed, 45 insertions, 12 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 83d0f42b619a..e55171f184f9 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -173,6 +173,8 @@ static void free_fib_info_rcu(struct rcu_head *head)
173 free_nh_exceptions(nexthop_nh); 173 free_nh_exceptions(nexthop_nh);
174 if (nexthop_nh->nh_rth_output) 174 if (nexthop_nh->nh_rth_output)
175 dst_release(&nexthop_nh->nh_rth_output->dst); 175 dst_release(&nexthop_nh->nh_rth_output->dst);
176 if (nexthop_nh->nh_rth_input)
177 dst_release(&nexthop_nh->nh_rth_input->dst);
176 } endfor_nexthops(fi); 178 } endfor_nexthops(fi);
177 179
178 release_net(fi->fib_net); 180 release_net(fi->fib_net);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8a0260010ea1..97cca8a03d94 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1231,6 +1231,9 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
1231{ 1231{
1232 struct rtable *orig, *prev, **p = &nh->nh_rth_output; 1232 struct rtable *orig, *prev, **p = &nh->nh_rth_output;
1233 1233
1234 if (rt_is_input_route(rt))
1235 p = &nh->nh_rth_input;
1236
1234 orig = *p; 1237 orig = *p;
1235 1238
1236 prev = cmpxchg(p, orig, rt); 1239 prev = cmpxchg(p, orig, rt);
@@ -1241,6 +1244,11 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
1241 } 1244 }
1242} 1245}
1243 1246
1247static bool rt_cache_valid(struct rtable *rt)
1248{
1249 return (rt && rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK);
1250}
1251
1244static void rt_set_nexthop(struct rtable *rt, __be32 daddr, 1252static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
1245 const struct fib_result *res, 1253 const struct fib_result *res,
1246 struct fib_nh_exception *fnhe, 1254 struct fib_nh_exception *fnhe,
@@ -1257,8 +1265,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
1257#ifdef CONFIG_IP_ROUTE_CLASSID 1265#ifdef CONFIG_IP_ROUTE_CLASSID
1258 rt->dst.tclassid = nh->nh_tclassid; 1266 rt->dst.tclassid = nh->nh_tclassid;
1259#endif 1267#endif
1260 if (!(rt->dst.flags & DST_HOST) && 1268 if (!(rt->dst.flags & DST_HOST))
1261 rt_is_output_route(rt))
1262 rt_cache_route(nh, rt); 1269 rt_cache_route(nh, rt);
1263 } 1270 }
1264 1271
@@ -1384,11 +1391,11 @@ static int __mkroute_input(struct sk_buff *skb,
1384 __be32 daddr, __be32 saddr, u32 tos, 1391 __be32 daddr, __be32 saddr, u32 tos,
1385 struct rtable **result) 1392 struct rtable **result)
1386{ 1393{
1387 struct fib_nh_exception *fnhe;
1388 struct rtable *rth; 1394 struct rtable *rth;
1389 int err; 1395 int err;
1390 struct in_device *out_dev; 1396 struct in_device *out_dev;
1391 unsigned int flags = 0; 1397 unsigned int flags = 0;
1398 bool do_cache;
1392 u32 itag; 1399 u32 itag;
1393 1400
1394 /* get a working reference to the output device */ 1401 /* get a working reference to the output device */
@@ -1431,13 +1438,21 @@ static int __mkroute_input(struct sk_buff *skb,
1431 } 1438 }
1432 } 1439 }
1433 1440
1434 fnhe = NULL; 1441 do_cache = false;
1435 if (res->fi) 1442 if (res->fi) {
1436 fnhe = find_exception(&FIB_RES_NH(*res), daddr); 1443 if (!(flags & RTCF_DIRECTSRC) && !itag) {
1444 rth = FIB_RES_NH(*res).nh_rth_input;
1445 if (rt_cache_valid(rth)) {
1446 dst_use(&rth->dst, jiffies);
1447 goto out;
1448 }
1449 do_cache = true;
1450 }
1451 }
1437 1452
1438 rth = rt_dst_alloc(out_dev->dev, 1453 rth = rt_dst_alloc(out_dev->dev,
1439 IN_DEV_CONF_GET(in_dev, NOPOLICY), 1454 IN_DEV_CONF_GET(in_dev, NOPOLICY),
1440 IN_DEV_CONF_GET(out_dev, NOXFRM), false); 1455 IN_DEV_CONF_GET(out_dev, NOXFRM), do_cache);
1441 if (!rth) { 1456 if (!rth) {
1442 err = -ENOBUFS; 1457 err = -ENOBUFS;
1443 goto cleanup; 1458 goto cleanup;
@@ -1456,8 +1471,8 @@ static int __mkroute_input(struct sk_buff *skb,
1456 rth->dst.input = ip_forward; 1471 rth->dst.input = ip_forward;
1457 rth->dst.output = ip_output; 1472 rth->dst.output = ip_output;
1458 1473
1459 rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag); 1474 rt_set_nexthop(rth, daddr, res, NULL, res->fi, res->type, itag);
1460 1475out:
1461 *result = rth; 1476 *result = rth;
1462 err = 0; 1477 err = 0;
1463 cleanup: 1478 cleanup:
@@ -1509,6 +1524,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1509 struct rtable *rth; 1524 struct rtable *rth;
1510 int err = -EINVAL; 1525 int err = -EINVAL;
1511 struct net *net = dev_net(dev); 1526 struct net *net = dev_net(dev);
1527 bool do_cache;
1512 1528
1513 /* IP on this device is disabled. */ 1529 /* IP on this device is disabled. */
1514 1530
@@ -1522,6 +1538,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
1522 if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) 1538 if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr))
1523 goto martian_source; 1539 goto martian_source;
1524 1540
1541 res.fi = NULL;
1525 if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0)) 1542 if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
1526 goto brd_input; 1543 goto brd_input;
1527 1544
@@ -1597,8 +1614,20 @@ brd_input:
1597 RT_CACHE_STAT_INC(in_brd); 1614 RT_CACHE_STAT_INC(in_brd);
1598 1615
1599local_input: 1616local_input:
1617 do_cache = false;
1618 if (res.fi) {
1619 if (!(flags & RTCF_DIRECTSRC) && !itag) {
1620 rth = FIB_RES_NH(res).nh_rth_input;
1621 if (rt_cache_valid(rth)) {
1622 dst_use(&rth->dst, jiffies);
1623 goto set_and_out;
1624 }
1625 do_cache = true;
1626 }
1627 }
1628
1600 rth = rt_dst_alloc(net->loopback_dev, 1629 rth = rt_dst_alloc(net->loopback_dev,
1601 IN_DEV_CONF_GET(in_dev, NOPOLICY), false, false); 1630 IN_DEV_CONF_GET(in_dev, NOPOLICY), false, do_cache);
1602 if (!rth) 1631 if (!rth)
1603 goto e_nobufs; 1632 goto e_nobufs;
1604 1633
@@ -1622,6 +1651,9 @@ local_input:
1622 rth->dst.error= -err; 1651 rth->dst.error= -err;
1623 rth->rt_flags &= ~RTCF_LOCAL; 1652 rth->rt_flags &= ~RTCF_LOCAL;
1624 } 1653 }
1654 if (do_cache)
1655 rt_cache_route(&FIB_RES_NH(res), rth);
1656set_and_out:
1625 skb_dst_set(skb, &rth->dst); 1657 skb_dst_set(skb, &rth->dst);
1626 err = 0; 1658 err = 0;
1627 goto out; 1659 goto out;
@@ -1756,8 +1788,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
1756 fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr); 1788 fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
1757 if (!fnhe) { 1789 if (!fnhe) {
1758 rth = FIB_RES_NH(*res).nh_rth_output; 1790 rth = FIB_RES_NH(*res).nh_rth_output;
1759 if (rth && 1791 if (rt_cache_valid(rth)) {
1760 rth->dst.obsolete == DST_OBSOLETE_FORCE_CHK) {
1761 dst_use(&rth->dst, jiffies); 1792 dst_use(&rth->dst, jiffies);
1762 return rth; 1793 return rth;
1763 } 1794 }