diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index e55171f184f9..267753060ffc 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -140,6 +140,21 @@ const struct fib_prop fib_props[RTN_MAX + 1] = { | |||
140 | }, | 140 | }, |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static void rt_fibinfo_free(struct rtable __rcu **rtp) | ||
144 | { | ||
145 | struct rtable *rt = rcu_dereference_protected(*rtp, 1); | ||
146 | |||
147 | if (!rt) | ||
148 | return; | ||
149 | |||
150 | /* Not even needed : RCU_INIT_POINTER(*rtp, NULL); | ||
151 | * because we waited an RCU grace period before calling | ||
152 | * free_fib_info_rcu() | ||
153 | */ | ||
154 | |||
155 | dst_free(&rt->dst); | ||
156 | } | ||
157 | |||
143 | static void free_nh_exceptions(struct fib_nh *nh) | 158 | static void free_nh_exceptions(struct fib_nh *nh) |
144 | { | 159 | { |
145 | struct fnhe_hash_bucket *hash = nh->nh_exceptions; | 160 | struct fnhe_hash_bucket *hash = nh->nh_exceptions; |
@@ -153,6 +168,9 @@ static void free_nh_exceptions(struct fib_nh *nh) | |||
153 | struct fib_nh_exception *next; | 168 | struct fib_nh_exception *next; |
154 | 169 | ||
155 | next = rcu_dereference_protected(fnhe->fnhe_next, 1); | 170 | next = rcu_dereference_protected(fnhe->fnhe_next, 1); |
171 | |||
172 | rt_fibinfo_free(&fnhe->fnhe_rth); | ||
173 | |||
156 | kfree(fnhe); | 174 | kfree(fnhe); |
157 | 175 | ||
158 | fnhe = next; | 176 | fnhe = next; |
@@ -161,6 +179,23 @@ static void free_nh_exceptions(struct fib_nh *nh) | |||
161 | kfree(hash); | 179 | kfree(hash); |
162 | } | 180 | } |
163 | 181 | ||
182 | static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) | ||
183 | { | ||
184 | int cpu; | ||
185 | |||
186 | if (!rtp) | ||
187 | return; | ||
188 | |||
189 | for_each_possible_cpu(cpu) { | ||
190 | struct rtable *rt; | ||
191 | |||
192 | rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1); | ||
193 | if (rt) | ||
194 | dst_free(&rt->dst); | ||
195 | } | ||
196 | free_percpu(rtp); | ||
197 | } | ||
198 | |||
164 | /* Release a nexthop info record */ | 199 | /* Release a nexthop info record */ |
165 | static void free_fib_info_rcu(struct rcu_head *head) | 200 | static void free_fib_info_rcu(struct rcu_head *head) |
166 | { | 201 | { |
@@ -171,10 +206,8 @@ static void free_fib_info_rcu(struct rcu_head *head) | |||
171 | dev_put(nexthop_nh->nh_dev); | 206 | dev_put(nexthop_nh->nh_dev); |
172 | if (nexthop_nh->nh_exceptions) | 207 | if (nexthop_nh->nh_exceptions) |
173 | free_nh_exceptions(nexthop_nh); | 208 | free_nh_exceptions(nexthop_nh); |
174 | if (nexthop_nh->nh_rth_output) | 209 | rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); |
175 | dst_release(&nexthop_nh->nh_rth_output->dst); | 210 | rt_fibinfo_free(&nexthop_nh->nh_rth_input); |
176 | if (nexthop_nh->nh_rth_input) | ||
177 | dst_release(&nexthop_nh->nh_rth_input->dst); | ||
178 | } endfor_nexthops(fi); | 211 | } endfor_nexthops(fi); |
179 | 212 | ||
180 | release_net(fi->fib_net); | 213 | release_net(fi->fib_net); |
@@ -281,6 +314,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi) | |||
281 | nfi->fib_scope == fi->fib_scope && | 314 | nfi->fib_scope == fi->fib_scope && |
282 | nfi->fib_prefsrc == fi->fib_prefsrc && | 315 | nfi->fib_prefsrc == fi->fib_prefsrc && |
283 | nfi->fib_priority == fi->fib_priority && | 316 | nfi->fib_priority == fi->fib_priority && |
317 | nfi->fib_type == fi->fib_type && | ||
284 | memcmp(nfi->fib_metrics, fi->fib_metrics, | 318 | memcmp(nfi->fib_metrics, fi->fib_metrics, |
285 | sizeof(u32) * RTAX_MAX) == 0 && | 319 | sizeof(u32) * RTAX_MAX) == 0 && |
286 | ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && | 320 | ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && |
@@ -358,7 +392,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | |||
358 | if (skb == NULL) | 392 | if (skb == NULL) |
359 | goto errout; | 393 | goto errout; |
360 | 394 | ||
361 | err = fib_dump_info(skb, info->pid, seq, event, tb_id, | 395 | err = fib_dump_info(skb, info->portid, seq, event, tb_id, |
362 | fa->fa_type, key, dst_len, | 396 | fa->fa_type, key, dst_len, |
363 | fa->fa_tos, fa->fa_info, nlm_flags); | 397 | fa->fa_tos, fa->fa_info, nlm_flags); |
364 | if (err < 0) { | 398 | if (err < 0) { |
@@ -367,7 +401,7 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, | |||
367 | kfree_skb(skb); | 401 | kfree_skb(skb); |
368 | goto errout; | 402 | goto errout; |
369 | } | 403 | } |
370 | rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE, | 404 | rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV4_ROUTE, |
371 | info->nlh, GFP_KERNEL); | 405 | info->nlh, GFP_KERNEL); |
372 | return; | 406 | return; |
373 | errout: | 407 | errout: |
@@ -800,10 +834,12 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
800 | fi->fib_flags = cfg->fc_flags; | 834 | fi->fib_flags = cfg->fc_flags; |
801 | fi->fib_priority = cfg->fc_priority; | 835 | fi->fib_priority = cfg->fc_priority; |
802 | fi->fib_prefsrc = cfg->fc_prefsrc; | 836 | fi->fib_prefsrc = cfg->fc_prefsrc; |
837 | fi->fib_type = cfg->fc_type; | ||
803 | 838 | ||
804 | fi->fib_nhs = nhs; | 839 | fi->fib_nhs = nhs; |
805 | change_nexthops(fi) { | 840 | change_nexthops(fi) { |
806 | nexthop_nh->nh_parent = fi; | 841 | nexthop_nh->nh_parent = fi; |
842 | nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable __rcu *); | ||
807 | } endfor_nexthops(fi) | 843 | } endfor_nexthops(fi) |
808 | 844 | ||
809 | if (cfg->fc_mx) { | 845 | if (cfg->fc_mx) { |
@@ -955,14 +991,14 @@ failure: | |||
955 | return ERR_PTR(err); | 991 | return ERR_PTR(err); |
956 | } | 992 | } |
957 | 993 | ||
958 | int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | 994 | int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, |
959 | u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, | 995 | u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, |
960 | struct fib_info *fi, unsigned int flags) | 996 | struct fib_info *fi, unsigned int flags) |
961 | { | 997 | { |
962 | struct nlmsghdr *nlh; | 998 | struct nlmsghdr *nlh; |
963 | struct rtmsg *rtm; | 999 | struct rtmsg *rtm; |
964 | 1000 | ||
965 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*rtm), flags); | 1001 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); |
966 | if (nlh == NULL) | 1002 | if (nlh == NULL) |
967 | return -EMSGSIZE; | 1003 | return -EMSGSIZE; |
968 | 1004 | ||