]>
Commit | Line | Data |
---|---|---|
373f9370 GKH |
1 | From foo@baz Wed Mar 11 11:44:33 CET 2015 |
2 | From: Pravin B Shelar <pshelar@nicira.com> | |
3 | Date: Tue, 17 Feb 2015 11:23:10 -0800 | |
4 | Subject: openvswitch: Fix net exit. | |
5 | ||
6 | From: Pravin B Shelar <pshelar@nicira.com> | |
7 | ||
8 | [ Upstream commit 7b4577a9da3702049650f7095506e9afd9f68849 ] | |
9 | ||
10 | Open vSwitch allows moving internal vport to different namespace | |
11 | while still connected to the bridge. But when namespace deleted | |
12 | OVS does not detach these vports, that results in dangling | |
13 | pointer to netdevice which causes kernel panic as follows. | |
14 | This issue is fixed by detaching all ovs ports from the deleted | |
15 | namespace at net-exit. | |
16 | ||
17 | BUG: unable to handle kernel NULL pointer dereference at 0000000000000028 | |
18 | IP: [<ffffffffa0aadaa5>] ovs_vport_locate+0x35/0x80 [openvswitch] | |
19 | Oops: 0000 [#1] SMP | |
20 | Call Trace: | |
21 | [<ffffffffa0aa6391>] lookup_vport+0x21/0xd0 [openvswitch] | |
22 | [<ffffffffa0aa65f9>] ovs_vport_cmd_get+0x59/0xf0 [openvswitch] | |
23 | [<ffffffff8167e07c>] genl_family_rcv_msg+0x1bc/0x3e0 | |
24 | [<ffffffff8167e319>] genl_rcv_msg+0x79/0xc0 | |
25 | [<ffffffff8167d919>] netlink_rcv_skb+0xb9/0xe0 | |
26 | [<ffffffff8167deac>] genl_rcv+0x2c/0x40 | |
27 | [<ffffffff8167cffd>] netlink_unicast+0x12d/0x1c0 | |
28 | [<ffffffff8167d3da>] netlink_sendmsg+0x34a/0x6b0 | |
29 | [<ffffffff8162e140>] sock_sendmsg+0xa0/0xe0 | |
30 | [<ffffffff8162e5e8>] ___sys_sendmsg+0x408/0x420 | |
31 | [<ffffffff8162f541>] __sys_sendmsg+0x51/0x90 | |
32 | [<ffffffff8162f592>] SyS_sendmsg+0x12/0x20 | |
33 | [<ffffffff81764ee9>] system_call_fastpath+0x12/0x17 | |
34 | ||
35 | Reported-by: Assaf Muller <amuller@redhat.com> | |
36 | Fixes: 46df7b81454("openvswitch: Add support for network namespaces.") | |
37 | Signed-off-by: Pravin B Shelar <pshelar@nicira.com> | |
38 | Reviewed-by: Thomas Graf <tgraf@noironetworks.com> | |
39 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
40 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
41 | --- | |
42 | net/openvswitch/datapath.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- | |
43 | net/openvswitch/vport.h | 2 ++ | |
44 | 2 files changed, 45 insertions(+), 2 deletions(-) | |
45 | ||
46 | --- a/net/openvswitch/datapath.c | |
47 | +++ b/net/openvswitch/datapath.c | |
48 | @@ -2113,14 +2113,55 @@ static int __net_init ovs_init_net(struc | |
49 | return 0; | |
50 | } | |
51 | ||
52 | -static void __net_exit ovs_exit_net(struct net *net) | |
53 | +static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, | |
54 | + struct list_head *head) | |
55 | { | |
56 | - struct datapath *dp, *dp_next; | |
57 | struct ovs_net *ovs_net = net_generic(net, ovs_net_id); | |
58 | + struct datapath *dp; | |
59 | + | |
60 | + list_for_each_entry(dp, &ovs_net->dps, list_node) { | |
61 | + int i; | |
62 | + | |
63 | + for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { | |
64 | + struct vport *vport; | |
65 | + | |
66 | + hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) { | |
67 | + struct netdev_vport *netdev_vport; | |
68 | + | |
69 | + if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL) | |
70 | + continue; | |
71 | + | |
72 | + netdev_vport = netdev_vport_priv(vport); | |
73 | + if (dev_net(netdev_vport->dev) == dnet) | |
74 | + list_add(&vport->detach_list, head); | |
75 | + } | |
76 | + } | |
77 | + } | |
78 | +} | |
79 | + | |
80 | +static void __net_exit ovs_exit_net(struct net *dnet) | |
81 | +{ | |
82 | + struct datapath *dp, *dp_next; | |
83 | + struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id); | |
84 | + struct vport *vport, *vport_next; | |
85 | + struct net *net; | |
86 | + LIST_HEAD(head); | |
87 | ||
88 | ovs_lock(); | |
89 | list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node) | |
90 | __dp_destroy(dp); | |
91 | + | |
92 | + rtnl_lock(); | |
93 | + for_each_net(net) | |
94 | + list_vports_from_net(net, dnet, &head); | |
95 | + rtnl_unlock(); | |
96 | + | |
97 | + /* Detach all vports from given namespace. */ | |
98 | + list_for_each_entry_safe(vport, vport_next, &head, detach_list) { | |
99 | + list_del(&vport->detach_list); | |
100 | + ovs_dp_detach_port(vport); | |
101 | + } | |
102 | + | |
103 | ovs_unlock(); | |
104 | ||
105 | cancel_work_sync(&ovs_net->dp_notify_work); | |
106 | --- a/net/openvswitch/vport.h | |
107 | +++ b/net/openvswitch/vport.h | |
108 | @@ -103,6 +103,7 @@ struct vport_portids { | |
109 | * @ops: Class structure. | |
110 | * @percpu_stats: Points to per-CPU statistics used and maintained by vport | |
111 | * @err_stats: Points to error statistics used and maintained by vport | |
112 | + * @detach_list: list used for detaching vport in net-exit call. | |
113 | */ | |
114 | struct vport { | |
115 | struct rcu_head rcu; | |
116 | @@ -117,6 +118,7 @@ struct vport { | |
117 | struct pcpu_sw_netstats __percpu *percpu_stats; | |
118 | ||
119 | struct vport_err_stats err_stats; | |
120 | + struct list_head detach_list; | |
121 | }; | |
122 | ||
123 | /** |