aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/rtnetlink.c35
-rw-r--r--tools/testing/selftests/net/Makefile2
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh199
3 files changed, 227 insertions, 9 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index dd4e50dfa248..9e9f1419be60 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -172,7 +172,7 @@ int __rtnl_register(int protocol, int msgtype,
172 BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); 172 BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
173 msgindex = rtm_msgindex(msgtype); 173 msgindex = rtm_msgindex(msgtype);
174 174
175 tab = rcu_dereference(rtnl_msg_handlers[protocol]); 175 tab = rcu_dereference_raw(rtnl_msg_handlers[protocol]);
176 if (tab == NULL) { 176 if (tab == NULL) {
177 tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL); 177 tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);
178 if (tab == NULL) 178 if (tab == NULL)
@@ -262,7 +262,7 @@ void rtnl_unregister_all(int protocol)
262 262
263 synchronize_net(); 263 synchronize_net();
264 264
265 while (refcount_read(&rtnl_msg_handlers_ref[protocol]) > 0) 265 while (refcount_read(&rtnl_msg_handlers_ref[protocol]) > 1)
266 schedule(); 266 schedule();
267 kfree(handlers); 267 kfree(handlers);
268} 268}
@@ -402,16 +402,24 @@ static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev)
402{ 402{
403 struct net_device *master_dev; 403 struct net_device *master_dev;
404 const struct rtnl_link_ops *ops; 404 const struct rtnl_link_ops *ops;
405 size_t size = 0;
405 406
406 master_dev = netdev_master_upper_dev_get((struct net_device *) dev); 407 rcu_read_lock();
408
409 master_dev = netdev_master_upper_dev_get_rcu((struct net_device *)dev);
407 if (!master_dev) 410 if (!master_dev)
408 return 0; 411 goto out;
412
409 ops = master_dev->rtnl_link_ops; 413 ops = master_dev->rtnl_link_ops;
410 if (!ops || !ops->get_slave_size) 414 if (!ops || !ops->get_slave_size)
411 return 0; 415 goto out;
412 /* IFLA_INFO_SLAVE_DATA + nested data */ 416 /* IFLA_INFO_SLAVE_DATA + nested data */
413 return nla_total_size(sizeof(struct nlattr)) + 417 size = nla_total_size(sizeof(struct nlattr)) +
414 ops->get_slave_size(master_dev, dev); 418 ops->get_slave_size(master_dev, dev);
419
420out:
421 rcu_read_unlock();
422 return size;
415} 423}
416 424
417static size_t rtnl_link_get_size(const struct net_device *dev) 425static size_t rtnl_link_get_size(const struct net_device *dev)
@@ -4167,7 +4175,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4167 if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) 4175 if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN))
4168 return -EPERM; 4176 return -EPERM;
4169 4177
4170 if (family > ARRAY_SIZE(rtnl_msg_handlers)) 4178 if (family >= ARRAY_SIZE(rtnl_msg_handlers))
4171 family = PF_UNSPEC; 4179 family = PF_UNSPEC;
4172 4180
4173 rcu_read_lock(); 4181 rcu_read_lock();
@@ -4196,7 +4204,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4196 4204
4197 refcount_inc(&rtnl_msg_handlers_ref[family]); 4205 refcount_inc(&rtnl_msg_handlers_ref[family]);
4198 4206
4199 if (type == RTM_GETLINK) 4207 if (type == RTM_GETLINK - RTM_BASE)
4200 min_dump_alloc = rtnl_calcit(skb, nlh); 4208 min_dump_alloc = rtnl_calcit(skb, nlh);
4201 4209
4202 rcu_read_unlock(); 4210 rcu_read_unlock();
@@ -4213,6 +4221,12 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
4213 return err; 4221 return err;
4214 } 4222 }
4215 4223
4224 doit = READ_ONCE(handlers[type].doit);
4225 if (!doit) {
4226 family = PF_UNSPEC;
4227 handlers = rcu_dereference(rtnl_msg_handlers[family]);
4228 }
4229
4216 flags = READ_ONCE(handlers[type].flags); 4230 flags = READ_ONCE(handlers[type].flags);
4217 if (flags & RTNL_FLAG_DOIT_UNLOCKED) { 4231 if (flags & RTNL_FLAG_DOIT_UNLOCKED) {
4218 refcount_inc(&rtnl_msg_handlers_ref[family]); 4232 refcount_inc(&rtnl_msg_handlers_ref[family]);
@@ -4316,6 +4330,11 @@ static struct pernet_operations rtnetlink_net_ops = {
4316 4330
4317void __init rtnetlink_init(void) 4331void __init rtnetlink_init(void)
4318{ 4332{
4333 int i;
4334
4335 for (i = 0; i < ARRAY_SIZE(rtnl_msg_handlers_ref); i++)
4336 refcount_set(&rtnl_msg_handlers_ref[i], 1);
4337
4319 if (register_pernet_subsys(&rtnetlink_net_ops)) 4338 if (register_pernet_subsys(&rtnetlink_net_ops))
4320 panic("rtnetlink_init: cannot initialize rtnetlink\n"); 4339 panic("rtnetlink_init: cannot initialize rtnetlink\n");
4321 4340
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 6135a8448900..de1f5772b878 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -3,7 +3,7 @@
3CFLAGS = -Wall -Wl,--no-as-needed -O2 -g 3CFLAGS = -Wall -Wl,--no-as-needed -O2 -g
4CFLAGS += -I../../../../usr/include/ 4CFLAGS += -I../../../../usr/include/
5 5
6TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh 6TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh
7TEST_GEN_FILES = socket 7TEST_GEN_FILES = socket
8TEST_GEN_FILES += psock_fanout psock_tpacket 8TEST_GEN_FILES += psock_fanout psock_tpacket
9TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa 9TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
new file mode 100755
index 000000000000..5b04ad912525
--- /dev/null
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -0,0 +1,199 @@
1#!/bin/sh
2#
3# This test is for checking rtnetlink callpaths, and get as much coverage as possible.
4#
5# set -e
6
7devdummy="test-dummy0"
8ret=0
9
10# set global exit status, but never reset nonzero one.
11check_err()
12{
13 if [ $ret -eq 0 ]; then
14 ret=$1
15 fi
16}
17
18kci_add_dummy()
19{
20 ip link add name "$devdummy" type dummy
21 check_err $?
22 ip link set "$devdummy" up
23 check_err $?
24}
25
26kci_del_dummy()
27{
28 ip link del dev "$devdummy"
29 check_err $?
30}
31
32# add a bridge with vlans on top
33kci_test_bridge()
34{
35 devbr="test-br0"
36 vlandev="testbr-vlan1"
37
38 ret=0
39 ip link add name "$devbr" type bridge
40 check_err $?
41
42 ip link set dev "$devdummy" master "$devbr"
43 check_err $?
44
45 ip link set "$devbr" up
46 check_err $?
47
48 ip link add link "$devbr" name "$vlandev" type vlan id 1
49 check_err $?
50 ip addr add dev "$vlandev" 10.200.7.23/30
51 check_err $?
52 ip -6 addr add dev "$vlandev" dead:42::1234/64
53 check_err $?
54 ip -d link > /dev/null
55 check_err $?
56 ip r s t all > /dev/null
57 check_err $?
58 ip -6 addr del dev "$vlandev" dead:42::1234/64
59 check_err $?
60
61 ip link del dev "$vlandev"
62 check_err $?
63 ip link del dev "$devbr"
64 check_err $?
65
66 if [ $ret -ne 0 ];then
67 echo "FAIL: bridge setup"
68 return 1
69 fi
70 echo "PASS: bridge setup"
71
72}
73
74kci_test_gre()
75{
76 gredev=neta
77 rem=10.42.42.1
78 loc=10.0.0.1
79
80 ret=0
81 ip tunnel add $gredev mode gre remote $rem local $loc ttl 1
82 check_err $?
83 ip link set $gredev up
84 check_err $?
85 ip addr add 10.23.7.10 dev $gredev
86 check_err $?
87 ip route add 10.23.8.0/30 dev $gredev
88 check_err $?
89 ip addr add dev "$devdummy" 10.23.7.11/24
90 check_err $?
91 ip link > /dev/null
92 check_err $?
93 ip addr > /dev/null
94 check_err $?
95 ip addr del dev "$devdummy" 10.23.7.11/24
96 check_err $?
97
98 ip link del $gredev
99 check_err $?
100
101 if [ $ret -ne 0 ];then
102 echo "FAIL: gre tunnel endpoint"
103 return 1
104 fi
105 echo "PASS: gre tunnel endpoint"
106}
107
108# tc uses rtnetlink too, for full tc testing
109# please see tools/testing/selftests/tc-testing.
110kci_test_tc()
111{
112 dev=lo
113 ret=0
114
115 tc qdisc add dev "$dev" root handle 1: htb
116 check_err $?
117 tc class add dev "$dev" parent 1: classid 1:10 htb rate 1mbit
118 check_err $?
119 tc filter add dev "$dev" parent 1:0 prio 5 handle ffe: protocol ip u32 divisor 256
120 check_err $?
121 tc filter add dev "$dev" parent 1:0 prio 5 handle ffd: protocol ip u32 divisor 256
122 check_err $?
123 tc filter add dev "$dev" parent 1:0 prio 5 handle ffc: protocol ip u32 divisor 256
124 check_err $?
125 tc filter add dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:3 u32 ht ffe:2: match ip src 10.0.0.3 flowid 1:10
126 check_err $?
127 tc filter add dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:2 u32 ht ffe:2: match ip src 10.0.0.2 flowid 1:10
128 check_err $?
129 tc filter show dev "$dev" parent 1:0 > /dev/null
130 check_err $?
131 tc filter del dev "$dev" protocol ip parent 1: prio 5 handle ffe:2:3 u32
132 check_err $?
133 tc filter show dev "$dev" parent 1:0 > /dev/null
134 check_err $?
135 tc qdisc del dev "$dev" root handle 1: htb
136 check_err $?
137
138 if [ $ret -ne 0 ];then
139 echo "FAIL: tc htb hierarchy"
140 return 1
141 fi
142 echo "PASS: tc htb hierarchy"
143
144}
145
146kci_test_polrouting()
147{
148 ret=0
149 ip rule add fwmark 1 lookup 100
150 check_err $?
151 ip route add local 0.0.0.0/0 dev lo table 100
152 check_err $?
153 ip r s t all > /dev/null
154 check_err $?
155 ip rule del fwmark 1 lookup 100
156 check_err $?
157 ip route del local 0.0.0.0/0 dev lo table 100
158 check_err $?
159
160 if [ $ret -ne 0 ];then
161 echo "FAIL: policy route test"
162 return 1
163 fi
164 echo "PASS: policy routing"
165}
166
167kci_test_rtnl()
168{
169 kci_add_dummy
170 if [ $ret -ne 0 ];then
171 echo "FAIL: cannot add dummy interface"
172 return 1
173 fi
174
175 kci_test_polrouting
176 kci_test_tc
177 kci_test_gre
178 kci_test_bridge
179
180 kci_del_dummy
181}
182
183#check for needed privileges
184if [ "$(id -u)" -ne 0 ];then
185 echo "SKIP: Need root privileges"
186 exit 0
187fi
188
189for x in ip tc;do
190 $x -Version 2>/dev/null >/dev/null
191 if [ $? -ne 0 ];then
192 echo "SKIP: Could not run test without the $x tool"
193 exit 0
194 fi
195done
196
197kci_test_rtnl
198
199exit $ret