diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_semantics.c | 2 | ||||
-rw-r--r-- | net/ipv4/route.c | 55 |
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 | ||
1247 | static bool rt_cache_valid(struct rtable *rt) | ||
1248 | { | ||
1249 | return (rt && rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK); | ||
1250 | } | ||
1251 | |||
1244 | static void rt_set_nexthop(struct rtable *rt, __be32 daddr, | 1252 | static 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 | 1475 | out: | |
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 | ||
1599 | local_input: | 1616 | local_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); | ||
1656 | set_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 | } |