aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_fib.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2015-01-05 17:57:44 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-05 22:55:24 -0500
commite715b6d3a5ef55834778d49224e60e8ccb5bf45f (patch)
tree61b0e9a29119fbe6062956f9429711f21eb1cefb /net/ipv6/ip6_fib.c
parent0409c9a5a7546043d32e8c46df0dcaf65f97f659 (diff)
net: fib6: convert cfg metric to u32 outside of table write lock
Do the nla validation earlier, outside the write lock. This is needed by followup patch which needs to be able to call request_module (which can sleep) if needed. Joint work with Daniel Borkmann. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r--net/ipv6/ip6_fib.c69
1 files changed, 36 insertions, 33 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index db4984e13f2f..03c520a4ebeb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -630,31 +630,35 @@ static bool rt6_qualify_for_ecmp(struct rt6_info *rt)
630 RTF_GATEWAY; 630 RTF_GATEWAY;
631} 631}
632 632
633static int fib6_commit_metrics(struct dst_entry *dst, 633static void fib6_copy_metrics(u32 *mp, const struct mx6_config *mxc)
634 struct nlattr *mx, int mx_len)
635{ 634{
636 bool dst_host = dst->flags & DST_HOST; 635 int i;
637 struct nlattr *nla;
638 int remaining;
639 u32 *mp;
640 636
641 mp = dst_host ? dst_metrics_write_ptr(dst) : 637 for (i = 0; i < RTAX_MAX; i++) {
642 kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); 638 if (test_bit(i, mxc->mx_valid))
643 if (unlikely(!mp)) 639 mp[i] = mxc->mx[i];
644 return -ENOMEM; 640 }
645 if (!dst_host) 641}
646 dst_init_metrics(dst, mp, 0); 642
643static int fib6_commit_metrics(struct dst_entry *dst, struct mx6_config *mxc)
644{
645 if (!mxc->mx)
646 return 0;
647 647
648 nla_for_each_attr(nla, mx, mx_len, remaining) { 648 if (dst->flags & DST_HOST) {
649 int type = nla_type(nla); 649 u32 *mp = dst_metrics_write_ptr(dst);
650 650
651 if (type) { 651 if (unlikely(!mp))
652 if (type > RTAX_MAX) 652 return -ENOMEM;
653 return -EINVAL;
654 653
655 mp[type - 1] = nla_get_u32(nla); 654 fib6_copy_metrics(mp, mxc);
656 } 655 } else {
656 dst_init_metrics(dst, mxc->mx, false);
657
658 /* We've stolen mx now. */
659 mxc->mx = NULL;
657 } 660 }
661
658 return 0; 662 return 0;
659} 663}
660 664
@@ -663,7 +667,7 @@ static int fib6_commit_metrics(struct dst_entry *dst,
663 */ 667 */
664 668
665static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, 669static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
666 struct nl_info *info, struct nlattr *mx, int mx_len) 670 struct nl_info *info, struct mx6_config *mxc)
667{ 671{
668 struct rt6_info *iter = NULL; 672 struct rt6_info *iter = NULL;
669 struct rt6_info **ins; 673 struct rt6_info **ins;
@@ -772,11 +776,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
772 pr_warn("NLM_F_CREATE should be set when creating new route\n"); 776 pr_warn("NLM_F_CREATE should be set when creating new route\n");
773 777
774add: 778add:
775 if (mx) { 779 err = fib6_commit_metrics(&rt->dst, mxc);
776 err = fib6_commit_metrics(&rt->dst, mx, mx_len); 780 if (err)
777 if (err) 781 return err;
778 return err; 782
779 }
780 rt->dst.rt6_next = iter; 783 rt->dst.rt6_next = iter;
781 *ins = rt; 784 *ins = rt;
782 rt->rt6i_node = fn; 785 rt->rt6i_node = fn;
@@ -796,11 +799,11 @@ add:
796 pr_warn("NLM_F_REPLACE set, but no existing node found!\n"); 799 pr_warn("NLM_F_REPLACE set, but no existing node found!\n");
797 return -ENOENT; 800 return -ENOENT;
798 } 801 }
799 if (mx) { 802
800 err = fib6_commit_metrics(&rt->dst, mx, mx_len); 803 err = fib6_commit_metrics(&rt->dst, mxc);
801 if (err) 804 if (err)
802 return err; 805 return err;
803 } 806
804 *ins = rt; 807 *ins = rt;
805 rt->rt6i_node = fn; 808 rt->rt6i_node = fn;
806 rt->dst.rt6_next = iter->dst.rt6_next; 809 rt->dst.rt6_next = iter->dst.rt6_next;
@@ -837,8 +840,8 @@ void fib6_force_start_gc(struct net *net)
837 * with source addr info in sub-trees 840 * with source addr info in sub-trees
838 */ 841 */
839 842
840int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, 843int fib6_add(struct fib6_node *root, struct rt6_info *rt,
841 struct nlattr *mx, int mx_len) 844 struct nl_info *info, struct mx6_config *mxc)
842{ 845{
843 struct fib6_node *fn, *pn = NULL; 846 struct fib6_node *fn, *pn = NULL;
844 int err = -ENOMEM; 847 int err = -ENOMEM;
@@ -933,7 +936,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,
933 } 936 }
934#endif 937#endif
935 938
936 err = fib6_add_rt2node(fn, rt, info, mx, mx_len); 939 err = fib6_add_rt2node(fn, rt, info, mxc);
937 if (!err) { 940 if (!err) {
938 fib6_start_gc(info->nl_net, rt); 941 fib6_start_gc(info->nl_net, rt);
939 if (!(rt->rt6i_flags & RTF_CACHE)) 942 if (!(rt->rt6i_flags & RTF_CACHE))