2011-10-26 06:26:31 +04:00
/*
2012-05-04 05:55:23 +04:00
* Copyright ( c ) 2007 - 2012 Nicira , Inc .
2011-10-26 06:26:31 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
*/
# include <linux/netdevice.h>
# include <net/genetlink.h>
2013-04-16 00:23:03 +04:00
# include <net/netns/generic.h>
2011-10-26 06:26:31 +04:00
# include "datapath.h"
# include "vport-internal_dev.h"
# include "vport-netdev.h"
2013-04-16 00:23:03 +04:00
static void dp_detach_port_notify ( struct vport * vport )
{
struct sk_buff * notify ;
struct datapath * dp ;
dp = vport - > dp ;
notify = ovs_vport_cmd_build_info ( vport , 0 , 0 ,
OVS_VPORT_CMD_DEL ) ;
ovs_dp_detach_port ( vport ) ;
if ( IS_ERR ( notify ) ) {
2013-11-19 18:19:38 +04:00
genl_set_err ( & dp_vport_genl_family , ovs_dp_get_net ( dp ) , 0 ,
2013-11-19 18:19:39 +04:00
0 , PTR_ERR ( notify ) ) ;
2013-04-16 00:23:03 +04:00
return ;
}
2013-11-19 18:19:38 +04:00
genlmsg_multicast_netns ( & dp_vport_genl_family ,
ovs_dp_get_net ( dp ) , notify , 0 ,
2013-11-19 18:19:39 +04:00
0 , GFP_KERNEL ) ;
2013-04-16 00:23:03 +04:00
}
void ovs_dp_notify_wq ( struct work_struct * work )
{
struct ovs_net * ovs_net = container_of ( work , struct ovs_net , dp_notify_work ) ;
struct datapath * dp ;
ovs_lock ( ) ;
list_for_each_entry ( dp , & ovs_net - > dps , list_node ) {
int i ;
for ( i = 0 ; i < DP_VPORT_HASH_BUCKETS ; i + + ) {
struct vport * vport ;
struct hlist_node * n ;
hlist_for_each_entry_safe ( vport , n , & dp - > ports [ i ] , dp_hash_node ) {
struct netdev_vport * netdev_vport ;
if ( vport - > ops - > type ! = OVS_VPORT_TYPE_NETDEV )
continue ;
netdev_vport = netdev_vport_priv ( vport ) ;
2013-10-16 01:54:11 +04:00
if ( ! ( netdev_vport - > dev - > priv_flags & IFF_OVS_DATAPATH ) )
2013-04-16 00:23:03 +04:00
dp_detach_port_notify ( vport ) ;
}
}
}
ovs_unlock ( ) ;
}
2011-10-26 06:26:31 +04:00
static int dp_device_event ( struct notifier_block * unused , unsigned long event ,
void * ptr )
{
2013-04-16 00:23:03 +04:00
struct ovs_net * ovs_net ;
2013-05-28 05:30:21 +04:00
struct net_device * dev = netdev_notifier_info_to_dev ( ptr ) ;
2013-04-16 00:23:03 +04:00
struct vport * vport = NULL ;
2011-10-26 06:26:31 +04:00
2013-04-16 00:23:03 +04:00
if ( ! ovs_is_internal_dev ( dev ) )
2011-10-26 06:26:31 +04:00
vport = ovs_netdev_get_vport ( dev ) ;
if ( ! vport )
return NOTIFY_DONE ;
2013-04-16 00:23:03 +04:00
if ( event = = NETDEV_UNREGISTER ) {
2013-10-16 01:54:11 +04:00
/* upper_dev_unlink and decrement promisc immediately */
ovs_netdev_detach_dev ( vport ) ;
/* schedule vport destroy, dev_put and genl notification */
2013-04-16 00:23:03 +04:00
ovs_net = net_generic ( dev_net ( dev ) , ovs_net_id ) ;
queue_work ( system_wq , & ovs_net - > dp_notify_work ) ;
2011-10-26 06:26:31 +04:00
}
return NOTIFY_DONE ;
}
struct notifier_block ovs_dp_device_notifier = {
. notifier_call = dp_device_event
} ;