* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Amit Shah @ 2010-10-19 7:32 UTC (permalink / raw)
To: Hans de Goede; +Cc: stable, Virtualization List
In-Reply-To: <4CBD4754.5030504@redhat.com>
On (Tue) Oct 19 2010 [09:23:00], Hans de Goede wrote:
> >>3) This patch will cause processes filling the virtqueue fast enough to block
> >> to never wake up again, due to a missing waitqueue wakeup, see:
> >> https://bugzilla.redhat.com/show_bug.cgi?id=643750
> >
> >Doesn't happen in my testcase, but this patch shouldn't cause that
> >problem if it exists -- it's a problem that exists even now for
> >nonblocking ports. So if such a bug exists, it needs to be fixed
> >independently.
>
> First of all lets agree that this is a real problem,
Sure, got a testcase for the test-virtserial or kvm-autotest projects?
;-)
I did try it and POLLOUT gets set for me immediately when I read one
buffer from the host.
> there is simply nothing
> waking the waitqueue were fops_write (or poll) block on when buffers become
> available in out_vq, it may be hard to come up with a test case which fills
> the queue fast enough to hit this scenario, but it is very real.
Not at all.
Connect guest
Connect host
On guest, check for POLLOUT. As long as it's set, write buffers.
When POLLOUT goes off, read one buffer from host. See if POLLOUT is set
again.
Also, as I mentioned in a private chat, the fix for that problem is easy
enough.
> I agree it is an independent problem, and should be fixed in a separate
> patch, but that patch should be part of the same set and become *before*
> this one, as this patch now extends the problem to ports opened in blocking
> mode too.
Strongly disagree. This patch fixes a problem wherein blocking-mode
writes to a port freeze the entire guest. That's a much uglier problem
to have than poll not indicating a port is writable again.
> BTW, many thanks for working on this, it is appreciated :)
Sure, thanks :-)
Amit
^ permalink raw reply
* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Hans de Goede @ 2010-10-19 7:23 UTC (permalink / raw)
To: Amit Shah; +Cc: stable, Virtualization List
In-Reply-To: <20101019071021.GB2505@amit-laptop.redhat.com>
Hi,
On 10/19/2010 09:10 AM, Amit Shah wrote:
> On (Tue) Oct 19 2010 [08:55:16], Hans de Goede wrote:
>> Hi,
>>
>> On 10/19/2010 07:45 AM, Amit Shah wrote:
>>> If the host is slow in reading data or doesn't read data at all,
>>> blocking write calls not only blocked the program that called write()
>>> but the entire guest itself.
>>>
>>> To overcome this, let's not block till the host signals it has given
>>> back the virtio ring element we passed it. Instead, send the buffer to
>>> the host and return to userspace. This operation then becomes similar
>>> to how non-blocking writes work, so let's use the existing code for this
>>> path as well.
>>>
>>> This code change also ensures blocking write calls do get blocked if
>>> there's not enough room in the virtio ring as well as they don't return
>>> -EAGAIN to userspace.
>>>
>>> Signed-off-by: Amit Shah<amit.shah@redhat.com>
>>> CC: stable@kernel.org
>>> ---
>>> drivers/char/virtio_console.c | 17 ++++++++++++++---
>>> 1 files changed, 14 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
>>> index c810481..0f69c5e 100644
>>> --- a/drivers/char/virtio_console.c
>>> +++ b/drivers/char/virtio_console.c
>>> @@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
>>>
>>> /*
>>> * Wait till the host acknowledges it pushed out the data we
>>> - * sent. This is done for ports in blocking mode or for data
>>> - * from the hvc_console; the tty operations are performed with
>>> - * spinlocks held so we can't sleep here.
>>> + * sent. This is done for data from the hvc_console; the tty
>>> + * operations are performed with spinlocks held so we can't
>>> + * sleep here. An alternative would be to copy the data to a
>>> + * buffer and relax the spinning requirement. The downside is
>>> + * we need to kmalloc a GFP_ATOMIC buffer each time the
>>> + * console driver writes something out.
>>> */
>>> while (!virtqueue_get_buf(out_vq,&len))
>>> cpu_relax();
>>> @@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
>>> goto free_buf;
>>> }
>>>
>>> + /*
>>> + * We now ask send_buf() to not spin for generic ports -- we
>>> + * can re-use the same code path that non-blocking file
>>> + * descriptors take for blocking file descriptors since the
>>> + * wait is already done and we're certain the write will go
>>> + * through to the host.
>>> + */
>>> + nonblock = true;
>>> ret = send_buf(port, buf, count, nonblock);
>>>
>>> if (nonblock&& ret> 0)
>>
>> 1) Hmm, this changes the code to kfree the buffer, but only if the send_buf
>> succeeded (which it always should given we did a will_block check first).
>
> The change is to *not* free the buffer. It will be freed later when the
> host indicates it's done with it (happens in reclaim_consumed_buffers()).
>
Ah, thanks for explaining that.
>> I cannot help but notice that the data was not freed on a blocking fd
>> before this patch, but is freed now. And I see nothing in send_buf to make
>> it take ownership of the buffer / free it in the blocking case, and not take
>> ownership in the blocking case. More over if anything I would expect send_buf
>> to take ownership in the non blocking case (as the data is not directly
>> consumed there), and not take owner ship in the blocking case, but the check
>> is the reverse. Also why is the buffer not freed if the write failed, that
>> makes no sense.
>
> The buffer used to be freed in the blocking case, as we knew for certain
> the host was done with the buffer. Now it's not, we'll free it later.
>
>> 2) Assuming that things are changed so that send_buf does take ownership of the
>> buffer in the nonblocking case, shouldn't the buffer then be allocated
>> with GPF_ATOMIC ?
>
> Why? We're not called from irq context.
>
Ok, my bad.
>> 3) This patch will cause processes filling the virtqueue fast enough to block
>> to never wake up again, due to a missing waitqueue wakeup, see:
>> https://bugzilla.redhat.com/show_bug.cgi?id=643750
>
> Doesn't happen in my testcase, but this patch shouldn't cause that
> problem if it exists -- it's a problem that exists even now for
> nonblocking ports. So if such a bug exists, it needs to be fixed
> independently.
First of all lets agree that this is a real problem, there is simply nothing
waking the waitqueue were fops_write (or poll) block on when buffers become
available in out_vq, it may be hard to come up with a test case which fills
the queue fast enough to hit this scenario, but it is very real.
I agree it is an independent problem, and should be fixed in a separate
patch, but that patch should be part of the same set and become *before*
this one, as this patch now extends the problem to ports opened in blocking
mode too.
BTW, many thanks for working on this, it is appreciated :)
Regards,
Hans
^ permalink raw reply
* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Amit Shah @ 2010-10-19 7:13 UTC (permalink / raw)
To: Hans de Goede; +Cc: stable, Virtualization List
In-Reply-To: <4CBD4167.1010104@redhat.com>
On (Tue) Oct 19 2010 [08:57:43], Hans de Goede wrote:
> Hi,
>
> Ok replying to my own reply, because I misread the code.
>
> On 10/19/2010 08:55 AM, Hans de Goede wrote:
> >Hi,
> >
> >On 10/19/2010 07:45 AM, Amit Shah wrote:
> >>If the host is slow in reading data or doesn't read data at all,
> >>blocking write calls not only blocked the program that called write()
> >>but the entire guest itself.
> >>
> >>To overcome this, let's not block till the host signals it has given
> >>back the virtio ring element we passed it. Instead, send the buffer to
> >>the host and return to userspace. This operation then becomes similar
> >>to how non-blocking writes work, so let's use the existing code for this
> >>path as well.
> >>
> >>This code change also ensures blocking write calls do get blocked if
> >>there's not enough room in the virtio ring as well as they don't return
> >>-EAGAIN to userspace.
> >>
> >>Signed-off-by: Amit Shah<amit.shah@redhat.com>
> >>CC: stable@kernel.org
> >>---
> >>drivers/char/virtio_console.c | 17 ++++++++++++++---
> >>1 files changed, 14 insertions(+), 3 deletions(-)
> >>
> >>diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
> >>index c810481..0f69c5e 100644
> >>--- a/drivers/char/virtio_console.c
> >>+++ b/drivers/char/virtio_console.c
> >>@@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
> >>
> >>/*
> >>* Wait till the host acknowledges it pushed out the data we
> >>- * sent. This is done for ports in blocking mode or for data
> >>- * from the hvc_console; the tty operations are performed with
> >>- * spinlocks held so we can't sleep here.
> >>+ * sent. This is done for data from the hvc_console; the tty
> >>+ * operations are performed with spinlocks held so we can't
> >>+ * sleep here. An alternative would be to copy the data to a
> >>+ * buffer and relax the spinning requirement. The downside is
> >>+ * we need to kmalloc a GFP_ATOMIC buffer each time the
> >>+ * console driver writes something out.
> >>*/
> >>while (!virtqueue_get_buf(out_vq,&len))
> >>cpu_relax();
> >>@@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
> >>goto free_buf;
> >>}
> >>
> >>+ /*
> >>+ * We now ask send_buf() to not spin for generic ports -- we
> >>+ * can re-use the same code path that non-blocking file
> >>+ * descriptors take for blocking file descriptors since the
> >>+ * wait is already done and we're certain the write will go
> >>+ * through to the host.
> >>+ */
> >>+ nonblock = true;
> >>ret = send_buf(port, buf, count, nonblock);
> >>
> >>if (nonblock&& ret> 0)
> >
> >1) Hmm, this changes the code to kfree the buffer, but only if the send_buf
> >succeeded (which it always should given we did a will_block check first).
> >
> >I cannot help but notice that the data was not freed on a blocking fd
> >before this patch, but is freed now. And I see nothing in send_buf to make
> >it take ownership of the buffer / free it in the blocking case, and not take
> >ownership in the blocking case.
>
> This part still stands.
>
> > More over if anything I would expect send_buf
> >to take ownership in the non blocking case (as the data is not directly
> >consumed there), and not take owner ship in the blocking case, but the check
> >is the reverse. Also why is the buffer not freed if the write failed, that
> >makes no sense.
> >
>
> This part is wrong the:
>
> if (nonblock && ret> 0)
>
> Check make it jump (goto) over the free, so it does make sense, but is coded
> rather convolutedly.
This means that:
a) we're not going to wait for the host to tell us it used the buffer,
so keep the buffer around.
b) we actually managed to send the buffer to the host.
I don't see why that's convoluted :-)
Amit
^ permalink raw reply
* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Amit Shah @ 2010-10-19 7:10 UTC (permalink / raw)
To: Hans de Goede; +Cc: stable, Virtualization List
In-Reply-To: <4CBD40D4.9050106@redhat.com>
On (Tue) Oct 19 2010 [08:55:16], Hans de Goede wrote:
> Hi,
>
> On 10/19/2010 07:45 AM, Amit Shah wrote:
> >If the host is slow in reading data or doesn't read data at all,
> >blocking write calls not only blocked the program that called write()
> >but the entire guest itself.
> >
> >To overcome this, let's not block till the host signals it has given
> >back the virtio ring element we passed it. Instead, send the buffer to
> >the host and return to userspace. This operation then becomes similar
> >to how non-blocking writes work, so let's use the existing code for this
> >path as well.
> >
> >This code change also ensures blocking write calls do get blocked if
> >there's not enough room in the virtio ring as well as they don't return
> >-EAGAIN to userspace.
> >
> >Signed-off-by: Amit Shah<amit.shah@redhat.com>
> >CC: stable@kernel.org
> >---
> > drivers/char/virtio_console.c | 17 ++++++++++++++---
> > 1 files changed, 14 insertions(+), 3 deletions(-)
> >
> >diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
> >index c810481..0f69c5e 100644
> >--- a/drivers/char/virtio_console.c
> >+++ b/drivers/char/virtio_console.c
> >@@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
> >
> > /*
> > * Wait till the host acknowledges it pushed out the data we
> >- * sent. This is done for ports in blocking mode or for data
> >- * from the hvc_console; the tty operations are performed with
> >- * spinlocks held so we can't sleep here.
> >+ * sent. This is done for data from the hvc_console; the tty
> >+ * operations are performed with spinlocks held so we can't
> >+ * sleep here. An alternative would be to copy the data to a
> >+ * buffer and relax the spinning requirement. The downside is
> >+ * we need to kmalloc a GFP_ATOMIC buffer each time the
> >+ * console driver writes something out.
> > */
> > while (!virtqueue_get_buf(out_vq,&len))
> > cpu_relax();
> >@@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
> > goto free_buf;
> > }
> >
> >+ /*
> >+ * We now ask send_buf() to not spin for generic ports -- we
> >+ * can re-use the same code path that non-blocking file
> >+ * descriptors take for blocking file descriptors since the
> >+ * wait is already done and we're certain the write will go
> >+ * through to the host.
> >+ */
> >+ nonblock = true;
> > ret = send_buf(port, buf, count, nonblock);
> >
> > if (nonblock&& ret> 0)
>
> 1) Hmm, this changes the code to kfree the buffer, but only if the send_buf
> succeeded (which it always should given we did a will_block check first).
The change is to *not* free the buffer. It will be freed later when the
host indicates it's done with it (happens in reclaim_consumed_buffers()).
> I cannot help but notice that the data was not freed on a blocking fd
> before this patch, but is freed now. And I see nothing in send_buf to make
> it take ownership of the buffer / free it in the blocking case, and not take
> ownership in the blocking case. More over if anything I would expect send_buf
> to take ownership in the non blocking case (as the data is not directly
> consumed there), and not take owner ship in the blocking case, but the check
> is the reverse. Also why is the buffer not freed if the write failed, that
> makes no sense.
The buffer used to be freed in the blocking case, as we knew for certain
the host was done with the buffer. Now it's not, we'll free it later.
> 2) Assuming that things are changed so that send_buf does take ownership of the
> buffer in the nonblocking case, shouldn't the buffer then be allocated
> with GPF_ATOMIC ?
Why? We're not called from irq context.
> 3) This patch will cause processes filling the virtqueue fast enough to block
> to never wake up again, due to a missing waitqueue wakeup, see:
> https://bugzilla.redhat.com/show_bug.cgi?id=643750
Doesn't happen in my testcase, but this patch shouldn't cause that
problem if it exists -- it's a problem that exists even now for
nonblocking ports. So if such a bug exists, it needs to be fixed
independently.
Amit
^ permalink raw reply
* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Hans de Goede @ 2010-10-19 6:57 UTC (permalink / raw)
To: Amit Shah; +Cc: stable, Virtualization List
In-Reply-To: <4CBD40D4.9050106@redhat.com>
Hi,
Ok replying to my own reply, because I misread the code.
On 10/19/2010 08:55 AM, Hans de Goede wrote:
> Hi,
>
> On 10/19/2010 07:45 AM, Amit Shah wrote:
>> If the host is slow in reading data or doesn't read data at all,
>> blocking write calls not only blocked the program that called write()
>> but the entire guest itself.
>>
>> To overcome this, let's not block till the host signals it has given
>> back the virtio ring element we passed it. Instead, send the buffer to
>> the host and return to userspace. This operation then becomes similar
>> to how non-blocking writes work, so let's use the existing code for this
>> path as well.
>>
>> This code change also ensures blocking write calls do get blocked if
>> there's not enough room in the virtio ring as well as they don't return
>> -EAGAIN to userspace.
>>
>> Signed-off-by: Amit Shah<amit.shah@redhat.com>
>> CC: stable@kernel.org
>> ---
>> drivers/char/virtio_console.c | 17 ++++++++++++++---
>> 1 files changed, 14 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
>> index c810481..0f69c5e 100644
>> --- a/drivers/char/virtio_console.c
>> +++ b/drivers/char/virtio_console.c
>> @@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
>>
>> /*
>> * Wait till the host acknowledges it pushed out the data we
>> - * sent. This is done for ports in blocking mode or for data
>> - * from the hvc_console; the tty operations are performed with
>> - * spinlocks held so we can't sleep here.
>> + * sent. This is done for data from the hvc_console; the tty
>> + * operations are performed with spinlocks held so we can't
>> + * sleep here. An alternative would be to copy the data to a
>> + * buffer and relax the spinning requirement. The downside is
>> + * we need to kmalloc a GFP_ATOMIC buffer each time the
>> + * console driver writes something out.
>> */
>> while (!virtqueue_get_buf(out_vq,&len))
>> cpu_relax();
>> @@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
>> goto free_buf;
>> }
>>
>> + /*
>> + * We now ask send_buf() to not spin for generic ports -- we
>> + * can re-use the same code path that non-blocking file
>> + * descriptors take for blocking file descriptors since the
>> + * wait is already done and we're certain the write will go
>> + * through to the host.
>> + */
>> + nonblock = true;
>> ret = send_buf(port, buf, count, nonblock);
>>
>> if (nonblock&& ret> 0)
>
> 1) Hmm, this changes the code to kfree the buffer, but only if the send_buf
> succeeded (which it always should given we did a will_block check first).
>
> I cannot help but notice that the data was not freed on a blocking fd
> before this patch, but is freed now. And I see nothing in send_buf to make
> it take ownership of the buffer / free it in the blocking case, and not take
> ownership in the blocking case.
This part still stands.
> More over if anything I would expect send_buf
> to take ownership in the non blocking case (as the data is not directly
> consumed there), and not take owner ship in the blocking case, but the check
> is the reverse. Also why is the buffer not freed if the write failed, that
> makes no sense.
>
This part is wrong the:
if (nonblock && ret> 0)
Check make it jump (goto) over the free, so it does make sense, but is coded
rather convolutedly.
> 2) Assuming that things are changed so that send_buf does take ownership of the
> buffer in the nonblocking case, shouldn't the buffer then be allocated
> with GPF_ATOMIC ?
>
> 3) This patch will cause processes filling the virtqueue fast enough to block
> to never wake up again, due to a missing waitqueue wakeup, see:
> https://bugzilla.redhat.com/show_bug.cgi?id=643750
These 2 parts still stand.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Hans de Goede @ 2010-10-19 6:55 UTC (permalink / raw)
To: Amit Shah; +Cc: stable, Virtualization List
In-Reply-To: <baecf865292e0cc96914d30fc601e3a96fad9845.1287467155.git.amit.shah@redhat.com>
Hi,
On 10/19/2010 07:45 AM, Amit Shah wrote:
> If the host is slow in reading data or doesn't read data at all,
> blocking write calls not only blocked the program that called write()
> but the entire guest itself.
>
> To overcome this, let's not block till the host signals it has given
> back the virtio ring element we passed it. Instead, send the buffer to
> the host and return to userspace. This operation then becomes similar
> to how non-blocking writes work, so let's use the existing code for this
> path as well.
>
> This code change also ensures blocking write calls do get blocked if
> there's not enough room in the virtio ring as well as they don't return
> -EAGAIN to userspace.
>
> Signed-off-by: Amit Shah<amit.shah@redhat.com>
> CC: stable@kernel.org
> ---
> drivers/char/virtio_console.c | 17 ++++++++++++++---
> 1 files changed, 14 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
> index c810481..0f69c5e 100644
> --- a/drivers/char/virtio_console.c
> +++ b/drivers/char/virtio_console.c
> @@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
>
> /*
> * Wait till the host acknowledges it pushed out the data we
> - * sent. This is done for ports in blocking mode or for data
> - * from the hvc_console; the tty operations are performed with
> - * spinlocks held so we can't sleep here.
> + * sent. This is done for data from the hvc_console; the tty
> + * operations are performed with spinlocks held so we can't
> + * sleep here. An alternative would be to copy the data to a
> + * buffer and relax the spinning requirement. The downside is
> + * we need to kmalloc a GFP_ATOMIC buffer each time the
> + * console driver writes something out.
> */
> while (!virtqueue_get_buf(out_vq,&len))
> cpu_relax();
> @@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
> goto free_buf;
> }
>
> + /*
> + * We now ask send_buf() to not spin for generic ports -- we
> + * can re-use the same code path that non-blocking file
> + * descriptors take for blocking file descriptors since the
> + * wait is already done and we're certain the write will go
> + * through to the host.
> + */
> + nonblock = true;
> ret = send_buf(port, buf, count, nonblock);
>
> if (nonblock&& ret> 0)
1) Hmm, this changes the code to kfree the buffer, but only if the send_buf
succeeded (which it always should given we did a will_block check first).
I cannot help but notice that the data was not freed on a blocking fd
before this patch, but is freed now. And I see nothing in send_buf to make
it take ownership of the buffer / free it in the blocking case, and not take
ownership in the blocking case. More over if anything I would expect send_buf
to take ownership in the non blocking case (as the data is not directly
consumed there), and not take owner ship in the blocking case, but the check
is the reverse. Also why is the buffer not freed if the write failed, that
makes no sense.
2) Assuming that things are changed so that send_buf does take ownership of the
buffer in the nonblocking case, shouldn't the buffer then be allocated
with GPF_ATOMIC ?
3) This patch will cause processes filling the virtqueue fast enough to block
to never wake up again, due to a missing waitqueue wakeup, see:
https://bugzilla.redhat.com/show_bug.cgi?id=643750
Regards,
Hans
^ permalink raw reply
* [PATCH] virtio: console: Don't block entire guest if host doesn't read data
From: Amit Shah @ 2010-10-19 5:45 UTC (permalink / raw)
To: Virtualization List; +Cc: Amit Shah, Hans de Goede, stable
If the host is slow in reading data or doesn't read data at all,
blocking write calls not only blocked the program that called write()
but the entire guest itself.
To overcome this, let's not block till the host signals it has given
back the virtio ring element we passed it. Instead, send the buffer to
the host and return to userspace. This operation then becomes similar
to how non-blocking writes work, so let's use the existing code for this
path as well.
This code change also ensures blocking write calls do get blocked if
there's not enough room in the virtio ring as well as they don't return
-EAGAIN to userspace.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
CC: stable@kernel.org
---
drivers/char/virtio_console.c | 17 ++++++++++++++---
1 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index c810481..0f69c5e 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -459,9 +459,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
/*
* Wait till the host acknowledges it pushed out the data we
- * sent. This is done for ports in blocking mode or for data
- * from the hvc_console; the tty operations are performed with
- * spinlocks held so we can't sleep here.
+ * sent. This is done for data from the hvc_console; the tty
+ * operations are performed with spinlocks held so we can't
+ * sleep here. An alternative would be to copy the data to a
+ * buffer and relax the spinning requirement. The downside is
+ * we need to kmalloc a GFP_ATOMIC buffer each time the
+ * console driver writes something out.
*/
while (!virtqueue_get_buf(out_vq, &len))
cpu_relax();
@@ -626,6 +629,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
goto free_buf;
}
+ /*
+ * We now ask send_buf() to not spin for generic ports -- we
+ * can re-use the same code path that non-blocking file
+ * descriptors take for blocking file descriptors since the
+ * wait is already done and we're certain the write will go
+ * through to the host.
+ */
+ nonblock = true;
ret = send_buf(port, buf, count, nonblock);
if (nonblock && ret > 0)
--
1.7.2.3
^ permalink raw reply related
* CFP: 7th IEEE International Workshop on Storage Network Architecture and Parallel I/Os (SNAPI 2011)
From: Ming Zhao @ 2010-10-18 4:37 UTC (permalink / raw)
To: access, acf-members, admin, agents, ahsntc-mailing-list, ai-stats
========================================================================
Call for Papers
7th IEEE International Workshop on
Storage Network Architecture and Parallel I/Os
(SNAPI 2011)
http://snapi2011.cis.fiu.edu
May 25, 2011 Denver, Colorado, USA
In conjunction with the 27th IEEE Conference on
Mass Storage Systems and Technologies (MSST 2011)
========================================================================
SCOPE:
------
The 7th IEEE Storage Networking Architecture and Parallel I/O (SNAPI
2011) Workshop aims to highlight the latest research in the
architecture, design, implementation, and evaluation of local and
networked storage and parallel I/O systems. The workshop is co-located
with the 27th IEEE Conference on Mass Storage Systems and Technologies
(MSST2011) that features a full week dedicated to "all things storage".
The SNAPI 2011 workshop, held in the middle of the MSST week, will
feature a full day of technical papers that showcase the latest work
from the academia, the labs, and the industry.
This year we would like to encourage a variety of submissions including
novel idea papers, real system experience papers, as well as analysis
and evaluation papers. Topics of interest include, but are not limited
to:
* Caching, replication, and consistency
* Energy-efficient storage
* Evaluation of networked storage architectures
* Experiences with real systems
* File and block based network storage
* Integration and evaluation of emerging storage technology
* I/O quality of service
* New abstractions/protocols for data, storage, and I/O
* Parallel I/O
* Performance, scalability, and manageability of networked storage
* SSD-based storage architectures and tiered storage
* Storage device and workload characterization
* Storage networking
* Storage reliability and failure management
* Storage virtualization
* Thin provisioning, consolidation, compression, and deduplication
* Wide-area networked storage
SUBMISSIONS INSTRUCTIONS:
-------------------------
Submissions should not exceed 8 single-space pages including all text,
figures, and references. Submissions must be typeset as double-column
text, using no less than 10 pt font, and using a text block that does
not exceed 6.5" width and 9" height.
The reviewing is double-blind. Authors must not be identified in the
submission either directly or indirectly. Please be careful so as to not
refer to your own work in the first person or leak authorship in any way
within the text of the paper. Reviewing will be performed by the members
of the SNAPI’11 Program Committee. Each paper will receive at least
three reviews from members of the Program Committee.
The final version of the paper prepared after incorporating reviewer
feedback should be submitted by April 1st, 2011. At least one author of
each accepted paper will be expected to attend the workshop and present
their work in a 25 minute talk.
BEST PAPER AWARD:
-----------------
Authors of the best paper, chosen by the Program Committee, will be
presented an award at the workshop.
Important dates:
----------------
* Full paper submission: January 28, 2011
* Notification of acceptance: March 4, 2011
* Final manuscripts due: April 1, 2011
* Workshop: May 25, 2011
Organization:
-------------
* Program Chair:
o Raju Rangaswami, Florida International University
* Program Committee:
o Angelos Bilas, FORTH and University of Crete
o Randal Burns, Johns Hopkins University
o Dan Feng, Huazhong University of Science and Technology
o Dirk Grunwald, University of Colorado, Boulder
o Ajay Gulati, VMware
o Ron Oldfield, Sandia National Laboratory
o Vijayan Prabhakaran, Microsoft Research
o Himabindu Pucha, IBM Research - Almaden
o A. L. Narasimha Reddy, Texas A&M University
o Alma Riska, College of William and Mary
o Philip Roth, Oak Ridge National Laboratory
o Jiri Schindler, NetApp
o Rajeev Thakur, Argonne National Laboratory
o Bhuvan Urgaonkar, Pennsylvania State University
o Youjip Won, Hanyang University
o Ming Zhao, Florida International University
* Web and Publicity Chair:
o Ming Zhao, Florida International University
* Steering Committee:
o Qing Yang, University of Rhode Island
o Hong Jiang, University of Nebraska-Lincoln
o Xubin He, Tennessee Tech University
SPONSORSHIP:
------------
IEEE Mass Storage Systems Technical Committee (MSSTC)
Information:
------------
* SNAPI 2001 Web: http://snapi2011.cis.fiu.edu
* MSST 2011 Web: http://storageconference.org
* Email: snapi2011@cis.fiu.edu
--
Ming Zhao, Assistant Professor
School of Computing and Information Sciences
Florida International University
Tel: (305) 348-2034, Fax: (305) 348-3549
Web: http://visa.cs.fiu.edu/ming
^ permalink raw reply
* [PATCH 5/5] staging: hv: Convert camel cased functions in channel_mgmt.c to lower case
From: Haiyang Zhang @ 2010-10-15 17:14 UTC (permalink / raw)
To: haiyangz, hjanssen, gregkh, linux-kernel, devel, virtualization
In-Reply-To: <1287162847-27536-4-git-send-email-haiyangz@linuxonhyperv.com>
From: Haiyang Zhang <haiyangz@microsoft.com>
Convert camel cased functions in channel_mgmt.c to lower case
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/channel.c | 2 +-
drivers/staging/hv/channel_mgmt.c | 90 +++++++++++++++++++------------------
drivers/staging/hv/channel_mgmt.h | 10 ++--
drivers/staging/hv/vmbus.c | 6 +-
4 files changed, 55 insertions(+), 53 deletions(-)
diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c
index 39b8fd3..45dda9b 100644
--- a/drivers/staging/hv/channel.c
+++ b/drivers/staging/hv/channel.c
@@ -698,7 +698,7 @@ void vmbus_close(struct vmbus_channel *channel)
list_del(&channel->ListEntry);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
- FreeVmbusChannel(channel);
+ free_channel(channel);
}
}
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index 7522cfd..0d5dbf3 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -235,9 +235,9 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
EXPORT_SYMBOL(hv_cb_utils);
/*
- * AllocVmbusChannel - Allocate and initialize a vmbus channel object
+ * alloc_channel - Allocate and initialize a vmbus channel object
*/
-struct vmbus_channel *AllocVmbusChannel(void)
+struct vmbus_channel *alloc_channel(void)
{
struct vmbus_channel *channel;
@@ -261,9 +261,9 @@ struct vmbus_channel *AllocVmbusChannel(void)
}
/*
- * ReleaseVmbusChannel - Release the vmbus channel object itself
+ * release_hannel - Release the vmbus channel object itself
*/
-static inline void ReleaseVmbusChannel(void *context)
+static inline void release_channel(void *context)
{
struct vmbus_channel *channel = context;
@@ -275,9 +275,9 @@ static inline void ReleaseVmbusChannel(void *context)
}
/*
- * FreeVmbusChannel - Release the resources used by the vmbus channel object
+ * free_channel - Release the resources used by the vmbus channel object
*/
-void FreeVmbusChannel(struct vmbus_channel *channel)
+void free_channel(struct vmbus_channel *channel)
{
del_timer_sync(&channel->poll_timer);
@@ -286,7 +286,7 @@ void FreeVmbusChannel(struct vmbus_channel *channel)
* workqueue/thread context
* ie we can't destroy ourselves.
*/
- osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
+ osd_schedule_callback(gVmbusConnection.WorkQueue, release_channel,
channel);
}
@@ -310,10 +310,10 @@ static void count_hv_channel(void)
/*
- * VmbusChannelProcessOffer - Process the offer by creating a channel/device
+ * vmbus_process_offer - Process the offer by creating a channel/device
* associated with this offer
*/
-static void VmbusChannelProcessOffer(void *context)
+static void vmbus_process_offer(void *context)
{
struct vmbus_channel *newchannel = context;
struct vmbus_channel *channel;
@@ -346,7 +346,7 @@ static void VmbusChannelProcessOffer(void *context)
if (!fnew) {
DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
newchannel->OfferMsg.ChildRelId);
- FreeVmbusChannel(newchannel);
+ free_channel(newchannel);
return;
}
@@ -378,7 +378,7 @@ static void VmbusChannelProcessOffer(void *context)
list_del(&newchannel->ListEntry);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
- FreeVmbusChannel(newchannel);
+ free_channel(newchannel);
} else {
/*
* This state is used to indicate a successful open
@@ -406,9 +406,10 @@ static void VmbusChannelProcessOffer(void *context)
}
/*
- * VmbusChannelProcessRescindOffer - Rescind the offer by initiating a device removal
+ * vmbus_process_rescind_offer -
+ * Rescind the offer by initiating a device removal
*/
-static void VmbusChannelProcessRescindOffer(void *context)
+static void vmbus_process_rescind_offer(void *context)
{
struct vmbus_channel *channel = context;
@@ -416,13 +417,13 @@ static void VmbusChannelProcessRescindOffer(void *context)
}
/*
- * VmbusChannelOnOffer - Handler for channel offers from vmbus in parent partition.
+ * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
*
* We ignore all offers except network and storage offers. For each network and
* storage offers, we create a channel object and queue a work item to the
* channel object to process the offer synchronously
*/
-static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
+static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_offer_channel *offer;
struct vmbus_channel *newchannel;
@@ -475,7 +476,7 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
guidinstance->data[14], guidinstance->data[15]);
/* Allocate the channel object and save this offer. */
- newchannel = AllocVmbusChannel();
+ newchannel = alloc_channel();
if (!newchannel) {
DPRINT_ERR(VMBUS, "unable to allocate channel object");
return;
@@ -489,16 +490,16 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
newchannel->MonitorBit = (u8)offer->MonitorId % 32;
/* TODO: Make sure the offer comes from our parent partition */
- osd_schedule_callback(newchannel->ControlWQ, VmbusChannelProcessOffer,
+ osd_schedule_callback(newchannel->ControlWQ, vmbus_process_offer,
newchannel);
}
/*
- * VmbusChannelOnOfferRescind - Rescind offer handler.
+ * vmbus_onoffer_rescind - Rescind offer handler.
*
* We queue a work item to process this offer synchronously
*/
-static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
+static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_rescind_offer *rescind;
struct vmbus_channel *channel;
@@ -512,28 +513,29 @@ static void VmbusChannelOnOfferRescind(struct vmbus_channel_message_header *hdr)
}
osd_schedule_callback(channel->ControlWQ,
- VmbusChannelProcessRescindOffer,
+ vmbus_process_rescind_offer,
channel);
}
/*
- * VmbusChannelOnOffersDelivered - This is invoked when all offers have been delivered.
+ * vmbus_onoffers_delivered -
+ * This is invoked when all offers have been delivered.
*
* Nothing to do here.
*/
-static void VmbusChannelOnOffersDelivered(
+static void vmbus_onoffers_delivered(
struct vmbus_channel_message_header *hdr)
{
}
/*
- * VmbusChannelOnOpenResult - Open result handler.
+ * vmbus_onopen_result - Open result handler.
*
* This is invoked when we received a response to our channel open request.
* Find the matching request, copy the response and signal the requesting
* thread.
*/
-static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
+static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_open_result *result;
struct list_head *curr;
@@ -573,13 +575,13 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
}
/*
- * VmbusChannelOnGpadlCreated - GPADL created handler.
+ * vmbus_ongpadl_created - GPADL created handler.
*
* This is invoked when we received a response to our gpadl create request.
* Find the matching request, copy the response and signal the requesting
* thread.
*/
-static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
+static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_gpadl_created *gpadlcreated;
struct list_head *curr;
@@ -623,13 +625,13 @@ static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
}
/*
- * VmbusChannelOnGpadlTorndown - GPADL torndown handler.
+ * vmbus_ongpadl_torndown - GPADL torndown handler.
*
* This is invoked when we received a response to our gpadl teardown request.
* Find the matching request, copy the response and signal the requesting
* thread.
*/
-static void VmbusChannelOnGpadlTorndown(
+static void vmbus_ongpadl_torndown(
struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_gpadl_torndown *gpadl_torndown;
@@ -669,13 +671,13 @@ static void VmbusChannelOnGpadlTorndown(
}
/*
- * VmbusChannelOnVersionResponse - Version response handler
+ * vmbus_onversion_response - Version response handler
*
* This is invoked when we received a response to our initiate contact request.
* Find the matching request, copy the response and signal the requesting
* thread.
*/
-static void VmbusChannelOnVersionResponse(
+static void vmbus_onversion_response(
struct vmbus_channel_message_header *hdr)
{
struct list_head *curr;
@@ -711,30 +713,30 @@ static void VmbusChannelOnVersionResponse(
static struct vmbus_channel_message_table_entry
gChannelMessageTable[ChannelMessageCount] = {
{ChannelMessageInvalid, NULL},
- {ChannelMessageOfferChannel, VmbusChannelOnOffer},
- {ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
+ {ChannelMessageOfferChannel, vmbus_onoffer},
+ {ChannelMessageRescindChannelOffer, vmbus_onoffer_rescind},
{ChannelMessageRequestOffers, NULL},
- {ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
+ {ChannelMessageAllOffersDelivered, vmbus_onoffers_delivered},
{ChannelMessageOpenChannel, NULL},
- {ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
+ {ChannelMessageOpenChannelResult, vmbus_onopen_result},
{ChannelMessageCloseChannel, NULL},
{ChannelMessageGpadlHeader, NULL},
{ChannelMessageGpadlBody, NULL},
- {ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
+ {ChannelMessageGpadlCreated, vmbus_ongpadl_created},
{ChannelMessageGpadlTeardown, NULL},
- {ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
+ {ChannelMessageGpadlTorndown, vmbus_ongpadl_torndown},
{ChannelMessageRelIdReleased, NULL},
{ChannelMessageInitiateContact, NULL},
- {ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
+ {ChannelMessageVersionResponse, vmbus_onversion_response},
{ChannelMessageUnload, NULL},
};
/*
- * VmbusOnChannelMessage - Handler for channel protocol messages.
+ * vmbus_onmessage - Handler for channel protocol messages.
*
* This is invoked in the vmbus worker thread context.
*/
-void VmbusOnChannelMessage(void *context)
+void vmbus_onmessage(void *context)
{
struct hv_message *msg = context;
struct vmbus_channel_message_header *hdr;
@@ -766,9 +768,9 @@ void VmbusOnChannelMessage(void *context)
}
/*
- * VmbusChannelRequestOffers - Send a request to get all our pending offers.
+ * vmbus_request_offers - Send a request to get all our pending offers.
*/
-int VmbusChannelRequestOffers(void)
+int vmbus_request_offers(void)
{
struct vmbus_channel_message_header *msg;
struct vmbus_channel_msginfo *msginfo;
@@ -823,10 +825,10 @@ Cleanup:
}
/*
- * VmbusChannelReleaseUnattachedChannels - Release channels that are
+ * vmbus_release_unattached_channels - Release channels that are
* unattached/unconnected ie (no drivers associated)
*/
-void VmbusChannelReleaseUnattachedChannels(void)
+void vmbus_release_unattached_channels(void)
{
struct vmbus_channel *channel, *pos;
struct vmbus_channel *start = NULL;
@@ -846,7 +848,7 @@ void VmbusChannelReleaseUnattachedChannels(void)
channel->DeviceObject);
VmbusChildDeviceRemove(channel->DeviceObject);
- FreeVmbusChannel(channel);
+ free_channel(channel);
} else {
if (!start)
start = channel;
diff --git a/drivers/staging/hv/channel_mgmt.h b/drivers/staging/hv/channel_mgmt.h
index f969267..b0ed31f 100644
--- a/drivers/staging/hv/channel_mgmt.h
+++ b/drivers/staging/hv/channel_mgmt.h
@@ -307,14 +307,14 @@ struct vmbus_channel_msginfo {
};
-struct vmbus_channel *AllocVmbusChannel(void);
+struct vmbus_channel *alloc_channel(void);
-void FreeVmbusChannel(struct vmbus_channel *Channel);
+void free_channel(struct vmbus_channel *channel);
-void VmbusOnChannelMessage(void *Context);
+void vmbus_onmessage(void *context);
-int VmbusChannelRequestOffers(void);
+int vmbus_request_offers(void);
-void VmbusChannelReleaseUnattachedChannels(void);
+void vmbus_release_unattached_channels(void);
#endif /* _CHANNEL_MGMT_H_ */
diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c
index 0f2e1be..b385e6f 100644
--- a/drivers/staging/hv/vmbus.c
+++ b/drivers/staging/hv/vmbus.c
@@ -57,7 +57,7 @@ static struct hv_device *gDevice; /* vmbus root device */
*/
static void VmbusGetChannelOffers(void)
{
- VmbusChannelRequestOffers();
+ vmbus_request_offers();
}
/*
@@ -134,7 +134,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev)
{
int ret = 0;
- VmbusChannelReleaseUnattachedChannels();
+ vmbus_release_unattached_channels();
VmbusDisconnect();
on_each_cpu(HvSynicCleanup, NULL, 1);
return ret;
@@ -171,7 +171,7 @@ static void VmbusOnMsgDPC(struct hv_driver *drv)
continue;
osd_schedule_callback(gVmbusConnection.WorkQueue,
- VmbusOnChannelMessage,
+ vmbus_onmessage,
(void *)copied);
}
--
1.6.3.2
^ permalink raw reply related
* [PATCH 4/5] staging: hv: Convert camel cased local variable names in channel_mgmt.c to lower case
From: Haiyang Zhang @ 2010-10-15 17:14 UTC (permalink / raw)
To: haiyangz, hjanssen, gregkh, linux-kernel, devel, virtualization
In-Reply-To: <1287162847-27536-3-git-send-email-haiyangz@linuxonhyperv.com>
From: Haiyang Zhang <haiyangz@microsoft.com>
Convert camel cased local variable names in channel_mgmt.c to lower case
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/channel_mgmt.c | 258 +++++++++++++++++++------------------
1 files changed, 133 insertions(+), 125 deletions(-)
diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c
index bdfd5af..7522cfd 100644
--- a/drivers/staging/hv/channel_mgmt.c
+++ b/drivers/staging/hv/channel_mgmt.c
@@ -277,9 +277,9 @@ static inline void ReleaseVmbusChannel(void *context)
/*
* FreeVmbusChannel - Release the resources used by the vmbus channel object
*/
-void FreeVmbusChannel(struct vmbus_channel *Channel)
+void FreeVmbusChannel(struct vmbus_channel *channel)
{
- del_timer_sync(&Channel->poll_timer);
+ del_timer_sync(&channel->poll_timer);
/*
* We have to release the channel's workqueue/thread in the vmbus's
@@ -287,7 +287,7 @@ void FreeVmbusChannel(struct vmbus_channel *Channel)
* ie we can't destroy ourselves.
*/
osd_schedule_callback(gVmbusConnection.WorkQueue, ReleaseVmbusChannel,
- Channel);
+ channel);
}
@@ -315,9 +315,9 @@ static void count_hv_channel(void)
*/
static void VmbusChannelProcessOffer(void *context)
{
- struct vmbus_channel *newChannel = context;
+ struct vmbus_channel *newchannel = context;
struct vmbus_channel *channel;
- bool fNew = true;
+ bool fnew = true;
int ret;
int cnt;
unsigned long flags;
@@ -327,26 +327,26 @@ static void VmbusChannelProcessOffer(void *context)
list_for_each_entry(channel, &gVmbusConnection.ChannelList, ListEntry) {
if (!memcmp(&channel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceType,
+ &newchannel->OfferMsg.Offer.InterfaceType,
sizeof(struct hv_guid)) &&
!memcmp(&channel->OfferMsg.Offer.InterfaceInstance,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
+ &newchannel->OfferMsg.Offer.InterfaceInstance,
sizeof(struct hv_guid))) {
- fNew = false;
+ fnew = false;
break;
}
}
- if (fNew)
- list_add_tail(&newChannel->ListEntry,
+ if (fnew)
+ list_add_tail(&newchannel->ListEntry,
&gVmbusConnection.ChannelList);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
- if (!fNew) {
+ if (!fnew) {
DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)",
- newChannel->OfferMsg.ChildRelId);
- FreeVmbusChannel(newChannel);
+ newchannel->OfferMsg.ChildRelId);
+ FreeVmbusChannel(newchannel);
return;
}
@@ -355,48 +355,48 @@ static void VmbusChannelProcessOffer(void *context)
* We need to set the DeviceObject field before calling
* VmbusChildDeviceAdd()
*/
- newChannel->DeviceObject = VmbusChildDeviceCreate(
- &newChannel->OfferMsg.Offer.InterfaceType,
- &newChannel->OfferMsg.Offer.InterfaceInstance,
- newChannel);
+ newchannel->DeviceObject = VmbusChildDeviceCreate(
+ &newchannel->OfferMsg.Offer.InterfaceType,
+ &newchannel->OfferMsg.Offer.InterfaceInstance,
+ newchannel);
DPRINT_DBG(VMBUS, "child device object allocated - %p",
- newChannel->DeviceObject);
+ newchannel->DeviceObject);
/*
* Add the new device to the bus. This will kick off device-driver
* binding which eventually invokes the device driver's AddDevice()
* method.
*/
- ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
+ ret = VmbusChildDeviceAdd(newchannel->DeviceObject);
if (ret != 0) {
DPRINT_ERR(VMBUS,
"unable to add child device object (relid %d)",
- newChannel->OfferMsg.ChildRelId);
+ newchannel->OfferMsg.ChildRelId);
spin_lock_irqsave(&gVmbusConnection.channel_lock, flags);
- list_del(&newChannel->ListEntry);
+ list_del(&newchannel->ListEntry);
spin_unlock_irqrestore(&gVmbusConnection.channel_lock, flags);
- FreeVmbusChannel(newChannel);
+ FreeVmbusChannel(newchannel);
} else {
/*
* This state is used to indicate a successful open
* so that when we do close the channel normally, we
* can cleanup properly
*/
- newChannel->State = CHANNEL_OPEN_STATE;
+ newchannel->State = CHANNEL_OPEN_STATE;
/* Open IC channels */
for (cnt = 0; cnt < MAX_MSG_TYPES; cnt++) {
- if (memcmp(&newChannel->OfferMsg.Offer.InterfaceType,
+ if (memcmp(&newchannel->OfferMsg.Offer.InterfaceType,
&hv_cb_utils[cnt].data,
sizeof(struct hv_guid)) == 0 &&
- vmbus_open(newChannel, 2 * PAGE_SIZE,
+ vmbus_open(newchannel, 2 * PAGE_SIZE,
2 * PAGE_SIZE, NULL, 0,
hv_cb_utils[cnt].callback,
- newChannel) == 0) {
- hv_cb_utils[cnt].channel = newChannel;
+ newchannel) == 0) {
+ hv_cb_utils[cnt].channel = newchannel;
DPRINT_INFO(VMBUS, "%s",
hv_cb_utils[cnt].log_msg);
count_hv_channel();
@@ -425,29 +425,29 @@ static void VmbusChannelProcessRescindOffer(void *context)
static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_offer_channel *offer;
- struct vmbus_channel *newChannel;
- struct hv_guid *guidType;
- struct hv_guid *guidInstance;
+ struct vmbus_channel *newchannel;
+ struct hv_guid *guidtype;
+ struct hv_guid *guidinstance;
int i;
- int fSupported = 0;
+ int fsupported = 0;
offer = (struct vmbus_channel_offer_channel *)hdr;
for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
if (memcmp(&offer->Offer.InterfaceType,
&gSupportedDeviceClasses[i], sizeof(struct hv_guid)) == 0) {
- fSupported = 1;
+ fsupported = 1;
break;
}
}
- if (!fSupported) {
+ if (!fsupported) {
DPRINT_DBG(VMBUS, "Ignoring channel offer notification for "
"child relid %d", offer->ChildRelId);
return;
}
- guidType = &offer->Offer.InterfaceType;
- guidInstance = &offer->Offer.InterfaceInstance;
+ guidtype = &offer->Offer.InterfaceType;
+ guidinstance = &offer->Offer.InterfaceInstance;
DPRINT_INFO(VMBUS, "Channel offer notification - "
"child relid %d monitor id %d allocated %d, "
@@ -457,40 +457,40 @@ static void VmbusChannelOnOffer(struct vmbus_channel_message_header *hdr)
"%02x%02x%02x%02x%02x%02x%02x%02x}",
offer->ChildRelId, offer->MonitorId,
offer->MonitorAllocated,
- guidType->data[3], guidType->data[2],
- guidType->data[1], guidType->data[0],
- guidType->data[5], guidType->data[4],
- guidType->data[7], guidType->data[6],
- guidType->data[8], guidType->data[9],
- guidType->data[10], guidType->data[11],
- guidType->data[12], guidType->data[13],
- guidType->data[14], guidType->data[15],
- guidInstance->data[3], guidInstance->data[2],
- guidInstance->data[1], guidInstance->data[0],
- guidInstance->data[5], guidInstance->data[4],
- guidInstance->data[7], guidInstance->data[6],
- guidInstance->data[8], guidInstance->data[9],
- guidInstance->data[10], guidInstance->data[11],
- guidInstance->data[12], guidInstance->data[13],
- guidInstance->data[14], guidInstance->data[15]);
+ guidtype->data[3], guidtype->data[2],
+ guidtype->data[1], guidtype->data[0],
+ guidtype->data[5], guidtype->data[4],
+ guidtype->data[7], guidtype->data[6],
+ guidtype->data[8], guidtype->data[9],
+ guidtype->data[10], guidtype->data[11],
+ guidtype->data[12], guidtype->data[13],
+ guidtype->data[14], guidtype->data[15],
+ guidinstance->data[3], guidinstance->data[2],
+ guidinstance->data[1], guidinstance->data[0],
+ guidinstance->data[5], guidinstance->data[4],
+ guidinstance->data[7], guidinstance->data[6],
+ guidinstance->data[8], guidinstance->data[9],
+ guidinstance->data[10], guidinstance->data[11],
+ guidinstance->data[12], guidinstance->data[13],
+ guidinstance->data[14], guidinstance->data[15]);
/* Allocate the channel object and save this offer. */
- newChannel = AllocVmbusChannel();
- if (!newChannel) {
+ newchannel = AllocVmbusChannel();
+ if (!newchannel) {
DPRINT_ERR(VMBUS, "unable to allocate channel object");
return;
}
- DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
+ DPRINT_DBG(VMBUS, "channel object allocated - %p", newchannel);
- memcpy(&newChannel->OfferMsg, offer,
+ memcpy(&newchannel->OfferMsg, offer,
sizeof(struct vmbus_channel_offer_channel));
- newChannel->MonitorGroup = (u8)offer->MonitorId / 32;
- newChannel->MonitorBit = (u8)offer->MonitorId % 32;
+ newchannel->MonitorGroup = (u8)offer->MonitorId / 32;
+ newchannel->MonitorBit = (u8)offer->MonitorId % 32;
/* TODO: Make sure the offer comes from our parent partition */
- osd_schedule_callback(newChannel->ControlWQ, VmbusChannelProcessOffer,
- newChannel);
+ osd_schedule_callback(newchannel->ControlWQ, VmbusChannelProcessOffer,
+ newchannel);
}
/*
@@ -537,9 +537,9 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_open_result *result;
struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_open_channel *openMsg;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_open_channel *openmsg;
unsigned long flags;
result = (struct vmbus_channel_open_result *)hdr;
@@ -552,17 +552,19 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageOpenChannel) {
- openMsg = (struct vmbus_channel_open_channel *)msgInfo->Msg;
- if (openMsg->ChildRelId == result->ChildRelId &&
- openMsg->OpenId == result->OpenId) {
- memcpy(&msgInfo->Response.OpenResult,
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType == ChannelMessageOpenChannel) {
+ openmsg =
+ (struct vmbus_channel_open_channel *)msginfo->Msg;
+ if (openmsg->ChildRelId == result->ChildRelId &&
+ openmsg->OpenId == result->OpenId) {
+ memcpy(&msginfo->Response.OpenResult,
result,
sizeof(struct vmbus_channel_open_result));
- osd_WaitEventSet(msgInfo->WaitEvent);
+ osd_WaitEventSet(msginfo->WaitEvent);
break;
}
}
@@ -579,16 +581,16 @@ static void VmbusChannelOnOpenResult(struct vmbus_channel_message_header *hdr)
*/
static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
{
- struct vmbus_channel_gpadl_created *gpadlCreated;
+ struct vmbus_channel_gpadl_created *gpadlcreated;
struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_header *gpadlHeader;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_header *gpadlheader;
unsigned long flags;
- gpadlCreated = (struct vmbus_channel_gpadl_created *)hdr;
+ gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr;
DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d",
- gpadlCreated->CreationStatus);
+ gpadlcreated->CreationStatus);
/*
* Find the establish msg, copy the result and signal/unblock the wait
@@ -598,19 +600,21 @@ static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
-
- if (requestHeader->MessageType == ChannelMessageGpadlHeader) {
- gpadlHeader = (struct vmbus_channel_gpadl_header *)requestHeader;
-
- if ((gpadlCreated->ChildRelId ==
- gpadlHeader->ChildRelId) &&
- (gpadlCreated->Gpadl == gpadlHeader->Gpadl)) {
- memcpy(&msgInfo->Response.GpadlCreated,
- gpadlCreated,
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
+
+ if (requestheader->MessageType == ChannelMessageGpadlHeader) {
+ gpadlheader =
+ (struct vmbus_channel_gpadl_header *)requestheader;
+
+ if ((gpadlcreated->ChildRelId ==
+ gpadlheader->ChildRelId) &&
+ (gpadlcreated->Gpadl == gpadlheader->Gpadl)) {
+ memcpy(&msginfo->Response.GpadlCreated,
+ gpadlcreated,
sizeof(struct vmbus_channel_gpadl_created));
- osd_WaitEventSet(msgInfo->WaitEvent);
+ osd_WaitEventSet(msginfo->WaitEvent);
break;
}
}
@@ -628,14 +632,14 @@ static void VmbusChannelOnGpadlCreated(struct vmbus_channel_message_header *hdr)
static void VmbusChannelOnGpadlTorndown(
struct vmbus_channel_message_header *hdr)
{
- struct vmbus_channel_gpadl_torndown *gpadlTorndown;
+ struct vmbus_channel_gpadl_torndown *gpadl_torndown;
struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
- struct vmbus_channel_gpadl_teardown *gpadlTeardown;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
+ struct vmbus_channel_gpadl_teardown *gpadl_teardown;
unsigned long flags;
- gpadlTorndown = (struct vmbus_channel_gpadl_torndown *)hdr;
+ gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr;
/*
* Find the open msg, copy the result and signal/unblock the wait event
@@ -644,17 +648,19 @@ static void VmbusChannelOnGpadlTorndown(
list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
- if (requestHeader->MessageType == ChannelMessageGpadlTeardown) {
- gpadlTeardown = (struct vmbus_channel_gpadl_teardown *)requestHeader;
+ if (requestheader->MessageType == ChannelMessageGpadlTeardown) {
+ gpadl_teardown =
+ (struct vmbus_channel_gpadl_teardown *)requestheader;
- if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl) {
- memcpy(&msgInfo->Response.GpadlTorndown,
- gpadlTorndown,
+ if (gpadl_torndown->Gpadl == gpadl_teardown->Gpadl) {
+ memcpy(&msginfo->Response.GpadlTorndown,
+ gpadl_torndown,
sizeof(struct vmbus_channel_gpadl_torndown));
- osd_WaitEventSet(msgInfo->WaitEvent);
+ osd_WaitEventSet(msginfo->WaitEvent);
break;
}
}
@@ -673,27 +679,29 @@ static void VmbusChannelOnVersionResponse(
struct vmbus_channel_message_header *hdr)
{
struct list_head *curr;
- struct vmbus_channel_msginfo *msgInfo;
- struct vmbus_channel_message_header *requestHeader;
+ struct vmbus_channel_msginfo *msginfo;
+ struct vmbus_channel_message_header *requestheader;
struct vmbus_channel_initiate_contact *initiate;
- struct vmbus_channel_version_response *versionResponse;
+ struct vmbus_channel_version_response *version_response;
unsigned long flags;
- versionResponse = (struct vmbus_channel_version_response *)hdr;
+ version_response = (struct vmbus_channel_version_response *)hdr;
spin_lock_irqsave(&gVmbusConnection.channelmsg_lock, flags);
list_for_each(curr, &gVmbusConnection.ChannelMsgList) {
/* FIXME: this should probably use list_entry() instead */
- msgInfo = (struct vmbus_channel_msginfo *)curr;
- requestHeader = (struct vmbus_channel_message_header *)msgInfo->Msg;
+ msginfo = (struct vmbus_channel_msginfo *)curr;
+ requestheader =
+ (struct vmbus_channel_message_header *)msginfo->Msg;
- if (requestHeader->MessageType ==
+ if (requestheader->MessageType ==
ChannelMessageInitiateContact) {
- initiate = (struct vmbus_channel_initiate_contact *)requestHeader;
- memcpy(&msgInfo->Response.VersionResponse,
- versionResponse,
+ initiate =
+ (struct vmbus_channel_initiate_contact *)requestheader;
+ memcpy(&msginfo->Response.VersionResponse,
+ version_response,
sizeof(struct vmbus_channel_version_response));
- osd_WaitEventSet(msgInfo->WaitEvent);
+ osd_WaitEventSet(msginfo->WaitEvent);
}
}
spin_unlock_irqrestore(&gVmbusConnection.channelmsg_lock, flags);
@@ -726,9 +734,9 @@ static struct vmbus_channel_message_table_entry
*
* This is invoked in the vmbus worker thread context.
*/
-void VmbusOnChannelMessage(void *Context)
+void VmbusOnChannelMessage(void *context)
{
- struct hv_message *msg = Context;
+ struct hv_message *msg = context;
struct vmbus_channel_message_header *hdr;
int size;
@@ -763,22 +771,22 @@ void VmbusOnChannelMessage(void *Context)
int VmbusChannelRequestOffers(void)
{
struct vmbus_channel_message_header *msg;
- struct vmbus_channel_msginfo *msgInfo;
+ struct vmbus_channel_msginfo *msginfo;
int ret;
- msgInfo = kmalloc(sizeof(*msgInfo) +
+ msginfo = kmalloc(sizeof(*msginfo) +
sizeof(struct vmbus_channel_message_header),
GFP_KERNEL);
- if (!msgInfo)
+ if (!msginfo)
return -ENOMEM;
- msgInfo->WaitEvent = osd_WaitEventCreate();
- if (!msgInfo->WaitEvent) {
- kfree(msgInfo);
+ msginfo->WaitEvent = osd_WaitEventCreate();
+ if (!msginfo->WaitEvent) {
+ kfree(msginfo);
return -ENOMEM;
}
- msg = (struct vmbus_channel_message_header *)msgInfo->Msg;
+ msg = (struct vmbus_channel_message_header *)msginfo->Msg;
msg->MessageType = ChannelMessageRequestOffers;
@@ -806,9 +814,9 @@ int VmbusChannelRequestOffers(void)
Cleanup:
- if (msgInfo) {
- kfree(msgInfo->WaitEvent);
- kfree(msgInfo);
+ if (msginfo) {
+ kfree(msginfo->WaitEvent);
+ kfree(msginfo);
}
return ret;
--
1.6.3.2
^ permalink raw reply related
* [PATCH 3/5] staging: hv: Convert camel cased parameter in channel_interface.h to lower case
From: Haiyang Zhang @ 2010-10-15 17:14 UTC (permalink / raw)
To: haiyangz, hjanssen, gregkh, linux-kernel, devel, virtualization
In-Reply-To: <1287162847-27536-2-git-send-email-haiyangz@linuxonhyperv.com>
From: Haiyang Zhang <haiyangz@microsoft.com>
Convert camel cased parameter in channel_interface.h to lower case
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/channel_interface.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/hv/channel_interface.h b/drivers/staging/hv/channel_interface.h
index 1007612..82cff3d 100644
--- a/drivers/staging/hv/channel_interface.h
+++ b/drivers/staging/hv/channel_interface.h
@@ -27,7 +27,7 @@
#include "vmbus_api.h"
-void get_channel_info(struct hv_device *Device,
- struct hv_device_info *DeviceInfo);
+void get_channel_info(struct hv_device *device,
+ struct hv_device_info *info);
#endif /* _CHANNEL_INTERFACE_H_ */
--
1.6.3.2
^ permalink raw reply related
* [PATCH 2/5] staging: hv: Convert camel cased function names in channel_interface.c to lower cases
From: Haiyang Zhang @ 2010-10-15 17:14 UTC (permalink / raw)
To: haiyangz, hjanssen, gregkh, linux-kernel, devel, virtualization
In-Reply-To: <1287162847-27536-1-git-send-email-haiyangz@linuxonhyperv.com>
From: Haiyang Zhang <haiyangz@microsoft.com>
Convert camel cased function names in channel_interface.c to lower cases
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/channel_interface.c | 40 ++++++++++++++++----------------
drivers/staging/hv/channel_interface.h | 2 +-
drivers/staging/hv/vmbus.c | 2 +-
3 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/drivers/staging/hv/channel_interface.c b/drivers/staging/hv/channel_interface.c
index d9d345e..abd7f7f 100644
--- a/drivers/staging/hv/channel_interface.c
+++ b/drivers/staging/hv/channel_interface.c
@@ -25,7 +25,7 @@
#include "osd.h"
#include "vmbus_private.h"
-static int IVmbusChannelOpen(struct hv_device *device, u32 sendbuffer_size,
+static int ivmbus_open(struct hv_device *device, u32 sendbuffer_size,
u32 recv_ringbuffer_size, void *userdata,
u32 userdatalen,
void (*channel_callback)(void *context),
@@ -36,12 +36,12 @@ static int IVmbusChannelOpen(struct hv_device *device, u32 sendbuffer_size,
channel_callback, context);
}
-static void IVmbusChannelClose(struct hv_device *device)
+static void ivmbus_close(struct hv_device *device)
{
vmbus_close(device->context);
}
-static int IVmbusChannelSendPacket(struct hv_device *device, const void *buffer,
+static int ivmbus_sendpacket(struct hv_device *device, const void *buffer,
u32 bufferlen, u64 requestid, u32 type,
u32 flags)
{
@@ -49,7 +49,7 @@ static int IVmbusChannelSendPacket(struct hv_device *device, const void *buffer,
requestid, type, flags);
}
-static int IVmbusChannelSendPacketPageBuffer(struct hv_device *device,
+static int ivmbus_sendpacket_pagebuffer(struct hv_device *device,
struct hv_page_buffer pagebuffers[],
u32 pagecount, void *buffer,
u32 bufferlen, u64 requestid)
@@ -59,7 +59,7 @@ static int IVmbusChannelSendPacketPageBuffer(struct hv_device *device,
requestid);
}
-static int IVmbusChannelSendPacketMultiPageBuffer(struct hv_device *device,
+static int ivmbus_sendpacket_multipagebuffer(struct hv_device *device,
struct hv_multipage_buffer *multi_pagebuffer,
void *buffer, u32 bufferlen, u64 requestid)
{
@@ -68,7 +68,7 @@ static int IVmbusChannelSendPacketMultiPageBuffer(struct hv_device *device,
bufferlen, requestid);
}
-static int IVmbusChannelRecvPacket(struct hv_device *device, void *buffer,
+static int ivmbus_recvpacket(struct hv_device *device, void *buffer,
u32 bufferlen, u32 *buffer_actuallen,
u64 *requestid)
{
@@ -76,7 +76,7 @@ static int IVmbusChannelRecvPacket(struct hv_device *device, void *buffer,
buffer_actuallen, requestid);
}
-static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *buffer,
+static int ivmbus_recvpacket_raw(struct hv_device *device, void *buffer,
u32 bufferlen, u32 *buffer_actuallen,
u64 *requestid)
{
@@ -84,14 +84,14 @@ static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *buffer,
buffer_actuallen, requestid);
}
-static int IVmbusChannelEstablishGpadl(struct hv_device *device, void *buffer,
+static int ivmbus_establish_gpadl(struct hv_device *device, void *buffer,
u32 bufferlen, u32 *gpadl_handle)
{
return vmbus_establish_gpadl(device->context, buffer, bufferlen,
gpadl_handle);
}
-static int IVmbusChannelTeardownGpadl(struct hv_device *device,
+static int ivmbus_teardown_gpadl(struct hv_device *device,
u32 gpadl_handle)
{
return vmbus_teardown_gpadl(device->context, gpadl_handle);
@@ -99,7 +99,7 @@ static int IVmbusChannelTeardownGpadl(struct hv_device *device,
}
-void GetChannelInfo(struct hv_device *device, struct hv_device_info *info)
+void get_channel_info(struct hv_device *device, struct hv_device_info *info)
{
struct vmbus_channel_debug_info debug_info;
@@ -142,14 +142,14 @@ void GetChannelInfo(struct hv_device *device, struct hv_device_info *info)
/* vmbus interface function pointer table */
const struct vmbus_channel_interface vmbus_ops = {
- .Open = IVmbusChannelOpen,
- .Close = IVmbusChannelClose,
- .SendPacket = IVmbusChannelSendPacket,
- .SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer,
- .SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer,
- .RecvPacket = IVmbusChannelRecvPacket,
- .RecvPacketRaw = IVmbusChannelRecvPacketRaw,
- .EstablishGpadl = IVmbusChannelEstablishGpadl,
- .TeardownGpadl = IVmbusChannelTeardownGpadl,
- .GetInfo = GetChannelInfo,
+ .Open = ivmbus_open,
+ .Close = ivmbus_close,
+ .SendPacket = ivmbus_sendpacket,
+ .SendPacketPageBuffer = ivmbus_sendpacket_pagebuffer,
+ .SendPacketMultiPageBuffer = ivmbus_sendpacket_multipagebuffer,
+ .RecvPacket = ivmbus_recvpacket,
+ .RecvPacketRaw = ivmbus_recvpacket_raw,
+ .EstablishGpadl = ivmbus_establish_gpadl,
+ .TeardownGpadl = ivmbus_teardown_gpadl,
+ .GetInfo = get_channel_info,
};
diff --git a/drivers/staging/hv/channel_interface.h b/drivers/staging/hv/channel_interface.h
index ec88219..1007612 100644
--- a/drivers/staging/hv/channel_interface.h
+++ b/drivers/staging/hv/channel_interface.h
@@ -27,7 +27,7 @@
#include "vmbus_api.h"
-void GetChannelInfo(struct hv_device *Device,
+void get_channel_info(struct hv_device *Device,
struct hv_device_info *DeviceInfo);
#endif /* _CHANNEL_INTERFACE_H_ */
diff --git a/drivers/staging/hv/vmbus.c b/drivers/staging/hv/vmbus.c
index ea2698c..0f2e1be 100644
--- a/drivers/staging/hv/vmbus.c
+++ b/drivers/staging/hv/vmbus.c
@@ -66,7 +66,7 @@ static void VmbusGetChannelOffers(void)
static void VmbusGetChannelInfo(struct hv_device *DeviceObject,
struct hv_device_info *DeviceInfo)
{
- GetChannelInfo(DeviceObject, DeviceInfo);
+ get_channel_info(DeviceObject, DeviceInfo);
}
/*
--
1.6.3.2
^ permalink raw reply related
* [PATCH 1/5] staging: hv: Convert camel cased local variables in channel_interface.c to lower cases
From: Haiyang Zhang @ 2010-10-15 17:14 UTC (permalink / raw)
To: haiyangz, hjanssen, gregkh, linux-kernel, devel, virtualization
From: Haiyang Zhang <haiyangz@microsoft.com>
Convert camel cased local variables in channel_interface.c to lower cases
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/channel_interface.c | 126 ++++++++++++++++----------------
1 files changed, 64 insertions(+), 62 deletions(-)
diff --git a/drivers/staging/hv/channel_interface.c b/drivers/staging/hv/channel_interface.c
index 4d35923..d9d345e 100644
--- a/drivers/staging/hv/channel_interface.c
+++ b/drivers/staging/hv/channel_interface.c
@@ -25,15 +25,15 @@
#include "osd.h"
#include "vmbus_private.h"
-static int IVmbusChannelOpen(struct hv_device *device, u32 SendBufferSize,
- u32 RecvRingBufferSize, void *UserData,
- u32 UserDataLen,
- void (*ChannelCallback)(void *context),
- void *Context)
+static int IVmbusChannelOpen(struct hv_device *device, u32 sendbuffer_size,
+ u32 recv_ringbuffer_size, void *userdata,
+ u32 userdatalen,
+ void (*channel_callback)(void *context),
+ void *context)
{
- return vmbus_open(device->context, SendBufferSize,
- RecvRingBufferSize, UserData, UserDataLen,
- ChannelCallback, Context);
+ return vmbus_open(device->context, sendbuffer_size,
+ recv_ringbuffer_size, userdata, userdatalen,
+ channel_callback, context);
}
static void IVmbusChannelClose(struct hv_device *device)
@@ -41,100 +41,102 @@ static void IVmbusChannelClose(struct hv_device *device)
vmbus_close(device->context);
}
-static int IVmbusChannelSendPacket(struct hv_device *device, const void *Buffer,
- u32 BufferLen, u64 RequestId, u32 Type,
- u32 Flags)
+static int IVmbusChannelSendPacket(struct hv_device *device, const void *buffer,
+ u32 bufferlen, u64 requestid, u32 type,
+ u32 flags)
{
- return vmbus_sendpacket(device->context, Buffer, BufferLen,
- RequestId, Type, Flags);
+ return vmbus_sendpacket(device->context, buffer, bufferlen,
+ requestid, type, flags);
}
static int IVmbusChannelSendPacketPageBuffer(struct hv_device *device,
- struct hv_page_buffer PageBuffers[],
- u32 PageCount, void *Buffer,
- u32 BufferLen, u64 RequestId)
+ struct hv_page_buffer pagebuffers[],
+ u32 pagecount, void *buffer,
+ u32 bufferlen, u64 requestid)
{
- return vmbus_sendpacket_pagebuffer(device->context, PageBuffers,
- PageCount, Buffer, BufferLen,
- RequestId);
+ return vmbus_sendpacket_pagebuffer(device->context, pagebuffers,
+ pagecount, buffer, bufferlen,
+ requestid);
}
static int IVmbusChannelSendPacketMultiPageBuffer(struct hv_device *device,
- struct hv_multipage_buffer *MultiPageBuffer,
- void *Buffer, u32 BufferLen, u64 RequestId)
+ struct hv_multipage_buffer *multi_pagebuffer,
+ void *buffer, u32 bufferlen, u64 requestid)
{
return vmbus_sendpacket_multipagebuffer(device->context,
- MultiPageBuffer, Buffer,
- BufferLen, RequestId);
+ multi_pagebuffer, buffer,
+ bufferlen, requestid);
}
-static int IVmbusChannelRecvPacket(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
+static int IVmbusChannelRecvPacket(struct hv_device *device, void *buffer,
+ u32 bufferlen, u32 *buffer_actuallen,
+ u64 *requestid)
{
- return vmbus_recvpacket(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
+ return vmbus_recvpacket(device->context, buffer, bufferlen,
+ buffer_actuallen, requestid);
}
-static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *BufferActualLen,
- u64 *RequestId)
+static int IVmbusChannelRecvPacketRaw(struct hv_device *device, void *buffer,
+ u32 bufferlen, u32 *buffer_actuallen,
+ u64 *requestid)
{
- return vmbus_recvpacket_raw(device->context, Buffer, BufferLen,
- BufferActualLen, RequestId);
+ return vmbus_recvpacket_raw(device->context, buffer, bufferlen,
+ buffer_actuallen, requestid);
}
-static int IVmbusChannelEstablishGpadl(struct hv_device *device, void *Buffer,
- u32 BufferLen, u32 *GpadlHandle)
+static int IVmbusChannelEstablishGpadl(struct hv_device *device, void *buffer,
+ u32 bufferlen, u32 *gpadl_handle)
{
- return vmbus_establish_gpadl(device->context, Buffer, BufferLen,
- GpadlHandle);
+ return vmbus_establish_gpadl(device->context, buffer, bufferlen,
+ gpadl_handle);
}
-static int IVmbusChannelTeardownGpadl(struct hv_device *device, u32 GpadlHandle)
+static int IVmbusChannelTeardownGpadl(struct hv_device *device,
+ u32 gpadl_handle)
{
- return vmbus_teardown_gpadl(device->context, GpadlHandle);
+ return vmbus_teardown_gpadl(device->context, gpadl_handle);
}
void GetChannelInfo(struct hv_device *device, struct hv_device_info *info)
{
- struct vmbus_channel_debug_info debugInfo;
+ struct vmbus_channel_debug_info debug_info;
if (!device->context)
return;
- vmbus_get_debug_info(device->context, &debugInfo);
+ vmbus_get_debug_info(device->context, &debug_info);
- info->ChannelId = debugInfo.RelId;
- info->ChannelState = debugInfo.State;
- memcpy(&info->ChannelType, &debugInfo.InterfaceType,
+ info->ChannelId = debug_info.RelId;
+ info->ChannelState = debug_info.State;
+ memcpy(&info->ChannelType, &debug_info.InterfaceType,
sizeof(struct hv_guid));
- memcpy(&info->ChannelInstance, &debugInfo.InterfaceInstance,
+ memcpy(&info->ChannelInstance, &debug_info.InterfaceInstance,
sizeof(struct hv_guid));
- info->MonitorId = debugInfo.MonitorId;
+ info->MonitorId = debug_info.MonitorId;
- info->ServerMonitorPending = debugInfo.ServerMonitorPending;
- info->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
- info->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
+ info->ServerMonitorPending = debug_info.ServerMonitorPending;
+ info->ServerMonitorLatency = debug_info.ServerMonitorLatency;
+ info->ServerMonitorConnectionId = debug_info.ServerMonitorConnectionId;
- info->ClientMonitorPending = debugInfo.ClientMonitorPending;
- info->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
- info->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
+ info->ClientMonitorPending = debug_info.ClientMonitorPending;
+ info->ClientMonitorLatency = debug_info.ClientMonitorLatency;
+ info->ClientMonitorConnectionId = debug_info.ClientMonitorConnectionId;
- info->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
- info->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
- info->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
- info->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
- info->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
+ info->Inbound.InterruptMask = debug_info.Inbound.CurrentInterruptMask;
+ info->Inbound.ReadIndex = debug_info.Inbound.CurrentReadIndex;
+ info->Inbound.WriteIndex = debug_info.Inbound.CurrentWriteIndex;
+ info->Inbound.BytesAvailToRead = debug_info.Inbound.BytesAvailToRead;
+ info->Inbound.BytesAvailToWrite = debug_info.Inbound.BytesAvailToWrite;
- info->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
- info->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
- info->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
- info->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
- info->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
+ info->Outbound.InterruptMask = debug_info.Outbound.CurrentInterruptMask;
+ info->Outbound.ReadIndex = debug_info.Outbound.CurrentReadIndex;
+ info->Outbound.WriteIndex = debug_info.Outbound.CurrentWriteIndex;
+ info->Outbound.BytesAvailToRead = debug_info.Outbound.BytesAvailToRead;
+ info->Outbound.BytesAvailToWrite =
+ debug_info.Outbound.BytesAvailToWrite;
}
--
1.6.3.2
^ permalink raw reply related
* Re: netlink versus pid namespaces
From: Andi Kleen @ 2010-10-15 15:23 UTC (permalink / raw)
To: Alexey Kuznetsov; +Cc: netdev, Andi Kleen, virtualization, xemul
In-Reply-To: <20101015151903.GA3487@ms2.inr.ac.ru>
On Fri, Oct 15, 2010 at 07:19:03PM +0400, Alexey Kuznetsov wrote:
> Hello!
>
> > netlink uses pids (or really tids I hope?) to address sockets
> > associated with processes.
>
> Not really. It uses port number which is called "pid" occasionally. Bad name.
> Autobind function simply selects tgid of calling process as the first guess.
Thanks for the clarification, Alexey. I guess I should have read more
code :/
-Andi
^ permalink raw reply
* Re: netlink versus pid namespaces
From: Alexey Kuznetsov @ 2010-10-15 15:19 UTC (permalink / raw)
To: Andi Kleen; +Cc: netdev, virtualization, xemul
In-Reply-To: <20101015142357.GA29321@basil.fritz.box>
Hello!
> netlink uses pids (or really tids I hope?) to address sockets
> associated with processes.
Not really. It uses port number which is called "pid" occasionally. Bad name.
Autobind function simply selects tgid of calling process as the first guess.
Actually sockets are addressed by pair (net namespace, port) and
communication is possible only inside net namespace. So, communication
between namespaces is already prohibited.
pid namespaces do not participate in the picture at all.
Alexey
^ permalink raw reply
* netlink versus pid namespaces
From: Andi Kleen @ 2010-10-15 14:23 UTC (permalink / raw)
To: netdev, xemul, kuznet, virtualization
Hi,
I have been trying to figure out how pid namespaces interact
with netlink.
netlink uses pids (or really tids I hope?) to address sockets
associated with processes.
The netlink code passes around pids without caring much about
the pid namespace. It does pass around some information about the
network namespace, but that doesn't help here because the pid
namespace is not necessarily related to the net namespace.
When the netlink consumer runs in kernel (like rtnetlink) and
happens to run in the same process context while receiving
and processing the data it should do the right thing because
it has the same pid namespace.
If it runs in some other process that is not guaranteed and
it may actually send the reply back to the wrong pid.
When a process receives netlink in user space and it isn't
in the same pid space as the sender it is unlikely that
the reply gets back.
Anything I'm missing here?
Does netlink need to be extended?
Or perhaps forbid passing netlink between name spaces?
Thanks,
-Andi
--
ak@linux.intel.com -- Speaking for myself only.
^ permalink raw reply
* Re: [E1000-eedc] [PATCH 4/9] implementation of IEEE 802.1Qbg in lldpad, part 2
From: Jens Osterkamp @ 2010-10-13 15:03 UTC (permalink / raw)
To: John Fastabend
Cc: chrisw@redhat.com, evb@yahoogroups.com,
e1000-eedc@lists.sourceforge.net,
virtualization@lists.linux-foundation.org
In-Reply-To: <4CB4A3A9.2060800@intel.com>
On Tuesday 12 October 2010, John Fastabend wrote:
> On 9/28/2010 8:10 AM, Jens Osterkamp wrote:
> > This is the implementation of the edge control protocol (ECP) and VSI
> > discovery protocol (VDP) currently being specified in IEEE 802.1Qbg.
> >
> > This implementation extends the infrastructure defined lldpad to send and
> > receive ECP frames with a new (yet to be defined) ethertype.
> > Received frames are validated and analyzed before the content is handed to the
> > upper layer protocol (ULP, VDP in this case) for further processing. Frames
> > to be transmitted are compiled from VSI (guest interface) profiles registered
> > on a interface.
> > Reception and transmission of ECP frames is controlled by RX and TX state
> > machines, timeouts are handled timeout functions.
> > The patch still contains a lot of debug code to allow low-level protocol
> > analysis.
> >
> > VDP serves as the upper layer protocol (ULP) for TLVs communicated via the
> > ECP protocol.
> > For this it registers as a new module in lldpad. The VDP module supports a
> > station and a bridge role. As a station, new VSI (virtual station interface)
> > profiles can be registered to the VDP module using lldptool or libvirt.
> > These profiles are then announced to an adjacent switch. Transmitted profiles
> > are processed to the desired state by the VDP station state machine.
> > As a bridge, the VDP module waits for new profiles received in TLVs by ECP.
> > The received profiles are processed to the desired state by a VDP bridge
> > state machine.
> >
> > VDP module parameters are stored in the "vdp" section under the appropriate
> > interface.
> >
> > The patch still contains a lot of debug code to allow analysis of VDP
> > protocol behavior.
> >
> > Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
> > ---
> > Makefile.am | 10 +-
> > ecp/ecp.c | 79 ++++
> > ecp/ecp.h | 101 +++++
> > ecp/ecp_rx.c | 599 ++++++++++++++++++++++++++
> > ecp/ecp_tx.c | 494 ++++++++++++++++++++++
> > include/lldp.h | 1 +
> > include/lldp_evb.h | 6 +
> > include/lldp_vdp.h | 159 +++++++
> > lldp/l2_packet.h | 2 +
> > lldp/ports.h | 11 +-
> > lldp_vdp.c | 1185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > lldpad.c | 2 +
> > 12 files changed, 2642 insertions(+), 7 deletions(-)
> > create mode 100644 ecp/ecp.c
> > create mode 100644 ecp/ecp.h
> > create mode 100644 ecp/ecp_rx.c
> > create mode 100644 ecp/ecp_tx.c
> > create mode 100644 include/lldp_vdp.h
> > create mode 100644 lldp_vdp.c
> >
[snip]
> > + return false;
> > + case ECP_RX_RECEIVE_ECPDU:
> > + if (vd->ecp.seqECPDU == vd->ecp.lastSequence) {
> > + printf("%s(%i):-(%s) seqECPDU %x, lastSequence %x\n", __func__, __LINE__,
> > + vd->ifname, vd->ecp.seqECPDU, vd->ecp.lastSequence);
> > + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> > + return true;
> > + }
> > + if (vd->ecp.seqECPDU != vd->ecp.lastSequence) {
> > + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> > + return true;
> > + }
> > + return false;
> > + case ECP_RX_SEND_ACK:
>
> How can we get to this state? Did I miss something or could the ECP_RX_SEND_ACK and ECP_RX_RESEND_ACK states be combined or ECP_RX_SEND_ACK removed outright?
Yep, can be combined but not entirely removed because different actions need to be taken for both states according to draft. Fixed in my next series.
>
> > + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> > + return false;
> > + case ECP_RX_RESEND_ACK:
> > + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> > + return false;
> > + default:
> > + printf("ERROR: The ECP_RX State Machine is broken!\n");
> > + log_message(MSG_ERR_RX_SM_INVALID, "%s", vd->ifname);
> > + return false;
[snip]
> > + if ((ptlv->size+fb_offset) > ETH_MAX_DATA_LEN)
> > + goto error;
> > + memcpy(vd->ecp.tx.frameout+fb_offset,
> > + ptlv->tlv, ptlv->size);
> > + datasize += ptlv->size;
> > + fb_offset += ptlv->size;
>
> I think the ptlv needs to be free'd here? Else where is it getting free'd.
Fixed in my next series.
>
> > + }
> > + }
> > +
> > + /* The End TLV marks the end of the LLDP PDU */
> > + ptlv = pack_end_tlv();
> > + if (!ptlv || ((ptlv->size + fb_offset) > ETH_MAX_DATA_LEN))
> > + goto error;
> > + memcpy(vd->ecp.tx.frameout + fb_offset, ptlv->tlv, ptlv->size);
> > + datasize += ptlv->size;
> > + fb_offset += ptlv->size;
> > + ptlv = free_pkd_tlv(ptlv);
> > +
> > + if (datasize > ETH_MAX_DATA_LEN)
[snip]
> > +
> > + memset(vdp, 0, sizeof(struct tlv_info_vdp));
> > + memcpy(vdp, tlv->info, tlv->length);
> > +
> > + if (vdp_validate_tlv(vdp)) {
> > + printf("%s(%i): Invalid TLV received !\n", __func__, __LINE__);
> > + goto out_err;
>
> Should be goto out_vdp
Fixed.
>
> > + }
> > +
> > + profile = malloc(sizeof(struct vsi_profile));
> > +
> > + if (!profile) {
> > + printf("%s(%i): unable to allocate profile !\n", __func__, __LINE__);
> > + goto out_vdp;
> > + }
> > +
> > + memset(profile, 0, sizeof(struct vsi_profile));
> > +
> > + profile->mode = vdp->mode;
> > + profile->response = vdp->response;
> > +
> > + profile->mgrid = vdp->mgrid;
> > + profile->id = ntoh24(vdp->id);
> > + profile->version = vdp->version;
> > + memcpy(&profile->instance, &vdp->instance, 16);
> > + memcpy(&profile->mac, &vdp->mac_vlan.mac, MAC_ADDR_LEN);
> > + profile->vlan = ntohs(vdp->mac_vlan.vlan);
> > +
> > + profile->port = port;
> > +
> > + if (vd->role == VDP_ROLE_STATION) {
> > + /* do we have the profile already ? */
> > + LIST_FOREACH(p, &vd->profile_head, profile) {
> > + if (vdp_profile_equal(p, profile)) {
> > + printf("%s(%i): station: profile found, localChange %i ackReceived %i!\n",
> > + __func__, __LINE__, p->localChange, p->ackReceived);
> > +
> > + p->ackReceived = true;
> > +
> > + vdp_vsi_sm_station(p);
> > + } else {
> > + printf("%s(%i): station: profile not found !\n", __func__, __LINE__);
> > + /* ignore profile */
> > + }
> > + }
> > + }
> > +
> > + if (vd->role == VDP_ROLE_BRIDGE) {
> > + /* do we have the profile already ? */
> > + LIST_FOREACH(p, &vd->profile_head, profile) {
> > + if (vdp_profile_equal(p, profile)) {
> > + break;
> > + }
> > + }
> > +
> > + if (p) {
> > + printf("%s(%i): bridge: profile found !\n", __func__, __LINE__);
> > + } else {
> > + printf("%s(%i): bridge: profile not found !\n", __func__, __LINE__);
> > + /* put it in the list */
> > + profile->state = VSI_UNASSOCIATED;
> > + LIST_INSERT_HEAD(&vd->profile_head, profile, profile );
> > + }
> > +
> > + vdp_vsi_sm_bridge(profile);
> > + }
> > +
>
>
> Here the profile is added to a list if the port is in the VDP_ROLE_BRIDGE mode. Otherwise the profile is only used to lookup an existing profile? Looks like there might be a memory leak if the profile already exists. Does the profile need to be cleaned up the somewhere?
The standard is not clear on what to with profiles that e.g. have been deassociated or have reached VSI_EXIT. In my next series I have added code to remove the profile in the VSI_EXIT case.
>
> > + return 0;
> > +
> > +out_vdp:
> > + free(vdp);
> > +out_err:
> > + printf("%s(%i): error !\n", __func__, __LINE__);
> > + return 1;
> > +
> > +}
>
>
> The rest looks good.
Thanks ! I will post a new series soon.
Jens
--
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
^ permalink raw reply
* Re: [E1000-eedc] [PATCH 2/9] implementation of IEEE 802.1Qbg in lldpad, part 1
From: Jens Osterkamp @ 2010-10-13 14:40 UTC (permalink / raw)
To: John Fastabend
Cc: chrisw@redhat.com, evb@yahoogroups.com, e1000-eedc,
virtualization@lists.linux-foundation.org
In-Reply-To: <4CB4A368.3030408@intel.com>
On Tuesday 12 October 2010, John Fastabend wrote:
> On 9/28/2010 8:10 AM, Jens Osterkamp wrote:
> > This patch contains the first part of an initial implementation of the
> > IEEE 802.1Qbg standard: it implements code for the exchange of EVB
> > capabilities between a host with virtual machines and an adjacent switch.
> > For this it adds a new EVB TLV to LLDP.
> >
> > Exchange of EVB TLV may be enabled or disabled on a per port basis.
> > Information about the information negotiated by the protocol can be
> > queried on the commandline with lldptool.
> >
> > This patch adds support for querying and setting parameters used in
> > the exchange of EVB TLV messages.
> > The parameters that can be set are:
> >
> > - forwarding mode
> > - host protocol capabilities (RTE, ECP, VDP)
> > - no. of supported VSIs
> > - retransmission timer exponent (RTE)
> >
> > The parameters are implemented as a local policy: all frames received by
> > an adjacent switch are validated against this policy and taken over where
> > appropriate. Negotiated parameters are stored in lldpads config, picked up
> > again and used at the next start.
> >
> > The patch applies to lldpad 0.9.38 and still contains code to log protocol
> > activity more verbosely than it would be necessary in the final version.
> >
> > Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
> > ---
> > Makefile.am | 10 +-
> > include/lldp.h | 19 ++
> > include/lldp_evb.h | 80 ++++++
> > include/lldp_evb_clif.h | 51 ++++
> > include/lldp_evb_cmds.h | 31 +++
> > include/lldp_tlv.h | 1 +
> > lldp_evb.c | 638 +++++++++++++++++++++++++++++++++++++++++++++++
> > lldp_evb_clif.c | 226 +++++++++++++++++
> > lldp_evb_cmds.c | 512 +++++++++++++++++++++++++++++++++++++
> > lldpad.c | 2 +
> > lldptool.c | 2 +
> > 11 files changed, 1568 insertions(+), 4 deletions(-)
> > create mode 100644 include/lldp_evb.h
> > create mode 100644 include/lldp_evb_clif.h
> > create mode 100644 include/lldp_evb_cmds.h
> > create mode 100644 lldp_evb.c
> > create mode 100644 lldp_evb_clif.c
> > create mode 100644 lldp_evb_cmds.c
> >
[snip]
> > +void evb_ifup(char *ifname)
> > +{
> > + struct evb_data *ed;
> > + struct evb_user_data *ud;
> > +
> > + ed = evb_data(ifname);
> > + if (ed) {
> > + fprintf(stderr, "### %s:%s exists\n", __func__, ifname);
> > + goto out_err;
> > + }
> > +
> > + /* not found, alloc/init per-port tlv data */
> > + ed = (struct evb_data *) calloc(1, sizeof(struct evb_data));
> > + if (!ed) {
> > + fprintf(stderr, "### %s:%s malloc %ld failed\n",
> > + __func__, ifname, sizeof(*ed));
> > + goto out_err;
> > + }
> > + strncpy(ed->ifname, ifname, IFNAMSIZ);
> > +
> > + if (!init_cfg()) {
> > + fprintf(stderr, "### %s:%s init_cfg failed\n", __func__, ifname);
>
> Need to free(ed) here too it looks like. Otherwise looks good.
Thank you for spotting this ! I fixed it in my code and will include it my next posting of the series.
Jens
--
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
^ permalink raw reply
* Re: [E1000-eedc] [PATCH 4/9] implementation of IEEE 802.1Qbg in lldpad, part 2
From: John Fastabend @ 2010-10-12 18:06 UTC (permalink / raw)
To: Jens Osterkamp
Cc: chrisw@redhat.com, evb@yahoogroups.com,
e1000-eedc@lists.sourceforge.net,
virtualization@lists.linux-foundation.org
In-Reply-To: <1285686662-8561-5-git-send-email-jens@linux.vnet.ibm.com>
On 9/28/2010 8:10 AM, Jens Osterkamp wrote:
> This is the implementation of the edge control protocol (ECP) and VSI
> discovery protocol (VDP) currently being specified in IEEE 802.1Qbg.
>
> This implementation extends the infrastructure defined lldpad to send and
> receive ECP frames with a new (yet to be defined) ethertype.
> Received frames are validated and analyzed before the content is handed to the
> upper layer protocol (ULP, VDP in this case) for further processing. Frames
> to be transmitted are compiled from VSI (guest interface) profiles registered
> on a interface.
> Reception and transmission of ECP frames is controlled by RX and TX state
> machines, timeouts are handled timeout functions.
> The patch still contains a lot of debug code to allow low-level protocol
> analysis.
>
> VDP serves as the upper layer protocol (ULP) for TLVs communicated via the
> ECP protocol.
> For this it registers as a new module in lldpad. The VDP module supports a
> station and a bridge role. As a station, new VSI (virtual station interface)
> profiles can be registered to the VDP module using lldptool or libvirt.
> These profiles are then announced to an adjacent switch. Transmitted profiles
> are processed to the desired state by the VDP station state machine.
> As a bridge, the VDP module waits for new profiles received in TLVs by ECP.
> The received profiles are processed to the desired state by a VDP bridge
> state machine.
>
> VDP module parameters are stored in the "vdp" section under the appropriate
> interface.
>
> The patch still contains a lot of debug code to allow analysis of VDP
> protocol behavior.
>
> Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
> ---
> Makefile.am | 10 +-
> ecp/ecp.c | 79 ++++
> ecp/ecp.h | 101 +++++
> ecp/ecp_rx.c | 599 ++++++++++++++++++++++++++
> ecp/ecp_tx.c | 494 ++++++++++++++++++++++
> include/lldp.h | 1 +
> include/lldp_evb.h | 6 +
> include/lldp_vdp.h | 159 +++++++
> lldp/l2_packet.h | 2 +
> lldp/ports.h | 11 +-
> lldp_vdp.c | 1185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> lldpad.c | 2 +
> 12 files changed, 2642 insertions(+), 7 deletions(-)
> create mode 100644 ecp/ecp.c
> create mode 100644 ecp/ecp.h
> create mode 100644 ecp/ecp_rx.c
> create mode 100644 ecp/ecp_tx.c
> create mode 100644 include/lldp_vdp.h
> create mode 100644 lldp_vdp.c
>
> diff --git a/Makefile.am b/Makefile.am
> index d59a6fa..4b69389 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -56,6 +56,8 @@ $(lldpad_include_HEADERS) $(noinst_HEADERS) \
> lldp/ports.c lldp/agent.c lldp/l2_packet_linux.c lldp/tx.c \
> lldp/rx.c lldp/agent.h lldp/l2_packet.h lldp/mibdata.h lldp/ports.h \
> lldp/states.h \
> +ecp/ecp.c ecp/ecp_tx.c \
> +ecp/ecp_rx.c \
> include/lldp.h include/lldp_mod.h \
> lldp_dcbx.c include/lldp_dcbx.h tlv_dcbx.c include/tlv_dcbx.h \
> lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h \
> @@ -67,16 +69,16 @@ lldp_tlv.c include/lldp_tlv.h \
> lldp_basman.c include/lldp_basman.h \
> lldp_med.c include/lldp_med.h \
> lldp_8023.c include/lldp_8023.h \
> -lldp_evb.c include/lldp_evb.h
> -
> -
> +lldp_evb.c include/lldp_evb.h \
> +lldp_vdp.c include/lldp_vdp.h
>
> dcbtool_SOURCES = dcbtool.c clif.c dcbtool_cmds.c parse_cli.l \
> $(lldpad_include_HEADERS) $(noinst_HEADERS)
>
> lldptool_SOURCES = lldptool.c clif.c lldptool_cmds.c common.c os_unix.c \
> lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c lldp_8023_clif.c \
> -lldp_dcbx_clif.c lldp_evb_clif.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
> +lldp_dcbx_clif.c lldp_evb_clif.c $(lldpad_include_HEADERS) \
> +$(noinst_HEADERS)
>
> nltest_SOURCES = nltest.c nltest.h
>
> diff --git a/ecp/ecp.c b/ecp/ecp.c
> new file mode 100644
> index 0000000..20a8e66
> --- /dev/null
> +++ b/ecp/ecp.c
> @@ -0,0 +1,79 @@
> +/*******************************************************************************
> +
> + implementation of ECP according to 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#include <net/if.h>
> +#include <sys/queue.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/utsname.h>
> +#include <linux/if_bridge.h>
> +#include "lldp.h"
> +#include "lldp_evb.h"
> +#include "lldp_vdp.h"
> +#include "messages.h"
> +#include "config.h"
> +#include "common.h"
> +#include "lldp/l2_packet.h"
> +#include "ecp/ecp.h"
> +
> +/* ecp_init - initialize ecp module
> + * @ifname: interface for which the module is initialized
> + *
> + * returns 0 on success, -1 on error
> + *
> + * finds the port to the interface name, sets up the receive handle for
> + * incoming ecp frames and initializes the ecp rx and tx state machines.
> + * should usually be called when a successful exchange of EVB TLVs has been
> + * made and ECP and VDP protocols are supported by both sides.
> + */
> +int ecp_init(char *ifname)
> +{
> + struct vdp_data *vd;
> +
> + printf("%s(%i): starting ECP for if %s !\n", __func__, __LINE__, ifname);
> +
> + vd = vdp_data(ifname);
> +
> + if (!vd) {
> + printf("%s(%i): unable to find vd %s ! \n", __func__, __LINE__, ifname);
> + goto fail;
> + }
> +
> + vd->ecp.l2 = l2_packet_init(vd->ifname, NULL, ETH_P_ECP,
> + ecp_rx_ReceiveFrame, vd, 1);
> + if (!vd->ecp.l2) {
> + printf("ERROR: Failed to open register layer 2 access to "
> + "ETH_P_ECP\n");
> + goto fail;
> + }
> +
> + ecp_tx_run_sm(vd);
> + ecp_rx_run_sm(vd);
> +
> + return 0;
> +
> +fail:
> + return -1;
> +}
> diff --git a/ecp/ecp.h b/ecp/ecp.h
> new file mode 100644
> index 0000000..cc9ca2b
> --- /dev/null
> +++ b/ecp/ecp.h
> @@ -0,0 +1,101 @@
> +/*******************************************************************************
> +
> + implementation of ECP according to 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#ifndef _ECP_H
> +#define _ECP_H
> +
> +#include "lldp_mod.h"
> +#include "include/lldp_vdp.h"
> +
> +#define ECP_SUBTYPE 0x0
> +
> +#define ECP_MAX_RETRIES 3
> +#define ECP_SEQUENCE_NR_START 0x0
> +
> +#define ECP_TRANSMISSION_TIMER EVB_RTM(RTE)*EVB_RTG
> +#define ECP_TRANSMISSION_DIVIDER 10000
> +
> +typedef enum {
> + ECP_REQUEST = 0,
> + ECP_ACK
> +} ecp_mode;
> +
> +struct ecp {
> + struct l2_packet_data *l2;
> + int sequence;
> + int retries;
> + int ackReceived;
> + int ackTimerExpired;
> + u16 lastSequence;
> + u16 seqECPDU;
> + struct portrx rx;
> + struct porttx tx;
> + struct portstats stats;
> +};
> +
> +struct ecp_hdr {
> + u8 oui[3];
> + u8 pad1;
> + u16 subtype;
> + u8 mode;
> + u16 seqnr;
> +} __attribute__ ((__packed__));
> +
> +enum {
> + ECP_TX_INIT_TRANSMIT,
> + ECP_TX_TRANSMIT_ECPDU,
> + ECP_TX_WAIT_FOR_ACK,
> + ECP_TX_REQUEST_PDU
> +};
> +
> +static const char *ecp_tx_states[] = {
> + "ECP_TX_IDLE",
> + "ECP_TX_INIT_TRANSMIT",
> + "ECP_TX_TRANSMIT_ECPDU",
> + "ECP_TX_WAIT_FOR_ACK",
> + "ECP_TX_REQUEST_PDU"
> +};
> +
> +enum {
> + ECP_RX_IDLE,
> + ECP_RX_INIT_RECEIVE,
> + ECP_RX_RECEIVE_WAIT,
> + ECP_RX_RECEIVE_ECPDU,
> + ECP_RX_SEND_ACK,
> + ECP_RX_RESEND_ACK,
> +};
> +
> +static const char *ecp_rx_states[] = {
> + "ECP_RX_IDLE",
> + "ECP_RX_INIT_RECEIVE",
> + "ECP_RX_RECEIVE_WAIT",
> + "ECP_RX_RECEIVE_ECPDU",
> + "ECP_RX_SEND_ACK",
> + "ECP_RX_RESEND_ACK",
> +};
> +
> +void ecp_rx_ReceiveFrame(void *, unsigned int, const u8 *, size_t );
> +
> +#endif /* _ECP_H */
> diff --git a/ecp/ecp_rx.c b/ecp/ecp_rx.c
> new file mode 100644
> index 0000000..3a5dff7
> --- /dev/null
> +++ b/ecp/ecp_rx.c
> @@ -0,0 +1,599 @@
> +/*******************************************************************************
> +
> + implementation of ECP according to 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#include "dcb_osdep.h"
> +#include "lldp/ports.h"
> +#include "lldp/l2_packet.h"
> +#include "messages.h"
> +#include "lldp.h"
> +#include "lldpad.h"
> +#include "lldp_mod.h"
> +#include "clif_msgs.h"
> +#include "lldp_mand.h"
> +#include "lldp_vdp.h"
> +
> +/* ecp_rx_Initialize - initializes the ecp rx state machine
> + * @vd: vd for the state machine
> + *
> + * no return value
> + *
> + * initialize some variables, get rid of old frame if necessary
> + */
> +void ecp_rx_Initialize(struct vdp_data *vd)
> +{
> + vd->ecp.rx.rcvFrame = false;
> + vd->ecp.rx.badFrame = false;
> +
> + vd->ecp.ackReceived = 0;
> +
> + if (vd->ecp.rx.framein) {
> + free(vd->ecp.rx.framein);
> + vd->ecp.rx.framein = NULL;
> + }
> + vd->ecp.rx.sizein = 0;
> +
> + return;
> +}
> +
> +/* ecp_rx_freeFrame - free up received frame
> + * @vd: vd for the state machine
> + *
> + * no return value
> + *
> + * frees up an old received frame, set pointer to NULL and size to 0.
> + */
> +void ecp_rx_freeFrame(struct vdp_data *vd)
> +{
> + free(vd->ecp.rx.framein);
> + vd->ecp.rx.framein = NULL;
> + vd->ecp.rx.sizein = 0;
> +}
> +
> +/* ecp_print_framein - print raw received frame
> + * @vd: vd for the state machine
> + *
> + * no return value
> + *
> + * prints out a raw version of a received frame. useful for low-level protocol
> + * debugging.
> + */
> +void ecp_print_framein(struct vdp_data *vd)
> +{
> + int i;
> +
> + for (i=0; i < vd->ecp.rx.sizein; i++) {
> + printf("%02x ", vd->ecp.rx.framein[i]);
> + if (!((i+1) % 16))
> + printf("\n");
> + }
> +
> + printf("\n");
> +}
> +
> +/* ecp_rx_SendAckFrame - send ack frame
> + * @vd: port used by ecp
> + *
> + * currently always returns 0
> + *
> + * copies current received frame over to frame out, fills in address of this
> + * port and set mode field to ACK. used by ecp_rx_send_ack_frame.
> + */
> +int ecp_rx_SendAckFrame(struct vdp_data *vd)
> +{
> + u16 tlv_offset = 0;
> + struct ecp_hdr *ecp_hdr;
> + struct l2_ethhdr *hdr;
> + u8 own_addr[ETH_ALEN];
> +
> + printf("%s(%i)-%s: acking frame \n", __func__, __LINE__, vd->ifname);
> +
> + assert(vd->ecp.rx.framein && vd->ecp.rx.sizein);
> +
> + /* copy over to frameout */
> + vd->ecp.tx.frameout = (u8 *)malloc(ETH_FRAME_LEN);
> + memcpy(vd->ecp.tx.frameout, vd->ecp.rx.framein, vd->ecp.rx.sizein);
> + vd->ecp.tx.sizeout = vd->ecp.rx.sizein;
> +
> + /* use my own addr to send ACK */
> + hdr = (struct l2_ethhdr *)vd->ecp.tx.frameout;
> + l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr);
> + memcpy(hdr->h_source, &own_addr, ETH_ALEN);
> +
> + tlv_offset = sizeof(struct l2_ethhdr);
> + ecp_hdr = (struct ecp_hdr *)&vd->ecp.tx.frameout[tlv_offset];
> + ecp_hdr->mode = ECP_ACK;
> +
> + return 0;
> +}
> +
> +/* ecp_rx_send_ack_frame - send out ack frame for received frame
> + * @vd: vd for the state machine
> + *
> + * no return value
> + *
> + * creates an ack frame for a just received frame, prints the about to be
> + * sent frame and finally transmits it.
> + */
> +void ecp_rx_send_ack_frame(struct vdp_data *vd)
> +{
> + ecp_rx_SendAckFrame(vd);
> +
> + ecp_print_frameout(vd);
> +
> + ecp_txFrame(vd);
> +
> + return;
> +}
> +
> +/* ecp_rx_ReceiveFrame - receive ecp frame
> + * @ctx: rx callback context, struct vd * in this case
> + * @ifindex: index of interface
> + * @buf: buffer which contains the frame just received
> + * @len: size of buffer (frame)
> + *
> + * no return value
> + *
> + * creates a local copy of the buffer and checks the header. keeps some
> + * statistics about ecp frames. Checks if it is a request or an ack frame and branches
> + * to ecp rx or ecp tx state machine.
> + */
> +void ecp_rx_ReceiveFrame(void *ctx, unsigned int ifindex, const u8 *buf, size_t len)
> +{
> +
> + struct vdp_data *vd = NULL;
> + struct port *port;
> + u8 frame_error = 0;
> + u16 tlv_offset;
> + struct l2_ethhdr *hdr;
> + struct l2_ethhdr example_hdr,*ex;
> + struct ecp_hdr *ecp_hdr;
> +
> + if (ctx)
> + vd = (struct vdp_data *)ctx;
> +
> + port = port_find_by_name(vd->ifname);
> +
> + printf("%s(%i)-%s: received packet with size %i\n", __func__, __LINE__,
> + vd->ifname, (int) len);
> +
> + if (port->adminStatus == disabled || port->adminStatus == enabledTxOnly)
> + return;
> +
> + if (vd->ecp.rx.framein &&
> + vd->ecp.rx.sizein == len &&
> + (memcmp(buf, vd->ecp.rx.framein, len) == 0)) {
> + vd->ecp.stats.statsFramesInTotal++;
> + return;
> + }
> +
> + if (vd->ecp.rx.framein)
> + free(vd->ecp.rx.framein);
> +
> + vd->ecp.rx.framein = (u8 *)malloc(len);
> + if (vd->ecp.rx.framein == NULL) {
> + printf("ERROR - could not allocate memory for rx'ed frame\n");
> + return;
> + }
> + memcpy(vd->ecp.rx.framein, buf, len);
> +
> + vd->ecp.rx.sizein = (u16)len;
> + ex = &example_hdr;
> + memcpy(ex->h_dest, multi_cast_source, ETH_ALEN);
> + ex->h_proto = htons(ETH_P_ECP);
> + hdr = (struct l2_ethhdr *)vd->ecp.rx.framein;
> +
> + if ((memcmp(hdr->h_dest,ex->h_dest, ETH_ALEN) != 0)) {
> + printf("ERROR multicast address error in incoming frame. "
> + "Dropping frame.\n");
> + frame_error++;
> + free(vd->ecp.rx.framein);
> + vd->ecp.rx.framein = NULL;
> + vd->ecp.rx.sizein = 0;
> + return;
> + }
> +
> + if (hdr->h_proto != example_hdr.h_proto) {
> + printf("ERROR Ethertype not ECP ethertype but ethertype "
> + "'%x' in incoming frame.\n", htons(hdr->h_proto));
> + frame_error++;
> + free(vd->ecp.rx.framein);
> + vd->ecp.rx.framein = NULL;
> + vd->ecp.rx.sizein = 0;
> + return;
> + }
> +
> + if (!frame_error) {
> + vd->ecp.stats.statsFramesInTotal++;
> + vd->ecp.rx.rcvFrame = 1;
> + }
> +
> + tlv_offset = sizeof(struct l2_ethhdr);
> +
> + ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.framein[tlv_offset];
> +
> + vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr);
> +
> + switch(ecp_hdr->mode) {
> + case ECP_REQUEST:
> + vd->ecp.ackReceived = false;
> + ecp_print_framein(vd);
> + ecp_rx_run_sm(vd);
> + break;
> + case ECP_ACK:
> + vd->ecp.ackReceived = true;
> + printf("%s(%i)-%s: received ack frame \n", __func__, __LINE__, vd->ifname);
> + ecp_print_framein(vd);
> + ecp_tx_run_sm(vd);
> + vd->ecp.ackReceived = false;
> + break;
> + default:
> + printf("ERROR: unknown mode %i!\n", ecp_hdr->mode);
> + return;
> + }
> +
> + ecp_rx_freeFrame(vd);
> +}
> +
> +/* ecp_rx_validateFrame - validates received frame
> + * @vd: vdp_data used by ecp
> + *
> + * no return value
> + *
> + * checks wether received frame has correct subtype and mode
> + */
> +
> +void ecp_rx_validateFrame(struct vdp_data *vd)
> +{
> + u16 tlv_offset = 0;
> + struct ecp_hdr *ecp_hdr;
> +
> + printf("%s(%i)-%s: validating frame \n", __func__, __LINE__, vd->ifname);
> +
> + assert(vd->ecp.rx.framein && vd->ecp.rx.sizein);
> +
> + tlv_offset = sizeof(struct l2_ethhdr);
> +
> + ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.framein[tlv_offset];
> +
> + printf("%s(%i)-%s: ecp packet with subtype %04x, mode %02x, sequence nr %04x\n",
> + __func__, __LINE__, vd->ifname, ecp_hdr->subtype, ecp_hdr->mode, ntohs(ecp_hdr->seqnr));
> +
> + if (ecp_hdr->subtype != ECP_SUBTYPE) {
> + printf("ERROR: unknown subtype !\n");
> + return;
> + }
> +
> + if ((ecp_hdr->oui[0] != 0x0) || (ecp_hdr->oui[1] != 0x1b) ||
> + (ecp_hdr->oui[2] != 0x3f)) {
> + printf("ERROR: incorrect OUI 0x%02x%02x%02x !\n",
> + ecp_hdr->oui[0], ecp_hdr->oui[1], ecp_hdr->oui[2]);
> + return;
> + }
> +
> + switch(ecp_hdr->mode) {
> + case ECP_REQUEST:
> + break;
> + case ECP_ACK:
> + break;
> + default:
> + printf("ERROR: unknown mode %i!\n", ecp_hdr->mode);
> + return;
> + }
> +
> + /* FIXME: also done in ecp_rx_ReceiveFrame,
> + * are both necessary ? */
> + vd->ecp.seqECPDU = ntohs(ecp_hdr->seqnr);
> +}
> +
> +/* ecp_rx_validate_frame - wrapper around ecp_rx_validateFrame
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + * sets rcvFrame to false and validates frame. used in ECP_RX_RECEIVE_ECPDU
> + * state of ecp_rx_run_sm
> + */
> +void ecp_rx_validate_frame(struct vdp_data *vd)
> +{
> + vd->ecp.rx.rcvFrame = false;
> + ecp_rx_validateFrame(vd);
> + return;
> +}
> +
> +/* ecp_rx_ProcessFrame - process received ecp frames
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + * walks through the packed vsi tlvs in an ecp frame, extracts them
> + * and passes them to the VDP ULP with vdp_indicate.
> + */
> +void ecp_rx_ProcessFrame(struct vdp_data *vd)
> +{
> + u16 tlv_cnt = 0;
> + u8 tlv_type = 0;
> + u16 tlv_length = 0;
> + u16 tlv_offset = 0;
> + u16 *tlv_head_ptr = NULL;
> + u8 frame_error = 0;
> + bool tlv_stored = false;
> + struct ecp_hdr *ecp_hdr;
> +
> + printf("%s(%i)-%s: processing frame \n", __func__, __LINE__, vd->ifname);
> +
> + assert(vd->ecp.rx.framein && vd->ecp.rx.sizein);
> +
> + tlv_offset = sizeof(struct l2_ethhdr);
> +
> + ecp_hdr = (struct ecp_hdr *)&vd->ecp.rx.framein[tlv_offset];
> +
> + printf("%s(%i)-%s: ecp packet with subtype %04x, mode %02x, sequence nr %04x\n",
> + __func__, __LINE__, vd->ifname, ecp_hdr->subtype, ecp_hdr->mode, ntohs(ecp_hdr->seqnr));
> +
> + if (ecp_hdr->mode == ECP_ACK)
> + return;
> +
> + /* processing of VSI_TLVs starts here */
> +
> + tlv_offset += sizeof(struct ecp_hdr);
> +
> + do {
> + tlv_cnt++;
> + if (tlv_offset > vd->ecp.rx.sizein) {
> + printf("%s(%i)-%s: ERROR: Frame overrun! tlv_offset %i, sizein %i cnt %i\n",
> + __func__, __LINE__, vd->ifname, tlv_offset, vd->ecp.rx.sizein, tlv_cnt);
> + frame_error++;
> + goto out;
> + }
> +
> + tlv_head_ptr = (u16 *)&vd->ecp.rx.framein[tlv_offset];
> + tlv_length = htons(*tlv_head_ptr) & 0x01FF;
> + tlv_type = (u8)(htons(*tlv_head_ptr) >> 9);
> +
> + u16 tmp_offset = tlv_offset + tlv_length;
> + if (tmp_offset > vd->ecp.rx.sizein) {
> + printf("ERROR: Frame overflow error: offset=%d, "
> + "rx.size=%d \n", tmp_offset, vd->ecp.rx.sizein);
> + frame_error++;
> + goto out;
> + }
> +
> + u8 *info = (u8 *)&vd->ecp.rx.framein[tlv_offset +
> + sizeof(*tlv_head_ptr)];
> +
> + struct unpacked_tlv *tlv = create_tlv();
> +
> + if (!tlv) {
> + printf("ERROR: Failed to malloc space for "
> + "incoming TLV. \n");
> + goto out;
> + }
> +
> + if ((tlv_length == 0) && (tlv->type != TYPE_0)) {
> + printf("ERROR: tlv_length == 0\n");
> + free_unpkd_tlv(tlv);
> + goto out;
> + }
> +
> + tlv->type = tlv_type;
> + tlv->length = tlv_length;
> + tlv->info = (u8 *)malloc(tlv_length);
> + if (tlv->info) {
> + memset(tlv->info,0, tlv_length);
> + memcpy(tlv->info, info, tlv_length);
> + } else {
> + printf("ERROR: Failed to malloc space for incoming "
> + "TLV info \n");
> + free_unpkd_tlv(tlv);
> + goto out;
> + }
> +
> + /* Validate the TLV */
> + tlv_offset += sizeof(*tlv_head_ptr) + tlv_length;
> +
> + if (tlv->type == TYPE_127) { /* private TLV */
> + /* give VSI TLV to VDP */
> + if (!vdp_indicate(vd, tlv, ecp_hdr->mode))
> + tlv_stored = true;
> + else {
> + /* TODO: put it in a list and try again later until
> + * timer and retries have expired */
> + tlv_stored = false;
> + }
> + }
> +
> + if ((tlv->type != TYPE_0) && !tlv_stored) {
> + printf("\n%s: allocated TLV (%u) "
> + " was not stored! (%p)\n", __func__, tlv->type,
> + tlv);
> + tlv = free_unpkd_tlv(tlv);
> + vd->ecp.stats.statsTLVsUnrecognizedTotal++;
> + }
> +
> + tlv = NULL;
> + tlv_stored = false;
> + } while(tlv_type != 0);
> +
> +out:
> + if (frame_error) {
> + vd->ecp.stats.statsFramesDiscardedTotal++;
> + vd->ecp.stats.statsFramesInErrorsTotal++;
> + vd->ecp.rx.badFrame = true;
> + }
> +
> + return;
> +}
> +
> +/* ecp_rx_change_state - changes the ecp rx sm state
> + * @vd: currently used port
> + * @newstate: new state for the sm
> + *
> + * no return value
> + *
> + * checks state transistion for consistency and finally changes the state of
> + * the profile.
> + */
> +void ecp_rx_change_state(struct vdp_data *vd, u8 newstate)
> +{
> + switch(newstate) {
> + case ECP_RX_IDLE:
> + break;
> + case ECP_RX_INIT_RECEIVE:
> + break;
> + case ECP_RX_RECEIVE_WAIT:
> + assert((vd->ecp.rx.state == ECP_RX_INIT_RECEIVE) ||
> + (vd->ecp.rx.state == ECP_RX_IDLE) ||
> + (vd->ecp.rx.state == ECP_RX_SEND_ACK) ||
> + (vd->ecp.rx.state == ECP_RX_RESEND_ACK));
> + break;
> + case ECP_RX_RECEIVE_ECPDU:
> + assert(vd->ecp.rx.state == ECP_RX_RECEIVE_WAIT);
> + break;
> + case ECP_RX_SEND_ACK:
> + assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU);
> + break;
> + case ECP_RX_RESEND_ACK:
> + assert(vd->ecp.rx.state == ECP_RX_RECEIVE_ECPDU);
> + break;
> + default:
> + printf("ERROR: The ECP_RX State Machine is broken!\n");
> + log_message(MSG_ERR_RX_SM_INVALID, "%s", vd->ifname);
> + }
> +
> + printf("%s(%i)-%s: state change %s -> %s\n", __func__, __LINE__,
> + vd->ifname, ecp_rx_states[vd->ecp.rx.state], ecp_rx_states[newstate]);
> +
> + vd->ecp.rx.state = newstate;
> +}
> +
> +/* ecp_set_rx_state - sets the ecp rx sm state
> + * @vd: currently used port
> + *
> + * returns true or false
> + *
> + * switches the state machine to the next state depending on the input
> + * variables. returns true or false depending on wether the state machine
> + * can be run again with the new state or can stop at the current state.
> + */
> +bool ecp_set_rx_state(struct vdp_data *vd)
> +{
> + struct port *port = port_find_by_name(vd->ifname);
> +
> + if (port->portEnabled == false) {
> + ecp_rx_change_state(vd, ECP_RX_IDLE);
> + }
> +
> + switch(vd->ecp.rx.state) {
> + case ECP_RX_IDLE:
> + if (port->portEnabled == true) {
> + ecp_rx_change_state(vd, ECP_RX_INIT_RECEIVE);
> + return true;
> + }
> + return false;
> + case ECP_RX_INIT_RECEIVE:
> + if ((port->adminStatus == enabledRxTx) ||
> + (port->adminStatus == enabledRxOnly)) {
> + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> + return true;
> + }
> + return false;
> + case ECP_RX_RECEIVE_WAIT:
> + if ((port->adminStatus == disabled) ||
> + (port->adminStatus == enabledTxOnly)) {
> + ecp_rx_change_state(vd, ECP_RX_IDLE);
> + return true;
> + }
> + if (vd->ecp.rx.rcvFrame == true) {
> + ecp_rx_change_state(vd, ECP_RX_RECEIVE_ECPDU);
> + return true;
> + }
> + return false;
> + case ECP_RX_RECEIVE_ECPDU:
> + if (vd->ecp.seqECPDU == vd->ecp.lastSequence) {
> + printf("%s(%i):-(%s) seqECPDU %x, lastSequence %x\n", __func__, __LINE__,
> + vd->ifname, vd->ecp.seqECPDU, vd->ecp.lastSequence);
> + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> + return true;
> + }
> + if (vd->ecp.seqECPDU != vd->ecp.lastSequence) {
> + ecp_rx_change_state(vd, ECP_RX_RESEND_ACK);
> + return true;
> + }
> + return false;
> + case ECP_RX_SEND_ACK:
How can we get to this state? Did I miss something or could the ECP_RX_SEND_ACK and ECP_RX_RESEND_ACK states be combined or ECP_RX_SEND_ACK removed outright?
> + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> + return false;
> + case ECP_RX_RESEND_ACK:
> + ecp_rx_change_state(vd, ECP_RX_RECEIVE_WAIT);
> + return false;
> + default:
> + printf("ERROR: The ECP_RX State Machine is broken!\n");
> + log_message(MSG_ERR_RX_SM_INVALID, "%s", vd->ifname);
> + return false;
> + }
> +}
> +
> +/* ecp_rx_run_sm - state machine for ecp rx
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + * runs the state machine for ecp rx.
> + */
> +void ecp_rx_run_sm(struct vdp_data *vd)
> +{
> + ecp_set_rx_state(vd);
> + do {
> + printf("%s(%i)-%s: ecp_rx - %s\n", __func__, __LINE__,
> + vd->ifname, ecp_rx_states[vd->ecp.tx.state]);
> +
> + switch(vd->ecp.rx.state) {
> + case ECP_RX_IDLE:
> + break;
> + case ECP_RX_INIT_RECEIVE:
> + ecp_rx_Initialize(vd);
> + break;
> + case ECP_RX_RECEIVE_WAIT:
> + break;
> + case ECP_RX_RECEIVE_ECPDU:
> + ecp_rx_validate_frame(vd);
> + break;
> + case ECP_RX_SEND_ACK:
> + ecp_rx_ProcessFrame(vd);
> + break;
> + case ECP_RX_RESEND_ACK:
> + ecp_rx_ProcessFrame(vd);
> + if (!vd->ecp.ackReceived) {
> + ecp_rx_send_ack_frame(vd);
> + ecp_rx_freeFrame(vd);
> + }
> + break;
> + default:
> + printf("ERROR: The ECP_RX State Machine is broken!\n");
> + log_message(MSG_ERR_TX_SM_INVALID, "%s", vd->ifname);
> + }
> + } while (ecp_set_rx_state(vd) == true);
> +
> +}
> diff --git a/ecp/ecp_tx.c b/ecp/ecp_tx.c
> new file mode 100644
> index 0000000..9ddf821
> --- /dev/null
> +++ b/ecp/ecp_tx.c
> @@ -0,0 +1,494 @@
> +/*******************************************************************************
> +
> + implementation of ECP according to 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#include "dcb_osdep.h"
> +#include "lldp/ports.h"
> +#include "lldp/l2_packet.h"
> +#include "eloop.h"
> +#include "messages.h"
> +#include "lldpad.h"
> +#include "lldp_tlv.h"
> +#include "lldp_mod.h"
> +#include "lldp_mand.h"
> +#include "lldp_evb.h"
> +#include "include/lldp_vdp.h"
> +
> +void ecp_tx_run_sm(struct vdp_data *);
> +
> +/* ecp_somethingChangedLocal - set flag if port has changed
> + * @vd: port to set the flag for
> + * @mode: mode to set the flag to
> + *
> + * no return value
> + *
> + * set the localChange flag with a mode to indicate a port has changed.
> + * used to signal an ecpdu needs to be sent out.
> + */
> +
> +void ecp_somethingChangedLocal(struct vdp_data *vd, int mode)
> +{
> + if (!vd)
> + return;
> +
> + vd->ecp.tx.localChange |= mode;
> +
> + return;
> +}
> +
> +/* ecp_print_frameout - print outbound frame
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + * prints a raw dump of an outbound ecp frame. useful for low-level protocol
> + * debugging.
> + */
> +void ecp_print_frameout(struct vdp_data *vd)
> +{
> + int i;
> +
> + for (i=0; i < vd->ecp.tx.sizeout; i++) {
> + printf("%02x ", vd->ecp.tx.frameout[i]);
> + if (!((i+1) % 16))
> + printf("\n");
> + }
> +
> + printf("\n");
> +}
> +
> +/* ecp_build_ECPDU - create an ecp protocol data unit
> + * @vd: currently used port
> + * @mode: mode to create pdu with (REQ or ACK)
> + *
> + * returns true on success, false on failure
> + *
> + * creates the frame header with the ports mac address, the ecp header with REQ
> + * or ACK mode, plus a list of packed TLVs created from the profiles on this
> + * port.
> + */
> +bool ecp_build_ECPDU(struct vdp_data *vd, int mode)
> +{
> + struct l2_ethhdr eth;
> + struct ecp_hdr ecp_hdr;
> + u8 own_addr[ETH_ALEN];
> + u32 fb_offset = 0;
> + u32 datasize = 0;
> + struct packed_tlv *ptlv = NULL;
> + struct vsi_profile *p;
> +
> + if (vd->ecp.tx.frameout) {
> + free(vd->ecp.tx.frameout);
> + vd->ecp.tx.frameout = NULL;
> + }
> +
> + /* TODO: different multicast address for sending ECP over S-channel (multi_cast_source_s)
> + * S-channels to implement later */
> + memcpy(eth.h_dest, multi_cast_source, ETH_ALEN);
> + l2_packet_get_own_src_addr(vd->ecp.l2,(u8 *)&own_addr);
> + memcpy(eth.h_source, &own_addr, ETH_ALEN);
> + eth.h_proto = htons(ETH_P_ECP);
> + vd->ecp.tx.frameout = (u8 *)malloc(ETH_FRAME_LEN);
> + if (vd->ecp.tx.frameout == NULL) {
> + printf("InfoECPDU: Failed to malloc frame buffer \n");
> + return false;
> + }
> + memset(vd->ecp.tx.frameout,0,ETH_FRAME_LEN);
> + memcpy(vd->ecp.tx.frameout, (void *)ð, sizeof(struct l2_ethhdr));
> + fb_offset += sizeof(struct l2_ethhdr);
> +
> + ecp_hdr.oui[0] = 0x0;
> + ecp_hdr.oui[1] = 0x1b;
> + ecp_hdr.oui[2] = 0x3f;
> +
> + ecp_hdr.pad1 = 0x0;
> +
> + ecp_hdr.subtype = ECP_SUBTYPE;
> + switch(mode) {
> + case VDP_PROFILE_REQ:
> + ecp_hdr.mode = ECP_REQUEST;
> + break;
> + case VDP_PROFILE_ACK:
> + ecp_hdr.mode = ECP_ACK;
> + break;
> + default:
> + printf("%s(%i): unknown mode for %s !\n", __func__, __LINE__,
> + vd->ifname);
> + }
> +
> + vd->ecp.lastSequence++;
> + ecp_hdr.seqnr = htons(vd->ecp.lastSequence);
> +
> + if ((sizeof(struct ecp_hdr)+fb_offset) > ETH_MAX_DATA_LEN)
> + goto error;
> + memcpy(vd->ecp.tx.frameout+fb_offset, (void *)&ecp_hdr, sizeof(struct ecp_hdr));
> + datasize += sizeof(struct ecp_hdr);
> + fb_offset += sizeof(struct ecp_hdr);
> +
> + /* create packed_tlvs for all profiles on this interface */
> + LIST_FOREACH(p, &vd->profile_head, profile) {
> + if(!p) {
> + printf("%s(%i): list vd->profile_head empty !\n", __func__, __LINE__);
> + continue;
> + }
> +
> + if (p->localChange != mode) {
> + printf("%s(%i): not sending out profile !\n", __func__, __LINE__);
> + continue;
> + }
> +
> + ptlv = vdp_gettlv(vd, p);
> +
> + if(!ptlv) {
> + printf("%s(%i): ptlv not created !\n", __func__, __LINE__);
> + continue;
> + }
> +
> + if (ptlv) {
> + if ((ptlv->size+fb_offset) > ETH_MAX_DATA_LEN)
> + goto error;
> + memcpy(vd->ecp.tx.frameout+fb_offset,
> + ptlv->tlv, ptlv->size);
> + datasize += ptlv->size;
> + fb_offset += ptlv->size;
I think the ptlv needs to be free'd here? Else where is it getting free'd.
> + }
> + }
> +
> + /* The End TLV marks the end of the LLDP PDU */
> + ptlv = pack_end_tlv();
> + if (!ptlv || ((ptlv->size + fb_offset) > ETH_MAX_DATA_LEN))
> + goto error;
> + memcpy(vd->ecp.tx.frameout + fb_offset, ptlv->tlv, ptlv->size);
> + datasize += ptlv->size;
> + fb_offset += ptlv->size;
> + ptlv = free_pkd_tlv(ptlv);
> +
> + if (datasize > ETH_MAX_DATA_LEN)
> + goto error;
> +
> + if (datasize < ETH_MIN_DATA_LEN)
> + vd->ecp.tx.sizeout = ETH_MIN_PKT_LEN;
> + else
> + vd->ecp.tx.sizeout = fb_offset;
> +
> + return true;
> +
> +error:
> + ptlv = free_pkd_tlv(ptlv);
> + if (vd->ecp.tx.frameout)
> + free(vd->ecp.tx.frameout);
> + vd->ecp.tx.frameout = NULL;
> + printf("InfoECPDU: packed TLV too large for tx frame\n");
> + return false;
> +}
> +
> +/* ecp_tx_Initialize - initializes the ecp tx state machine
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + * initializes some variables for the ecp tx state machine.
> + */
> +void ecp_tx_Initialize(struct vdp_data *vd)
> +{
> + if (vd->ecp.tx.frameout) {
> + free(vd->ecp.tx.frameout);
> + vd->ecp.tx.frameout = NULL;
> + }
> + vd->ecp.tx.localChange = VDP_PROFILE_REQ;
> + vd->ecp.lastSequence = ECP_SEQUENCE_NR_START;
> + vd->ecp.stats.statsFramesOutTotal = 0;
> + vd->ecp.ackTimerExpired = false;
> + vd->ecp.retries = 0;
> +
> + struct port *port = port_find_by_name(vd->ifname);
> + l2_packet_get_port_state(vd->ecp.l2, (u8 *)&(port->portEnabled));
> +
> + return;
> +}
> +
> +/* ecp_txFrame - transmit ecp frame
> + * @vd: currently used port
> + *
> + * returns the number of characters sent on success, -1 on failure
> + *
> + * sends out the frame stored in the frameout structure using l2_packet_send.
> + */
> +u8 ecp_txFrame(struct vdp_data *vd)
> +{
> + int status = 0;
> +
> + status = l2_packet_send(vd->ecp.l2, (u8 *)&multi_cast_source,
> + htons(ETH_P_ECP),vd->ecp.tx.frameout,vd->ecp.tx.sizeout);
> + vd->ecp.stats.statsFramesOutTotal++;
> +
> + return status;
> +}
> +
> +/* ecp_tx_create_frame - create ecp frame
> + * @vd: currently used port
> + *
> + * no return value
> + *
> + *
> + */
> +void ecp_tx_create_frame(struct vdp_data *vd)
> +{
> + /* send REQs */
> + if (vd->ecp.tx.localChange & VDP_PROFILE_REQ) {
> + printf("%s(%i)-%s: sending REQs\n", __func__, __LINE__, vd->ifname);
> + ecp_build_ECPDU(vd, VDP_PROFILE_REQ);
> + ecp_print_frameout(vd);
> + ecp_txFrame(vd);
> + }
> +
> + /* send ACKs */
> + if (vd->ecp.tx.localChange & VDP_PROFILE_ACK) {
> + printf("%s(%i)-%s: sending ACKs\n", __func__, __LINE__, vd->ifname);
> + ecp_build_ECPDU(vd, VDP_PROFILE_ACK);
> + ecp_print_frameout(vd);
> + ecp_txFrame(vd);
> + }
> +
> + vd->ecp.tx.localChange = 0;
> + return;
> +}
> +
> +/* ecp_timeout_handler - handles the ack timer expiry
> + * @eloop_data: data structure of event loop
> + * @user_ctx: user context, port here
> + *
> + * no return value
> + *
> + * called when the ECP ack timer has expired. sets a flag and calls the ECP
> + * state machine.
> + */
> +static void ecp_tx_timeout_handler(void *eloop_data, void *user_ctx)
> +{
> + struct vdp_data *vd;
> +
> + vd = (struct vdp_data *) user_ctx;
> +
> + vd->ecp.ackTimerExpired = true;
> +
> + printf("%s(%i)-%s: timer expired\n", __func__, __LINE__,
> + vd->ifname);
> +
> + ecp_tx_run_sm(vd);
> +}
> +
> +/* ecp_tx_stop_ackTimer - stop the ECP ack timer
> + * @vd: currently used port
> + *
> + * returns the number of removed handlers
> + *
> + * stops the ECP ack timer. used when a ack frame for the port has been
> + * received.
> + */
> +static int ecp_tx_stop_ackTimer(struct vdp_data *vd)
> +{
> + printf("%s(%i)-%s: stopping timer\n", __func__, __LINE__,
> + vd->ifname);
> +
> + return eloop_cancel_timeout(ecp_tx_timeout_handler, NULL, (void *) vd);
> +}
> +
> +/* ecp_tx_start_ackTimer - starts the ECP ack timer
> + * @profile: profile to process
> + *
> + * returns 0 on success, -1 on error
> + *
> + * starts the ack timer when a frame has been sent out.
> + */
> +static void ecp_tx_start_ackTimer(struct vdp_data *vd)
> +{
> + unsigned int secs, usecs;
> +
> + vd->ecp.ackTimerExpired = false;
> +
> + secs = ECP_TRANSMISSION_TIMER / ECP_TRANSMISSION_DIVIDER;
> + usecs = ECP_TRANSMISSION_TIMER % ECP_TRANSMISSION_DIVIDER;
> +
> + printf("%s(%i)-%s: starting timer\n", __func__, __LINE__,
> + vd->ifname);
> +
> + eloop_register_timeout(secs, usecs, ecp_tx_timeout_handler, NULL, (void *) vd);
> +}
> +
> +/* ecp_tx_change_state - changes the ecp tx sm state
> + * @vd: currently used port
> + * @newstate: new state for the sm
> + *
> + * no return value
> + *
> + * checks state transistion for consistency and finally changes the state of
> + * the profile.
> + */
> +static void ecp_tx_change_state(struct vdp_data *vd, u8 newstate)
> +{
> + switch(newstate) {
> + case ECP_TX_INIT_TRANSMIT:
> + break;
> + case ECP_TX_TRANSMIT_ECPDU:
> + assert((vd->ecp.tx.state == ECP_TX_INIT_TRANSMIT) ||
> + (vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK) ||
> + (vd->ecp.tx.state == ECP_TX_REQUEST_PDU));
> + break;
> + case ECP_TX_WAIT_FOR_ACK:
> + assert(vd->ecp.tx.state == ECP_TX_TRANSMIT_ECPDU);
> + break;
> + case ECP_TX_REQUEST_PDU:
> + assert(vd->ecp.tx.state == ECP_TX_WAIT_FOR_ACK);
> + break;
> + default:
> + printf("ERROR: The ECP_TX State Machine is broken!\n");
> + log_message(MSG_ERR_TX_SM_INVALID, "%s", vd->ifname);
> + }
> +
> + printf("%s(%i)-%s: state change %s -> %s\n", __func__, __LINE__,
> + vd->ifname, ecp_tx_states[vd->ecp.tx.state], ecp_tx_states[newstate]);
> +
> + vd->ecp.tx.state = newstate;
> + return;
> +}
> +
> +/* ecp_set_tx_state - sets the ecp tx sm state
> + * @vd: currently used port
> + *
> + * returns true or false
> + *
> + * switches the state machine to the next state depending on the input
> + * variables. returns true or false depending on wether the state machine
> + * can be run again with the new state or can stop at the current state.
> + */
> +static bool ecp_set_tx_state(struct vdp_data *vd)
> +{
> + struct port *port = port_find_by_name(vd->ifname);
> +
> + if (!port) {
> + printf("%s(%i): port not found !\n", __func__, __LINE__);
> + return 0;
> + }
> +
> + if ((port->portEnabled == false) && (port->prevPortEnabled == true)) {
> + printf("set_tx_state: port was disabled\n");
> + ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT);
> + }
> + port->prevPortEnabled = port->portEnabled;
> +
> + switch (vd->ecp.tx.state) {
> + case ECP_TX_INIT_TRANSMIT:
> + if (port->portEnabled && ((port->adminStatus == enabledRxTx) ||
> + (port->adminStatus == enabledTxOnly)) && vd->ecp.tx.localChange) {
> + ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU);
> + return true;
> + }
> + return false;
> + case ECP_TX_TRANSMIT_ECPDU:
> + if ((port->adminStatus == disabled) ||
> + (port->adminStatus == enabledRxOnly)) {
> + ecp_tx_change_state(vd, ECP_TX_INIT_TRANSMIT);
> + return true;
> + }
> + ecp_tx_change_state(vd, ECP_TX_WAIT_FOR_ACK);
> + return true;
> + case ECP_TX_WAIT_FOR_ACK:
> + if (vd->ecp.ackTimerExpired) {
> + vd->ecp.retries++;
> + if (vd->ecp.retries < ECP_MAX_RETRIES) {
> + ecp_somethingChangedLocal(vd, VDP_PROFILE_REQ);
> + ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU);
> + return true;
> + }
> + if (vd->ecp.retries == ECP_MAX_RETRIES) {
> + printf("%s(%i)-%s: 1 \n", __func__, __LINE__,
> + vd->ifname);
> + ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU);
> + return true;
> + }
> + }
> + if (vd->ecp.ackReceived && vd->ecp.seqECPDU == vd->ecp.lastSequence) {
> + vd->ecp.ackReceived = false;
> + ecp_tx_change_state(vd, ECP_TX_REQUEST_PDU);
> + return true;
> + }
> + return false;
> + case ECP_TX_REQUEST_PDU:
> + if (vd->ecp.tx.localChange & VDP_PROFILE_REQ) {
> + ecp_tx_change_state(vd, ECP_TX_TRANSMIT_ECPDU);
> + return true;
> + }
> + return false;
> + default:
> + printf("ERROR: The TX State Machine is broken!\n");
> + log_message(MSG_ERR_TX_SM_INVALID, "%s", vd->ifname);
> + return false;
> + }
> +}
> +
> +/* ecp_tx_run_sm - state machine for ecp tx
> + * @vd: currently used vdp_data
> + *
> + * no return value
> + *
> + * runs the state machine for ecp tx.
> + */
> +void ecp_tx_run_sm(struct vdp_data *vd)
> +{
> + do {
> + printf("%s(%i)-%s: ecp_tx - %s\n", __func__, __LINE__,
> + vd->ifname, ecp_tx_states[vd->ecp.tx.state]);
> +
> + switch(vd->ecp.tx.state) {
> + case ECP_TX_INIT_TRANSMIT:
> + ecp_tx_Initialize(vd);
> + break;
> + case ECP_TX_TRANSMIT_ECPDU:
> + ecp_tx_create_frame(vd);
> + ecp_tx_start_ackTimer(vd);
> + break;
> + case ECP_TX_WAIT_FOR_ACK:
> + if (vd->ecp.ackReceived) {
> + printf("%s(%i)-%s: ECP_TX_WAIT_FOR_ACK ackReceived\n", __func__, __LINE__,
> + vd->ifname);
> + printf("%s(%i)-%s: 2: seqECPDU %x lastSequence %x \n", __func__, __LINE__,
> + vd->ifname, vd->ecp.seqECPDU, vd->ecp.lastSequence);
> + vd->ecp.tx.localChange = 0;
> + ecp_tx_stop_ackTimer(vd);
> + }
> + break;
> + case ECP_TX_REQUEST_PDU:
> + vd->ecp.retries = 0;
> + printf("%s(%i)-%s: ECP_TX_REQUEST_PDU lastSequence %x\n", __func__, __LINE__,
> + vd->ifname, vd->ecp.lastSequence);
> + break;
> + default:
> + printf("%s(%i): ERROR The TX State Machine is broken!\n", __func__,
> + __LINE__);
> + log_message(MSG_ERR_TX_SM_INVALID, "%s", vd->ifname);
> + }
> + } while (ecp_set_tx_state(vd) == true);
> +
> + return;
> +}
> diff --git a/include/lldp.h b/include/lldp.h
> index e00ba7a..fd515cd 100644
> --- a/include/lldp.h
> +++ b/include/lldp.h
> @@ -190,6 +190,7 @@ enum {
>
> /* IEEE 802.1Qbg subtype */
> #define LLDP_EVB_SUBTYPE 0
> +#define LLDP_VDP_SUBTYPE 0x2
>
> /* forwarding mode */
> #define LLDP_EVB_CAPABILITY_FORWARD_STANDARD (1 << 7)
> diff --git a/include/lldp_evb.h b/include/lldp_evb.h
> index 667f9ad..d028c21 100644
> --- a/include/lldp_evb.h
> +++ b/include/lldp_evb.h
> @@ -37,6 +37,12 @@ typedef enum {
> EVB_CONFIRMATION
> } evb_state;
>
> +#define RTE 13
> +/* retransmission granularity (RTG) in microseconds */
> +#define EVB_RTG 10
> +/* retransmission multiplier (RTM) */
> +#define EVB_RTM(rte) (2<<(RTE-1))
> +
> struct tlv_info_evb {
> u8 oui[3];
> u8 sub;
> diff --git a/include/lldp_vdp.h b/include/lldp_vdp.h
> new file mode 100644
> index 0000000..b97d8c0
> --- /dev/null
> +++ b/include/lldp_vdp.h
> @@ -0,0 +1,159 @@
> +/*******************************************************************************
> +
> + implementation of according to IEEE 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#ifndef _LLDP_VDP_H
> +#define _LLDP_VDP_H
> +
> +#include "lldp_mod.h"
> +#include "ecp/ecp.h"
> +
> +#define LLDP_MOD_VDP OUI_IEEE_8021Qbg+1
> +
> +#define VDP_MODE_PREASSOCIATE 0x0
> +#define VDP_MODE_PREASSOCIATE_WITH_RR 0x1
> +#define VDP_MODE_ASSOCIATE 0x2
> +#define VDP_MODE_DEASSOCIATE 0x3
> +
> +#define VDP_RESPONSE_SUCCESS 0x0
> +#define VDP_RESPONSE_INVALID_FORMAT 0x1
> +#define VDP_RESPONSE_INSUFF_RESOURCES 0x2
> +#define VDP_RESPONSE_UNUSED_VTID 0x3
> +#define VDP_RESPONSE_VTID_VIOLATION 0x4
> +#define VDP_RESPONSE_VTID_VER_VIOLATION 0x5
> +#define VDP_RESPONSE_OUT_OF_SYNC 0x6
> +
> +enum {
> + VDP_PROFILE_NOCHANGE = 0,
> + VDP_PROFILE_REQ,
> + VDP_PROFILE_ACK,
> + VDP_PROFILE_NACK,
> +};
> +
> +#define VDP_MACVLAN_FORMAT_1 1
> +
> +#define VDP_TRANSMISSION_TIMER 3*EVB_RTM(RTE)*EVB_RTG
> +#define VDP_TRANSMISSION_DIVIDER 10000
> +
> +#define VDP_ROLE_STATION 0
> +#define VDP_ROLE_BRIDGE 1
> +
> +enum {
> + VSI_UNASSOCIATED = 0,
> + VSI_ASSOC_PROCESSING,
> + VSI_ASSOCIATED,
> + VSI_PREASSOC_PROCESSING,
> + VSI_PREASSOCIATED,
> + VSI_DEASSOC_PROCESSING,
> + VSI_EXIT,
> +};
> +
> +static char *vsi_states[] = {
> + "VSI_UNASSOCIATED",
> + "VSI_ASSOC_PROCESSING",
> + "VSI_ASSOCIATED",
> + "VSI_PREASSOC_PROCESSING",
> + "VSI_PREASSOCIATED",
> + "VSI_DEASSOC_PROCESSING",
> + "VSI_EXIT"
> +};
> +
> +struct mac_vlan {
> + u8 mac[6];
> + u16 vlan;
> +} __attribute__ ((__packed__));
> +
> +struct tlv_info_vdp {
> + u8 oui[3];
> + u8 sub;
> + u8 mode;
> + u8 response;
> + u8 mgrid;
> + u8 id[3];
> + u8 version;
> + u8 instance[16];
> + u8 format;
> + u16 entries;
> + struct mac_vlan mac_vlan;
> +} __attribute__ ((__packed__));
> +
> +struct vsi_profile {
> + int mode;
> + int response;
> + u8 mgrid;
> + int id;
> + u8 version;
> + u8 instance[16];
> + u8 mac[6]; /* TODO: currently only one MAC/VLAN pair supported, more later */
> + u16 vlan;
> + struct port *port;
> + int ackTimerExpired;
> + int ackReceived;
> + int state;
> + int localChange;
> + LIST_ENTRY(vsi_profile) profile;
> +};
> +
> +struct vdp_data {
> + char ifname[IFNAMSIZ];
> + struct ecp ecp;
> + struct unpacked_tlv *vdp;
> + int role;
> + LIST_HEAD(profile_head, vsi_profile) profile_head;
> + LIST_ENTRY(vdp_data) entry;
> +};
> +
> +struct vdp_user_data {
> + LIST_HEAD(vdp_head, vdp_data) head;
> +};
> +
> +struct lldp_module *vdp_register(void);
> +void vdp_unregister(struct lldp_module *mod);
> +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);
> +
> +#define MAC_ADDR_STRLEN 18
> +#define INSTANCE_STRLEN 32
> +
> +#define PRINT_PROFILE(s, p) \
> +{ int c; \
> + c = sprintf(s, "\nmode: %i\n", p->mode); s += c; \
> + c = sprintf(s, "response: %i\n", p->response); s += c; \
> + c = sprintf(s, "state: %i\n", p->state); s += c; \
> + c = sprintf(s, "mgrid: %i\n", p->mgrid); s += c; \
> + c = sprintf(s, "id: %x\n", p->id); \
> + s += c; \
> + c = sprintf(s, "version: %i\n", p->version); s += c; \
> + char instance[INSTANCE_STRLEN+2]; \
> + instance2str(p->instance, instance, sizeof(instance)); \
> + c = sprintf(s, "instance: %s\n", &instance[0]); s += c; \
> + char macbuf[MAC_ADDR_STRLEN+1]; \
> + mac2str(p->mac, macbuf, MAC_ADDR_STRLEN); \
> + c = sprintf(s, "mac: %s\n", macbuf); s += c; \
> + c = sprintf(s, "vlan: %i\n\n", p->vlan); s += c; \
> +}
> +
> +#endif /* _LLDP_VDP_H */
> diff --git a/lldp/l2_packet.h b/lldp/l2_packet.h
> index 16f3683..0962429 100644
> --- a/lldp/l2_packet.h
> +++ b/lldp/l2_packet.h
> @@ -36,6 +36,8 @@
>
> #define ETH_P_LLDP 0x88cc
>
> +/* TODO: use extended ethertype until final ethertype is available */
> +#define ETH_P_ECP 0x88b7
>
> #define ETH_FRAME_LEN 1514
>
> diff --git a/lldp/ports.h b/lldp/ports.h
> index 0138efe..44dc5f1 100644
> --- a/lldp/ports.h
> +++ b/lldp/ports.h
> @@ -142,15 +142,20 @@ struct port {
> u8 portEnabled;
> u8 prevPortEnabled;
> u8 adminStatus;
> - u8 rxChanges;
> - u16 lldpdu;
> +
> + /* protocol specific */
> struct l2_packet_data *l2;
> struct portrx rx;
> struct porttx tx;
> - struct porttlvs tlvs;
> struct portstats stats;
> struct porttimers timers;
> + u8 rxChanges;
> + u16 lldpdu;
> struct msap msap;
> +
> + /* not sure */
> + struct porttlvs tlvs;
> +
> struct port *next;
> };
>
> diff --git a/lldp_vdp.c b/lldp_vdp.c
> new file mode 100644
> index 0000000..c2b21bb
> --- /dev/null
> +++ b/lldp_vdp.c
> @@ -0,0 +1,1185 @@
> +/*******************************************************************************
> +
> + implementation of VDP according to IEEE 802.1Qbg
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#include <net/if.h>
> +#include <sys/queue.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/utsname.h>
> +#include <linux/if_bridge.h>
> +#include "lldp.h"
> +#include "lldp_vdp.h"
> +#include "ecp/ecp.h"
> +#include "eloop.h"
> +#include "lldp_evb.h"
> +#include "messages.h"
> +#include "config.h"
> +#include "common.h"
> +#include "lldp_vdp_clif.h"
> +#include "lldp_vdp_cmds.h"
> +
> +/* vdp_data - searches vdp_data in the list of modules for this port
> + * @ifname: interface name to search for
> + *
> + * returns vdp_data on success, NULL on error
> + *
> + * searches the list of user_data for the VDP module user_data.
> + */
> +struct vdp_data *vdp_data(char *ifname)
> +{
> + struct vdp_user_data *ud;
> + struct vdp_data *vd = NULL;
> +
> + ud = find_module_user_data_by_if(ifname, &lldp_head, LLDP_MOD_VDP);
> + if (ud) {
> + LIST_FOREACH(vd, &ud->head, entry) {
> + if (!strncmp(ifname, vd->ifname, IFNAMSIZ))
> + return vd;
> + }
> + }
> + return NULL;
> +}
> +
> +/* vdp_free_tlv - free tlv in vdp_data
> + * @vd: vdp_data
> + *
> + * no return value
> + *
> + * frees up tlv in vdp_data. used in vdp_free_data.
> + */
> +static void vdp_free_tlv(struct vdp_data *vd)
> +{
> + if (vd) {
> + FREE_UNPKD_TLV(vd, vdp);
> + }
> +}
> +
> +/* vdp_free_data - frees up vdp data
> + * @ud: user data structure
> + *
> + * no return value
> + *
> + * removes vd_structure from the user_data list. frees up tlv in vdp_data.
> + * used in vdp_unregister.
> + */
> +static void vdp_free_data(struct vdp_user_data *ud)
> +{
> + struct vdp_data *vd;
> + if (ud) {
> + while (!LIST_EMPTY(&ud->head)) {
> + vd = LIST_FIRST(&ud->head);
> + LIST_REMOVE(vd, entry);
> + vdp_free_tlv(vd);
> + free(vd);
> + }
> + }
> +}
> +
> +/* vdp_print_profile - print a vsi profile
> + * @profile: profile to print
> + *
> + * no return value
> + *
> + * 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)
> +{
> + char *s, *t;
> +
> + s = t = malloc(VDP_BUF_SIZE);
> +
> + if (!s) {
> + printf("%s(%i): unable to allocate string !\n", __func__, __LINE__);
> + }
> +
> + PRINT_PROFILE(t, profile);
> +
> + printf("profile: %s\n", s);
> +
> + free(s);
> +}
> +
> +/* vdp_somethingChangedLocal - set flag if profile has changed
> + * @profile: profile to set the flag for
> + * @mode: mode to set the flag to
> + *
> + * no return value
> + *
> + * set the localChange flag with a mode to indicate a profile has changed.
> + * used next time when a ecpdu with profiles is sent out.
> + */
> +void vdp_somethingChangedLocal(struct vsi_profile *profile, int mode)
> +{
> + profile->localChange = mode;
> +}
> +
> +/* vdp_ackTimer_expired - checks for expired ack timer
> + * @profile: profile to be checked
> + *
> + * returns true or false
> + *
> + * returns value of profile->ackTimerExpired, true if ack timer has expired,
> + * false otherwise.
> + */
> +static bool vdp_ackTimer_expired(struct vsi_profile *profile)
> +{
> + return profile->ackTimerExpired;
> +}
> +
> +/* vdp_timeout_handler - handles the ack timer expiry
> + * @eloop_data: data structure of event loop
> + * @user_ctx: user context, profile here
> + *
> + * no return value
> + *
> + * called when the VDP ack timer has expired. sets a flag and calls the VDP
> + * state machine.
> + */
> +void vdp_timeout_handler(void *eloop_data, void *user_ctx)
> +{
> + struct vsi_profile *profile;
> +
> + profile = (struct vsi_profile *) user_ctx;
> +
> + profile->ackTimerExpired = true;
> +
> + printf("%s(%i)-%s: timer expired\n", __func__, __LINE__,
> + profile->port->ifname);
> +
> + vdp_vsi_sm_station(profile);
> +}
> +
> +/* vdp_stop_ackTimer - stop the VDP ack timer
> + * @profile: profile to process
> + *
> + * returns the number of removed handlers
> + *
> + * stops the VDP ack timer. used when a ack frame for the profile has been
> + * received.
> + */
> +static int vdp_stop_ackTimer(struct vsi_profile *profile)
> +{
> + printf("%s(%i)-%s: stopping timer\n", __func__, __LINE__,
> + profile->port->ifname);
> +
> + return eloop_cancel_timeout(vdp_timeout_handler, NULL, (void *) profile);
> +}
> +
> +/* vdp_start_ackTimer - starts the VDP ack timer
> + * @profile: profile to process
> + *
> + * returns 0 on success, -1 on error
> + *
> + * starts the ack timer when a frame has been sent out.
> + */
> +static int vdp_start_ackTimer(struct vsi_profile *profile)
> +{
> + unsigned int secs, usecs;
> +
> + profile->ackTimerExpired = false;
> +
> + secs = VDP_TRANSMISSION_TIMER / VDP_TRANSMISSION_DIVIDER;
> + usecs = VDP_TRANSMISSION_TIMER % VDP_TRANSMISSION_DIVIDER;
> +
> + printf("%s(%i)-%s: starting timer\n", __func__, __LINE__,
> + profile->port->ifname);
> +
> + return eloop_register_timeout(secs, usecs, vdp_timeout_handler, NULL, (void *) profile);
> +}
> +
> +/* vdp_vsi_change_station_state - changes the VDP station sm state
> + * @profile: profile to process
> + * @newstate: new state for the sm
> + *
> + * no return value
> + *
> + * actually changes the state of the profile
> + */
> +void vdp_vsi_change_station_state(struct vsi_profile *profile, u8 newstate)
> +{
> + switch(newstate) {
> + case VSI_UNASSOCIATED:
> + break;
> + case VSI_ASSOC_PROCESSING:
> + assert((profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_UNASSOCIATED));
> + break;
> + case VSI_ASSOCIATED:
> + assert(profile->state == VSI_ASSOC_PROCESSING);
> + break;
> + case VSI_PREASSOC_PROCESSING:
> + assert(profile->state == VSI_UNASSOCIATED);
> + break;
> + case VSI_PREASSOCIATED:
> + assert(profile->state == VSI_PREASSOC_PROCESSING);
> + break;
> + case VSI_DEASSOC_PROCESSING:
> + assert((profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_ASSOCIATED));
> + break;
> + case VSI_EXIT:
> + assert((profile->state == VSI_ASSOC_PROCESSING) ||
> + (profile->state == VSI_PREASSOC_PROCESSING) ||
> + (profile->state == VSI_DEASSOC_PROCESSING) ||
> + (profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_ASSOCIATED));
> + break;
> + default:
> + printf("ERROR: The VDP station State Machine is broken!\n");
> + break;
> + }
> +
> + printf("%s(%i)-%s: state change %s -> %s\n", __func__, __LINE__,
> + profile->port->ifname, vsi_states[profile->state], vsi_states[newstate]);
> +
> + profile->state = newstate;
> +}
> +
> +/* vdp_vsi_set_station_state - sets the vdp sm station state
> + * @profile: profile to process
> + *
> + * returns true or false
> + *
> + * switches the state machine to the next state depending on the input
> + * variables. returns true or false depending on wether the state machine
> + * can be run again with the new state or can stop at the current state.
> + */
> +static bool vdp_vsi_set_station_state(struct vsi_profile *profile)
> +{
> + switch(profile->state) {
> + case VSI_UNASSOCIATED:
> + if ((profile->mode == VDP_MODE_PREASSOCIATE) ||
> + (profile->mode == VDP_MODE_PREASSOCIATE_WITH_RR)) {
> + vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_ASSOC_PROCESSING:
> + if (profile->ackReceived) {
> + vdp_vsi_change_station_state(profile, VSI_ASSOCIATED);
> + return true;
> + } else if (!profile->ackReceived && vdp_ackTimer_expired(profile)) {
> + vdp_vsi_change_station_state(profile, VSI_EXIT);
> + return true;
> + }
> + return false;
> + case VSI_ASSOCIATED:
> + if (profile->mode == VDP_MODE_PREASSOCIATE) {
> + vdp_vsi_change_station_state(profile, VSI_PREASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_DEASSOCIATE) {
> + vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_PREASSOC_PROCESSING:
> + if (profile->ackReceived) {
> + vdp_vsi_change_station_state(profile, VSI_PREASSOCIATED);
> + return true;
> + } else if (vdp_ackTimer_expired(profile)) {
> + vdp_vsi_change_station_state(profile, VSI_EXIT);
> + return true;
> + }
> + case VSI_PREASSOCIATED:
> + if (profile->mode == VDP_MODE_DEASSOCIATE) {
> + vdp_vsi_change_station_state(profile, VSI_DEASSOC_PROCESSING);
> + return true;
> + }
> + if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_station_state(profile, VSI_ASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_DEASSOC_PROCESSING:
> + if ((profile->ackReceived) || vdp_ackTimer_expired(profile)) {
> + vdp_vsi_change_station_state(profile, VSI_EXIT);
> + return true;
> + }
> + return false;
> + case VSI_EXIT:
> + return false;
> + default:
> + printf("ERROR: The VSI RX State Machine is broken!\n");
> + log_message(MSG_ERR_RX_SM_INVALID, "");
> + return false;
> + }
> +}
> +
> +/* vdp_vsi_sm_station - state machine for vdp station role
> + * @profile: profile for which the state is processed
> + *
> + * no return value
> + *
> + * runs the state machine for the station role of VDP.
> + */
> +void vdp_vsi_sm_station(struct vsi_profile *profile)
> +{
> + struct vdp_data *vd = vdp_data(profile->port->ifname);
> +
> + vdp_vsi_set_station_state(profile);
> + do {
> + printf("%s(%i)-%s: station - %s\n", __func__, __LINE__,
> + profile->port->ifname, vsi_states[profile->state]);
> +
> + switch(profile->state) {
> + case VSI_UNASSOCIATED:
> + break;
> + case VSI_ASSOC_PROCESSING:
> + vdp_somethingChangedLocal(profile, VDP_PROFILE_REQ);
> + ecp_somethingChangedLocal(vd, VDP_PROFILE_REQ);
> + ecp_tx_run_sm(vd);
> + vdp_start_ackTimer(profile);
> + break;
> + case VSI_ASSOCIATED:
> + vdp_stop_ackTimer(profile);
> + /* TODO:
> + * vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
> + * if (!vsiError) vsistate=ASSOCIATED */
> + break;
> + case VSI_PREASSOC_PROCESSING:
> + /* send out profile */
> + vdp_somethingChangedLocal(profile, VDP_PROFILE_REQ);
> + ecp_somethingChangedLocal(vd, VDP_PROFILE_REQ);
> + ecp_tx_run_sm(vd);
> + vdp_start_ackTimer(profile);
> + break;
> + case VSI_PREASSOCIATED:
> + profile->ackReceived = false;
> + vdp_somethingChangedLocal(profile, VDP_PROFILE_NOCHANGE);
> + vdp_stop_ackTimer(profile);
> + /* TODO vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
> + * if (!vsiError) vsistate=PREASSOCIATED */
> + break;
> + case VSI_DEASSOC_PROCESSING:
> + vdp_somethingChangedLocal(profile, VDP_PROFILE_REQ);
> + ecp_somethingChangedLocal(vd, VDP_PROFILE_REQ);
> + ecp_tx_run_sm(vd);
> + vdp_start_ackTimer(profile);
> + break;
> + case VSI_EXIT:
> + /* TODO: send DEASSOC here ? */
> + vdp_stop_ackTimer(profile);
> + vdp_remove_profile(profile);
> + break;
> + default:
> + printf("ERROR: The VSI RX station State Machine is broken!\n");
> + log_message(MSG_ERR_TX_SM_INVALID, "");
> + }
> + } while (vdp_vsi_set_station_state(profile) == true);
> +
> +}
> +
> +/* vdp_vsi_change_bridge_state - changes the VDP bridge sm state
> + * @profile: profile to process
> + * @newstate: new state for the sm
> + *
> + * no return value
> + *
> + * actually changes the state of the profile
> + */
> +static void vdp_vsi_change_bridge_state(struct vsi_profile *profile, u8 newstate)
> +{
> + switch(newstate) {
> + case VSI_UNASSOCIATED:
> + break;
> + case VSI_ASSOC_PROCESSING:
> + assert((profile->state == VSI_UNASSOCIATED) ||
> + (profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_ASSOCIATED));
> + break;
> + case VSI_ASSOCIATED:
> + assert(profile->state == VSI_ASSOC_PROCESSING);
> + break;
> + case VSI_PREASSOC_PROCESSING:
> + assert((profile->state == VSI_UNASSOCIATED) ||
> + (profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_ASSOCIATED));
> + break;
> + case VSI_PREASSOCIATED:
> + assert(profile->state == VSI_PREASSOC_PROCESSING);
> + break;
> + case VSI_DEASSOC_PROCESSING:
> + assert((profile->state == VSI_UNASSOCIATED) ||
> + (profile->state == VSI_PREASSOCIATED) ||
> + (profile->state == VSI_ASSOCIATED));
> + break;
> + case VSI_EXIT:
> + assert((profile->state == VSI_DEASSOC_PROCESSING) ||
> + (profile->state == VSI_PREASSOC_PROCESSING) ||
> + (profile->state == VSI_ASSOC_PROCESSING));
> + break;
> + default:
> + printf("ERROR: The VDP bridge State Machine is broken!\n");
> + break;
> + }
> + profile->state = newstate;
> +}
> +
> +/* vdp_vsi_set_bridge_state - sets the vdp sm bridge state
> + * @profile: profile to process
> + *
> + * returns true or false
> + *
> + * switches the state machine to the next state depending on the input
> + * variables. returns true or false depending on wether the state machine
> + * can be run again with the new state or can stop at the current state.
> + */
> +static bool vdp_vsi_set_bridge_state(struct vsi_profile *profile)
> +{
> + switch(profile->state) {
> + case VSI_UNASSOCIATED:
> + if ((profile->mode == VDP_MODE_DEASSOCIATE)) /* || (INACTIVE)) */ {
> + vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_PREASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_ASSOC_PROCESSING:
> + /* TODO: handle error case
> + if (!vsiError) ||
> + (vsiError && vsiState == Assoc) {
> + */
> + if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_ASSOCIATED);
> + return true;
> + }
> + return false;
> + case VSI_ASSOCIATED:
> + if (profile->mode == VDP_MODE_ASSOCIATE) /* || ( INACTIVE )*/ {
> + vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_PREASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_PREASSOC_PROCESSING:
> + if (profile->response != VDP_RESPONSE_SUCCESS) {
> + vdp_vsi_change_bridge_state(profile, VSI_EXIT);
> + return true;
> + }
> + vdp_vsi_change_bridge_state(profile, VSI_PREASSOCIATED);
> + return false;
> + case VSI_PREASSOCIATED:
> + if (profile->mode == VDP_MODE_ASSOCIATE) {
> + vdp_vsi_change_bridge_state(profile, VSI_ASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_DEASSOCIATE ) {
> + vdp_vsi_change_bridge_state(profile, VSI_DEASSOC_PROCESSING);
> + return true;
> + } else if (profile->mode == VDP_MODE_PREASSOCIATE ) {
> + vdp_vsi_change_bridge_state(profile, VSI_PREASSOC_PROCESSING);
> + return true;
> + }
> + return false;
> + case VSI_DEASSOC_PROCESSING:
> + vdp_vsi_change_bridge_state(profile, VSI_EXIT);
> + return false;
> + case VSI_EXIT:
> + return false;
> + default:
> + printf("ERROR: The VSI RX State Machine (bridge) is broken!\n");
> + log_message(MSG_ERR_RX_SM_INVALID, "");
> + return false;
> + }
> +}
> +
> +/* vdp_vsi_sm_bridge - state machine for vdp bridge role
> + * @profile: profile for which the state is processed
> + *
> + * no return value
> + *
> + * runs the state machine for the bridge role of VDP.
> + */
> +static void vdp_vsi_sm_bridge(struct vsi_profile *profile)
> +{
> + struct vdp_data *vd = vdp_data(profile->port->ifname);
> +
> + vdp_vsi_set_bridge_state(profile);
> + do {
> + printf("%s(%i)-%s: bridge - %s\n", __func__, __LINE__,
> + profile->port->ifname, vsi_states[profile->state]);
> + switch(profile->state) {
> + case VSI_UNASSOCIATED:
> + break;
> + case VSI_ASSOC_PROCESSING:
> + /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
> + * if (vsiError)
> + * txTLV(Assoc NACK)
> + * else
> + * txTLV(Assoc ACK)
> + */
> + break;
> + case VSI_ASSOCIATED:
> + break;
> + case VSI_PREASSOC_PROCESSING:
> + /* TODO: vsiError = ProcRxandSetCfg(remoteTLV, localtlv, vsistate);
> + * if (vsiError)
> + * txTLV(PreAssoc NACK)
> + * else
> + * txTLV(PreAssoc ACK)
> + */
> + /* for now, we always succeed */
> + profile->response = VDP_RESPONSE_SUCCESS;
> + printf("%s(%i)-%s: framein %p, sizein %i\n", __func__, __LINE__,
> + profile->port->ifname, vd->ecp.rx.framein,
> + vd->ecp.rx.sizein);
> + ecp_rx_send_ack_frame(profile->port);
> + break;
> + case VSI_PREASSOCIATED:
> + printf("%s(%i)-%s: \n", __func__, __LINE__, profile->port->ifname);
> + break;
> + case VSI_DEASSOC_PROCESSING:
> + /* TODO: txTLV(DeAssoc ACK) */
> + break;
> + case VSI_EXIT:
> + vdp_remove_profile(profile);
> + break;
> + default:
> + printf("ERROR: The VSI RX bridge State Machine is broken!\n");
> + log_message(MSG_ERR_TX_SM_INVALID, "");
> + }
> + } while (vdp_vsi_set_bridge_state(profile) == true);
> +
> +}
> +
> +/*
> + * vdp_print_vsi_tlv - print the raw contents of a VSI TLV
> + * @tlv: the unpacked tlv which gets printed
> + *
> + * No return value
> + *
> + * used for protocol debug purposes
> + */
> +static void vdp_print_vsi_tlv(struct unpacked_tlv *tlv)
> +{
> + int i;
> +
> + printf("### %s:type %i, length %i, info:\n", __func__, tlv->type, tlv->length);
> +
> + for (i=0; i < tlv->length; i++) {
> + printf("%02x ", tlv->info[i]);
> + if (!((i+1) % 16))
> + printf("\n");
> + }
> +
> + printf("\n");
> +}
> +
> +/*
> + * vdp_validate_tlv - validates vsi tlvs
> + * @vdp: decoded vsi tlv
> + *
> + * Returns 0 on success, 1 on error
> + *
> + * checks the contents of an already decoded vsi tlv for inconsistencies
> + */
> +static int vdp_validate_tlv(struct tlv_info_vdp *vdp)
> +{
> + if (ntoh24(vdp->oui) != OUI_IEEE_8021Qbg) {
> + printf("vdp->oui %06x \n", ntoh24(vdp->oui));
> + goto out_err;
> + }
> +
> + if (vdp->sub != LLDP_VDP_SUBTYPE) {
> + printf("vdp->sub %02x \n", vdp->sub);
> + goto out_err;
> + }
> +
> + if ((vdp->mode < VDP_MODE_PREASSOCIATE) ||
> + (vdp->mode > VDP_MODE_DEASSOCIATE)) {
> + printf("Unknown mode %02x in vsi tlv !\n", vdp->mode);
> + goto out_err;
> + }
> +
> + if ((vdp->response < VDP_RESPONSE_SUCCESS) ||
> + (vdp->response > VDP_RESPONSE_OUT_OF_SYNC)) {
> + printf("Unknown response %02x \n", vdp->response);
> + goto out_err;
> + }
> +
> + if (vdp->format != VDP_MACVLAN_FORMAT_1) {
> + printf("Unknown format %02x in vsi tlv !\n", vdp->format);
> + goto out_err;
> + }
> +
> + if (ntohs(vdp->entries) != 1) {
> + printf("Multiple entries %02x in vsi tlv !\n", vdp->entries);
> + goto out_err;
> + }
> +
> + return 0;
> +
> +out_err:
> + return 1;
> +}
> +
> +/*
> + * vdp_indicate - receive VSI TLVs from ECP
> + * @port: the port on which the tlv was received
> + * @tlv: the unpacked tlv to receive
> + * @ecp_mode: the mode under which the tlv was received (ACK or REQ)
> + *
> + * Returns 0 on success
> + *
> + * receives a vsi tlv and creates a profile. Take appropriate action
> + * depending on the role of the (receive) port
> + */
> +int vdp_indicate(struct vdp_data *vd, struct unpacked_tlv *tlv, int ecp_mode)
> +{
> + struct tlv_info_vdp *vdp;
> + struct vsi_profile *p, *profile;
> + struct port *port = port_find_by_name(vd->ifname);
> +
> + printf("%s(%i): indicating vdp for for %s !\n", __func__, __LINE__, vd->ifname);
> +
> + if (!port) {
> + printf("%s(%i): port not found for %s !\n", __func__, __LINE__, vd->ifname);
> + goto out_err;
> + }
> +
> + vdp = malloc(sizeof(struct tlv_info_vdp));
> +
> + if (!vdp) {
> + printf("%s(%i): unable to allocate vdp !\n", __func__, __LINE__);
> + goto out_err;
> + }
> +
> + memset(vdp, 0, sizeof(struct tlv_info_vdp));
> + memcpy(vdp, tlv->info, tlv->length);
> +
> + if (vdp_validate_tlv(vdp)) {
> + printf("%s(%i): Invalid TLV received !\n", __func__, __LINE__);
> + goto out_err;
Should be goto out_vdp
> + }
> +
> + profile = malloc(sizeof(struct vsi_profile));
> +
> + if (!profile) {
> + printf("%s(%i): unable to allocate profile !\n", __func__, __LINE__);
> + goto out_vdp;
> + }
> +
> + memset(profile, 0, sizeof(struct vsi_profile));
> +
> + profile->mode = vdp->mode;
> + profile->response = vdp->response;
> +
> + profile->mgrid = vdp->mgrid;
> + profile->id = ntoh24(vdp->id);
> + profile->version = vdp->version;
> + memcpy(&profile->instance, &vdp->instance, 16);
> + memcpy(&profile->mac, &vdp->mac_vlan.mac, MAC_ADDR_LEN);
> + profile->vlan = ntohs(vdp->mac_vlan.vlan);
> +
> + profile->port = port;
> +
> + if (vd->role == VDP_ROLE_STATION) {
> + /* do we have the profile already ? */
> + LIST_FOREACH(p, &vd->profile_head, profile) {
> + if (vdp_profile_equal(p, profile)) {
> + printf("%s(%i): station: profile found, localChange %i ackReceived %i!\n",
> + __func__, __LINE__, p->localChange, p->ackReceived);
> +
> + p->ackReceived = true;
> +
> + vdp_vsi_sm_station(p);
> + } else {
> + printf("%s(%i): station: profile not found !\n", __func__, __LINE__);
> + /* ignore profile */
> + }
> + }
> + }
> +
> + if (vd->role == VDP_ROLE_BRIDGE) {
> + /* do we have the profile already ? */
> + LIST_FOREACH(p, &vd->profile_head, profile) {
> + if (vdp_profile_equal(p, profile)) {
> + break;
> + }
> + }
> +
> + if (p) {
> + printf("%s(%i): bridge: profile found !\n", __func__, __LINE__);
> + } else {
> + printf("%s(%i): bridge: profile not found !\n", __func__, __LINE__);
> + /* put it in the list */
> + profile->state = VSI_UNASSOCIATED;
> + LIST_INSERT_HEAD(&vd->profile_head, profile, profile );
> + }
> +
> + vdp_vsi_sm_bridge(profile);
> + }
> +
Here the profile is added to a list if the port is in the VDP_ROLE_BRIDGE mode. Otherwise the profile is only used to lookup an existing profile? Looks like there might be a memory leak if the profile already exists. Does the profile need to be cleaned up the somewhere?
> + return 0;
> +
> +out_vdp:
> + free(vdp);
> +out_err:
> + printf("%s(%i): error !\n", __func__, __LINE__);
> + return 1;
> +
> +}
The rest looks good.
Thanks,
John
^ permalink raw reply
* Re: [E1000-eedc] [PATCH 2/9] implementation of IEEE 802.1Qbg in lldpad, part 1
From: John Fastabend @ 2010-10-12 18:05 UTC (permalink / raw)
To: Jens Osterkamp
Cc: chrisw@redhat.com, evb@yahoogroups.com, e1000-eedc,
virtualization@lists.linux-foundation.org
In-Reply-To: <1285686662-8561-3-git-send-email-jens@linux.vnet.ibm.com>
On 9/28/2010 8:10 AM, Jens Osterkamp wrote:
> This patch contains the first part of an initial implementation of the
> IEEE 802.1Qbg standard: it implements code for the exchange of EVB
> capabilities between a host with virtual machines and an adjacent switch.
> For this it adds a new EVB TLV to LLDP.
>
> Exchange of EVB TLV may be enabled or disabled on a per port basis.
> Information about the information negotiated by the protocol can be
> queried on the commandline with lldptool.
>
> This patch adds support for querying and setting parameters used in
> the exchange of EVB TLV messages.
> The parameters that can be set are:
>
> - forwarding mode
> - host protocol capabilities (RTE, ECP, VDP)
> - no. of supported VSIs
> - retransmission timer exponent (RTE)
>
> The parameters are implemented as a local policy: all frames received by
> an adjacent switch are validated against this policy and taken over where
> appropriate. Negotiated parameters are stored in lldpads config, picked up
> again and used at the next start.
>
> The patch applies to lldpad 0.9.38 and still contains code to log protocol
> activity more verbosely than it would be necessary in the final version.
>
> Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
> ---
> Makefile.am | 10 +-
> include/lldp.h | 19 ++
> include/lldp_evb.h | 80 ++++++
> include/lldp_evb_clif.h | 51 ++++
> include/lldp_evb_cmds.h | 31 +++
> include/lldp_tlv.h | 1 +
> lldp_evb.c | 638 +++++++++++++++++++++++++++++++++++++++++++++++
> lldp_evb_clif.c | 226 +++++++++++++++++
> lldp_evb_cmds.c | 512 +++++++++++++++++++++++++++++++++++++
> lldpad.c | 2 +
> lldptool.c | 2 +
> 11 files changed, 1568 insertions(+), 4 deletions(-)
> create mode 100644 include/lldp_evb.h
> create mode 100644 include/lldp_evb_clif.h
> create mode 100644 include/lldp_evb_cmds.h
> create mode 100644 lldp_evb.c
> create mode 100644 lldp_evb_clif.c
> create mode 100644 lldp_evb_cmds.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 743e16f..d59a6fa 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -37,7 +37,7 @@ lldpad_include_HEADERS = include/dcb_types.h include/dcbtool.h \
> include/dcb_osdep.h include/clif.h include/lldp_dcbx_cmds.h include/common.h \
> include/lldpad.h include/os.h include/includes.h include/lldp_mand_cmds.h \
> include/clif_msgs.h include/lldp_basman_cmds.h include/lldp_8023_cmds.h \
> -include/lldp_med_cmds.h include/lldp_dcbx_cfg.h
> +include/lldp_med_cmds.h include/lldp_dcbx_cfg.h include/lldp_evb_cmds.h
>
> noinst_HEADERS = include/config.h include/ctrl_iface.h \
> include/dcb_driver_if_types.h include/dcb_driver_interface.h \
> @@ -47,7 +47,7 @@ include/event_iface.h include/messages.h include/parse_cli.h include/version.h \
> include/lldptool_cli.h include/list.h \
> include/lldp_mand_clif.h include/lldp_basman_clif.h include/lldp_med_clif.h \
> include/lldp_8023_clif.h include/lldp_dcbx_clif.h include/lldptool.h \
> -include/lldp_rtnl.h
> +include/lldp_rtnl.h include/lldp_evb_clif.h
>
> lldpad_SOURCES = lldpad.c config.c drv_cfg.c ctrl_iface.c event_iface.c eloop.c \
> common.c os_unix.c lldp_dcbx_cmds.c log.c lldpad_shm.c \
> @@ -62,10 +62,12 @@ lldp_dcbx_cfg.c include/lldp_dcbx_cfg.h \
> lldp_util.c include/lldp_util.h \
> lldp_mand.c include/lldp_mand.h \
> lldp_mand_cmds.c lldp_basman_cmds.c lldp_8023_cmds.c lldp_med_cmds.c \
> +lldp_evb_cmds.c \
> lldp_tlv.c include/lldp_tlv.h \
> lldp_basman.c include/lldp_basman.h \
> lldp_med.c include/lldp_med.h \
> -lldp_8023.c include/lldp_8023.h
> +lldp_8023.c include/lldp_8023.h \
> +lldp_evb.c include/lldp_evb.h
>
>
>
> @@ -74,7 +76,7 @@ $(lldpad_include_HEADERS) $(noinst_HEADERS)
>
> lldptool_SOURCES = lldptool.c clif.c lldptool_cmds.c common.c os_unix.c \
> lldp_mand_clif.c lldp_basman_clif.c lldp_med_clif.c lldp_8023_clif.c \
> -lldp_dcbx_clif.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
> +lldp_dcbx_clif.c lldp_evb_clif.c $(lldpad_include_HEADERS) $(noinst_HEADERS)
>
> nltest_SOURCES = nltest.c nltest.h
>
> diff --git a/include/lldp.h b/include/lldp.h
> index 66532bd..e00ba7a 100644
> --- a/include/lldp.h
> +++ b/include/lldp.h
> @@ -45,6 +45,8 @@
> /* Telecommunications Industry Association TR-41 Committee */
> #define OUI_TIA_TR41 0x0012bb
>
> +#define OUI_IEEE_8021Qbg 0x001b3f
> +
> /* IEEE 802.3AB Clause 9: TLV Types */
> #define CHASSIS_ID_TLV 1
> #define PORT_ID_TLV 2
> @@ -186,5 +188,22 @@ enum {
> #define LLDP_8023_LINKAGG_CAPABLE (1 << 0)
> #define LLDP_8023_LINKAGG_ENABLED (1 << 1)
>
> +/* IEEE 802.1Qbg subtype */
> +#define LLDP_EVB_SUBTYPE 0
> +
> +/* forwarding mode */
> +#define LLDP_EVB_CAPABILITY_FORWARD_STANDARD (1 << 7)
> +#define LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY (1 << 6)
> +
> +/* EVB supported protocols */
> +#define LLDP_EVB_CAPABILITY_PROTOCOL_RTE (1 << 2)
> +#define LLDP_EVB_CAPABILITY_PROTOCOL_ECP (1 << 1)
> +#define LLDP_EVB_CAPABILITY_PROTOCOL_VDP (1 << 0)
> +
> +/* EVB specific values */
> +#define LLDP_EVB_DEFAULT_MAX_VSI 4096
> +#define LLDP_EVB_DEFAULT_SVSI 3295
> +#define LLDP_EVB_DEFAULT_RTE 15
> +
> void somethingChangedLocal(char *ifname);
> #endif /* _LLDP_H */
> diff --git a/include/lldp_evb.h b/include/lldp_evb.h
> new file mode 100644
> index 0000000..667f9ad
> --- /dev/null
> +++ b/include/lldp_evb.h
> @@ -0,0 +1,80 @@
> +/*******************************************************************************
> +
> + implementation of EVB TLVs for LLDP
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#ifndef _LLDP_EVB_H
> +#define _LLDP_EVB_H
> +
> +#include "lldp_mod.h"
> +
> +#define LLDP_MOD_EVB OUI_IEEE_8021Qbg
> +#define LLDP_OUI_SUBTYPE { 0x00, 0x1b, 0x3f, 0x00 }
> +
> +typedef enum {
> + EVB_OFFER_CAPABILITIES = 0,
> + EVB_CONFIGURE,
> + EVB_CONFIRMATION
> +} evb_state;
> +
> +struct tlv_info_evb {
> + u8 oui[3];
> + u8 sub;
> + /* supported forwarding mode */
> + u8 smode;
> + /* supported capabilities */
> + u8 scap;
> + /* currently configured forwarding mode */
> + u8 cmode;
> + /* currently configured capabilities */
> + u8 ccap;
> + /* supported no. of vsi */
> + u16 svsi;
> + /* currently configured no. of vsi */
> + u16 cvsi;
> + /* retransmission exponent */
> + u8 rte;
> +} __attribute__ ((__packed__));
> +
> +struct evb_data {
> + char ifname[IFNAMSIZ];
> + struct unpacked_tlv *evb;
> + struct tlv_info_evb *tie;
> + /* local policy */
> + struct tlv_info_evb *policy;
> + int state;
> + LIST_ENTRY(evb_data) entry;
> +};
> +
> +struct evb_user_data {
> + LIST_HEAD(evb_head, evb_data) head;
> +};
> +
> +struct lldp_module *evb_register(void);
> +void evb_unregister(struct lldp_module *mod);
> +struct packed_tlv *evb_gettlv(struct port *port);
> +void evb_ifdown(char *);
> +void evb_ifup(char *);
> +struct evb_data *evb_data(char *ifname);
> +
> +#endif /* _LLDP_EVB_H */
> diff --git a/include/lldp_evb_clif.h b/include/lldp_evb_clif.h
> new file mode 100644
> index 0000000..acaee5e
> --- /dev/null
> +++ b/include/lldp_evb_clif.h
> @@ -0,0 +1,51 @@
> +/*******************************************************************************
> +
> + implementation of EVB TLVs for LLDP
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#ifndef _LLDP_EVB_CLIF_H
> +#define _LLDP_EVB_CLIF_H
> +
> +struct lldp_module *evb_cli_register(void);
> +void evb_cli_unregister(struct lldp_module *);
> +int evb_print_tlv(u32, u16, char *);
> +
> +#define EVB_BUF_SIZE 256
> +
> +#define ARG_EVB_FORWARDING_MODE "fmode"
> +
> +#define VAL_EVB_FMODE_BRIDGE "bridge"
> +#define VAL_EVB_FMODE_REFLECTIVE_RELAY "reflectiverelay"
> +
> +#define ARG_EVB_CAPABILITIES "capabilities"
> +
> +#define VAL_EVB_CAPA_RTE "rte"
> +#define VAL_EVB_CAPA_ECP "ecp"
> +#define VAL_EVB_CAPA_VDP "vdp"
> +#define VAL_EVB_CAPA_NONE "none"
> +
> +#define ARG_EVB_VSIS "vsis"
> +
> +#define ARG_EVB_RTE "rte"
> +
> +#endif
> diff --git a/include/lldp_evb_cmds.h b/include/lldp_evb_cmds.h
> new file mode 100644
> index 0000000..1367e5d
> --- /dev/null
> +++ b/include/lldp_evb_cmds.h
> @@ -0,0 +1,31 @@
> +/*******************************************************************************
> +
> + implementation of EVB TLVs for LLDP
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#ifndef _LLDP_EVB_CMDS_H
> +#define _LLDP_EVB_CMDS_H
> +
> +struct arg_handlers *evb_get_arg_handlers();
> +
> +#endif
> diff --git a/include/lldp_tlv.h b/include/lldp_tlv.h
> index a32cc71..fe3a75a 100644
> --- a/include/lldp_tlv.h
> +++ b/include/lldp_tlv.h
> @@ -144,6 +144,7 @@ int tlv_ok(struct unpacked_tlv *tlv);
> #define TLVID_8021(sub) TLVID(OUI_IEEE_8021, (sub))
> #define TLVID_8023(sub) TLVID(OUI_IEEE_8023, (sub))
> #define TLVID_MED(sub) TLVID(OUI_TIA_TR41, (sub))
> +#define TLVID_8021Qbg(sub) TLVID(OUI_IEEE_8021Qbg, (sub))
>
> /* the size in bytes needed for a packed tlv from unpacked tlv */
> #define TLVSIZE(t) ((t) ? (2 + (t)->length) : 0)
> diff --git a/lldp_evb.c b/lldp_evb.c
> new file mode 100644
> index 0000000..fa2aed3
> --- /dev/null
> +++ b/lldp_evb.c
> @@ -0,0 +1,638 @@
> +/*******************************************************************************
> +
> + implementation of EVB TLVs for LLDP
> + (c) Copyright IBM Corp. 2010
> +
> + Author(s): Jens Osterkamp <jens@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.
> +
> + This program is distributed in the hope 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> +*******************************************************************************/
> +
> +#include <net/if.h>
> +#include <sys/queue.h>
> +#include <sys/socket.h>
> +#include <sys/ioctl.h>
> +#include <sys/utsname.h>
> +#include <linux/if_bridge.h>
> +#include <string.h>
> +#include "lldp.h"
> +#include "lldp_evb.h"
> +#include "messages.h"
> +#include "config.h"
> +#include "common.h"
> +#include "lldp_mand_clif.h"
> +#include "lldp_evb_clif.h"
> +#include "lldp_evb_cmds.h"
> +
> +extern struct lldp_head lldp_head;
> +
> +struct evb_data *evb_data(char *ifname)
> +{
> + struct evb_user_data *ud;
> + struct evb_data *ed = NULL;
> +
> + ud = find_module_user_data_by_if(ifname, &lldp_head, LLDP_MOD_EVB);
> + if (ud) {
> + LIST_FOREACH(ed, &ud->head, entry) {
> + if (!strncmp(ifname, ed->ifname, IFNAMSIZ))
> + return ed;
> + }
> + }
> + return NULL;
> +}
> +
> +static void evb_print_tlvinfo(struct tlv_info_evb *tie)
> +{
> + printf("%s(%i): supported forwarding mode: %02x\n", __FILE__, __LINE__, tie->smode);
> + printf("%s(%i): configured forwarding mode: %02x\n", __FILE__, __LINE__, tie->cmode);
> + printf("%s(%i): supported capabilities: %02x\n", __FILE__, __LINE__, tie->scap);
> + printf("%s(%i): configured capabilities: %02x\n", __FILE__, __LINE__, tie->ccap);
> + printf("%s(%i): supported no. of vsis: %04i\n", __FILE__, __LINE__, tie->svsi);
> + printf("%s(%i): configured no. of vsis: %04i\n", __FILE__, __LINE__, tie->cvsi);
> + printf("%s(%i): rte: %02i\n\n", __FILE__, __LINE__, tie->rte);
> +}
> +
> +/*
> + * evb_bld_cfg_tlv - build the EVB TLV
> + * @ed: the evb data struct
> + *
> + * Returns 0 on success
> + */
> +static int evb_bld_cfg_tlv(struct evb_data *ed)
> +{
> + int rc = 0;
> + int i;
> + struct unpacked_tlv *tlv = NULL;
> +
> + /* free ed->evb if it exists */
> + FREE_UNPKD_TLV(ed, evb);
> +
> + if (!is_tlv_txenabled(ed->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE))) {
> + fprintf(stderr, "%s:%s:EVB tx is currently disabled !\n",
> + __func__, ed->ifname);
> + rc = EINVAL;
> + goto out_err;
> + }
> +
> + tlv = create_tlv();
> + if (!tlv)
> + goto out_err;
> +
> + tlv->type = ORG_SPECIFIC_TLV;
> + tlv->length = sizeof(struct tlv_info_evb);
> + tlv->info = (u8 *)malloc(tlv->length);
> + if(!tlv->info) {
> + free(tlv);
> + tlv = NULL;
> + rc = ENOMEM;
> + goto out_err;
> + }
> + memcpy(tlv->info, ed->tie, tlv->length);
> +
> + printf("### %s:type %i, length %i, info ", __func__, tlv->type, tlv->length);
> +
> + for (i=0; i < tlv->length; i++)
> + printf("%02x ", tlv->info[i]);
> +
> + printf("\n");
> +
> + ed->evb = tlv;
> +out_err:
> + return rc;
> +}
> +
> +static void evb_free_tlv(struct evb_data *ed)
> +{
> + if (ed)
> + FREE_UNPKD_TLV(ed, evb);
> +}
> +
> +/* evb_init_cfg_tlv:
> + *
> + * fill up tlv_info_evb structure with reasonable info
> + */
> +static int evb_init_cfg_tlv(struct evb_data *ed)
> +{
> + char arg_path[EVB_BUF_SIZE];
> + char *param;
> +
> + /* load policy from config */
> + ed->policy = (struct tlv_info_evb *) calloc(1, sizeof(struct tlv_info_evb));
> +
> + if (!ed->policy)
> + return ENOMEM;
> +
> + /* set defaults */
> + hton24(ed->policy->oui, LLDP_MOD_EVB);
> + ed->policy->smode = LLDP_EVB_CAPABILITY_FORWARD_STANDARD;
> + ed->policy->scap = 0;
> + ed->policy->cmode = 0;
> + ed->policy->ccap = 0;
> + ed->policy->svsi = 0 /*LLDP_EVB_DEFAULT_SVSI*/;
> + ed->policy->rte = 0 /*LLDP_EVB_DEFAULT_RTE*/;
> +
> + /* pull forwarding mode into policy */
> + snprintf(arg_path, sizeof(arg_path), "%s%08x.fmode",
> + TLVID_PREFIX, TLVID_8021Qbg(LLDP_EVB_SUBTYPE));
> +
> + if (get_cfg(ed->ifname, arg_path, (void *) ¶m, CONFIG_TYPE_STRING)) {
> + printf("%s:%s: loading EVB policy for forwarding mode failed, using default.\n",
> + __func__, ed->ifname);
> + } else {
> + if (strcasestr(param, VAL_EVB_FMODE_BRIDGE)) {
> + ed->policy->smode = LLDP_EVB_CAPABILITY_FORWARD_STANDARD;
> + }
> +
> + if (strcasestr(param, VAL_EVB_FMODE_REFLECTIVE_RELAY)) {
> + ed->policy->smode = LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY;
> + }
> +
> + printf("%s:%s: policy param fmode = %s.\n", __func__, ed->ifname, param);
> + printf("%s:%s: policy param smode = %x.\n", __func__, ed->ifname, ed->policy->smode);
> + }
> +
> + /* pull capabilities into policy */
> + snprintf(arg_path, sizeof(arg_path), "%s%08x.capabilities",
> + TLVID_PREFIX, TLVID_8021Qbg(LLDP_EVB_SUBTYPE));
> +
> + if (get_cfg(ed->ifname, arg_path, (void *) ¶m, CONFIG_TYPE_STRING)) {
> + printf("%s:%s: loading EVB policy for capabilities failed, using default.\n",
> + __func__, ed->ifname);
> + } else {
> + if (strcasestr(param, VAL_EVB_CAPA_RTE)) {
> + ed->policy->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_RTE;
> + }
> +
> + if (strcasestr(param, VAL_EVB_CAPA_ECP)) {
> + ed->policy->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_ECP;
> + }
> +
> + if (strcasestr(param, VAL_EVB_CAPA_VDP)) {
> + ed->policy->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDP;
> + }
> +
> + printf("%s:%s: policy param capabilities = %s.\n", __func__, ed->ifname, param);
> + printf("%s:%s: policy param scap = %x.\n", __func__, ed->ifname, ed->policy->scap);
> + }
> +
> + /* pull rte into policy */
> + snprintf(arg_path, sizeof(arg_path), "%s%08x.rte",
> + TLVID_PREFIX, TLVID_8021Qbg(LLDP_EVB_SUBTYPE));
> +
> + if (get_cfg(ed->ifname, arg_path, (void *) ¶m, CONFIG_TYPE_STRING)) {
> + printf("%s:%s: loading EVB policy for rte failed, using default.\n",
> + __func__, ed->ifname);
> + } else {
> + ed->policy->rte = atoi(param);
> +
> + printf("%s:%s: policy param rte = %s.\n", __func__, ed->ifname, param);
> + printf("%s:%s: policy param rte = %i.\n", __func__, ed->ifname, ed->policy->rte);
> + }
> +
> + /* pull vsis into policy */
> + snprintf(arg_path, sizeof(arg_path), "%s%08x.vsis",
> + TLVID_PREFIX, TLVID_8021Qbg(LLDP_EVB_SUBTYPE));
> +
> + if (get_cfg(ed->ifname, arg_path, (void *) ¶m, CONFIG_TYPE_STRING)) {
> + printf("%s:%s: loading EVB policy for vsis failed, using default.\n",
> + __func__, ed->ifname);
> + } else {
> + ed->policy->svsi = atoi(param);
> +
> + printf("%s:%s: policy param vsis = %s.\n", __func__, ed->ifname, param);
> + printf("%s:%s: policy param vsis = %i.\n", __func__, ed->ifname, ed->policy->svsi);
> + }
> +
> + /* load last used EVB TLV ... */
> + ed->tie = (struct tlv_info_evb *) calloc(1, sizeof(struct tlv_info_evb));
> +
> + if (!ed->tie)
> + return ENOMEM;
> +
> + if (get_config_tlvinfo_bin(ed->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE),
> + (void *)ed->tie, sizeof(struct tlv_info_evb))) {
> + printf("%s:%s: loading last used EVB TLV failed, using default.\n",
> + __func__, ed->ifname);
> + hton24(ed->tie->oui, LLDP_MOD_EVB);
> + ed->tie->smode = ed->policy->smode;
> + ed->tie->cmode = 0x0;
> + ed->tie->scap = ed->policy->scap;
> + ed->tie->ccap = 0x0;
> + ed->tie->svsi = LLDP_EVB_DEFAULT_SVSI;
> + ed->tie->cvsi = 0x0;
> + ed->tie->rte = LLDP_EVB_DEFAULT_RTE;
> + } else {
> + printf("%s(%i): loaded last used EVB TLV from file.\n", __FILE__, __LINE__);
> + }
> +
> + return 0;
> +}
> +
> +static int evb_bld_tlv(struct evb_data *ed)
> +{
> + int rc = 0;
> +
> + if (!port_find_by_name(ed->ifname)) {
> + rc = EEXIST;
> + goto out_err;
> + }
> +
> + if (!init_cfg()) {
> + rc = ENOENT;
> + goto out_err;
> + }
> +
> + if (evb_bld_cfg_tlv(ed)) {
> + fprintf(stderr, "### %s:%s:evb_bld_cfg_tlv() failed\n",
> + __func__, ed->ifname);
> + rc = EINVAL;
> + goto out_err_destroy;
> + }
> +
> + return rc;
> +
> +out_err_destroy:
> + destroy_cfg();
> +out_err:
> + return rc;
> +}
> +
> +static void evb_free_data(struct evb_user_data *ud)
> +{
> + struct evb_data *ed;
> + if (ud) {
> + while (!LIST_EMPTY(&ud->head)) {
> + ed = LIST_FIRST(&ud->head);
> + LIST_REMOVE(ed, entry);
> + evb_free_tlv(ed);
> + free(ed);
> + }
> + }
> +}
> +
> +struct packed_tlv *evb_gettlv(struct port *port)
> +{
> + int size;
> + struct evb_data *ed;
> + struct packed_tlv *ptlv = NULL;
> +
> + ed = evb_data(port->ifname);
> + if (!ed)
> + goto out_err;
> +
> + evb_free_tlv(ed);
> +
> + if (evb_bld_tlv(ed)) {
> + fprintf(stderr, "### %s:%s evb_bld_tlv failed\n",
> + __func__, port->ifname);
> + goto out_err;
> + }
> +
> + size = TLVSIZE(ed->evb);
> +
> + if (!size)
> + goto out_err;
> +
> + ptlv = create_ptlv();
> + if (!ptlv)
> + goto out_err;
> +
> + ptlv->tlv = malloc(size);
> + if (!ptlv->tlv)
> + goto out_free;
> +
> + ptlv->size = 0;
> + PACK_TLV_AFTER(ed->evb, ptlv, size, out_free);
> + return ptlv;
> +out_free:
> + /* FIXME: free function returns pointer ? */
> + ptlv = free_pkd_tlv(ptlv);
> +out_err:
> + fprintf(stderr,"### %s:%s: failed\n", __func__, port->ifname);
> + return NULL;
> +}
> +
> +/* evb_check_and_fill
> + *
> + * checks values received in TLV and takes over some values
> + */
> +int evb_check_and_fill(struct evb_data *ed, struct tlv_info_evb *tie)
> +{
> + /* sanity check of received data in tie */
> + if ((tie->smode & (LLDP_EVB_CAPABILITY_FORWARD_STANDARD |
> + LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY)) == 0)
> + return TLV_ERR;
> +
> + if ((tie->svsi < 0) || (tie->svsi > LLDP_EVB_DEFAULT_MAX_VSI))
> + return TLV_ERR;
> +
> + if ((tie->cvsi < 0) || (tie->cvsi > LLDP_EVB_DEFAULT_MAX_VSI))
> + return TLV_ERR;
> +
> + /* check bridge capabilities against local policy*/
> + /* if bridge supports RR and we support it as well, request it
> + * by setting smode in tlv to be sent out (ed->tie->smode) */
> + if ( (tie->smode & ed->policy->smode) ==
> + LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY ) {
> + ed->tie->smode = LLDP_EVB_CAPABILITY_FORWARD_REFLECTIVE_RELAY;
> + } else {
> + ed->tie->smode = LLDP_EVB_CAPABILITY_FORWARD_STANDARD;
> + }
> +
> + /* If both sides support RTE, set it */
> + if ((tie->scap & ed->policy->scap) & LLDP_EVB_CAPABILITY_PROTOCOL_RTE)
> + ed->tie->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_RTE;
> +
> + /* If both sides support ECP, set it */
> + if ((tie->scap & ed->policy->scap) & LLDP_EVB_CAPABILITY_PROTOCOL_ECP)
> + ed->tie->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_ECP;
> +
> + /* If both sides support VDP, set it */
> + if ((tie->scap & ed->policy->scap) & LLDP_EVB_CAPABILITY_PROTOCOL_VDP)
> + ed->tie->scap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDP;
> +
> + /* If supported caps include VDP take over min value of both */
> + if (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP)
> + ed->tie->cvsi = MIN(ed->policy->svsi,tie->svsi);
> +
> + /* If both sides support RTE and value offer is > 0, set it */
> + if ((ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) &&
> + (tie->rte > 0) && (ed->policy->rte > 0))
> + ed->tie->rte = MAX(ed->policy->rte,tie->rte);
> +
> + if (set_config_tlvinfo_bin(ed->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE),
> + (void *)ed->tie, sizeof(struct tlv_info_evb))) {
> + printf("%s(%i): error saving tlv_info_evb !\n", __FILE__, __LINE__);
> + } else {
> + printf("%s(%i): saved tlv_info_evb to config !\n", __FILE__, __LINE__);
> + }
> +
> + /* maybe switch has already set the mode based on the saved info sent
> + * out on ifup */
> +
> + if (tie->cmode == ed->tie->smode)
> + ed->tie->cmode = tie->cmode;
> +
> + return TLV_OK;
> +}
> +
> +/* evb_compare
> + *
> + * compare our own and received tlv_info_evb
> + */
> +static int evb_compare(struct evb_data *ed, struct tlv_info_evb *tie)
> +{
> + printf("%s(%i): \n", __func__, __LINE__);
> +
> + if (ed->tie->cmode == tie->cmode)
> + return 0;
> + else
> + return 1;
> +}
> +
> +/* evb_statemachine:
> + *
> + * handle possible states during EVB capabilities exchange
> + *
> + * possible states: EVB_OFFER_CAPABILITIES
> + * EVB_CONFIGURE
> + * EVB_CONFIRMATION
> + */
> +static void evb_statemachine(struct evb_data *ed, struct tlv_info_evb *tie)
> +{
> + switch(ed->state) {
> + case EVB_OFFER_CAPABILITIES:
> + /* waiting for valid packets to pour in
> + * if valid packet was received,
> + * - check parameters with what we have offered for this if,
> + * - fill structure with data,
> + * - enable local tx
> + * - switch to EVB_CONFIGURE
> + */
> + printf("%s: state -> EVB_OFFER_CAPABILITIES\n", __func__);
> + if (evb_check_and_fill(ed, tie) != TLV_OK) {
> + fprintf(stderr, "Invalid contents of EVB Cfg TLV !\n");
> + return;
> + }
> + somethingChangedLocal(ed->ifname); /* trigger tx with new values */
> + ed->state = EVB_CONFIGURE;
> + break;
> + case EVB_CONFIGURE:
> + /* we received a valid packet, if contents is same with our local settings
> + * we can switch state to EVB_CONFIRMATION.*/
> + printf("%s: state -> EVB_CONFIGURE\n", __func__);
> + if (evb_compare(ed, tie)) {
> + ed->state= EVB_OFFER_CAPABILITIES;
> + } else {
> + printf("tlv_info_evb now equal !\n");
> + ed->state = EVB_CONFIRMATION;
> + }
> + somethingChangedLocal(ed->ifname);
> + break;
> + case EVB_CONFIRMATION:
> + /* we are already in confirmation and received a new packet with
> + * different parameters ? Check parameters. switch state back to
> + * EVB_CONFIGURE ? */
> + printf("%s: state -> EVB_CONFIRMATION\n", __func__);
> + break;
> + default:
> + fprintf(stderr, "EVB statemachine reached invalid state !\n");
> + break;
> + }
> +}
> +
> +/*
> + * evb_rchange: process RX TLV LLDPDU
> + *
> + * TLV not consumed on error
> + */
> +static int evb_rchange(struct port *port, struct unpacked_tlv *tlv)
> +{
> + int i;
> + struct evb_data *ed;
> + struct tlv_info_evb *tie = (struct tlv_info_evb *) tlv->info;
> + u8 oui_subtype[OUI_SUB_SIZE] = LLDP_OUI_SUBTYPE;
> +
> + if (!init_cfg()) {
> + return SUBTYPE_INVALID;
> + }
> +
> + ed = evb_data(port->ifname);
> +
> + if (!ed)
> + return SUBTYPE_INVALID;
> +
> + if (tlv->type == TYPE_127) {
> + /* check for length */
> + if (tlv->length < (OUI_SUB_SIZE)) {
> + return TLV_ERR;
> + }
> +
> + /* check for oui */
> + if (memcmp(tlv->info, &oui_subtype, OUI_SUB_SIZE)) {
> + return SUBTYPE_INVALID;
> + }
> +
> + /* disable rx if tx has been disabled by administrator */
> + if (!is_tlv_txenabled(ed->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE))) {
> + fprintf(stderr, "### %s:%s:EVB Config disabled\n",
> + __func__, ed->ifname);
> + return TLV_OK;
> + }
> +
> + fprintf(stderr, "%s:type %i, length %i, info ", __func__, tlv->type, tlv->length);
> +
> + for (i=0; i < tlv->length; i++) {
> + fprintf(stderr, "%02x ", tlv->info[i]);
> + }
> +
> + printf("\n");
> +
> + evb_print_tlvinfo(tie);
> +
> + /* change state */
> + evb_statemachine(ed, tie);
> +
> + /* check which values have been taken over */
> + evb_print_tlvinfo(ed->tie);
> + }
> +
> + return TLV_OK;
> +}
> +
> +void evb_ifdown(char *ifname)
> +{
> + struct evb_data *ed;
> +
> + printf("%s called !\n", __func__);
> +
> + ed = evb_data(ifname);
> + if (!ed)
> + goto out_err;
> +
> + free(ed->tie);
> + LIST_REMOVE(ed, entry);
> + evb_free_tlv(ed);
> + free(ed);
> + fprintf(stderr, "### %s:port %s removed\n", __func__, ifname);
> + return;
> +out_err:
> + fprintf(stderr, "### %s:port %s remove failed\n", __func__, ifname);
> +
> + return;
> +}
> +
> +void evb_ifup(char *ifname)
> +{
> + struct evb_data *ed;
> + struct evb_user_data *ud;
> +
> + ed = evb_data(ifname);
> + if (ed) {
> + fprintf(stderr, "### %s:%s exists\n", __func__, ifname);
> + goto out_err;
> + }
> +
> + /* not found, alloc/init per-port tlv data */
> + ed = (struct evb_data *) calloc(1, sizeof(struct evb_data));
> + if (!ed) {
> + fprintf(stderr, "### %s:%s malloc %ld failed\n",
> + __func__, ifname, sizeof(*ed));
> + goto out_err;
> + }
> + strncpy(ed->ifname, ifname, IFNAMSIZ);
> +
> + if (!init_cfg()) {
> + fprintf(stderr, "### %s:%s init_cfg failed\n", __func__, ifname);
Need to free(ed) here too it looks like. Otherwise looks good.
Thanks,
John
^ permalink raw reply
* [PATCH 1/1] staging: hv: Doubled ringbuffer size for Hyper-v network driver
From: Hank Janssen @ 2010-10-12 17:45 UTC (permalink / raw)
To: hjanssen, Haiyang Zhang, gregkh, virtualization, devel,
linux-kernel
From: Hank Janssen <hjanssen@microsoft.com>
Double the default network ringsize buffer for Hyper-V network driver.
In very heavily loaded systems the there is a chance you run out of
ringbuffer space and error out.
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Hank Janssen <hjanssen@microsoft.com>
---
drivers/staging/hv/netvsc_drv.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c
index 56e1157..45e082a 100644
--- a/drivers/staging/hv/netvsc_drv.c
+++ b/drivers/staging/hv/netvsc_drv.c
@@ -59,7 +59,7 @@ struct netvsc_driver_context {
/* Need this many pages to handle worst case fragmented packet */
#define PACKET_PAGES_HIWATER (MAX_SKB_FRAGS + 2)
-static int ring_size = roundup_pow_of_two(2*MAX_SKB_FRAGS+1);
+static int ring_size = 128;
module_param(ring_size, int, S_IRUGO);
MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
--
1.6.0.2
^ permalink raw reply related
* Re: [patch 1/2] vhost: potential integer overflows
From: Dan Carpenter @ 2010-10-12 14:51 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Juan Quintela, David S. Miller, Rusty Russell, kvm,
virtualization, netdev, kernel-janitors
In-Reply-To: <20101012122548.GA25446@redhat.com>
On Tue, Oct 12, 2010 at 02:25:48PM +0200, Michael S. Tsirkin wrote:
>
> As far as I can see, maximum value for num is 64K - 1:
>
> if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
> r = -EINVAL;
> break;
> }
>
> How can any of the above two trigger?
> It seems easier to check value for sanity at a single place where it's
> passed from userspace to kernel.
>
Gar. Sorry for that. My mistake.
regards,
dan carpenter
^ permalink raw reply
* Re: [patch 2/2] vhost: fix return code for log_access_ok()
From: Michael S. Tsirkin @ 2010-10-12 12:28 UTC (permalink / raw)
To: Dan Carpenter
Cc: Juan Quintela, David S. Miller, Rusty Russell, kvm,
virtualization, netdev, kernel-janitors
In-Reply-To: <20101011172419.GG5851@bicker>
On Mon, Oct 11, 2010 at 07:24:19PM +0200, Dan Carpenter wrote:
> access_ok() returns 1 if it's OK otherwise it should return 0.
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
Good catch, thanks!
Acked-by: Michael S. Tsirkin <mst@redhat.com>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index c2aa12c..f82fe57 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -371,7 +371,7 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz)
> /* Make sure 64 bit math will not overflow. */
> if (a > ULONG_MAX - (unsigned long)log_base ||
> a + (unsigned long)log_base > ULONG_MAX)
> - return -EFAULT;
> + return 0;
>
> return access_ok(VERIFY_WRITE, log_base + a,
> (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8);
^ permalink raw reply
* Re: [patch 1/2] vhost: potential integer overflows
From: Michael S. Tsirkin @ 2010-10-12 12:25 UTC (permalink / raw)
To: Dan Carpenter
Cc: Juan Quintela, David S. Miller, Rusty Russell, kvm,
virtualization, netdev, kernel-janitors
In-Reply-To: <20101011172256.GF5851@bicker>
On Mon, Oct 11, 2010 at 07:22:57PM +0200, Dan Carpenter wrote:
> I did an audit for potential integer overflows of values which get passed
> to access_ok() and here are the results.
>
> Signed-off-by: Dan Carpenter <error27@gmail.com>
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index dd3d6f7..c2aa12c 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -429,6 +429,14 @@ static int vq_access_ok(unsigned int num,
> struct vring_avail __user *avail,
> struct vring_used __user *used)
> {
> +
> + if (num > UINT_MAX / sizeof *desc)
> + return 0;
> + if (num > UINT_MAX / sizeof *avail->ring - sizeof *avail)
> + return 0;
> + if (num > UINT_MAX / sizeof *used->ring - sizeof *used)
> + return 0;
> +
> return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
> access_ok(VERIFY_READ, avail,
> sizeof *avail + num * sizeof *avail->ring) &&
> @@ -447,6 +455,9 @@ int vhost_log_access_ok(struct vhost_dev *dev)
> /* Caller should have vq mutex and device mutex */
> static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
> {
> + if (vq->num > UINT_MAX / sizeof *vq->used->ring - sizeof *vq->used)
> + return 0;
> +
> return vq_memory_access_ok(log_base, vq->dev->memory,
> vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
> (!vq->log_used || log_access_ok(log_base, vq->log_addr,
> @@ -606,12 +617,17 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
> }
>
> /* Also validate log access for used ring if enabled. */
> - if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
> - !log_access_ok(vq->log_base, a.log_guest_addr,
> + if (a.flags & (0x1 << VHOST_VRING_F_LOG)) {
> + if (vq->num > UINT_MAX / sizeof *vq->used->ring - sizeof *vq->used) {
> + r = -EINVAL;
> + break;
> + }
> + if (!log_access_ok(vq->log_base, a.log_guest_addr,
> sizeof *vq->used +
> vq->num * sizeof *vq->used->ring)) {
> - r = -EINVAL;
> - break;
> + r = -EINVAL;
> + break;
> + }
> }
> }
>
As far as I can see, maximum value for num is 64K - 1:
if (!s.num || s.num > 0xffff || (s.num & (s.num - 1))) {
r = -EINVAL;
break;
}
How can any of the above two trigger?
It seems easier to check value for sanity at a single place where it's
passed from userspace to kernel.
--
MST
^ permalink raw reply
* Re: [patch 1/2] vhost: potential integer overflows
From: Al Viro @ 2010-10-11 17:26 UTC (permalink / raw)
To: Dan Carpenter
Cc: Michael S. Tsirkin, Juan Quintela, David S. Miller, Rusty Russell,
kvm, virtualization, netdev, kernel-janitors
In-Reply-To: <20101011172256.GF5851@bicker>
On Mon, Oct 11, 2010 at 07:22:57PM +0200, Dan Carpenter wrote:
> I did an audit for potential integer overflows of values which get passed
> to access_ok() and here are the results.
FWIW, UINT_MAX is wrong here. What you want is maximal size_t value.
> Signed-off-by: Dan Carpenter <error27@gmail.com>
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index dd3d6f7..c2aa12c 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -429,6 +429,14 @@ static int vq_access_ok(unsigned int num,
> struct vring_avail __user *avail,
> struct vring_used __user *used)
> {
> +
> + if (num > UINT_MAX / sizeof *desc)
> + return 0;
> + if (num > UINT_MAX / sizeof *avail->ring - sizeof *avail)
> + return 0;
> + if (num > UINT_MAX / sizeof *used->ring - sizeof *used)
> + return 0;
> +
> return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
> access_ok(VERIFY_READ, avail,
> sizeof *avail + num * sizeof *avail->ring) &&
> @@ -447,6 +455,9 @@ int vhost_log_access_ok(struct vhost_dev *dev)
> /* Caller should have vq mutex and device mutex */
> static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
> {
> + if (vq->num > UINT_MAX / sizeof *vq->used->ring - sizeof *vq->used)
> + return 0;
> +
> return vq_memory_access_ok(log_base, vq->dev->memory,
> vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
> (!vq->log_used || log_access_ok(log_base, vq->log_addr,
> @@ -606,12 +617,17 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
> }
>
> /* Also validate log access for used ring if enabled. */
> - if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
> - !log_access_ok(vq->log_base, a.log_guest_addr,
> + if (a.flags & (0x1 << VHOST_VRING_F_LOG)) {
> + if (vq->num > UINT_MAX / sizeof *vq->used->ring - sizeof *vq->used) {
> + r = -EINVAL;
> + break;
> + }
> + if (!log_access_ok(vq->log_base, a.log_guest_addr,
> sizeof *vq->used +
> vq->num * sizeof *vq->used->ring)) {
> - r = -EINVAL;
> - break;
> + r = -EINVAL;
> + break;
> + }
> }
> }
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox