diff options
| -rw-r--r-- | include/net/flow.h | 1 | ||||
| -rw-r--r-- | net/ipv4/route.c | 21 |
2 files changed, 18 insertions, 4 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index e1dd5082ec7e..628e11b98c58 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
| @@ -21,6 +21,7 @@ struct flowi_common { | |||
| 21 | __u8 flowic_flags; | 21 | __u8 flowic_flags; |
| 22 | #define FLOWI_FLAG_ANYSRC 0x01 | 22 | #define FLOWI_FLAG_ANYSRC 0x01 |
| 23 | #define FLOWI_FLAG_CAN_SLEEP 0x02 | 23 | #define FLOWI_FLAG_CAN_SLEEP 0x02 |
| 24 | #define FLOWI_FLAG_KNOWN_NH 0x04 | ||
| 24 | __u32 flowic_secid; | 25 | __u32 flowic_secid; |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3a116cb0991a..1a0da8dc8180 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1762,6 +1762,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
| 1762 | struct in_device *in_dev; | 1762 | struct in_device *in_dev; |
| 1763 | u16 type = res->type; | 1763 | u16 type = res->type; |
| 1764 | struct rtable *rth; | 1764 | struct rtable *rth; |
| 1765 | bool do_cache; | ||
| 1765 | 1766 | ||
| 1766 | in_dev = __in_dev_get_rcu(dev_out); | 1767 | in_dev = __in_dev_get_rcu(dev_out); |
| 1767 | if (!in_dev) | 1768 | if (!in_dev) |
| @@ -1798,24 +1799,36 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
| 1798 | } | 1799 | } |
| 1799 | 1800 | ||
| 1800 | fnhe = NULL; | 1801 | fnhe = NULL; |
| 1802 | do_cache = fi != NULL; | ||
| 1801 | if (fi) { | 1803 | if (fi) { |
| 1802 | struct rtable __rcu **prth; | 1804 | struct rtable __rcu **prth; |
| 1805 | struct fib_nh *nh = &FIB_RES_NH(*res); | ||
| 1803 | 1806 | ||
| 1804 | fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr); | 1807 | fnhe = find_exception(nh, fl4->daddr); |
| 1805 | if (fnhe) | 1808 | if (fnhe) |
| 1806 | prth = &fnhe->fnhe_rth; | 1809 | prth = &fnhe->fnhe_rth; |
| 1807 | else | 1810 | else { |
| 1808 | prth = __this_cpu_ptr(FIB_RES_NH(*res).nh_pcpu_rth_output); | 1811 | if (unlikely(fl4->flowi4_flags & |
| 1812 | FLOWI_FLAG_KNOWN_NH && | ||
| 1813 | !(nh->nh_gw && | ||
| 1814 | nh->nh_scope == RT_SCOPE_LINK))) { | ||
| 1815 | do_cache = false; | ||
| 1816 | goto add; | ||
| 1817 | } | ||
| 1818 | prth = __this_cpu_ptr(nh->nh_pcpu_rth_output); | ||
| 1819 | } | ||
| 1809 | rth = rcu_dereference(*prth); | 1820 | rth = rcu_dereference(*prth); |
| 1810 | if (rt_cache_valid(rth)) { | 1821 | if (rt_cache_valid(rth)) { |
| 1811 | dst_hold(&rth->dst); | 1822 | dst_hold(&rth->dst); |
| 1812 | return rth; | 1823 | return rth; |
| 1813 | } | 1824 | } |
| 1814 | } | 1825 | } |
| 1826 | |||
| 1827 | add: | ||
| 1815 | rth = rt_dst_alloc(dev_out, | 1828 | rth = rt_dst_alloc(dev_out, |
| 1816 | IN_DEV_CONF_GET(in_dev, NOPOLICY), | 1829 | IN_DEV_CONF_GET(in_dev, NOPOLICY), |
| 1817 | IN_DEV_CONF_GET(in_dev, NOXFRM), | 1830 | IN_DEV_CONF_GET(in_dev, NOXFRM), |
| 1818 | fi); | 1831 | do_cache); |
| 1819 | if (!rth) | 1832 | if (!rth) |
| 1820 | return ERR_PTR(-ENOBUFS); | 1833 | return ERR_PTR(-ENOBUFS); |
| 1821 | 1834 | ||
