summaryrefslogtreecommitdiff
blob: 858f24c2f595d3a211b8ae81ddcb8d5103dbe4e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
commit d4d1107c3a49a4dadf6dc8ac55d6fefa25a8e06a
Author: Alexei Starovoitov <ast@plumgrid.com>
Date:   Wed Oct 16 15:28:23 2013 -0700

    cherry-pick 8e04c6e10c28e42c715eb9fef749554c123bddbc

diff --git a/AUTHORS b/AUTHORS
index 2d29e66..7a62704 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,8 @@ The following people, in alphabetical order, have either authored or
 signed off on commits in the Open vSwitch version control repository.
 
 Aaron Rosen             arosen@clemson.edu
+Alexandru Copot         alex.mihai.c@gmail.com
+Alexei Starovoitov      ast@plumgrid.com
 Alexey I. Froloff       raorn@altlinux.org
 Alex Wang               alexw@nicira.com
 Andrew Evans            aevans@nicira.com
diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c
index 847f611..a973623 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -66,8 +66,7 @@ void ovs_dp_notify_wq(struct work_struct *work)
 					continue;
 
 				netdev_vport = netdev_vport_priv(vport);
-				if (netdev_vport->dev->reg_state == NETREG_UNREGISTERED ||
-				    netdev_vport->dev->reg_state == NETREG_UNREGISTERING)
+				if (!(ovs_netdev_get_vport(netdev_vport->dev)))
 					dp_detach_port_notify(vport);
 			}
 		}
@@ -89,6 +88,10 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
 		return NOTIFY_DONE;
 
 	if (event == NETDEV_UNREGISTER) {
+		/* upper_dev_unlink and decrement promisc immediately */
+		ovs_netdev_detach_dev(vport);
+
+		/* schedule vport destroy, dev_put and genl notification */
 		ovs_net = net_generic(dev_net(dev), ovs_net_id);
 		queue_work(&ovs_net->dp_notify_work);
 	}
diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h
index 4e2b7f5..908ed86 100644
--- a/datapath/linux/compat/include/linux/netdevice.h
+++ b/datapath/linux/compat/include/linux/netdevice.h
@@ -118,6 +118,11 @@ static inline void netdev_upper_dev_unlink(struct net_device *dev,
 					   struct net_device *upper_dev)
 {
 }
+
+static inline struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
+{
+	return NULL;
+}
 #endif
 
 #endif
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index 215a47e..0c9f603 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -201,16 +201,27 @@ static void free_port_rcu(struct rcu_head *rcu)
 	ovs_vport_free(vport_from_priv(netdev_vport));
 }
 
-static void netdev_destroy(struct vport *vport)
+void ovs_netdev_detach_dev(struct vport *vport)
 {
 	struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
 
-	netdev_exit();
-	rtnl_lock();
+	ASSERT_RTNL();
 	netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
 	netdev_rx_handler_unregister(netdev_vport->dev);
-	netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp));
+	netdev_upper_dev_unlink(netdev_vport->dev,
+				netdev_master_upper_dev_get(netdev_vport->dev));
 	dev_set_promiscuity(netdev_vport->dev, -1);
+}
+
+static void netdev_destroy(struct vport *vport)
+{
+	struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+
+	netdev_exit();
+
+	rtnl_lock();
+	if (ovs_netdev_get_vport(netdev_vport->dev))
+		ovs_netdev_detach_dev(vport);
 	rtnl_unlock();
 
 	call_rcu(&netdev_vport->rcu, free_port_rcu);
diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h
index dd298b5..8df01c1 100644
--- a/datapath/vport-netdev.h
+++ b/datapath/vport-netdev.h
@@ -39,5 +39,6 @@ netdev_vport_priv(const struct vport *vport)
 }
 
 const char *ovs_netdev_get_name(const struct vport *);
+void ovs_netdev_detach_dev(struct vport *);
 
 #endif /* vport_netdev.h */