/*
 * netvsc_linkstatus_callback - Link up/down notification
 */
static void netvsc_linkstatus_callback(struct hv_device *device_obj,
				       unsigned int status)
{
	struct vm_device *device_ctx = to_vm_device(device_obj);
	struct net_device *net = dev_get_drvdata(&device_ctx->device);
	struct net_device_context *ndev_ctx;

	DPRINT_ENTER(NETVSC_DRV);

	if (!net) {
		DPRINT_ERR(NETVSC_DRV, "got link status but net device "
				"not initialized yet");
		return;
	}

	if (status == 1) {
		netif_carrier_on(net);
		netif_wake_queue(net);
		netif_notify_peers(net);
		ndev_ctx = netdev_priv(net);
		schedule_work(&ndev_ctx->work);
	} else {
		netif_carrier_off(net);
		netif_stop_queue(net);
	}
	DPRINT_EXIT(NETVSC_DRV);
}
/*
 * Send GARP packet to network peers after migrations.
 * After Quick Migration, the network is not immediately operational in the
 * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
 * another netif_notify_peers() into a scheduled work, otherwise GARP packet
 * will not be sent after quick migration, and cause network disconnection.
 */
static void netvsc_send_garp(struct work_struct *w)
{
	struct net_device_context *ndev_ctx;
	struct net_device *net;

	msleep(20);
	ndev_ctx = container_of(w, struct net_device_context, work);
	net = dev_get_drvdata(&ndev_ctx->device_ctx->device);
	netif_notify_peers(net);
}
Exemple #3
0
/*
 * Send GARP packet to network peers after migrations.
 * After Quick Migration, the network is not immediately operational in the
 * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
 * another netif_notify_peers() into a delayed work, otherwise GARP packet
 * will not be sent after quick migration, and cause network disconnection.
 * Also, we update the carrier status here.
 */
static void netvsc_link_change(void *data)
{
	struct delayed_work *w = (struct delayed_work *)data;
	struct net_device_context *ndev_ctx;
	struct net_device *net;
	struct netvsc_device *net_device;
	struct rndis_device *rdev;
	bool notify, refresh = false;
	char *argv[] = { "/etc/init.d/network", "restart", NULL };
	char *envp[] = { "HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };

	rtnl_lock();

	ndev_ctx = container_of(w, struct net_device_context, dwork);
	net_device = hv_get_drvdata(ndev_ctx->device_ctx);
	rdev = net_device->extension;
	net = net_device->ndev;

	if (rdev->link_state) {
		netif_carrier_off(net);
		notify = false;
	} else {
		netif_carrier_on(net);
		notify = true;
		if (rdev->link_change) {
			rdev->link_change = false;
			refresh = true;
		}
	}

	rtnl_unlock();

	if (refresh)
		call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);

	if (notify)
		netif_notify_peers(net);
}