aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c52
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
143static 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
143static void free_nh_exceptions(struct fib_nh *nh) 158static 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
182static 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 */
165static void free_fib_info_rcu(struct rcu_head *head) 200static 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;
373errout: 407errout:
@@ -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
958int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 994int 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