2019-05-29 17:12:43 +03:00
// SPDX-License-Identifier: GPL-2.0-only
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
*/
# 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 ;
2017-11-02 22:04:37 +03:00
notify = ovs_vport_cmd_build_info ( vport , ovs_dp_get_net ( dp ) ,
0 , 0 , OVS_VPORT_CMD_DEL ) ;
2013-04-16 00:23:03 +04:00
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 ) {
2015-12-01 20:33:36 +03:00
if ( vport - > ops - > type = = OVS_VPORT_TYPE_INTERNAL )
2013-04-16 00:23:03 +04:00
continue ;
2019-07-05 19:05:46 +03:00
if ( ! ( netif_is_ovs_port ( vport - > dev ) ) )
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
} ;