aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r--net/ipv4/fib_frontend.c32
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
69fail: 69fail:
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 */
112struct fib_table *fib_get_table(struct net *net, u32 id) 113struct 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
922static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) 921static 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
950static void nl_fib_input(struct sk_buff *skb) 956static 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;