aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
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 }