diff options
Diffstat (limited to 'net/openvswitch/dp_notify.c')
-rw-r--r-- | net/openvswitch/dp_notify.c | 82 |
1 files changed, 57 insertions, 25 deletions
diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 5558350e0d33..ef4feec6cd84 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c | |||
@@ -18,46 +18,78 @@ | |||
18 | 18 | ||
19 | #include <linux/netdevice.h> | 19 | #include <linux/netdevice.h> |
20 | #include <net/genetlink.h> | 20 | #include <net/genetlink.h> |
21 | #include <net/netns/generic.h> | ||
21 | 22 | ||
22 | #include "datapath.h" | 23 | #include "datapath.h" |
23 | #include "vport-internal_dev.h" | 24 | #include "vport-internal_dev.h" |
24 | #include "vport-netdev.h" | 25 | #include "vport-netdev.h" |
25 | 26 | ||
27 | static void dp_detach_port_notify(struct vport *vport) | ||
28 | { | ||
29 | struct sk_buff *notify; | ||
30 | struct datapath *dp; | ||
31 | |||
32 | dp = vport->dp; | ||
33 | notify = ovs_vport_cmd_build_info(vport, 0, 0, | ||
34 | OVS_VPORT_CMD_DEL); | ||
35 | ovs_dp_detach_port(vport); | ||
36 | if (IS_ERR(notify)) { | ||
37 | netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0, | ||
38 | ovs_dp_vport_multicast_group.id, | ||
39 | PTR_ERR(notify)); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0, | ||
44 | ovs_dp_vport_multicast_group.id, | ||
45 | GFP_KERNEL); | ||
46 | } | ||
47 | |||
48 | void ovs_dp_notify_wq(struct work_struct *work) | ||
49 | { | ||
50 | struct ovs_net *ovs_net = container_of(work, struct ovs_net, dp_notify_work); | ||
51 | struct datapath *dp; | ||
52 | |||
53 | ovs_lock(); | ||
54 | list_for_each_entry(dp, &ovs_net->dps, list_node) { | ||
55 | int i; | ||
56 | |||
57 | for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) { | ||
58 | struct vport *vport; | ||
59 | struct hlist_node *n; | ||
60 | |||
61 | hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) { | ||
62 | struct netdev_vport *netdev_vport; | ||
63 | |||
64 | if (vport->ops->type != OVS_VPORT_TYPE_NETDEV) | ||
65 | continue; | ||
66 | |||
67 | netdev_vport = netdev_vport_priv(vport); | ||
68 | if (netdev_vport->dev->reg_state == NETREG_UNREGISTERED || | ||
69 | netdev_vport->dev->reg_state == NETREG_UNREGISTERING) | ||
70 | dp_detach_port_notify(vport); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | ovs_unlock(); | ||
75 | } | ||
76 | |||
26 | static int dp_device_event(struct notifier_block *unused, unsigned long event, | 77 | static int dp_device_event(struct notifier_block *unused, unsigned long event, |
27 | void *ptr) | 78 | void *ptr) |
28 | { | 79 | { |
80 | struct ovs_net *ovs_net; | ||
29 | struct net_device *dev = ptr; | 81 | struct net_device *dev = ptr; |
30 | struct vport *vport; | 82 | struct vport *vport = NULL; |
31 | 83 | ||
32 | if (ovs_is_internal_dev(dev)) | 84 | if (!ovs_is_internal_dev(dev)) |
33 | vport = ovs_internal_dev_get_vport(dev); | ||
34 | else | ||
35 | vport = ovs_netdev_get_vport(dev); | 85 | vport = ovs_netdev_get_vport(dev); |
36 | 86 | ||
37 | if (!vport) | 87 | if (!vport) |
38 | return NOTIFY_DONE; | 88 | return NOTIFY_DONE; |
39 | 89 | ||
40 | switch (event) { | 90 | if (event == NETDEV_UNREGISTER) { |
41 | case NETDEV_UNREGISTER: | 91 | ovs_net = net_generic(dev_net(dev), ovs_net_id); |
42 | if (!ovs_is_internal_dev(dev)) { | 92 | queue_work(system_wq, &ovs_net->dp_notify_work); |
43 | struct sk_buff *notify; | ||
44 | struct datapath *dp = vport->dp; | ||
45 | |||
46 | notify = ovs_vport_cmd_build_info(vport, 0, 0, | ||
47 | OVS_VPORT_CMD_DEL); | ||
48 | ovs_dp_detach_port(vport); | ||
49 | if (IS_ERR(notify)) { | ||
50 | netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0, | ||
51 | ovs_dp_vport_multicast_group.id, | ||
52 | PTR_ERR(notify)); | ||
53 | break; | ||
54 | } | ||
55 | |||
56 | genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0, | ||
57 | ovs_dp_vport_multicast_group.id, | ||
58 | GFP_KERNEL); | ||
59 | } | ||
60 | break; | ||
61 | } | 93 | } |
62 | 94 | ||
63 | return NOTIFY_DONE; | 95 | return NOTIFY_DONE; |