diff options
| -rw-r--r-- | include/net/ip_fib.h | 3 | ||||
| -rw-r--r-- | net/ipv4/fib_semantics.c | 20 | ||||
| -rw-r--r-- | net/ipv4/route.c | 18 |
3 files changed, 34 insertions, 7 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index e521a03515b1..e331746029b4 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/rcupdate.h> | 21 | #include <linux/rcupdate.h> |
| 22 | #include <net/fib_rules.h> | 22 | #include <net/fib_rules.h> |
| 23 | #include <net/inetpeer.h> | 23 | #include <net/inetpeer.h> |
| 24 | #include <linux/percpu.h> | ||
| 24 | 25 | ||
| 25 | struct fib_config { | 26 | struct fib_config { |
| 26 | u8 fc_dst_len; | 27 | u8 fc_dst_len; |
| @@ -81,7 +82,7 @@ struct fib_nh { | |||
| 81 | __be32 nh_gw; | 82 | __be32 nh_gw; |
| 82 | __be32 nh_saddr; | 83 | __be32 nh_saddr; |
| 83 | int nh_saddr_genid; | 84 | int nh_saddr_genid; |
| 84 | struct rtable __rcu *nh_rth_output; | 85 | struct rtable __rcu * __percpu *nh_pcpu_rth_output; |
| 85 | struct rtable __rcu *nh_rth_input; | 86 | struct rtable __rcu *nh_rth_input; |
| 86 | struct fnhe_hash_bucket *nh_exceptions; | 87 | struct fnhe_hash_bucket *nh_exceptions; |
| 87 | }; | 88 | }; |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 625cf185c489..fe2ca02a1979 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
| @@ -176,6 +176,23 @@ static void rt_nexthop_free(struct rtable __rcu **rtp) | |||
| 176 | dst_free(&rt->dst); | 176 | dst_free(&rt->dst); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static void rt_nexthop_free_cpus(struct rtable __rcu * __percpu *rtp) | ||
| 180 | { | ||
| 181 | int cpu; | ||
| 182 | |||
| 183 | if (!rtp) | ||
| 184 | return; | ||
| 185 | |||
| 186 | for_each_possible_cpu(cpu) { | ||
| 187 | struct rtable *rt; | ||
| 188 | |||
| 189 | rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1); | ||
| 190 | if (rt) | ||
| 191 | dst_free(&rt->dst); | ||
| 192 | } | ||
| 193 | free_percpu(rtp); | ||
| 194 | } | ||
| 195 | |||
| 179 | /* Release a nexthop info record */ | 196 | /* Release a nexthop info record */ |
| 180 | static void free_fib_info_rcu(struct rcu_head *head) | 197 | static void free_fib_info_rcu(struct rcu_head *head) |
| 181 | { | 198 | { |
| @@ -186,7 +203,7 @@ static void free_fib_info_rcu(struct rcu_head *head) | |||
| 186 | dev_put(nexthop_nh->nh_dev); | 203 | dev_put(nexthop_nh->nh_dev); |
| 187 | if (nexthop_nh->nh_exceptions) | 204 | if (nexthop_nh->nh_exceptions) |
| 188 | free_nh_exceptions(nexthop_nh); | 205 | free_nh_exceptions(nexthop_nh); |
| 189 | rt_nexthop_free(&nexthop_nh->nh_rth_output); | 206 | rt_nexthop_free_cpus(nexthop_nh->nh_pcpu_rth_output); |
| 190 | rt_nexthop_free(&nexthop_nh->nh_rth_input); | 207 | rt_nexthop_free(&nexthop_nh->nh_rth_input); |
| 191 | } endfor_nexthops(fi); | 208 | } endfor_nexthops(fi); |
| 192 | 209 | ||
| @@ -817,6 +834,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
| 817 | fi->fib_nhs = nhs; | 834 | fi->fib_nhs = nhs; |
| 818 | change_nexthops(fi) { | 835 | change_nexthops(fi) { |
| 819 | nexthop_nh->nh_parent = fi; | 836 | nexthop_nh->nh_parent = fi; |
| 837 | nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable __rcu *); | ||
| 820 | } endfor_nexthops(fi) | 838 | } endfor_nexthops(fi) |
| 821 | 839 | ||
| 822 | if (cfg->fc_mx) { | 840 | if (cfg->fc_mx) { |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2bd107477469..4f6276ce0af3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
| @@ -1206,11 +1206,15 @@ static inline void rt_free(struct rtable *rt) | |||
| 1206 | 1206 | ||
| 1207 | static void rt_cache_route(struct fib_nh *nh, struct rtable *rt) | 1207 | static void rt_cache_route(struct fib_nh *nh, struct rtable *rt) |
| 1208 | { | 1208 | { |
| 1209 | struct rtable *orig, *prev, **p = (struct rtable **)&nh->nh_rth_output; | 1209 | struct rtable *orig, *prev, **p; |
| 1210 | 1210 | ||
| 1211 | if (rt_is_input_route(rt)) | 1211 | if (rt_is_input_route(rt)) { |
| 1212 | p = (struct rtable **)&nh->nh_rth_input; | 1212 | p = (struct rtable **)&nh->nh_rth_input; |
| 1213 | 1213 | } else { | |
| 1214 | if (!nh->nh_pcpu_rth_output) | ||
| 1215 | goto nocache; | ||
| 1216 | p = (struct rtable **)__this_cpu_ptr(nh->nh_pcpu_rth_output); | ||
| 1217 | } | ||
| 1214 | orig = *p; | 1218 | orig = *p; |
| 1215 | 1219 | ||
| 1216 | prev = cmpxchg(p, orig, rt); | 1220 | prev = cmpxchg(p, orig, rt); |
| @@ -1223,6 +1227,7 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt) | |||
| 1223 | * unsuccessful at storing this route into the cache | 1227 | * unsuccessful at storing this route into the cache |
| 1224 | * we really need to set it. | 1228 | * we really need to set it. |
| 1225 | */ | 1229 | */ |
| 1230 | nocache: | ||
| 1226 | rt->dst.flags |= DST_NOCACHE; | 1231 | rt->dst.flags |= DST_NOCACHE; |
| 1227 | } | 1232 | } |
| 1228 | } | 1233 | } |
| @@ -1749,8 +1754,11 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
| 1749 | fnhe = NULL; | 1754 | fnhe = NULL; |
| 1750 | if (fi) { | 1755 | if (fi) { |
| 1751 | fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr); | 1756 | fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr); |
| 1752 | if (!fnhe) { | 1757 | if (!fnhe && FIB_RES_NH(*res).nh_pcpu_rth_output) { |
| 1753 | rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_output); | 1758 | struct rtable __rcu **prth; |
| 1759 | |||
| 1760 | prth = __this_cpu_ptr(FIB_RES_NH(*res).nh_pcpu_rth_output); | ||
| 1761 | rth = rcu_dereference(*prth); | ||
| 1754 | if (rt_cache_valid(rth)) { | 1762 | if (rt_cache_valid(rth)) { |
| 1755 | dst_hold(&rth->dst); | 1763 | dst_hold(&rth->dst); |
| 1756 | return rth; | 1764 | return rth; |
