Linux virtualization list
 help / color / mirror / Atom feed
* Re: [PATCH 5/5] staging: hv: Gracefully handle SCSI resets - RESEND
From: Joe Perches @ 2010-09-01 16:28 UTC (permalink / raw)
  To: Hank Janssen; +Cc: gregkh, linux-kernel, virtualization, devel, haiyangz
In-Reply-To: <4C7D4848.6090409@sailtheuniverse.com>

On Tue, 2010-08-31 at 11:22 -0700, Hank Janssen wrote:
> If we get a SCSI host bus reset we now gracefully handle it, and we 
> take the device offline. This before sometimes caused hangs.
> ---
>  drivers/staging/hv/storvsc.c |   36 +++++++++++++++++++++++++++++++++++-
[]
> +	/*
> +	 * Wait for traffic in transit to complete
> +	 */
> +	while (atomic_read(&storDevice->NumOutstandingRequests))
> +		udelay(1000);
> +

Is it useful to have a maximum check or timeout?
Maybe use usleep_range?

^ permalink raw reply

* RE: [PATCH 5/5] staging: hv: Gracefully handle SCSI resets
From: Hank Janssen @ 2010-09-01 15:22 UTC (permalink / raw)
  To: Greg KH
  Cc: 'linux-kernel@vger.kernel.org',
	'devel@driverdev.osuosl.org',
	'virtualization@lists.osdl.org', Haiyang Zhang,
	'gregkh@suse.de'
In-Reply-To: <20100830235133.GB22941@kroah.com>


>From: Greg KH [mailto:greg@kroah.com] 
>Sent: Monday, August 30, 2010 4:52 PM
>
>This patch is corrupted as well, something odd is going on in your email system :(
>
>care to resend it?

Of course, I will resend these from my own account in a few minutes after I check them
At least it will bypass lookout at that point :)

Hank.

^ permalink raw reply

* Re: [PATCH 2/5] staging: hv: Fixed lockup problem with bounce_buffer scatter list - RESEND
From: Hank Janssen @ 2010-08-31 20:03 UTC (permalink / raw)
  To: Joe Perches; +Cc: gregkh, linux-kernel, devel, virtualization, Haiyang Zhang
In-Reply-To: <1283359091.1797.179.camel@Joe-Laptop>

On 09/01/2010 09:38 AM, Joe Perches wrote:
> On Tue, 2010-08-31 at 11:13 -0700, Hank Janssen wrote:
> 
>> diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
> []
>> -			request->DataBuffer.PfnArray[i] =
>> -					page_to_pfn(sg_page((&sgl[i])));
>> +			request->DataBuffer.PfnArray[i] = 
>> +				page_to_pfn(sg_page((&sgl[i])));
> 
> I did a bit of a doubletake reading this last change.
> 
> This isn't actually a part of your fix and it introduces
> a whitespace error.
> 

I will resubmit this patch and clean up the whitespace error.

When change the code I normally also change the indentation to the
correct format for that area of the code. That is how the whitespace
snuck in there.

Thanks,

Hank.

^ permalink raw reply

* [PATCH 5/5] staging: hv: Gracefully handle SCSI resets - RESEND
From: Hank Janssen @ 2010-08-31 18:22 UTC (permalink / raw)
  To: gregkh, linux-kernel, virtualization, devel; +Cc: haiyangz


(Send from a linux machine, not routed through exchange)

If we get a SCSI host bus reset we now gracefully handle it, and we 
take the device offline. This before sometimes caused hangs.

Signed-off-by:Hank Janssen <hjanssen@microsoft.com
Signed-off-by:Haiyang Zhang <haiyangz@microsoft.com


---
 drivers/staging/hv/storvsc.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c
index 6bd2ff1..5f222cf 100644
--- a/drivers/staging/hv/storvsc.c
+++ b/drivers/staging/hv/storvsc.c
@@ -48,7 +48,9 @@ struct storvsc_device {
 
 	/* 0 indicates the device is being destroyed */
 	atomic_t RefCount;
-
+	
+	int reset;
+	spinlock_t lock;
 	atomic_t NumOutstandingRequests;
 
 	/*
@@ -93,6 +95,9 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
 	atomic_cmpxchg(&storDevice->RefCount, 0, 2);
 
 	storDevice->Device = Device;
+	storDevice->reset  = 0;
+	spin_lock_init(&storDevice->lock);
+
 	Device->Extension = storDevice;
 
 	return storDevice;
@@ -101,6 +106,7 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
 static inline void FreeStorDevice(struct storvsc_device *Device)
 {
 	/* ASSERT(atomic_read(&Device->RefCount) == 0); */
+	/*kfree(Device->lock);*/
 	kfree(Device);
 }
 
@@ -108,13 +114,24 @@ static inline void FreeStorDevice(struct storvsc_device *Device)
 static inline struct storvsc_device *GetStorDevice(struct hv_device *Device)
 {
 	struct storvsc_device *storDevice;
+	unsigned long flags;
 
 	storDevice = (struct storvsc_device *)Device->Extension;
+
+	spin_lock_irqsave(&storDevice->lock, flags);
+
+	if (storDevice->reset == 1) {
+		spin_unlock_irqrestore(&storDevice->lock, flags);
+		return NULL;
+	}
+
 	if (storDevice && atomic_read(&storDevice->RefCount) > 1)
 		atomic_inc(&storDevice->RefCount);
 	else
 		storDevice = NULL;
 
+	spin_unlock_irqrestore(&storDevice->lock, flags);
+
 	return storDevice;
 }
 
@@ -122,13 +139,19 @@ static inline struct storvsc_device *GetStorDevice(struct hv_device *Device)
 static inline struct storvsc_device *MustGetStorDevice(struct hv_device *Device)
 {
 	struct storvsc_device *storDevice;
+	unsigned long flags;
 
 	storDevice = (struct storvsc_device *)Device->Extension;
+
+	spin_lock_irqsave(&storDevice->lock, flags);
+
 	if (storDevice && atomic_read(&storDevice->RefCount))
 		atomic_inc(&storDevice->RefCount);
 	else
 		storDevice = NULL;
 
+	spin_unlock_irqrestore(&storDevice->lock, flags);
+
 	return storDevice;
 }
 
@@ -614,6 +637,7 @@ int StorVscOnHostReset(struct hv_device *Device)
 	struct storvsc_device *storDevice;
 	struct storvsc_request_extension *request;
 	struct vstor_packet *vstorPacket;
+	unsigned long flags;
 	int ret;
 
 	DPRINT_INFO(STORVSC, "resetting host adapter...");
@@ -625,6 +649,16 @@ int StorVscOnHostReset(struct hv_device *Device)
 		return -1;
 	}
 
+	spin_lock_irqsave(&storDevice->lock, flags);
+	storDevice->reset = 1;
+	spin_unlock_irqrestore(&storDevice->lock, flags);
+
+	/*
+	 * Wait for traffic in transit to complete
+	 */
+	while (atomic_read(&storDevice->NumOutstandingRequests))
+		udelay(1000);
+
 	request = &storDevice->ResetRequest;
 	vstorPacket = &request->VStorPacket;
 
-- 
1.6.0.2

^ permalink raw reply related

* [PATCH 2/5] staging: hv: Fixed lockup problem with bounce_buffer scatter list - RESEND
From: Hank Janssen @ 2010-08-31 18:13 UTC (permalink / raw)
  To: gregkh, linux-kernel, virtualization, devel; +Cc: haiyangz


(Send from a linux machine, not routed through exchange)

Fixed lockup problem with bounce_buffer scatter list which caused 
crashes in heavy loads.

Signed-off-by:Hank Janssen <hjanssen@microsoft.com
Signed-off-by:Haiyang Zhang <haiyangz@microsoft.com

---
 drivers/staging/hv/storvsc_drv.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
index 3b9ccb0..169d701 100644
--- a/drivers/staging/hv/storvsc_drv.c
+++ b/drivers/staging/hv/storvsc_drv.c
@@ -615,6 +615,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
 	unsigned int request_size = 0;
 	int i;
 	struct scatterlist *sgl;
+	unsigned int sg_count = 0;
 
 	DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
 		   "queue depth %d tagged %d", scmnd, scmnd->sc_data_direction,
@@ -697,6 +698,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
 	request->DataBuffer.Length = scsi_bufflen(scmnd);
 	if (scsi_sg_count(scmnd)) {
 		sgl = (struct scatterlist *)scsi_sglist(scmnd);
+		sg_count = scsi_sg_count(scmnd);
 
 		/* check if we need to bounce the sgl */
 		if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
@@ -731,15 +733,16 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
 					      scsi_sg_count(scmnd));
 
 			sgl = cmd_request->bounce_sgl;
+			sg_count = cmd_request->bounce_sgl_count;
 		}
 
 		request->DataBuffer.Offset = sgl[0].offset;
 
-		for (i = 0; i < scsi_sg_count(scmnd); i++) {
+		for (i = 0; i < sg_count; i++) {
 			DPRINT_DBG(STORVSC_DRV, "sgl[%d] len %d offset %d\n",
 				   i, sgl[i].length, sgl[i].offset);
-			request->DataBuffer.PfnArray[i] =
-					page_to_pfn(sg_page((&sgl[i])));
+			request->DataBuffer.PfnArray[i] = 
+				page_to_pfn(sg_page((&sgl[i])));
 		}
 	} else if (scsi_sglist(scmnd)) {
 		/* ASSERT(scsi_bufflen(scmnd) <= PAGE_SIZE); */
-- 
1.6.0.2

^ permalink raw reply related

* Re: [PATCH 0/4] virtio: console: fixes, SIGIO
From: Amit Shah @ 2010-08-31 11:36 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Virtualization List
In-Reply-To: <cover.1282798831.git.amit.shah@redhat.com>

On (Thu) Aug 26 2010 [10:34:04], Amit Shah wrote:
> Hi Rusty,
> 
> The main thing in these patches is the introduction of injecting SIGIO
> on host-side connect/disconnect events and when new data is available
> for ports.
> 
> The first two patches fix bugs that I haven't seen, but look like the
> right thing to do.
> 
> These have been tested extensively using the test-virtserial test
> suite.
> 
> Please apply,

Since you haven't picked this up already, I'll send a new series that
has more fixes and another call to SIGIO. I'll also split up the series
in two patchsets, one for hot-unplug related fixes and one for the
SIGIO.

		Amit

^ permalink raw reply

* Re: hv block drivers
From: Alexander Graf @ 2010-08-31 10:46 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: virtualization, Xen-devel@lists.xensource.com, Stefano Stabellini,
	linux-kernel@vger.kernel.org,
	'virtualization@lists.osdl.org'
In-Reply-To: <201008302119.00069.arnd@arndb.de>


On 30.08.2010, at 21:18, Arnd Bergmann wrote:

> On Monday 30 August 2010 19:35:35 Jeremy Fitzhardinge wrote:
>> On 08/30/2010 10:31 AM, Hank Janssen wrote:
>>> For a more general question, When/if we make it out of staging, where should these drivers live?
>>> 
>>>      drivers/hyper-v or drivers/scsi and drivers/ide.
>>> 
>>> Is there a standard that is being followed?
>> 
>> If they're not actually scsi/ide subsystem drivers, then drivers/block
>> would seem like the best place (and drivers/ide is truly ancient stuff,
>> I think).
> 
> Agreed, although I was suggesting to make them SCSI drivers, so they
> would go to drivers/scsi/ or a subdirectory of it in that case.

It's basically the same as the VMware PV SCSI driver, no? And that one is in drivers/scsi/vmw_pvscsi.c.


Alex

^ permalink raw reply

* Re: [PATCH 5/5] staging: hv: Gracefully handle SCSI resets
From: Greg KH @ 2010-08-30 23:51 UTC (permalink / raw)
  To: Hank Janssen
  Cc: 'linux-kernel@vger.kernel.org',
	'devel@driverdev.osuosl.org',
	'virtualization@lists.osdl.org', Haiyang Zhang,
	'gregkh@suse.de'
In-Reply-To: <8AFC7968D54FB448A30D8F38F259C56223FEC8AF@TK5EX14MBXC114.redmond.corp.microsoft.com>

On Thu, Aug 05, 2010 at 07:30:37PM +0000, Hank Janssen wrote:
> From: Hank Janssen <hjanssen@microsoft.com>
> 
> If we get a SCSI host bus reset we now gracefully handle it, and we take the
> device offline. This before sometimes caused hangs.
> 
> Signed-off-by:Hank Janssen <hjanssen@microsoft.com>
> Signed-off-by:Haiyang Zhang <haiyangz@microsoft.com>
> Cc: stable <stable@kernel.org>
> 
> ---
>  drivers/staging/hv/storvsc.c |   36 +++++++++++++++++++++++++++++++++++-
>  1 files changed, 35 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/staging/hv/storvsc.c b/drivers/staging/hv/storvsc.c index 6bd2ff1..5f222cf 100644
> --- a/drivers/staging/hv/storvsc.c
> +++ b/drivers/staging/hv/storvsc.c
> @@ -48,7 +48,9 @@ struct storvsc_device {
>  
>  	/* 0 indicates the device is being destroyed */
>  	atomic_t RefCount;
> -
> +	
> +	int reset;
> +	spinlock_t lock;
>  	atomic_t NumOutstandingRequests;
>  
>  	/*
> @@ -93,6 +95,9 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)
>  	atomic_cmpxchg(&storDevice->RefCount, 0, 2);
>  
>  	storDevice->Device = Device;
> +	storDevice->reset  = 0;
> +	spin_lock_init(&storDevice->lock);
> +
>  	Device->Extension = storDevice;
>  
>  	return storDevice;
> @@ -101,6 +106,7 @@ static inline struct storvsc_device *AllocStorDevice(struct hv_device *Device)  static inline void FreeStorDevice(struct storvsc_device *Device)  {
>  	/* ASSERT(atomic_read(&Device->RefCount) == 0); */

This patch is corrupted as well, something odd is going on in your email
system :(

care to resend it?

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH 2/5] staging: hv: Fixed lockup problem with bounce_buffer scatter list
From: Greg KH @ 2010-08-30 23:49 UTC (permalink / raw)
  To: Hank Janssen
  Cc: 'linux-kernel@vger.kernel.org',
	'devel@driverdev.osuosl.org',
	'virtualization@lists.osdl.org', Haiyang Zhang,
	'gregkh@suse.de'
In-Reply-To: <8AFC7968D54FB448A30D8F38F259C56223FEC88B@TK5EX14MBXC114.redmond.corp.microsoft.com>

On Thu, Aug 05, 2010 at 07:29:53PM +0000, Hank Janssen wrote:
> From: Hank Janssen <hjanssen@microsoft.com>
> 
> Fixed lockup problem with bounce_buffer scatter list which caused
> crashes in heavy loads. Under heavy loads with many clients we this
> problem appear, it causes a kernel Panic.
> 
> Signed-off-by:Hank Janssen <hjanssen@microsoft.com>
> Signed-off-by:Haiyang Zhang <haiyangz@microsoft.com>
> Cc: stable <stable@kernel.org>
> ---
>  drivers/staging/hv/storvsc_drv.c |    9 ++++++---
>  1 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c
> index 3b9ccb0..169d701 100644
> --- a/drivers/staging/hv/storvsc_drv.c
> +++ b/drivers/staging/hv/storvsc_drv.c
> @@ -615,6 +615,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
>  	unsigned int request_size = 0;
>  	int i;
>  	struct scatterlist *sgl;
> +	unsigned int sg_count = 0;
>  
>  	DPRINT_DBG(STORVSC_DRV, "scmnd %p dir %d, use_sg %d buf %p len %d "
>  		   "queue depth %d tagged %d", scmnd, scmnd->sc_data_direction, @@ -697,6 +698,7 @@ static int storvsc_queuecommand(struct scsi_cmnd *scmnd,
>  	request->DataBuffer.Length = scsi_bufflen(scmnd);


This patch is corrupted.  It applies, but doesn't do what you want it to
do :(

Care to resend?

thanks,

greg k-h

^ permalink raw reply

* Re: hv block drivers
From: Arnd Bergmann @ 2010-08-30 19:18 UTC (permalink / raw)
  To: virtualization
  Cc: Jeremy Fitzhardinge, Hank Janssen,
	'virtualization@lists.osdl.org',
	Xen-devel@lists.xensource.com, linux-kernel@vger.kernel.org,
	Stefano Stabellini
In-Reply-To: <4C7BEBE7.8060502@goop.org>

On Monday 30 August 2010 19:35:35 Jeremy Fitzhardinge wrote:
>  On 08/30/2010 10:31 AM, Hank Janssen wrote:
> > For a more general question, When/if we make it out of staging, where should these drivers live?
> >
> >       drivers/hyper-v or drivers/scsi and drivers/ide.
> >
> > Is there a standard that is being followed?
> 
> If they're not actually scsi/ide subsystem drivers, then drivers/block
> would seem like the best place (and drivers/ide is truly ancient stuff,
> I think).

Agreed, although I was suggesting to make them SCSI drivers, so they
would go to drivers/scsi/ or a subdirectory of it in that case.

	Arnd

^ permalink raw reply

* Re: hv block drivers
From: Jeremy Fitzhardinge @ 2010-08-30 17:35 UTC (permalink / raw)
  To: Hank Janssen
  Cc: Arnd Bergmann, 'virtualization@lists.osdl.org',
	linux-kernel@vger.kernel.org, Stefano Stabellini,
	Xen-devel@lists.xensource.com
In-Reply-To: <8AFC7968D54FB448A30D8F38F259C56224274727@TK5EX14MBXC118.redmond.corp.microsoft.com>

 On 08/30/2010 10:31 AM, Hank Janssen wrote:
> For a more general question, When/if we make it out of staging, where should these drivers live?
>
> 	drivers/hyper-v or drivers/scsi and drivers/ide.
>
> Is there a standard that is being followed?

If they're not actually scsi/ide subsystem drivers, then drivers/block
would seem like the best place (and drivers/ide is truly ancient stuff,
I think).

    J

^ permalink raw reply

* RE: hv block drivers
From: Hank Janssen @ 2010-08-30 17:31 UTC (permalink / raw)
  To: Arnd Bergmann, Jeremy Fitzhardinge
  Cc: 'virtualization@lists.osdl.org',
	linux-kernel@vger.kernel.org, Stefano Stabellini,
	Xen-devel@lists.xensource.com
In-Reply-To: <201008301908.51521.arnd@arndb.de>


>On Monday 30 August 2010 Arnd Bergmann wrote: 
>>On Monday 30 August 2010, Jeremy Fitzhardinge wrote:
>> Have you investigated making virtio a scsi device?
>
>I doubt that there is much value in changing it now, and it's not something I'd be interested in working on.
>For the HyperV drivers, it probably makes sense because half of it is trying to look 
>like SCSI anyway, while the other half is trying to look like ATA. For the ATA driver, 
>the obvious choice would be to make it a libata backend, though my impression 
>from a brief look at the driver was that it's better to copy some of the libata code 
>and integrate it into the hv SCSI driver.

Arnd,

Thanks for following up! I was cleaning up some other part of the drivers (not related to IDE/SCSI) 
And on my todo list is to clean up the IDE/SCSI drivers. I will go through the libata code and see
If there is anything in there that I can use to make these drivers somewhat saner.

I am not sure if I can combine them into one yet, Hyper-V treats both drivers differently. And there
Are some rumored changes to Hyper-V that would make these changes maybe even a bit more difficult.

I will use this mailing list to bounce ideas off of. 

I still need to clean up your other suggestion as well, the static declarations :)

For a more general question, When/if we make it out of staging, where should these drivers live?

	drivers/hyper-v or drivers/scsi and drivers/ide.

Is there a standard that is being followed?

Hank.

^ permalink raw reply

* Re: hv block drivers
From: Arnd Bergmann @ 2010-08-30 17:08 UTC (permalink / raw)
  To: Jeremy Fitzhardinge
  Cc: Hank Janssen, 'virtualization@lists.osdl.org',
	linux-kernel, Stefano Stabellini, Xen-devel@lists.xensource.com
In-Reply-To: <4C7BD9A6.1090108@goop.org>

On Monday 30 August 2010, Jeremy Fitzhardinge wrote:
> Have you investigated making virtio a scsi device?

I doubt that there is much value in changing it now, and it's not something
I'd be interested in working on.

For the HyperV drivers, it probably makes sense because half of it is
trying to look like SCSI anyway, while the other half is trying to look
like ATA. For the ATA driver, the obvious choice would be to make it
a libata backend, though my impression from a brief look at the driver
was that it's better to copy some of the libata code and integrate it
into the hv SCSI driver.

	Arnd

^ permalink raw reply

* Re: hv block drivers
From: Jeremy Fitzhardinge @ 2010-08-30 16:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Hank Janssen, 'virtualization@lists.osdl.org',
	linux-kernel, Stefano Stabellini, Xen-devel@lists.xensource.com
In-Reply-To: <201008301643.42253.arnd@arndb.de>

 On 08/30/2010 07:43 AM, Arnd Bergmann wrote:
> Hi Hank,
>
> I wanted to follow up on the block device driver discussion we had at
> LinuxCon, based on some other input I got.
>
> What most people recommended was to make both the hv scsi and the
> hv ata code scsi device drivers, *not* make them standalone block
> drivers as I originally recommended.
>
> The main reason for this is consistent naming of the devices. We
> have a lot of user code that can deal with /dev/sd* devices, but
> introducing the /dev/vd* devices for virtio caused a lot of pain
> that you probably shouldn't have to go through.

We're having the same kind of problem with the Xen xvdX device naming. 
For a fully PV system it doesn't matter to much, but when you've got PV
drivers taking the place of a regular emulated hardware device it would
be nice to have a similar device name.

But there isn't a lot of similarity between the Xen block interface and
SCSI beyond the basic block transfer bits, so I was wondering how good a
match it would really be.

Have you investigated making virtio a scsi device?

    J

^ permalink raw reply

* hv block drivers
From: Arnd Bergmann @ 2010-08-30 14:43 UTC (permalink / raw)
  To: Hank Janssen; +Cc: linux-kernel, 'virtualization@lists.osdl.org'

Hi Hank,

I wanted to follow up on the block device driver discussion we had at
LinuxCon, based on some other input I got.

What most people recommended was to make both the hv scsi and the
hv ata code scsi device drivers, *not* make them standalone block
drivers as I originally recommended.

The main reason for this is consistent naming of the devices. We
have a lot of user code that can deal with /dev/sd* devices, but
introducing the /dev/vd* devices for virtio caused a lot of pain
that you probably shouldn't have to go through.

I'm not sure whether the two should be one or two drivers. My
feeling here is that it might be nice to have a single scsi
host driver for both that has two modes of driving the device,
one sending the SCSI commands down the virtual bus, the other
one interpreting the SCSI commands in the same way that libata
does.

	Arnd

^ permalink raw reply

* [PATCH 4/4] virtio: console: Send SIGIO on new data arrival on ports
From: Amit Shah @ 2010-08-26  5:04 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Amit Shah, Virtualization List
In-Reply-To: <cover.1282798831.git.amit.shah@redhat.com>

Send a SIGIO signal when new data arrives on a port. This is sent only
when the process has requested for the signal to be sent using fcntl().

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index b74d097..be0a8e4 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1350,6 +1350,10 @@ static void in_intr(struct virtqueue *vq)
 
 	wake_up_interruptible(&port->waitqueue);
 
+	/* Send a SIGIO indicating new data in case the process asked for it */
+	if (port->async_queue && port->guest_connected)
+		kill_fasync(&port->async_queue, SIGIO, POLL_IN);
+
 	if (is_console_port(port) && hvc_poll(port->cons.hvc))
 		hvc_kick();
 }
-- 
1.7.2.2

^ permalink raw reply related

* [PATCH 3/4] virtio: console: Send SIGIO to processes that request it for host events
From: Amit Shah @ 2010-08-26  5:04 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Amit Shah, Virtualization List
In-Reply-To: <cover.1282798831.git.amit.shah@redhat.com>

A process can request for SIGIO on host connect / disconnect events
using the O_ASYNC file flag using fcntl().

If that's requested, and if the guest-side connection for the port is
open, any host-side open/close events for that port will raise a SIGIO.
The process can then use poll() within the signal handler to find out
which port triggered the signal.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index a34f40e..b74d097 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -187,6 +187,9 @@ struct port {
 	/* The 'name' of the port that we expose via sysfs properties */
 	char *name;
 
+	/* We can notify apps of host connect / disconnect events via SIGIO */
+	struct fasync_struct *async_queue;
+
 	/* The 'id' to identify the port with the Host */
 	u32 id;
 
@@ -719,6 +722,14 @@ static int port_fops_open(struct inode *inode, struct file *filp)
 	return 0;
 }
 
+static int port_fops_fasync(int fd, struct file *filp, int mode)
+{
+	struct port *port;
+
+	port = filp->private_data;
+	return fasync_helper(fd, filp, mode, &port->async_queue);
+}
+
 /*
  * The file operations that we support: programs in the guest can open
  * a console device, read from it, write to it, poll for data and
@@ -732,6 +743,7 @@ static const struct file_operations port_fops = {
 	.write = port_fops_write,
 	.poll  = port_fops_poll,
 	.release = port_fops_release,
+	.fasync = port_fops_fasync,
 };
 
 /*
@@ -1011,6 +1023,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->name = NULL;
 	port->inbuf = NULL;
 	port->cons.hvc = NULL;
+	port->async_queue = NULL;
 
 	port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
 
@@ -1234,6 +1247,13 @@ static void handle_control_message(struct ports_device *portdev,
 		spin_lock_irq(&port->outvq_lock);
 		reclaim_consumed_buffers(port);
 		spin_unlock_irq(&port->outvq_lock);
+
+		/*
+		 * If the guest is connected, it'll be interested in
+		 * knowing the host connection state changed.
+		 */
+		if (port->async_queue && port->guest_connected)
+			kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
 		break;
 	case VIRTIO_CONSOLE_PORT_NAME:
 		/*
-- 
1.7.2.2

^ permalink raw reply related

* [PATCH 2/4] virtio: console: Annotate virtcons_remove with __devexit_p
From: Amit Shah @ 2010-08-26  5:04 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Amit Shah, Virtualization List
In-Reply-To: <cover.1282798831.git.amit.shah@redhat.com>

virtcons_remove is called on device unplug. Mark with __devexit_p.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 92ae3f8..a34f40e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1585,7 +1585,7 @@ fail:
 	return err;
 }
 
-static void virtcons_remove(struct virtio_device *vdev)
+static void __devexit virtcons_remove(struct virtio_device *vdev)
 {
 	struct ports_device *portdev;
 	struct port *port, *port2;
@@ -1631,7 +1631,7 @@ static struct virtio_driver virtio_console = {
 	.driver.owner =	THIS_MODULE,
 	.id_table =	id_table,
 	.probe =	virtcons_probe,
-	.remove =	virtcons_remove,
+	.remove =	__devexit_p(virtcons_remove),
 	.config_changed = config_intr,
 };
 
-- 
1.7.2.2

^ permalink raw reply related

* [PATCH 1/4] virtio: console: Un-block reads on chardev close
From: Amit Shah @ 2010-08-26  5:04 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Amit Shah, Virtualization List
In-Reply-To: <cover.1282798831.git.amit.shah@redhat.com>

If a chardev is closed, any blocked read / poll calls should just return
and not attempt to use other state.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 942a982..92ae3f8 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -522,6 +522,10 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 /* The condition that must be true for polling to end */
 static bool will_read_block(struct port *port)
 {
+	if (!port->guest_connected) {
+		/* Port got hot-unplugged. Let's exit. */
+		return false;
+	}
 	return !port_has_data(port) && port->host_connected;
 }
 
-- 
1.7.2.2

^ permalink raw reply related

* [PATCH 0/4] virtio: console: fixes, SIGIO
From: Amit Shah @ 2010-08-26  5:04 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Amit Shah, Virtualization List

Hi Rusty,

The main thing in these patches is the introduction of injecting SIGIO
on host-side connect/disconnect events and when new data is available
for ports.

The first two patches fix bugs that I haven't seen, but look like the
right thing to do.

These have been tested extensively using the test-virtserial test
suite.

Please apply,
		Amit.

Amit Shah (4):
  virtio: console: Un-block reads on chardev close
  virtio: console: Annotate virtcons_remove with __devexit_p
  virtio: console: Send SIGIO to processes that request it for host
    events
  virtio: console: Send SIGIO on new data arrival on ports

 drivers/char/virtio_console.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)

-- 
1.7.2.2

^ permalink raw reply

* Re: [PATCH 1/3] S390: take a full byte as ext_param indicator
From: Marcelo Tosatti @ 2010-08-25 21:20 UTC (permalink / raw)
  To: Alexander Graf
  Cc: linux-s390, KVM list, borntraeger, Carsten Otte, virtualization,
	Christian Ehrhardt
In-Reply-To: <1282657732-20902-1-git-send-email-agraf@suse.de>

On Tue, Aug 24, 2010 at 03:48:50PM +0200, Alexander Graf wrote:
> Currenty the ext_param field only distinguishes between "config change" and
> "vring interrupt". We can do a lot more with it though, so let's enable a
> full byte of possible values and constants to #defines while at it.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>
> 
> ---
> 
> v1 -> v2:
> 
>   - move defines to virtio_s390.h
> ---
>  arch/s390/include/asm/kvm_virtio.h |    6 ++++++
>  drivers/s390/kvm/kvm_virtio.c      |   19 +++++++++++++------
>  2 files changed, 19 insertions(+), 6 deletions(-)

Applied, thanks.

^ permalink raw reply

* [PATCH 10/10] do not use macv[tap/lan] interfaces as ports
From: Jens Osterkamp @ 2010-08-25 12:27 UTC (permalink / raw)
  To: e1000-eedc, virtualization, evb; +Cc: chrisw, Jens Osterkamp
In-Reply-To: <1282739262-14968-1-git-send-email-jens@linux.vnet.ibm.com>

At startup lldpad walks through all network interfaces in the system and
creates internal data structures for them. Some interfaces as e.g. vlan
and wlan are skipped in the walkthrough, some have to be treated special
(e.g. bond devices).
This patch adds macvtap and macvlan interfaces to the list of devices that
are skipped as we do not want to send out EVB/ECP frames on them.

Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
---
 config.c            |    2 +
 include/lldp_util.h |    1 +
 lldp_util.c         |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 0 deletions(-)

diff --git a/config.c b/config.c
index 26afe3b..fdb63f7 100644
--- a/config.c
+++ b/config.c
@@ -365,6 +365,8 @@ void init_ports(void)
 					p->if_name);
 		} else if (is_vlan(p->if_name)) {
 			;
+		} else if (is_macvtap(p->if_name)) {
+			;
 		} else if (is_bridge(p->if_name)) {
 			; /* ignore bridge device */
 		} else if (check_link_status(p->if_name)) {
diff --git a/include/lldp_util.h b/include/lldp_util.h
index 3353067..ef2c562 100644
--- a/include/lldp_util.h
+++ b/include/lldp_util.h
@@ -40,6 +40,7 @@ int is_bridge(const char *ifname);
 int is_vlan(const char *ifname);
 int is_vlan_capable(const char *ifname);
 int is_wlan(const char *ifname);
+int is_macvtap(const char *ifname);
 int is_valid_mac(const u8 *mac);
 int is_san_mac(u8 *addr);
 int is_ether(const char *ifname);
diff --git a/lldp_util.c b/lldp_util.c
index f39fe6b..522c7ee 100644
--- a/lldp_util.c
+++ b/lldp_util.c
@@ -34,6 +34,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <net/if_arp.h>
+#include <netlink/msg.h>
 #include <arpa/inet.h>
 #include <linux/if.h>
 #include <linux/if_bonding.h>
@@ -42,6 +43,7 @@
 #include <linux/wireless.h>
 #include <linux/sockios.h>
 #include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
 #include <dirent.h>
 #include "lldp.h"
 #include "lldp_util.h"
@@ -57,6 +59,8 @@ int is_valid_lldp_device(const char *device_name)
 		return 0;
 	if (is_bridge(device_name))
 		return 0;
+	if (is_macvtap(device_name))
+		return 0;
 	return 1;
 }
 
@@ -534,6 +538,88 @@ int is_wlan(const char *ifname)
 	return rc;
 }
 
+#define NLMSG_SIZE 1024
+
+static struct nla_policy ifla_info_policy[IFLA_INFO_MAX + 1] =
+{
+  [IFLA_INFO_KIND]       = { .type = NLA_STRING},
+  [IFLA_INFO_DATA]       = { .type = NLA_NESTED },
+};
+
+int is_macvtap(const char *ifname)
+{
+	int ret, s;
+	struct nlmsghdr *nlh;
+	struct ifinfomsg *ifinfo;
+	struct nlattr *tb[IFLA_MAX+1],
+		      *tb2[IFLA_INFO_MAX+1];
+
+	s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+
+	if (s < 0) {
+		goto out;
+	}
+
+	nlh = malloc(NLMSG_SIZE);
+
+	if (!nlh) {
+		goto out;
+	}
+
+	nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+        nlh->nlmsg_type = RTM_GETLINK;
+        nlh->nlmsg_flags = NLM_F_REQUEST;
+
+	ifinfo = NLMSG_DATA(nlh);
+	ifinfo->ifi_family = AF_UNSPEC;
+	ifinfo->ifi_index = get_ifidx(ifname);
+
+	ret = send(s, nlh, nlh->nlmsg_len, 0);
+
+	if (ret < 0) {
+		goto out;
+	}
+
+	memset(nlh, 0, NLMSG_SIZE);
+
+	do {
+		ret = recv(s, (void *) nlh, NLMSG_SIZE, MSG_DONTWAIT);
+	} while ((ret < 0) && errno == EINTR);
+
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg),
+			(struct nlattr **)&tb, IFLA_MAX, NULL)) {
+		goto out;
+	}
+
+	if (tb[IFLA_IFNAME]) {
+		ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+	} else {
+		ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
+	}
+
+	if (tb[IFLA_LINKINFO]) {
+		if (nla_parse_nested(tb2, IFLA_INFO_MAX, tb[IFLA_LINKINFO],
+				     ifla_info_policy)) {
+			goto out;
+		}
+
+		if (tb2[IFLA_INFO_KIND]) {
+			char *kind = (char*)(RTA_DATA(tb2[IFLA_INFO_KIND]));
+			if (!(strcmp("macvtap", kind) && strcmp("macvlan", kind))) {
+				close(s);
+				return true;
+			}
+		}
+
+	} else {
+		goto out;
+	}
+
+out:
+	close(s);
+	return false;
+}
+
 int is_router(const char *ifname)
 {
 	int rc = 0;
-- 
1.7.1

^ permalink raw reply related

* [PATCH 09/10] lldpad support for libvirt netlink message
From: Jens Osterkamp @ 2010-08-25 12:27 UTC (permalink / raw)
  To: e1000-eedc, virtualization, evb
  Cc: chrisw, Gerhard Stenzel, Stefan Berger, Jens Osterkamp
In-Reply-To: <1282739262-14968-1-git-send-email-jens@linux.vnet.ibm.com>

This code receives a IEEE 802.1Qbg virtual station instance from libvirt in
a SETLINK message. The parsed VSI is then handed over to VDP for processing.
The VDP state machine processes the VSI while libvirt polls the result using
GETLINK.

Requires at least Linux kernel 2.6.35-rc1.

Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
Signed-off-by: Gerhard Stenzel <gstenzel@linux.vnet.ibm.com>
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 event_iface.c         |  609 ++++++++++++++++++++++++++++++++++++++++++++++++-
 include/event_iface.h |    1 +
 include/lldp_vdp.h    |    2 +
 lldp_vdp.c            |    2 +-
 lldpad.c              |   10 +
 5 files changed, 617 insertions(+), 7 deletions(-)

diff --git a/event_iface.c b/event_iface.c
index 439e4d0..2685210 100644
--- a/event_iface.c
+++ b/event_iface.c
@@ -3,6 +3,13 @@
   LLDP Agent Daemon (LLDPAD) Software
   Copyright(c) 2007-2010 Intel Corporation.
 
+  implementation of libvirt netlink interface
+  (c) Copyright IBM Corp. 2010
+
+  Author(s): Jens Osterkamp <jens@linux.vnet.ibm.com>
+	     Stefan Berger <stefanb@linux.vnet.ibm.com>
+	     Gerhard Stenzel <gstenzel@linux.vnet.ibm.com>
+
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
   version 2, as published by the Free Software Foundation.
@@ -31,12 +38,16 @@
 #include <sys/socket.h>
 #include <linux/rtnetlink.h>
 #include <linux/if.h>
+#include <linux/if_link.h>
 #include <linux/if_vlan.h>
 #include <linux/sockios.h>
 #include <syslog.h>
 #include <unistd.h>
+#include <linux/netlink.h>
+#include <netlink/msg.h>
 #include "lldpad.h"
 #include "lldp_mod.h"
+#include "lldp_vdp.h"
 #include "common.h"
 #include "eloop.h"
 #include "drv_cfg.h"
@@ -55,6 +66,32 @@ static void event_if_decode_rta(int type, struct rtattr *rta);
 static char *device_name = NULL;
 static int link_status = 0;
 
+static struct nla_policy ifla_vf_policy[IFLA_VF_MAX + 1] =
+{
+  [IFLA_VF_MAC]     = { .minlen = sizeof(struct ifla_vf_mac),
+			.maxlen = sizeof(struct ifla_vf_mac)},
+  [IFLA_VF_VLAN]    = { .minlen = sizeof(struct ifla_vf_vlan),
+                        .maxlen = sizeof(struct ifla_vf_vlan)},
+};
+
+static struct nla_policy ifla_vf_ports_policy[IFLA_VF_PORT_MAX + 1] =
+{
+  [IFLA_VF_PORT] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy ifla_port_policy[IFLA_PORT_MAX + 1] =
+{
+  [IFLA_PORT_VF]            = { .type = NLA_U32 },
+  [IFLA_PORT_PROFILE]       = { .type = NLA_STRING },
+  [IFLA_PORT_VSI_TYPE]      = { .minlen = sizeof(struct ifla_port_vsi) },
+  [IFLA_PORT_INSTANCE_UUID] = { .minlen = PORT_UUID_MAX,
+                                .maxlen = PORT_UUID_MAX, },
+  [IFLA_PORT_HOST_UUID]     = { .minlen = PORT_UUID_MAX,
+                                .maxlen = PORT_UUID_MAX, },
+  [IFLA_PORT_REQUEST]       = { .type = NLA_U8  },
+  [IFLA_PORT_RESPONSE]      = { .type = NLA_U16 },
+};
+
 static void event_if_decode_rta(int type, struct rtattr *rta)
 {
 
@@ -220,15 +257,536 @@ static void event_if_decode_nlmsg(int route_type, void *data, int len)
 	}
 }
 
-
 static void event_if_process_recvmsg(struct nlmsghdr *nlmsg)
 {
 
 	/* print out details */
+	fprintf(stderr, "%s:%s: nlmsg_type: %d\n", __FILE__, __FUNCTION__, nlmsg->nlmsg_type);
 	event_if_decode_nlmsg(nlmsg->nlmsg_type, NLMSG_DATA(nlmsg),
 		NLMSG_PAYLOAD(nlmsg, 0));
 }
 
+static int event_if_parse_getmsg(struct nlmsghdr *nlh, int *ifindex,
+				 char *ifname)
+{
+	struct nlattr *tb[IFLA_MAX+1];
+	struct ifinfomsg *ifinfo;
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg),
+			(struct nlattr **)&tb, IFLA_MAX, NULL)) {
+		fprintf(stderr, "Error parsing request...\n");
+		return -EINVAL;
+	}
+
+	if (tb[IFLA_IFNAME]) {
+		ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+		fprintf(stderr, "IFLA_IFNAME=%s\n", ifname);
+	} else {
+		ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
+		*ifindex = ifinfo->ifi_index;
+		fprintf(stderr, "interface index: %d\n", ifinfo->ifi_index);
+	}
+
+	return 0;
+}
+
+static int event_if_parse_setmsg(struct nlmsghdr *nlh)
+{
+	struct nlattr *tb[IFLA_MAX+1],
+		      *tb3[IFLA_PORT_MAX+1],
+		      *tb_vfinfo[IFLA_VF_MAX+1],
+		      *tb_vfinfo_list;
+	struct vsi_profile *profile, *p;
+	struct ifinfomsg *ifinfo;
+	char *ifname;
+	int rem;
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+	profile = malloc(sizeof(struct vsi_profile));
+	if (!profile)
+		return -ENOMEM;
+	memset(profile, 0, sizeof(struct vsi_profile));
+
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg),
+			(struct nlattr **)&tb, IFLA_MAX, NULL)) {
+		fprintf(stderr, "Error parsing request...\n");
+		return -EINVAL;
+	}
+
+	fprintf(stderr, "%s(%d): nlmsg_len %i\n", __FILE__, __LINE__, nlh->nlmsg_len);
+
+	if (tb[IFLA_IFNAME]) {
+		ifname = (char *)RTA_DATA(tb[IFLA_IFNAME]);
+		fprintf(stderr, "IFLA_IFNAME=%s\n", ifname);
+	} else {
+		ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
+		fprintf(stderr, "interface index: %d\n", ifinfo->ifi_index);
+	}
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+	if (!tb[IFLA_VFINFO_LIST]) {
+		fprintf(stderr, "IFLA_VFINFO_LIST missing.\n");
+		return -EINVAL;
+	} else {
+		fprintf(stderr, "FOUND IFLA_VFINFO_LIST!\n");
+	}
+
+	nla_for_each_nested(tb_vfinfo_list, tb[IFLA_VFINFO_LIST], rem) {
+		if (nla_type(tb_vfinfo_list) != IFLA_VF_INFO) {
+			fprintf(stderr, "nested parsing of IFLA_VFINFO_LIST failed.\n");
+			return -EINVAL;
+		}
+
+		if (nla_parse_nested(tb_vfinfo, IFLA_VF_MAX, tb_vfinfo_list,
+				     ifla_vf_policy)) {
+			fprintf(stderr, "nested parsing of IFLA_VF_INFO failed.\n");
+			return -EINVAL;
+		}
+	}
+
+	if (tb_vfinfo[IFLA_VF_MAC]) {
+		struct ifla_vf_mac *mac = RTA_DATA(tb_vfinfo[IFLA_VF_MAC]);
+		u8 *m = mac->mac;
+		fprintf(stderr, "IFLA_VF_MAC=%2x:%2x:%2x:%2x:%2x:%2x\n",
+			m[0], m[1], m[2], m[3], m[4], m[5]);
+		memcpy(&profile->mac, m, ETH_ALEN);
+	}
+
+	if (tb_vfinfo[IFLA_VF_VLAN]) {
+		struct ifla_vf_vlan *vlan = RTA_DATA(tb_vfinfo[IFLA_VF_VLAN]);
+		fprintf(stderr, "IFLA_VF_VLAN=%d\n", vlan->vlan);
+		profile->vlan = (u16) vlan->vlan;
+	}
+
+	if (tb[IFLA_VF_PORTS]) {
+		struct nlattr *tb_vf_ports;
+
+		fprintf(stderr,"FOUND IFLA_VF_PORTS\n");
+
+		nla_for_each_nested(tb_vf_ports, tb[IFLA_VF_PORTS], rem) {
+
+			fprintf(stderr,"ITERATING\n");
+
+			if (nla_type(tb_vf_ports) != IFLA_VF_PORT) {
+				fprintf(stderr,"not a IFLA_VF_PORT. skipping\n");
+				continue;
+			}
+
+			if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb_vf_ports,
+					     ifla_port_policy)) {
+				fprintf(stderr, "nested parsing on level 2 failed.\n");
+				return -EINVAL;
+			}
+
+			fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+			if (tb3[IFLA_PORT_VF]) {
+				fprintf(stderr, "IFLA_PORT_VF=%d\n", *(uint32_t*)(RTA_DATA(tb3[IFLA_PORT_VF])));
+			}
+
+			if (tb3[IFLA_PORT_PROFILE]) {
+				fprintf(stderr, "IFLA_PORT_PROFILE=%s\n", (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE]));
+			}
+
+			if (tb3[IFLA_PORT_VSI_TYPE]) {
+				struct ifla_port_vsi *pvsi;
+				int tid = 0;
+
+				pvsi = (struct ifla_port_vsi*)RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
+				tid = pvsi->vsi_type_id[2] << 16 |
+					pvsi->vsi_type_id[1] << 8 |
+					pvsi->vsi_type_id[0];
+				fprintf(stderr, "mgr_id : %d\n"
+					"type_id : %d\n"
+					"type_version : %d\n",
+					pvsi->vsi_mgr_id,
+					tid,
+					pvsi->vsi_type_version);
+
+				profile->mgrid = pvsi->vsi_mgr_id;
+				profile->id = tid;
+				profile->version = pvsi->vsi_type_version;
+			}
+
+			if (tb3[IFLA_PORT_INSTANCE_UUID]) {
+				int i;
+				unsigned char *uuid;
+				uuid = (unsigned char *)RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
+				fprintf(stderr, "IFLA_PORT_INSTANCE_UUID=");
+
+				for (i = 0; i < 16; i++) {
+					fprintf(stderr, "%x",uuid[i]);
+				}
+
+				fprintf(stderr, "\n");
+
+				memcpy(&profile->instance,
+				       RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]), 16);
+			}
+
+			if (tb3[IFLA_PORT_REQUEST]) {
+				fprintf(stderr, "IFLA_PORT_REQUEST=%d\n",
+					*(uint8_t*)RTA_DATA(tb3[IFLA_PORT_REQUEST]));
+					profile->mode = *(uint8_t*)RTA_DATA(tb3[IFLA_PORT_REQUEST]);
+			}
+
+			if (tb3[IFLA_PORT_RESPONSE]) {
+				fprintf(stderr, "IFLA_PORT_RESPONSE=%d\n",
+					*(uint16_t*)RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
+				profile->response = *(uint16_t*)RTA_DATA(tb3[IFLA_PORT_RESPONSE]);
+			}
+		}
+	}
+
+	if (ifname) {
+		struct port *port = port_find_by_name(ifname);
+
+		if (port) {
+			profile->port = port;
+		} else {
+			printf("%s(%i): Could not find port for %s\n", __func__,
+			       __LINE__, ifname);
+			return -EEXIST;
+		}
+	}
+
+	p = vdp_add_profile(profile);
+
+	if (!p) {
+		free(profile);
+		return -EINVAL;
+	}
+
+	vdp_somethingChangedLocal(profile, VDP_PROFILE_REQ);
+	vdp_vsi_sm_station(p);
+
+	return 0;
+}
+
+static void event_if_parseResponseMsg(struct nlmsghdr *nlh)
+{
+	struct nlattr *tb[IFLA_MAX+1],
+		      *tb2[IFLA_VF_PORT_MAX + 1],
+		      *tb3[IFLA_PORT_MAX+1];
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+	if (nlmsg_parse(nlh, sizeof(struct ifinfomsg),
+			(struct nlattr **)&tb, IFLA_MAX, NULL)) {
+		fprintf(stderr, "Error parsing response...\n");
+		return;
+	}
+
+	if (tb[IFLA_IFNAME]) {
+		fprintf(stderr, "IFLA_IFNAME=%s\n", (char *)RTA_DATA(tb[IFLA_IFNAME]));
+	} else {
+		struct ifinfomsg *ifinfo = (struct ifinfomsg *)NLMSG_DATA(nlh);
+		fprintf(stderr, "interface index: %d\n", ifinfo->ifi_index);
+	}
+
+	if (tb[IFLA_VF_PORTS]) {
+		if (nla_parse_nested(tb2, IFLA_VF_PORT_MAX, tb[IFLA_VF_PORTS],
+				     ifla_vf_ports_policy)) {
+			fprintf(stderr, "nested parsing on level 1 failed.\n");
+			return;
+		}
+
+        if (tb2[IFLA_VF_PORT]) {
+		if (nla_parse_nested(tb3, IFLA_PORT_MAX, tb2[IFLA_VF_PORT],
+				     ifla_port_policy)) {
+			fprintf(stderr, "nested parsing on level 2 failed.\n");
+			return;
+		}
+
+		if (tb3[IFLA_PORT_VF]) {
+			fprintf(stderr, "IFLA_PORT_VF=%d\n", *(uint32_t*)(RTA_DATA(tb3[IFLA_PORT_VF])));
+		}
+
+		if (tb3[IFLA_PORT_PROFILE]) {
+			fprintf(stderr, "IFLA_PORT_PROFILE=%s\n", (char *)RTA_DATA(tb3[IFLA_PORT_PROFILE]));
+		}
+
+		if (tb3[IFLA_PORT_VSI_TYPE]) {
+			struct ifla_port_vsi *pvsi;
+			int tid = 0;
+			pvsi = (struct ifla_port_vsi*)RTA_DATA(tb3[IFLA_PORT_VSI_TYPE]);
+			tid = pvsi->vsi_type_id[2] << 16 |
+				pvsi->vsi_type_id[1] << 8 |
+				pvsi->vsi_type_id[0];
+			fprintf(stderr, "mgr_id : %d\n"
+				"type_id : %d\n"
+				"type_version : %d\n",
+				pvsi->vsi_mgr_id,
+				tid,
+				pvsi->vsi_type_version);
+		}
+
+		if (tb3[IFLA_PORT_INSTANCE_UUID]) {
+			int i;
+			unsigned char *uuid;
+			uuid = (unsigned char *)RTA_DATA(tb3[IFLA_PORT_INSTANCE_UUID]);
+
+			fprintf(stderr, "IFLA_PORT_INSTANCE_UUID=");
+
+			for (i = 0; i < 16; i++) {
+				fprintf(stderr, "%x",uuid[i]);
+			}
+
+			fprintf(stderr, "\n");
+		}
+
+		if (tb3[IFLA_PORT_REQUEST]) {
+			fprintf(stderr, "IFLA_PORT_REQUEST=%d\n",
+				*(uint8_t*)RTA_DATA(tb3[IFLA_PORT_REQUEST]));
+		}
+
+		if (tb3[IFLA_PORT_RESPONSE]) {
+			fprintf(stderr, "IFLA_PORT_RESPONSE=%d\n",
+				*(uint16_t*)RTA_DATA(tb3[IFLA_PORT_RESPONSE]));
+		}
+	}
+	}
+}
+
+struct nl_msg *event_if_constructResponse(struct nlmsghdr *nlh, int ifindex)
+{
+	struct nl_msg *nl_msg;
+	struct nlattr *vf_ports = NULL, *vf_port;
+	struct ifinfomsg ifinfo;
+	struct vdp_data *vd;
+	uint32_t pid = nlh->nlmsg_pid;
+	uint32_t seq = nlh->nlmsg_seq;
+	char *ifname = malloc(IFNAMSIZ);
+	struct vsi_profile *p;
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+
+	nl_msg = nlmsg_alloc();
+
+	if (!nl_msg) {
+		printf("%s(%i): Unable to allocate netlink message !\n", __func__, __LINE__);
+		return NULL;
+	}
+
+	if (!if_indextoname(ifindex, ifname)) {
+		printf("%s(%i): No name found for interface with index %i !\n", __func__, __LINE__,
+		       ifindex);
+	}
+
+	vd = vdp_data(ifname);
+	if (!vd) {
+		printf("%s(%i): Could not find vdp_data for %s !\n", __func__, __LINE__,
+		       ifname);
+		return NULL;
+	}
+
+	if (nlmsg_put(nl_msg, pid, seq, NLMSG_DONE, 0, 0) == NULL)
+		goto err_exit;
+
+	ifinfo.ifi_index = ifindex;
+
+	if (nlmsg_append(nl_msg, &ifinfo, sizeof(ifinfo), NLMSG_ALIGNTO) < 0)
+		goto err_exit;
+
+	vf_ports = nla_nest_start(nl_msg, IFLA_VF_PORTS);
+
+	if (!vf_ports)
+		goto err_exit;
+
+	/* loop over all existing profiles on this interface and
+	 * put them into the nested IFLA_VF_PORT structure */
+	LIST_FOREACH(p, &vd->profile_head, profile) {
+		if (p) {
+			vdp_print_profile(p);
+
+			vf_port  = nla_nest_start(nl_msg, IFLA_VF_PORT);
+
+			if (!vf_port)
+				goto err_exit;
+
+			if (nla_put(nl_msg, IFLA_PORT_INSTANCE_UUID, 16, p->instance) < 0)
+				goto err_exit;
+
+			if (nla_put_u32(nl_msg, IFLA_PORT_VF, PORT_SELF_VF) < 0)
+				goto err_exit;
+
+			if (p->mode == p->state) {
+				if (nla_put_u16(nl_msg, IFLA_PORT_RESPONSE,
+						PORT_VDP_RESPONSE_SUCCESS) < 0)
+					goto err_exit;
+			} else {
+				if (p->state == VSI_EXIT) {
+					if (p->response > PORT_VDP_RESPONSE_SUCCESS) {
+						if (nla_put_u16(nl_msg, IFLA_PORT_RESPONSE, p->response) < 0)
+							goto err_exit;
+					} else {
+						if (nla_put_u16(nl_msg, IFLA_PORT_RESPONSE,
+								PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES) < 0)
+							goto err_exit;
+					}
+				}
+			}
+
+			nla_nest_end(nl_msg, vf_port);
+		}
+	}
+
+	if (vf_ports)
+		nla_nest_end(nl_msg, vf_ports);
+
+	return nl_msg;
+
+err_exit:
+	nlmsg_free(nl_msg);
+
+	return NULL;
+}
+
+struct nl_msg *event_if_simpleResponse(uint32_t pid, uint32_t seq, int err)
+{
+	struct nl_msg *nl_msg = nlmsg_alloc();
+	struct nlmsgerr nlmsgerr;
+
+	memset(&nlmsgerr, 0x0, sizeof(nlmsgerr));
+
+	nlmsgerr.error = err;
+	fprintf(stderr,"RESPONSE ERROR CODE: %d\n",err);
+
+	if (nlmsg_put(nl_msg, pid, seq, NLMSG_ERROR, 0, 0) == NULL)
+		goto err_exit;
+
+	if (nlmsg_append(nl_msg, &nlmsgerr, sizeof(nlmsgerr), NLMSG_ALIGNTO) < 0)
+		goto err_exit;
+
+	return nl_msg;
+
+err_exit:
+	nlmsg_free(nl_msg);
+
+	return NULL;
+}
+
+static void event_iface_receive_user_space(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct nlmsghdr *nlh;
+	struct nl_msg *nl_msg;
+	struct msghdr msg;
+	struct sockaddr_nl dest_addr;
+	struct iovec iov;
+	int result;
+	int err;
+	int ifindex = 0;
+	char *ifname = NULL;
+
+	nlh = (struct nlmsghdr *)calloc(1,
+					NLMSG_SPACE(MAX_PAYLOAD));
+	if (!nlh) {
+		printf("%s(%i): could not allocate nlh !\n", __func__,
+		       __LINE__);
+		return;
+	}
+	memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	memset(&dest_addr, 0, sizeof(dest_addr));
+	iov.iov_base = (void *)nlh;
+	iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
+	msg.msg_name = (void *)&dest_addr;
+	msg.msg_namelen = sizeof(dest_addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+
+	fprintf(stderr, "Waiting for message \n");
+	result = recvmsg(sock, &msg, MSG_DONTWAIT);
+
+	fprintf(stderr, "%s:%s: recvmsg received %d bytes\n", __FILE__, __FUNCTION__, result);
+
+	if(result < 0) {
+		fprintf(stderr,"Error receiving from netlink socket : %s\n", strerror(errno));
+	}
+
+	fprintf(stderr, "%s:%s: dest_addr.nl_pid: %d\n", __FILE__, __FUNCTION__, dest_addr.nl_pid);
+	fprintf(stderr, "%s:%s: nlh.nl_pid: %d\n", __FILE__, __FUNCTION__, nlh->nlmsg_pid);
+	fprintf(stderr, "%s:%s: nlh_type: %d\n", __FILE__, __FUNCTION__, nlh->nlmsg_type);
+	fprintf(stderr, "%s:%s: nlh_seq: 0x%x\n", __FILE__, __FUNCTION__, nlh->nlmsg_seq);
+	fprintf(stderr, "%s:%s: nlh_len: 0x%x\n", __FILE__, __FUNCTION__, nlh->nlmsg_len);
+
+	switch (nlh->nlmsg_type) {
+		case RTM_SETLINK:
+			fprintf(stderr,"--> RTM_SETLINK\n");
+
+			err = event_if_parse_setmsg(nlh);
+
+			/* send simple response wether profile was accepted
+			 * or not */
+			nl_msg = event_if_simpleResponse(nlh->nlmsg_pid,
+							 nlh->nlmsg_seq,
+							 err);
+			nlh = nlmsg_hdr(nl_msg);
+			break;
+		case RTM_GETLINK:
+			fprintf(stderr,"--> RTM_GETLINK\n");
+
+			err = event_if_parse_getmsg(nlh, &ifindex, ifname);
+
+			if (err) {
+				nl_msg = event_if_simpleResponse(nlh->nlmsg_pid,
+								 nlh->nlmsg_seq,
+								 err);
+			} else if (ifname) {
+				ifindex = if_nametoindex(ifname);
+				printf("%s(%i): ifname %s (%d)\n", __func__,
+				       __LINE__, ifname, ifindex);
+			} else {
+				ifname = malloc(IFNAMSIZ);
+				printf("%s(%i): ifindex %i\n", __func__,
+				       __LINE__, ifindex);
+			}
+
+			nl_msg = event_if_constructResponse(nlh, ifindex);
+
+			if (!nl_msg) {
+				printf("%s(%i): Unable to construct response !\n",
+				       __func__, __LINE__);
+				goto out_err;
+			}
+
+			nlh = nlmsg_hdr(nl_msg);
+
+			fprintf(stderr, "------------\nRESPONSE:\n");
+
+			event_if_parseResponseMsg(nlh);
+
+			fprintf(stderr, "------------\n");
+			break;
+	}
+
+	iov.iov_base = (void*)nlh;
+	iov.iov_len = nlh->nlmsg_len;
+
+	msg.msg_name = (void *)&dest_addr;
+	msg.msg_namelen = sizeof(dest_addr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	result = sendmsg(sock, &msg, 0);
+
+	if (result < 0) {
+		fprintf(stderr,"Error sending on netlink socket : %s\n", strerror(errno));
+	} else {
+		fprintf(stderr,"sent %d bytes!\n",result);
+	}
+
+out_err:
+	free(nlh);
+}
+
 static void event_iface_receive(int sock, void *eloop_ctx, void *sock_ctx)
 {
 	struct nlmsghdr *nlh;
@@ -236,10 +794,11 @@ static void event_iface_receive(int sock, void *eloop_ctx, void *sock_ctx)
 	char buf[MAX_MSG_SIZE];
 	socklen_t fromlen = sizeof(dest_addr);
 	int result;
-	
+
 	result = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
 		       (struct sockaddr *) &dest_addr, &fromlen);
 
+	fprintf(stderr, "%s:%s: result: %d\n", __FILE__, __FUNCTION__, result);
 	if (result < 0) {
 		perror("recvfrom(Event interface)");
 		if ((errno == ENOBUFS) || (errno == EAGAIN))
@@ -250,10 +809,14 @@ static void event_iface_receive(int sock, void *eloop_ctx, void *sock_ctx)
 
 	TRACE("PRINT BUF info.\n")
 
-	device_name = NULL;
-	link_status = IF_OPER_UNKNOWN;
-	nlh = (struct nlmsghdr *)buf;
-	event_if_process_recvmsg(nlh);
+	/* Separate handler for kernel messages from userspace messages*/
+	fprintf(stderr, "%s:%s: dest_addr.nl_pid: %d\n", __FILE__, __FUNCTION__, dest_addr.nl_pid);
+	if (dest_addr.nl_pid == 0) {
+		device_name = NULL;
+		link_status = IF_OPER_UNKNOWN;
+		nlh = (struct nlmsghdr *)buf;
+		event_if_process_recvmsg(nlh);
+	}
 }
 
 int event_iface_init()
@@ -262,6 +825,7 @@ int event_iface_init()
 	int rcv_size = MAX_MSG_SIZE;
 	struct sockaddr_nl snl;
 
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
 	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
 
 	if (fd < 0)
@@ -282,6 +846,39 @@ int event_iface_init()
 	}
 
 	eloop_register_read_sock(fd, event_iface_receive, NULL, NULL);
+	//	event_iface_init2();
+	return 0;
+}
+
+int event_iface_init_user_space()
+{
+	int fd;
+	int rcv_size = MAX_MSG_SIZE;
+	struct sockaddr_nl snl;
+
+	fprintf(stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
+	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+
+	if (fd < 0)
+		return fd;
+
+	if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_size, sizeof(int)) < 0) {
+		close(fd);
+		return -EIO;
+	}
+
+	memset((void *)&snl, 0, sizeof(struct sockaddr_nl));
+	snl.nl_family = AF_NETLINK;
+	snl.nl_pid = getpid();  /* self pid */
+	snl.nl_groups = 0;
+
+	if (bind(fd, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)) < 0) {
+		close(fd);
+		fprintf(stderr,"Error binding to netlink socket : %s\n", strerror(errno));
+		return -EIO;
+	}
+
+	eloop_register_read_sock(fd, event_iface_receive_user_space, NULL, NULL);
 	return 0;
 }
 
diff --git a/include/event_iface.h b/include/event_iface.h
index b2c93f0..d80158d 100644
--- a/include/event_iface.h
+++ b/include/event_iface.h
@@ -29,6 +29,7 @@
 #define  _EVENT_IFACE_H_
 
 int event_iface_init(void);
+int event_iface_init_user_space(void);
 int event_iface_deinit(void);
 int oper_add_device(char *device_name);
 
diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h
index b97d8c0..53f814c 100644
--- a/include/lldp_vdp.h
+++ b/include/lldp_vdp.h
@@ -134,6 +134,8 @@ struct vdp_data *vdp_data(char *ifname);
 struct packed_tlv *vdp_gettlv(struct vdp_data *vd, struct vsi_profile *profile);
 void vdp_vsi_sm_station(struct vsi_profile *profile);
 struct vsi_profile *vdp_add_profile(struct vsi_profile *profile);
+void vdp_somethingChangedLocal(struct vsi_profile *profile, int mode);
+void vdp_print_profile(struct vsi_profile *profile);
 
 #define MAC_ADDR_STRLEN		18
 #define INSTANCE_STRLEN		32
diff --git a/lldp_vdp.c b/lldp_vdp.c
index 7d5936b..b8690a6 100644
--- a/lldp_vdp.c
+++ b/lldp_vdp.c
@@ -105,7 +105,7 @@ static void vdp_free_data(struct vdp_user_data *ud)
  * prints the contents of a profile first to a string using the PRINT_PROFILE
  * macro, and then to the screen. Used for debug purposes.
  */
-static inline void vdp_print_profile(struct vsi_profile *profile)
+void vdp_print_profile(struct vsi_profile *profile)
 {
 	char *s, *t;
 
diff --git a/lldpad.c b/lldpad.c
index c0938af..69faa29 100644
--- a/lldpad.c
+++ b/lldpad.c
@@ -374,6 +374,16 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
+	/* setup event netlink interface for user space processes.
+	 * This needs to be setup first to ensure it gets lldpads
+	 * pid as netlink address.
+	 */
+	if (event_iface_init_user_space() < 0) {
+		log_message(MSG_ERR_SERVICE_START_FAILURE,
+			"%s", "failed to register user space event interface");
+		exit(1);
+	}
+
 	init_modules("");
 
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH 08/10] use connect instead of bind
From: Jens Osterkamp @ 2010-08-25 12:27 UTC (permalink / raw)
  To: e1000-eedc, virtualization, evb; +Cc: chrisw, Gerhard Stenzel, Jens Osterkamp
In-Reply-To: <1282739262-14968-1-git-send-email-jens@linux.vnet.ibm.com>

modifies the setup of the netlink socket in drv_cfg.c to use pid 0 instead
of the processes pid.
Also replaces bind with connect to allow the reception of netlink messages
from libvirt.
Preparation patch for communication between libvirt and lldpad.

Signed-off-by: Gerhard Stenzel <gstenzel@linux.vnet.ibm.com>
---
 drv_cfg.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drv_cfg.c b/drv_cfg.c
index 6c02555..23c11f3 100644
--- a/drv_cfg.c
+++ b/drv_cfg.c
@@ -71,9 +71,9 @@ static int init_socket(void)
 
 	memset((void *)&snl, 0, sizeof(struct sockaddr_nl));
 	snl.nl_family = AF_NETLINK;
-	snl.nl_pid = getpid();
+	snl.nl_pid = 0;
 
-	if (bind(sd, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)) < 0) {
+	if (connect(sd, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)) < 0) {
 		close(sd);
 		return -EIO;
 	}
@@ -195,6 +195,7 @@ static struct nlmsghdr *get_msg(unsigned int seq)
 			nlh = NULL;
 			break;
 		}
+		fprintf(stderr, "%s:%s: nlmsg_type: %d\n", __FILE__, __FUNCTION__, nlh->nlmsg_type);
 		if ((nlh->nlmsg_type == RTM_GETDCB ||
 			nlh->nlmsg_type == RTM_SETDCB) &&
 			nlh->nlmsg_seq == seq) {
-- 
1.7.1

^ permalink raw reply related

* [PATCH 07/10] add libnl dependency to configure.ac
From: Jens Osterkamp @ 2010-08-25 12:27 UTC (permalink / raw)
  To: e1000-eedc, virtualization, evb; +Cc: chrisw, Jens Osterkamp
In-Reply-To: <1282739262-14968-1-git-send-email-jens@linux.vnet.ibm.com>

Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
---
 configure.ac |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/configure.ac b/configure.ac
index 619c6c4..8b9d08a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,6 +12,11 @@ PKG_CHECK_MODULES(LIBCONFIG, libconfig,
 AC_SUBST(LIBCONFIG_CFLAGS)
 AC_SUBST(LIBCONFIG_LIBS)
 
+PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.1)
+AC_SUBST(LIBNL_CFLAGS)
+AC_SUBST(LIBNL_LIBS)
+
+AC_CHECK_LIB(nl, rtnl_link_get_by_name)
 AC_CONFIG_SUBDIRS([libconfig-1.3.2])
 AC_CONFIG_FILES([Makefile include/version.h lldpad.spec lldpad.pc dcbd.pc])
 AC_OUTPUT
-- 
1.7.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox