2011-10-25 19:26:31 -07:00
/*
2012-05-03 18:55:23 -07:00
* Copyright ( c ) 2007 - 2012 Nicira , Inc .
2011-10-25 19:26:31 -07: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-15 13:23:03 -07:00
# include <net/netns/generic.h>
2011-10-25 19:26:31 -07:00
# include "datapath.h"
# include "vport-internal_dev.h"
# include "vport-netdev.h"
2013-04-15 13:23:03 -07: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 ) ) {
netlink_set_err ( ovs_dp_get_net ( dp ) - > genl_sock , 0 ,
ovs_dp_vport_multicast_group . id ,
PTR_ERR ( notify ) ) ;
return ;
}
genlmsg_multicast_netns ( ovs_dp_get_net ( dp ) , notify , 0 ,
ovs_dp_vport_multicast_group . id ,
GFP_KERNEL ) ;
}
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 ) ;
if ( netdev_vport - > dev - > reg_state = = NETREG_UNREGISTERED | |
netdev_vport - > dev - > reg_state = = NETREG_UNREGISTERING )
dp_detach_port_notify ( vport ) ;
}
}
}
ovs_unlock ( ) ;
}
2011-10-25 19:26:31 -07:00
static int dp_device_event ( struct notifier_block * unused , unsigned long event ,
void * ptr )
{
2013-04-15 13:23:03 -07:00
struct ovs_net * ovs_net ;
2011-10-25 19:26:31 -07:00
struct net_device * dev = ptr ;
2013-04-15 13:23:03 -07:00
struct vport * vport = NULL ;
2011-10-25 19:26:31 -07:00
2013-04-15 13:23:03 -07:00
if ( ! ovs_is_internal_dev ( dev ) )
2011-10-25 19:26:31 -07:00
vport = ovs_netdev_get_vport ( dev ) ;
if ( ! vport )
return NOTIFY_DONE ;
2013-04-15 13:23:03 -07:00
if ( event = = NETDEV_UNREGISTER ) {
ovs_net = net_generic ( dev_net ( dev ) , ovs_net_id ) ;
queue_work ( system_wq , & ovs_net - > dp_notify_work ) ;
2011-10-25 19:26:31 -07:00
}
return NOTIFY_DONE ;
}
struct notifier_block ovs_dp_device_notifier = {
. notifier_call = dp_device_event
} ;