summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPravin B Shelar <pshelar@nicira.com>2015-02-17 14:23:10 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-20 15:32:08 -0500
commit7b4577a9da3702049650f7095506e9afd9f68849 (patch)
tree25c9d3b8c6c50acde434604872d985659ab85f1e /net
parent34eea79e2664b314cab6a30fc582fdfa7a1bb1df (diff)
openvswitch: Fix net exit.
Open vSwitch allows moving internal vport to different namespace while still connected to the bridge. But when namespace deleted OVS does not detach these vports, that results in dangling pointer to netdevice which causes kernel panic as follows. This issue is fixed by detaching all ovs ports from the deleted namespace at net-exit. BUG: unable to handle kernel NULL pointer dereference at 0000000000000028 IP: [<ffffffffa0aadaa5>] ovs_vport_locate+0x35/0x80 [openvswitch] Oops: 0000 [#1] SMP Call Trace: [<ffffffffa0aa6391>] lookup_vport+0x21/0xd0 [openvswitch] [<ffffffffa0aa65f9>] ovs_vport_cmd_get+0x59/0xf0 [openvswitch] [<ffffffff8167e07c>] genl_family_rcv_msg+0x1bc/0x3e0 [<ffffffff8167e319>] genl_rcv_msg+0x79/0xc0 [<ffffffff8167d919>] netlink_rcv_skb+0xb9/0xe0 [<ffffffff8167deac>] genl_rcv+0x2c/0x40 [<ffffffff8167cffd>] netlink_unicast+0x12d/0x1c0 [<ffffffff8167d3da>] netlink_sendmsg+0x34a/0x6b0 [<ffffffff8162e140>] sock_sendmsg+0xa0/0xe0 [<ffffffff8162e5e8>] ___sys_sendmsg+0x408/0x420 [<ffffffff8162f541>] __sys_sendmsg+0x51/0x90 [<ffffffff8162f592>] SyS_sendmsg+0x12/0x20 [<ffffffff81764ee9>] system_call_fastpath+0x12/0x17 Reported-by: Assaf Muller <amuller@redhat.com> Fixes: 46df7b81454("openvswitch: Add support for network namespaces.") Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Reviewed-by: Thomas Graf <tgraf@noironetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/openvswitch/datapath.c45
-rw-r--r--net/openvswitch/vport.h2
2 files changed, 45 insertions, 2 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index ae5e77cdc0ca..5bae7243c577 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -2194,14 +2194,55 @@ static int __net_init ovs_init_net(struct net *net)
2194 return 0; 2194 return 0;
2195} 2195}
2196 2196
2197static void __net_exit ovs_exit_net(struct net *net) 2197static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
2198 struct list_head *head)
2198{ 2199{
2199 struct datapath *dp, *dp_next;
2200 struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 2200 struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
2201 struct datapath *dp;
2202
2203 list_for_each_entry(dp, &ovs_net->dps, list_node) {
2204 int i;
2205
2206 for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
2207 struct vport *vport;
2208
2209 hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
2210 struct netdev_vport *netdev_vport;
2211
2212 if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
2213 continue;
2214
2215 netdev_vport = netdev_vport_priv(vport);
2216 if (dev_net(netdev_vport->dev) == dnet)
2217 list_add(&vport->detach_list, head);
2218 }
2219 }
2220 }
2221}
2222
2223static void __net_exit ovs_exit_net(struct net *dnet)
2224{
2225 struct datapath *dp, *dp_next;
2226 struct ovs_net *ovs_net = net_generic(dnet, ovs_net_id);
2227 struct vport *vport, *vport_next;
2228 struct net *net;
2229 LIST_HEAD(head);
2201 2230
2202 ovs_lock(); 2231 ovs_lock();
2203 list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node) 2232 list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
2204 __dp_destroy(dp); 2233 __dp_destroy(dp);
2234
2235 rtnl_lock();
2236 for_each_net(net)
2237 list_vports_from_net(net, dnet, &head);
2238 rtnl_unlock();
2239
2240 /* Detach all vports from given namespace. */
2241 list_for_each_entry_safe(vport, vport_next, &head, detach_list) {
2242 list_del(&vport->detach_list);
2243 ovs_dp_detach_port(vport);
2244 }
2245
2205 ovs_unlock(); 2246 ovs_unlock();
2206 2247
2207 cancel_work_sync(&ovs_net->dp_notify_work); 2248 cancel_work_sync(&ovs_net->dp_notify_work);
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index f8ae295fb001..bc85331a6c60 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -103,6 +103,7 @@ struct vport_portids {
103 * @ops: Class structure. 103 * @ops: Class structure.
104 * @percpu_stats: Points to per-CPU statistics used and maintained by vport 104 * @percpu_stats: Points to per-CPU statistics used and maintained by vport
105 * @err_stats: Points to error statistics used and maintained by vport 105 * @err_stats: Points to error statistics used and maintained by vport
106 * @detach_list: list used for detaching vport in net-exit call.
106 */ 107 */
107struct vport { 108struct vport {
108 struct rcu_head rcu; 109 struct rcu_head rcu;
@@ -117,6 +118,7 @@ struct vport {
117 struct pcpu_sw_netstats __percpu *percpu_stats; 118 struct pcpu_sw_netstats __percpu *percpu_stats;
118 119
119 struct vport_err_stats err_stats; 120 struct vport_err_stats err_stats;
121 struct list_head detach_list;
120}; 122};
121 123
122/** 124/**