mirror of
https://github.com/openvswitch/ovs
synced 2025-10-11 13:57:52 +00:00
Commit f14d80834
"datapath: genl_notify() on port disappearances" frees the
vport before passing it to ovs_vport_cmd_build_info(), which reads the
freed data.
Without this commit, the following commands consistently trigger a kernel
BUG report on my test VM (which has slab debugging enabled) on 3 attempts:
tunctl
ovs-vsctl add-port br0 tap0
tunctl -d tap0
With this commit, I consistently don't see the BUG, on a few hundred tries
in a tight loop.
The interesting log information is:
device tap0 entered promiscuous mode
device tap0 left promiscuous mode
BUG: unable to handle kernel paging request at 6b6b6ba7
IP: [<c88269ed>] get_vport_protected+0x8/0x52 [openvswitch_mod]
*pde = 00000000
Oops: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:04.0/net/eth1/carrier
Modules linked in: brcompat_mod openvswitch_mod
Pid: 653, comm: tunctl Not tainted 2.6.37+ #25 /Bochs
EIP: 0060:[<c88269ed>] EFLAGS: 00010246 CPU: 0
EIP is at get_vport_protected+0x8/0x52 [openvswitch_mod]
EAX: 6b6b6ba7 EBX: 00000000 ECX: 00000000 EDX: 00000000
ESI: c6d98400 EDI: c5c32074 EBP: c6ff1de8 ESP: c6ff1de4
DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068
Process tunctl (pid: 653, ti=c6ff0000 task=c5c3a820 task.ti=c6ff0000)
Stack:
00000000 c6ff1df8 c8826b1d 6b6b6b6b c6d77ab0 c6ff1e14 c8826dc6 c7489160
00000f40 c6d98400 c6d77ab0 00000000 c6ff1e3c c88286fa 00000000 00000000
00000002 02ff1e34 00000000 c6d77ab0 c6df98a0 00000006 c6ff1e54 c8828aa2
Call Trace:
[<c8826b1d>] ? get_dpifindex+0x1b/0x31 [openvswitch_mod]
[<c8826dc6>] ? ovs_vport_cmd_fill_info+0x40/0x183 [openvswitch_mod]
[<c88286fa>] ? ovs_vport_cmd_build_info+0x3f/0x62 [openvswitch_mod]
[<c8828aa2>] ? dp_device_event+0x56/0xb0 [openvswitch_mod]
[<c1046c0d>] ? notifier_call_chain+0x6d/0x96
[<c1046c52>] ? raw_notifier_call_chain+0xc/0xe
[<c1254c10>] ? call_netdevice_notifiers+0x3c/0x43
[<c1255029>] ? rollback_registered_many+0xd4/0x18b
[<c1255146>] ? rollback_registered+0x23/0x28
[<c1255199>] ? unregister_netdevice_queue+0x4e/0x6b
[<c1227d2e>] ? tun_chr_close+0x3f/0x76
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
69 lines
1.4 KiB
C
69 lines
1.4 KiB
C
/*
|
|
* Distributed under the terms of the GNU GPL version 2.
|
|
* Copyright (c) 2007, 2008, 2009, 2010, 2011 Nicira Networks.
|
|
*
|
|
* Significant portions of this file may be copied from parts of the Linux
|
|
* kernel, by Linus Torvalds and others.
|
|
*/
|
|
|
|
/* Handle changes to managed devices */
|
|
|
|
#include <linux/netdevice.h>
|
|
#include <net/genetlink.h>
|
|
|
|
#include "datapath.h"
|
|
#include "vport-internal_dev.h"
|
|
#include "vport-netdev.h"
|
|
|
|
static int dp_device_event(struct notifier_block *unused, unsigned long event,
|
|
void *ptr)
|
|
{
|
|
struct net_device *dev = ptr;
|
|
struct vport *vport;
|
|
struct datapath *dp;
|
|
|
|
if (is_internal_dev(dev))
|
|
vport = internal_dev_get_vport(dev);
|
|
else
|
|
vport = netdev_get_vport(dev);
|
|
|
|
if (!vport)
|
|
return NOTIFY_DONE;
|
|
|
|
dp = vport->dp;
|
|
|
|
switch (event) {
|
|
case NETDEV_UNREGISTER:
|
|
if (!is_internal_dev(dev)) {
|
|
struct sk_buff *reply;
|
|
|
|
reply = ovs_vport_cmd_build_info(vport, 0, 0,
|
|
OVS_VPORT_CMD_DEL);
|
|
dp_detach_port(vport);
|
|
if (IS_ERR(reply)) {
|
|
netlink_set_err(INIT_NET_GENL_SOCK, 0,
|
|
dp_vport_multicast_group.id,
|
|
PTR_ERR(reply));
|
|
break;
|
|
}
|
|
|
|
genl_notify(reply, dev_net(dev), 0,
|
|
dp_vport_multicast_group.id, NULL,
|
|
GFP_KERNEL);
|
|
}
|
|
break;
|
|
|
|
case NETDEV_CHANGENAME:
|
|
if (vport->port_no != OVSP_LOCAL) {
|
|
dp_sysfs_del_if(vport);
|
|
dp_sysfs_add_if(vport);
|
|
}
|
|
break;
|
|
}
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
struct notifier_block dp_device_notifier = {
|
|
.notifier_call = dp_device_event
|
|
};
|