diff options
Diffstat (limited to 'net/ipv4/fib_frontend.c')
| -rw-r--r-- | net/ipv4/fib_frontend.c | 32 |
1 files changed, 17 insertions, 15 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 23104a3f2924..23b9b3e86f4c 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
| @@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(struct net *net) | |||
| 67 | return 0; | 67 | return 0; |
| 68 | 68 | ||
| 69 | fail: | 69 | fail: |
| 70 | kfree(local_table); | 70 | fib_free_table(local_table); |
| 71 | return -ENOMEM; | 71 | return -ENOMEM; |
| 72 | } | 72 | } |
| 73 | #else | 73 | #else |
| @@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct net *net, u32 id) | |||
| 109 | return tb; | 109 | return tb; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | /* caller must hold either rtnl or rcu read lock */ | ||
| 112 | struct fib_table *fib_get_table(struct net *net, u32 id) | 113 | struct fib_table *fib_get_table(struct net *net, u32 id) |
| 113 | { | 114 | { |
| 114 | struct fib_table *tb; | 115 | struct fib_table *tb; |
| @@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct net *net, u32 id) | |||
| 119 | id = RT_TABLE_MAIN; | 120 | id = RT_TABLE_MAIN; |
| 120 | h = id & (FIB_TABLE_HASHSZ - 1); | 121 | h = id & (FIB_TABLE_HASHSZ - 1); |
| 121 | 122 | ||
| 122 | rcu_read_lock(); | ||
| 123 | head = &net->ipv4.fib_table_hash[h]; | 123 | head = &net->ipv4.fib_table_hash[h]; |
| 124 | hlist_for_each_entry_rcu(tb, head, tb_hlist) { | 124 | hlist_for_each_entry_rcu(tb, head, tb_hlist) { |
| 125 | if (tb->tb_id == id) { | 125 | if (tb->tb_id == id) |
| 126 | rcu_read_unlock(); | ||
| 127 | return tb; | 126 | return tb; |
| 128 | } | ||
| 129 | } | 127 | } |
| 130 | rcu_read_unlock(); | ||
| 131 | return NULL; | 128 | return NULL; |
| 132 | } | 129 | } |
| 133 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 130 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
| @@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_addr_type(struct net *net, | |||
| 167 | if (ipv4_is_multicast(addr)) | 164 | if (ipv4_is_multicast(addr)) |
| 168 | return RTN_MULTICAST; | 165 | return RTN_MULTICAST; |
| 169 | 166 | ||
| 167 | rcu_read_lock(); | ||
| 168 | |||
| 170 | local_table = fib_get_table(net, RT_TABLE_LOCAL); | 169 | local_table = fib_get_table(net, RT_TABLE_LOCAL); |
| 171 | if (local_table) { | 170 | if (local_table) { |
| 172 | ret = RTN_UNICAST; | 171 | ret = RTN_UNICAST; |
| 173 | rcu_read_lock(); | ||
| 174 | if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) { | 172 | if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) { |
| 175 | if (!dev || dev == res.fi->fib_dev) | 173 | if (!dev || dev == res.fi->fib_dev) |
| 176 | ret = res.type; | 174 | ret = res.type; |
| 177 | } | 175 | } |
| 178 | rcu_read_unlock(); | ||
| 179 | } | 176 | } |
| 177 | |||
| 178 | rcu_read_unlock(); | ||
| 180 | return ret; | 179 | return ret; |
| 181 | } | 180 | } |
| 182 | 181 | ||
| @@ -919,7 +918,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | |||
| 919 | #undef BRD1_OK | 918 | #undef BRD1_OK |
| 920 | } | 919 | } |
| 921 | 920 | ||
| 922 | static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) | 921 | static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn) |
| 923 | { | 922 | { |
| 924 | 923 | ||
| 925 | struct fib_result res; | 924 | struct fib_result res; |
| @@ -929,6 +928,11 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) | |||
| 929 | .flowi4_tos = frn->fl_tos, | 928 | .flowi4_tos = frn->fl_tos, |
| 930 | .flowi4_scope = frn->fl_scope, | 929 | .flowi4_scope = frn->fl_scope, |
| 931 | }; | 930 | }; |
| 931 | struct fib_table *tb; | ||
| 932 | |||
| 933 | rcu_read_lock(); | ||
| 934 | |||
| 935 | tb = fib_get_table(net, frn->tb_id_in); | ||
| 932 | 936 | ||
| 933 | frn->err = -ENOENT; | 937 | frn->err = -ENOENT; |
| 934 | if (tb) { | 938 | if (tb) { |
| @@ -945,6 +949,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) | |||
| 945 | } | 949 | } |
| 946 | local_bh_enable(); | 950 | local_bh_enable(); |
| 947 | } | 951 | } |
| 952 | |||
| 953 | rcu_read_unlock(); | ||
| 948 | } | 954 | } |
| 949 | 955 | ||
| 950 | static void nl_fib_input(struct sk_buff *skb) | 956 | static void nl_fib_input(struct sk_buff *skb) |
| @@ -952,7 +958,6 @@ static void nl_fib_input(struct sk_buff *skb) | |||
| 952 | struct net *net; | 958 | struct net *net; |
| 953 | struct fib_result_nl *frn; | 959 | struct fib_result_nl *frn; |
| 954 | struct nlmsghdr *nlh; | 960 | struct nlmsghdr *nlh; |
| 955 | struct fib_table *tb; | ||
| 956 | u32 portid; | 961 | u32 portid; |
| 957 | 962 | ||
| 958 | net = sock_net(skb->sk); | 963 | net = sock_net(skb->sk); |
| @@ -967,9 +972,7 @@ static void nl_fib_input(struct sk_buff *skb) | |||
| 967 | nlh = nlmsg_hdr(skb); | 972 | nlh = nlmsg_hdr(skb); |
| 968 | 973 | ||
| 969 | frn = (struct fib_result_nl *) nlmsg_data(nlh); | 974 | frn = (struct fib_result_nl *) nlmsg_data(nlh); |
| 970 | tb = fib_get_table(net, frn->tb_id_in); | 975 | nl_fib_lookup(net, frn); |
| 971 | |||
| 972 | nl_fib_lookup(frn, tb); | ||
| 973 | 976 | ||
| 974 | portid = NETLINK_CB(skb).portid; /* netlink portid */ | 977 | portid = NETLINK_CB(skb).portid; /* netlink portid */ |
| 975 | NETLINK_CB(skb).portid = 0; /* from kernel */ | 978 | NETLINK_CB(skb).portid = 0; /* from kernel */ |
| @@ -1108,11 +1111,10 @@ static void ip_fib_net_exit(struct net *net) | |||
| 1108 | { | 1111 | { |
| 1109 | unsigned int i; | 1112 | unsigned int i; |
| 1110 | 1113 | ||
| 1114 | rtnl_lock(); | ||
| 1111 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 1115 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
| 1112 | fib4_rules_exit(net); | 1116 | fib4_rules_exit(net); |
| 1113 | #endif | 1117 | #endif |
| 1114 | |||
| 1115 | rtnl_lock(); | ||
| 1116 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { | 1118 | for (i = 0; i < FIB_TABLE_HASHSZ; i++) { |
| 1117 | struct fib_table *tb; | 1119 | struct fib_table *tb; |
| 1118 | struct hlist_head *head; | 1120 | struct hlist_head *head; |
