* [GIT PULL] first round of vhost-net enhancements for net-next
From: Michael S. Tsirkin @ 2010-05-03 21:32 UTC (permalink / raw)
To: David Miller; +Cc: kvm, virtualization, netdev, linux-kernel
David,
The following tree includes a couple of enhancements that help vhost-net.
Please pull them for net-next. Another set of patches is under
debugging/testing and I hope to get them ready in time for 2.6.35,
so there may be another pull request later.
Thanks!
The following changes since commit 7ef527377b88ff05fb122a47619ea506c631c914:
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6 (2010-05-02 22:02:06 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git vhost
Michael S. Tsirkin (2):
tun: add ioctl to modify vnet header size
macvtap: add ioctl to modify vnet header size
drivers/net/macvtap.c | 31 +++++++++++++++++++++++++++----
drivers/net/tun.c | 32 ++++++++++++++++++++++++++++----
include/linux/if_tun.h | 2 ++
3 files changed, 57 insertions(+), 8 deletions(-)
--
MST
^ permalink raw reply
* Re: [GIT PULL] first round of vhost-net enhancements for net-next
From: David Miller @ 2010-05-03 22:07 UTC (permalink / raw)
To: mst; +Cc: kvm, virtualization, netdev, linux-kernel
In-Reply-To: <20100503213244.GA16006@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Tue, 4 May 2010 00:32:45 +0300
> The following tree includes a couple of enhancements that help vhost-net.
> Please pull them for net-next. Another set of patches is under
> debugging/testing and I hope to get them ready in time for 2.6.35,
> so there may be another pull request later.
Pulled, thanks.
^ permalink raw reply
* Re: [GIT PULL] first round of vhost-net enhancements for net-next
From: David Miller @ 2010-05-03 22:08 UTC (permalink / raw)
To: mst; +Cc: kvm, virtualization, netdev, linux-kernel
In-Reply-To: <20100503.150729.00474027.davem@davemloft.net>
From: David Miller <davem@davemloft.net>
Date: Mon, 03 May 2010 15:07:29 -0700 (PDT)
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Tue, 4 May 2010 00:32:45 +0300
>
>> The following tree includes a couple of enhancements that help vhost-net.
>> Please pull them for net-next. Another set of patches is under
>> debugging/testing and I hope to get them ready in time for 2.6.35,
>> so there may be another pull request later.
>
> Pulled, thanks.
Nevermind, reverted.
Do you even compile test what you send to people?
drivers/net/macvtap.c: In function ‘macvtap_ioctl’:
drivers/net/macvtap.c:713: warning: control reaches end of non-void function
You're really batting 1000 today Michael...
^ permalink raw reply
* Re: [GIT PULL] first round of vhost-net enhancements for net-next
From: Michael S. Tsirkin @ 2010-05-03 22:20 UTC (permalink / raw)
To: David Miller; +Cc: kvm, virtualization, netdev, linux-kernel
In-Reply-To: <20100503.150829.254849182.davem@davemloft.net>
On Mon, May 03, 2010 at 03:08:29PM -0700, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Mon, 03 May 2010 15:07:29 -0700 (PDT)
>
> > From: "Michael S. Tsirkin" <mst@redhat.com>
> > Date: Tue, 4 May 2010 00:32:45 +0300
> >
> >> The following tree includes a couple of enhancements that help vhost-net.
> >> Please pull them for net-next. Another set of patches is under
> >> debugging/testing and I hope to get them ready in time for 2.6.35,
> >> so there may be another pull request later.
> >
> > Pulled, thanks.
>
> Nevermind, reverted.
>
> Do you even compile test what you send to people?
>
> drivers/net/macvtap.c: In function ‘macvtap_ioctl’:
> drivers/net/macvtap.c:713: warning: control reaches end of non-void function
>
> You're really batting 1000 today Michael...
Ouch. Should teach me not to send out stuff after midnight. Sorry about
the noise.
--
MST
^ permalink raw reply
* Re: [PATCHv7] add mergeable buffers support to vhost_net
From: Michael S. Tsirkin @ 2010-05-03 22:48 UTC (permalink / raw)
To: David L Stevens; +Cc: netdev, kvm, virtualization
In-Reply-To: <1272488232.11307.4.camel@w-dls.beaverton.ibm.com>
On Wed, Apr 28, 2010 at 01:57:12PM -0700, David L Stevens wrote:
> This patch adds mergeable receive buffer support to vhost_net.
>
> Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
>
> diff -ruNp net-next-v0/drivers/vhost/net.c net-next-v7/drivers/vhost/net.c
> --- net-next-v0/drivers/vhost/net.c 2010-04-24 21:36:54.000000000 -0700
> +++ net-next-v7/drivers/vhost/net.c 2010-04-28 12:26:18.000000000 -0700
> @@ -74,6 +74,23 @@ static int move_iovec_hdr(struct iovec *
> }
> return seg;
> }
> +/* Copy iovec entries for len bytes from iovec. Return segments used. */
> +static int copy_iovec_hdr(const struct iovec *from, struct iovec *to,
> + size_t len, int iovcount)
> +{
> + int seg = 0;
> + size_t size;
> + while (len && seg < iovcount) {
> + size = min(from->iov_len, len);
> + to->iov_base = from->iov_base;
> + to->iov_len = size;
> + len -= size;
> + ++from;
> + ++to;
> + ++seg;
> + }
> + return seg;
> +}
>
> /* Caller must have TX VQ lock */
> static void tx_poll_stop(struct vhost_net *net)
> @@ -109,7 +126,7 @@ static void handle_tx(struct vhost_net *
> };
> size_t len, total_len = 0;
> int err, wmem;
> - size_t hdr_size;
> + size_t vhost_hlen;
> struct socket *sock = rcu_dereference(vq->private_data);
> if (!sock)
> return;
> @@ -128,13 +145,13 @@ static void handle_tx(struct vhost_net *
>
> if (wmem < sock->sk->sk_sndbuf / 2)
> tx_poll_stop(net);
> - hdr_size = vq->hdr_size;
> + vhost_hlen = vq->vhost_hlen;
>
> for (;;) {
> - head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
> - ARRAY_SIZE(vq->iov),
> - &out, &in,
> - NULL, NULL);
> + head = vhost_get_desc(&net->dev, vq, vq->iov,
> + ARRAY_SIZE(vq->iov),
> + &out, &in,
> + NULL, NULL);
> /* Nothing new? Wait for eventfd to tell us they refilled. */
> if (head == vq->num) {
> wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> @@ -155,20 +172,20 @@ static void handle_tx(struct vhost_net *
> break;
> }
> /* Skip header. TODO: support TSO. */
> - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
> + s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, out);
> msg.msg_iovlen = out;
> len = iov_length(vq->iov, out);
> /* Sanity check */
> if (!len) {
> vq_err(vq, "Unexpected header len for TX: "
> "%zd expected %zd\n",
> - iov_length(vq->hdr, s), hdr_size);
> + iov_length(vq->hdr, s), vhost_hlen);
> break;
> }
> /* TODO: Check specific error and bomb out unless ENOBUFS? */
> err = sock->ops->sendmsg(NULL, sock, &msg, len);
> if (unlikely(err < 0)) {
> - vhost_discard_vq_desc(vq);
> + vhost_discard_desc(vq, 1);
> tx_poll_start(net, sock);
> break;
> }
> @@ -187,12 +204,25 @@ static void handle_tx(struct vhost_net *
> unuse_mm(net->dev.mm);
> }
>
> +static int vhost_head_len(struct vhost_virtqueue *vq, struct sock *sk)
> +{
> + struct sk_buff *head;
> + int len = 0;
> +
> + lock_sock(sk);
> + head = skb_peek(&sk->sk_receive_queue);
> + if (head)
> + len = head->len + vq->sock_hlen;
> + release_sock(sk);
> + return len;
> +}
> +
> /* Expects to be always run from workqueue - which acts as
> * read-size critical section for our kind of RCU. */
> static void handle_rx(struct vhost_net *net)
> {
> struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
> - unsigned head, out, in, log, s;
> + unsigned in, log, s;
> struct vhost_log *vq_log;
> struct msghdr msg = {
> .msg_name = NULL,
> @@ -203,14 +233,14 @@ static void handle_rx(struct vhost_net *
> .msg_flags = MSG_DONTWAIT,
> };
>
> - struct virtio_net_hdr hdr = {
> - .flags = 0,
> - .gso_type = VIRTIO_NET_HDR_GSO_NONE
> + struct virtio_net_hdr_mrg_rxbuf hdr = {
> + .hdr.flags = 0,
> + .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
> };
>
> size_t len, total_len = 0;
> - int err;
> - size_t hdr_size;
> + int err, headcount, datalen;
> + size_t vhost_hlen;
> struct socket *sock = rcu_dereference(vq->private_data);
> if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
> return;
> @@ -218,18 +248,19 @@ static void handle_rx(struct vhost_net *
> use_mm(net->dev.mm);
> mutex_lock(&vq->mutex);
> vhost_disable_notify(vq);
> - hdr_size = vq->hdr_size;
> + vhost_hlen = vq->vhost_hlen;
>
> vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
> vq->log : NULL;
>
> - for (;;) {
> - head = vhost_get_vq_desc(&net->dev, vq, vq->iov,
> - ARRAY_SIZE(vq->iov),
> - &out, &in,
> - vq_log, &log);
> + while ((datalen = vhost_head_len(vq, sock->sk))) {
> + headcount = vhost_get_desc_n(vq, vq->heads,
> + datalen + vhost_hlen,
> + &in, vq_log, &log);
> + if (headcount < 0)
> + break;
> /* OK, now we need to know about added descriptors. */
> - if (head == vq->num) {
> + if (!headcount) {
> if (unlikely(vhost_enable_notify(vq))) {
> /* They have slipped one in as we were
> * doing that: check again. */
> @@ -241,46 +272,53 @@ static void handle_rx(struct vhost_net *
> break;
> }
> /* We don't need to be notified again. */
> - if (out) {
> - vq_err(vq, "Unexpected descriptor format for RX: "
> - "out %d, int %d\n",
> - out, in);
> - break;
> - }
> - /* Skip header. TODO: support TSO/mergeable rx buffers. */
> - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
> + if (vhost_hlen)
> + /* Skip header. TODO: support TSO. */
> + s = move_iovec_hdr(vq->iov, vq->hdr, vhost_hlen, in);
> + else
> + s = copy_iovec_hdr(vq->iov, vq->hdr, vq->sock_hlen, in);
> msg.msg_iovlen = in;
> len = iov_length(vq->iov, in);
> /* Sanity check */
> if (!len) {
> vq_err(vq, "Unexpected header len for RX: "
> "%zd expected %zd\n",
> - iov_length(vq->hdr, s), hdr_size);
> + iov_length(vq->hdr, s), vhost_hlen);
> break;
> }
> err = sock->ops->recvmsg(NULL, sock, &msg,
> len, MSG_DONTWAIT | MSG_TRUNC);
> /* TODO: Check specific error and bomb out unless EAGAIN? */
> if (err < 0) {
> - vhost_discard_vq_desc(vq);
> + vhost_discard_desc(vq, headcount);
> break;
> }
> - /* TODO: Should check and handle checksum. */
> - if (err > len) {
> - pr_err("Discarded truncated rx packet: "
> - " len %d > %zd\n", err, len);
> - vhost_discard_vq_desc(vq);
> + if (err != datalen) {
> + pr_err("Discarded rx packet: "
> + " len %d, expected %zd\n", err, datalen);
> + vhost_discard_desc(vq, headcount);
> continue;
> }
> len = err;
> - err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
> - if (err) {
> - vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
> - vq->iov->iov_base, err);
> + if (vhost_hlen &&
> + memcpy_toiovecend(vq->hdr, (unsigned char *)&hdr, 0,
> + vhost_hlen)) {
> + vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
> + vq->iov->iov_base);
> break;
> }
> - len += hdr_size;
> - vhost_add_used_and_signal(&net->dev, vq, head, len);
> + /* TODO: Should check and handle checksum. */
> + if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF) &&
> + memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount,
> + offsetof(typeof(hdr), num_buffers),
> + sizeof(hdr.num_buffers))) {
> + vq_err(vq, "Failed num_buffers write");
> + vhost_discard_desc(vq, headcount);
> + break;
> + }
> + len += vhost_hlen;
> + vhost_add_used_and_signal_n(&net->dev, vq, vq->heads,
> + headcount);
> if (unlikely(vq_log))
> vhost_log_write(vq, vq_log, log, len);
> total_len += len;
> @@ -561,9 +599,21 @@ done:
>
> static int vhost_net_set_features(struct vhost_net *n, u64 features)
> {
> - size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
> - sizeof(struct virtio_net_hdr) : 0;
> + size_t vhost_hlen, sock_hlen, hdr_len;
> int i;
> +
> + hdr_len = (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ?
> + sizeof(struct virtio_net_hdr_mrg_rxbuf) :
> + sizeof(struct virtio_net_hdr);
> + if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
> + /* vhost provides vnet_hdr */
> + vhost_hlen = hdr_len;
> + sock_hlen = 0;
> + } else {
> + /* socket provides vnet_hdr */
> + vhost_hlen = 0;
> + sock_hlen = hdr_len;
> + }
> mutex_lock(&n->dev.mutex);
> if ((features & (1 << VHOST_F_LOG_ALL)) &&
> !vhost_log_access_ok(&n->dev)) {
> @@ -574,7 +624,8 @@ static int vhost_net_set_features(struct
> smp_wmb();
> for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
> mutex_lock(&n->vqs[i].mutex);
> - n->vqs[i].hdr_size = hdr_size;
> + n->vqs[i].vhost_hlen = vhost_hlen;
> + n->vqs[i].sock_hlen = sock_hlen;
> mutex_unlock(&n->vqs[i].mutex);
> }
> vhost_net_flush(n);
> diff -ruNp net-next-v0/drivers/vhost/vhost.c net-next-v7/drivers/vhost/vhost.c
> --- net-next-v0/drivers/vhost/vhost.c 2010-04-22 11:31:57.000000000 -0700
> +++ net-next-v7/drivers/vhost/vhost.c 2010-04-28 11:16:13.000000000 -0700
> @@ -114,7 +114,8 @@ static void vhost_vq_reset(struct vhost_
> vq->used_flags = 0;
> vq->log_used = false;
> vq->log_addr = -1ull;
> - vq->hdr_size = 0;
> + vq->vhost_hlen = 0;
> + vq->sock_hlen = 0;
> vq->private_data = NULL;
> vq->log_base = NULL;
> vq->error_ctx = NULL;
> @@ -861,6 +862,53 @@ static unsigned get_indirect(struct vhos
> return 0;
> }
>
> +/* This is a multi-buffer version of vhost_get_desc
> + * @vq - the relevant virtqueue
> + * datalen - data length we'll be reading
> + * @iovcount - returned count of io vectors we fill
> + * @log - vhost log
> + * @log_num - log offset
> + * returns number of buffer heads allocated, negative on error
> + */
> +int vhost_get_desc_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + int datalen, unsigned *iovcount, struct vhost_log *log,
> + unsigned int *log_num)
> +{
> + unsigned int out, in;
> + int seg = 0;
> + int headcount = 0;
> + int r;
> +
> + while (datalen > 0) {
> + if (headcount >= VHOST_NET_MAX_SG) {
> + r = -ENOBUFS;
> + goto err;
> + }
> + heads[headcount].id = vhost_get_desc(vq->dev, vq, vq->iov + seg,
> + ARRAY_SIZE(vq->iov) - seg, &out,
> + &in, log, log_num);
By the way, logging here looks broken to me.
Does live migration work for you?
log_num gets zeroed out on each call to vhost_get_desc.
I guess we could just change vhost_get_desc not to zero out
log_num at the start, do it here instead,
and pass in log + *log_num instead of log_num.
Need to also document the API for vhost_get_desc noting
that log_num is incremented, not stored to.
Pls think about it.
> + if (heads[headcount].id == vq->num) {
> + r = 0;
> + goto err;
> + }
> + if (out || in <= 0) {
> + vq_err(vq, "unexpected descriptor format for RX: "
> + "out %d, in %d\n", out, in);
> + r = -EINVAL;
> + goto err;
> + }
> + heads[headcount].len = iov_length(vq->iov + seg, in);
> + datalen -= heads[headcount].len;
> + ++headcount;
> + seg += in;
> + }
> + *iovcount = seg;
> + return headcount;
> +err:
> + vhost_discard_desc(vq, headcount);
> + return r;
> +}
> +
> /* This looks in the virtqueue and for the first available buffer, and converts
> * it to an iovec for convenient access. Since descriptors consist of some
> * number of output then some number of input descriptors, it's actually two
> @@ -868,7 +916,7 @@ static unsigned get_indirect(struct vhos
> *
> * This function returns the descriptor number found, or vq->num (which
> * is never a valid descriptor number) if none was found. */
> -unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> +unsigned vhost_get_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
> struct iovec iov[], unsigned int iov_size,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num)
> @@ -986,9 +1034,9 @@ unsigned vhost_get_vq_desc(struct vhost_
> }
>
> /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
> -void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
> +void vhost_discard_desc(struct vhost_virtqueue *vq, int n)
> {
> - vq->last_avail_idx--;
> + vq->last_avail_idx -= n;
> }
>
> /* After we've used one of their buffers, we tell them about it. We'll then
> @@ -1033,6 +1081,68 @@ int vhost_add_used(struct vhost_virtqueu
> return 0;
> }
>
> +static void vhost_log_used(struct vhost_virtqueue *vq,
> + struct vring_used_elem __user *used)
> +{
> + /* Make sure data is seen before log. */
> + smp_wmb();
> + /* Log used ring entry write. */
> + log_write(vq->log_base,
> + vq->log_addr +
> + ((void __user *)used - (void __user *)vq->used),
> + sizeof *used);
> + /* Log used index update. */
> + log_write(vq->log_base,
> + vq->log_addr + offsetof(struct vring_used, idx),
> + sizeof vq->used->idx);
> + if (vq->log_ctx)
> + eventfd_signal(vq->log_ctx, 1);
> +}
> +
> +static int __vhost_add_used_n(struct vhost_virtqueue *vq,
> + struct vring_used_elem *heads,
> + unsigned count)
> +{
> + struct vring_used_elem __user *used;
> + int start;
> +
> + start = vq->last_used_idx % vq->num;
> + used = vq->used->ring + start;
> + if (copy_to_user(used, heads, count * sizeof *used)) {
> + vq_err(vq, "Failed to write used");
> + return -EFAULT;
> + }
> + /* Make sure buffer is written before we update index. */
> + smp_wmb();
> + if (put_user(vq->last_used_idx + count, &vq->used->idx)) {
> + vq_err(vq, "Failed to increment used idx");
> + return -EFAULT;
> + }
> + if (unlikely(vq->log_used))
> + vhost_log_used(vq, used);
> + vq->last_used_idx += count;
> + return 0;
> +}
> +
> +/* After we've used one of their buffers, we tell them about it. We'll then
> + * want to notify the guest, using eventfd. */
> +int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
> + unsigned count)
> +{
> + int start, n, r;
> +
> + start = vq->last_used_idx % vq->num;
> + n = vq->num - start;
> + if (n < count) {
> + r = __vhost_add_used_n(vq, heads, n);
> + if (r < 0)
> + return r;
> + heads += n;
> + count -= n;
> + }
> + return __vhost_add_used_n(vq, heads, count);
> +}
> +
> /* This actually signals the guest, using eventfd. */
> void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> {
> @@ -1062,6 +1172,15 @@ void vhost_add_used_and_signal(struct vh
> vhost_signal(dev, vq);
> }
>
> +/* multi-buffer version of vhost_add_used_and_signal */
> +void vhost_add_used_and_signal_n(struct vhost_dev *dev,
> + struct vhost_virtqueue *vq,
> + struct vring_used_elem *heads, unsigned count)
> +{
> + vhost_add_used_n(vq, heads, count);
> + vhost_signal(dev, vq);
> +}
> +
> /* OK, now we need to know about added descriptors. */
> bool vhost_enable_notify(struct vhost_virtqueue *vq)
> {
> @@ -1086,7 +1205,7 @@ bool vhost_enable_notify(struct vhost_vi
> return false;
> }
>
> - return avail_idx != vq->last_avail_idx;
> + return avail_idx != vq->avail_idx;
> }
>
> /* We don't need to be notified again. */
> diff -ruNp net-next-v0/drivers/vhost/vhost.h net-next-v7/drivers/vhost/vhost.h
> --- net-next-v0/drivers/vhost/vhost.h 2010-04-24 21:37:41.000000000 -0700
> +++ net-next-v7/drivers/vhost/vhost.h 2010-04-26 10:35:25.000000000 -0700
> @@ -84,7 +84,9 @@ struct vhost_virtqueue {
> struct iovec indirect[VHOST_NET_MAX_SG];
> struct iovec iov[VHOST_NET_MAX_SG];
> struct iovec hdr[VHOST_NET_MAX_SG];
> - size_t hdr_size;
> + size_t vhost_hlen;
> + size_t sock_hlen;
> + struct vring_used_elem heads[VHOST_NET_MAX_SG];
> /* We use a kind of RCU to access private pointer.
> * All readers access it from workqueue, which makes it possible to
> * flush the workqueue instead of synchronize_rcu. Therefore readers do
> @@ -120,16 +122,23 @@ long vhost_dev_ioctl(struct vhost_dev *,
> int vhost_vq_access_ok(struct vhost_virtqueue *vq);
> int vhost_log_access_ok(struct vhost_dev *);
>
> -unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
> +int vhost_get_desc_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + int datalen, unsigned int *iovcount, struct vhost_log *log,
> + unsigned int *log_num);
> +unsigned vhost_get_desc(struct vhost_dev *, struct vhost_virtqueue *,
> struct iovec iov[], unsigned int iov_count,
> unsigned int *out_num, unsigned int *in_num,
> struct vhost_log *log, unsigned int *log_num);
> -void vhost_discard_vq_desc(struct vhost_virtqueue *);
> +void vhost_discard_desc(struct vhost_virtqueue *, int);
>
> int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
> -void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> +int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads,
> + unsigned count);
> void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
> - unsigned int head, int len);
> + unsigned int id, int len);
> +void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
> + struct vring_used_elem *heads, unsigned count);
> +void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
> void vhost_disable_notify(struct vhost_virtqueue *);
> bool vhost_enable_notify(struct vhost_virtqueue *);
>
> @@ -149,7 +158,8 @@ enum {
> VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
> (1 << VIRTIO_RING_F_INDIRECT_DESC) |
> (1 << VHOST_F_LOG_ALL) |
> - (1 << VHOST_NET_F_VIRTIO_NET_HDR),
> + (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
> + (1 << VIRTIO_NET_F_MRG_RXBUF),
> };
>
> static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
>
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Rusty Russell @ 2010-05-04 4:38 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: tytso, kvm, Neil Brown, qemu-devel, virtualization,
Anthony Liguori, Jens Axboe, hch
In-Reply-To: <20100218222220.GA14847@redhat.com>
On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
> I took a stub at documenting CMD and FLUSH request types in virtio
> block. Christoph, could you look over this please?
>
> I note that the interface seems full of warts to me,
> this might be a first step to cleaning them.
ISTR Christoph had withdrawn some patches in this area, and was waiting
for him to resubmit?
I've given up on figuring out the block device. What seem to me to be sane
semantics along the lines of memory barriers are foreign to disk people: they
want (and depend on) flushing everywhere.
For example, tdb transactions do not require a flush, they only require what
I would call a barrier: that prior data be written out before any future data.
Surely that would be more efficient in general than a flush! In fact, TDB
wants only writes to *that file* (and metadata) written out first; it has no
ordering issues with other I/O on the same device.
A generic I/O interface would allow you to specify "this request depends on these
outstanding requests" and leave it at that. It might have some sync flush
command for dumb applications and OSes. The userspace API might be not be as
precise and only allow such a barrier against all prior writes on this fd.
ISTR someone mentioning a desire for such an API years ago, so CC'ing the
usual I/O suspects...
Cheers,
Rusty.
^ permalink raw reply
* Re: [Qemu-devel] Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Stefan Hajnoczi @ 2010-05-04 6:56 UTC (permalink / raw)
To: Rusty Russell
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, Jens Axboe, hch
In-Reply-To: <201005041408.25069.rusty@rustcorp.com.au>
[-- Attachment #1.1: Type: text/plain, Size: 1396 bytes --]
A userspace barrier API would be very useful instead of doing fsync when
only ordering is required. I'd like to follow that discussion too.
Stefan
On 4 May 2010 05:39, "Rusty Russell" <rusty@rustcorp.com.au> wrote:
On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
> I took a stub at documenting CMD and FLU...
ISTR Christoph had withdrawn some patches in this area, and was waiting
for him to resubmit?
I've given up on figuring out the block device. What seem to me to be sane
semantics along the lines of memory barriers are foreign to disk people:
they
want (and depend on) flushing everywhere.
For example, tdb transactions do not require a flush, they only require what
I would call a barrier: that prior data be written out before any future
data.
Surely that would be more efficient in general than a flush! In fact, TDB
wants only writes to *that file* (and metadata) written out first; it has no
ordering issues with other I/O on the same device.
A generic I/O interface would allow you to specify "this request depends on
these
outstanding requests" and leave it at that. It might have some sync flush
command for dumb applications and OSes. The userspace API might be not be
as
precise and only allow such a barrier against all prior writes on this fd.
ISTR someone mentioning a desire for such an API years ago, so CC'ing the
usual I/O suspects...
Cheers,
Rusty.
[-- Attachment #1.2: Type: text/html, Size: 1742 bytes --]
[-- Attachment #2: Type: text/plain, Size: 184 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Avi Kivity @ 2010-05-04 8:34 UTC (permalink / raw)
To: Rusty Russell
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, Anthony Liguori, Jens Axboe, hch
In-Reply-To: <201005041408.25069.rusty@rustcorp.com.au>
On 05/04/2010 07:38 AM, Rusty Russell wrote:
> On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
>
>> I took a stub at documenting CMD and FLUSH request types in virtio
>> block. Christoph, could you look over this please?
>>
>> I note that the interface seems full of warts to me,
>> this might be a first step to cleaning them.
>>
> ISTR Christoph had withdrawn some patches in this area, and was waiting
> for him to resubmit?
>
> I've given up on figuring out the block device. What seem to me to be sane
> semantics along the lines of memory barriers are foreign to disk people: they
> want (and depend on) flushing everywhere.
>
> For example, tdb transactions do not require a flush, they only require what
> I would call a barrier: that prior data be written out before any future data.
> Surely that would be more efficient in general than a flush! In fact, TDB
> wants only writes to *that file* (and metadata) written out first; it has no
> ordering issues with other I/O on the same device.
>
I think that's SCSI ordered tags.
> A generic I/O interface would allow you to specify "this request depends on these
> outstanding requests" and leave it at that. It might have some sync flush
> command for dumb applications and OSes. The userspace API might be not be as
> precise and only allow such a barrier against all prior writes on this fd.
>
Depends on all previous requests, and will commit before all following
requests. ie a full barrier.
> ISTR someone mentioning a desire for such an API years ago, so CC'ing the
> usual I/O suspects...
>
I'd love to see TCQ exposed to user space.
--
error compiling committee.c: too many arguments to function
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Jens Axboe @ 2010-05-04 8:41 UTC (permalink / raw)
To: Rusty Russell
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, Anthony Liguori, hch
In-Reply-To: <201005041408.25069.rusty@rustcorp.com.au>
On Tue, May 04 2010, Rusty Russell wrote:
> On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
> > I took a stub at documenting CMD and FLUSH request types in virtio
> > block. Christoph, could you look over this please?
> >
> > I note that the interface seems full of warts to me,
> > this might be a first step to cleaning them.
>
> ISTR Christoph had withdrawn some patches in this area, and was waiting
> for him to resubmit?
>
> I've given up on figuring out the block device. What seem to me to be sane
> semantics along the lines of memory barriers are foreign to disk people: they
> want (and depend on) flushing everywhere.
>
> For example, tdb transactions do not require a flush, they only require what
> I would call a barrier: that prior data be written out before any future data.
> Surely that would be more efficient in general than a flush! In fact, TDB
> wants only writes to *that file* (and metadata) written out first; it has no
> ordering issues with other I/O on the same device.
>
> A generic I/O interface would allow you to specify "this request depends on these
> outstanding requests" and leave it at that. It might have some sync flush
> command for dumb applications and OSes. The userspace API might be not be as
> precise and only allow such a barrier against all prior writes on this fd.
>
> ISTR someone mentioning a desire for such an API years ago, so CC'ing the
> usual I/O suspects...
It would be nice to have a more fuller API for this, but the reality is
that only the flush approach is really workable. Even just strict
ordering of requests could only be supported on SCSI, and even there the
kernel still lacks proper guarantees on error handling to prevent
reordering there.
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Christoph Hellwig @ 2010-05-04 10:05 UTC (permalink / raw)
To: Rusty Russell
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, Anthony Liguori, Jens Axboe, hch
In-Reply-To: <201005041408.25069.rusty@rustcorp.com.au>
On Tue, May 04, 2010 at 02:08:24PM +0930, Rusty Russell wrote:
> On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
> > I took a stub at documenting CMD and FLUSH request types in virtio
> > block. Christoph, could you look over this please?
> >
> > I note that the interface seems full of warts to me,
> > this might be a first step to cleaning them.
>
> ISTR Christoph had withdrawn some patches in this area, and was waiting
> for him to resubmit?
Any patches I've withdrawn in this area are withdrawn for good. But
what I really need to do is to review Michaels spec updates, sorry.
UI'll get back to it today.
^ permalink raw reply
* [GIT PULL] amended: first round of vhost-net enhancements for net-next
From: Michael S. Tsirkin @ 2010-05-04 11:21 UTC (permalink / raw)
To: David Miller; +Cc: kvm, virtualization, netdev, linux-kernel
David,
This is an amended pull request: I have rebased the tree to the
correct patches. This has been through basic tests and seems
to work fine here.
The following tree includes a couple of enhancements that help vhost-net.
Please pull them for net-next. Another set of patches is under
debugging/testing and I hope to get them ready in time for 2.6.35,
so there may be another pull request later.
Thanks!
The following changes since commit 7ef527377b88ff05fb122a47619ea506c631c914:
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6 (2010-05-02 22:02:06 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git vhost
Michael S. Tsirkin (2):
tun: add ioctl to modify vnet header size
macvtap: add ioctl to modify vnet header size
drivers/net/macvtap.c | 27 +++++++++++++++++++++++----
drivers/net/tun.c | 32 ++++++++++++++++++++++++++++----
include/linux/if_tun.h | 2 ++
3 files changed, 53 insertions(+), 8 deletions(-)
--
MST
^ permalink raw reply
* implementation of IEEE 802.1Qbg in lldpad, part1
From: Jens Osterkamp @ 2010-05-04 11:47 UTC (permalink / raw)
To: e1000-eedc, virtualization, evb; +Cc: chrisw
Hi all,
this series of patches contains an implementation of the first part
of IEEE 802.1Qbg, the exchange of EVB TLVs to negotiate VSI capabalities.
It supports setting the parameters of the TLV exchange from the command
line using lldptool.
The patches are based on lldpad 0.9.34. lldpad is a project hosted on
sourceforge.net. For more information about lldpad take a look at
http://sourceforge.net/projects/e1000/files/
section "DCB Tools / lldpad".
best regards,
Jens
^ permalink raw reply
* [PATCH 1/3] consolidation of MIN and MAX macros in common.h
From: Jens Osterkamp @ 2010-05-04 11:47 UTC (permalink / raw)
To: e1000-eedc, virtualization, evb; +Cc: chrisw, Jens Osterkamp
In-Reply-To: <1272973669-6694-1-git-send-email-jens@linux.vnet.ibm.com>
This patch consolidates a modified version of the already existing MIN
macro in lldpad to include/common.h and add a MAX macro.
Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
---
include/common.h | 14 ++++++++++++++
include/dcb_protocol.h | 4 ----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/include/common.h b/include/common.h
index 01746ea..ab07dc2 100644
--- a/include/common.h
+++ b/include/common.h
@@ -387,4 +387,18 @@ typedef int socklen_t;
const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len);
+#define MIN(x,y) \
+ ({ \
+ typeof (x) __x = (x); \
+ typeof (y) __y = (y); \
+ __x < __y ? __x : __y; \
+ })
+
+#define MAX(x,y) \
+ ({ \
+ typeof (x) __x = (x); \
+ typeof (y) __y = (y); \
+ __x > __y ? __x : __y; \
+ })
+
#endif /* COMMON_H */
diff --git a/include/dcb_protocol.h b/include/dcb_protocol.h
index 67f653c..c7b856f 100644
--- a/include/dcb_protocol.h
+++ b/include/dcb_protocol.h
@@ -58,10 +58,6 @@ typedef enum {
#define DUP_DCBX_TLV_LLINK 0x0020
#define TOO_MANY_NGHBRS 0x0040
-//#ifndef min /*todo: change to min()
- #define MIN(x, y) ((x) < (y) ? x : y)
-//#endif
-
#define INIT_DCB_OUI {0x00,0x1b,0x21}
bool add_adapter(char *device_name);
--
1.7.0.1
^ permalink raw reply related
* [PATCH 2/3] implementation of IEEE 802.1Qbg in lldpad, part 1
From: Jens Osterkamp @ 2010-05-04 11:47 UTC (permalink / raw)
To: e1000-eedc, virtualization, evb; +Cc: chrisw, Jens Osterkamp
In-Reply-To: <1272973669-6694-1-git-send-email-jens@linux.vnet.ibm.com>
This patch contains the first part of an initial implementation of the
IEEE 802.1Qbg standard: It contains code for the exchange of EVB TLV
capabilities between a host with virtual machines and an adjacent switch.
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.
The patch applies to lldpad 0.9.34 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 | 20 ++
include/lldp_evb.h | 58 +++++
include/lldp_evb_clif.h | 33 +++
include/lldp_evb_cmds.h | 31 +++
include/lldp_tlv.h | 1 +
lldp_evb.c | 567 +++++++++++++++++++++++++++++++++++++++++++++++
lldp_evb_clif.c | 232 +++++++++++++++++++
lldp_evb_cmds.c | 127 +++++++++++
lldpad.c | 2 +
lldptool.c | 2 +
11 files changed, 1079 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 68e4144..554baec 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,7 +39,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 \
@@ -49,7 +49,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 \
@@ -64,10 +64,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
@@ -76,7 +78,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..21347b0 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,23 @@ 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_RELAXEDRELAY (1 << 6)
+
+/* EVB supported protocols */
+#define LLDP_EVB_CAPABILITY_PROTOCOL_RTE (1 << 3)
+#define LLDP_EVB_CAPABILITY_PROTOCOL_ECP (1 << 2)
+#define LLDP_EVB_CAPABILITY_PROTOCOL_VDPL (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..3559dde
--- /dev/null
+++ b/include/lldp_evb.h
@@ -0,0 +1,58 @@
+/*******************************************************************************
+
+ 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 evb_data {
+ char ifname[IFNAMSIZ];
+ struct unpacked_tlv *evb;
+ struct tlv_info_evb *tie;
+ 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 *);
+
+#endif /* _LLDP_EVB_H */
diff --git a/include/lldp_evb_clif.h b/include/lldp_evb_clif.h
new file mode 100644
index 0000000..56011d1
--- /dev/null
+++ b/include/lldp_evb_clif.h
@@ -0,0 +1,33 @@
+/*******************************************************************************
+
+ 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, u8 *);
+
+#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..304a9f4
--- /dev/null
+++ b/lldp_evb.c
@@ -0,0 +1,567 @@
+/*******************************************************************************
+
+ 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 "lldp.h"
+#include "lldp_evb.h"
+#include "messages.h"
+#include "config.h"
+#include "common.h"
+#include "lldp_evb_clif.h"
+#include "lldp_evb_cmds.h"
+
+extern struct lldp_head lldp_head;
+
+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__));
+
+static struct evb_data *evb_data(const char *ifname)
+{
+ struct evb_user_data *ud;
+ struct evb_data *bd = NULL;
+
+ ud = find_module_user_data_by_if(ifname, &lldp_head, LLDP_MOD_EVB);
+ if (ud) {
+ LIST_FOREACH(bd, &ud->head, entry) {
+ if (!strncmp(ifname, bd->ifname, IFNAMSIZ))
+ return bd;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * evb_bld_cfg_tlv - build the EVB TLV
+ * @bd: the evb data struct
+ *
+ * Returns 0 on success
+ */
+static int evb_bld_cfg_tlv(struct evb_data *bd)
+{
+ int rc = 0;
+ int i;
+ struct unpacked_tlv *tlv = NULL;
+ struct tlv_info_evb evb;
+
+ /* free bd->evb if it exists */
+ FREE_UNPKD_TLV(bd, evb);
+
+ if (!is_tlv_txenabled(bd->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE))) {
+ fprintf(stderr, "### %s:%s:EVB Config disabled\n",
+ __func__, bd->ifname);
+ rc = EINVAL;
+ goto out_err;
+ }
+
+ /* load from config */
+ memset(&evb, 0, sizeof(evb));
+ if (get_config_tlvinfo_bin(bd->ifname, TLVID_8021Qbg(LLDP_EVB_SUBTYPE),
+ (void *)&evb, sizeof(evb))) {
+ hton24(evb.oui, LLDP_MOD_EVB);
+ fprintf(stderr, "### %s:%s:Build EVB Config from scratch\n",
+ __func__, bd->ifname);
+ evb.sub = LLDP_EVB_SUBTYPE;
+ evb.smode = bd->tie->smode;
+ evb.scap = bd->tie->scap;
+ evb.cmode = bd->tie->cmode;
+ evb.ccap = bd->tie->ccap;
+ evb.svsi = bd->tie->svsi;
+ evb.cvsi = bd->tie->cvsi;
+ evb.rte = bd->tie->rte;
+ }
+
+ tlv = create_tlv();
+ if (!tlv)
+ goto out_err;
+
+ tlv->type = ORG_SPECIFIC_TLV;
+ tlv->length = sizeof(evb);
+ tlv->info = (u8 *)malloc(tlv->length);
+ if(!tlv->info) {
+ free(tlv);
+ tlv = NULL;
+ rc = ENOMEM;
+ goto out_err;
+ }
+ memcpy(tlv->info, &evb, 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");
+
+ bd->evb = tlv;
+out_err:
+ return rc;
+}
+
+static void evb_free_tlv(struct evb_data *bd)
+{
+ if (bd) {
+ FREE_UNPKD_TLV(bd, evb);
+ }
+}
+
+/* evb_init_cfg_tlv:
+ *
+ * fill up tlv_info_evb structure with reasonable info
+ */
+static int evb_init_cfg_tlv(struct evb_data *bd)
+{
+ bd->tie = (struct tlv_info_evb *) calloc(1, sizeof(struct tlv_info_evb));
+ if (!bd->tie)
+ return ENOMEM;
+
+ /* TODO: these should be set reasonable default, and must be able to change via config */
+ /* if possible, we request RR */
+ bd->tie->smode = LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY;
+ /* capabilities we support */
+ bd->tie->scap = LLDP_EVB_CAPABILITY_PROTOCOL_RTE | LLDP_EVB_CAPABILITY_PROTOCOL_ECP
+ | LLDP_EVB_CAPABILITY_PROTOCOL_VDP | LLDP_EVB_CAPABILITY_PROTOCOL_VDPL;
+ /* FIXME: for test: support something different than bridge */
+ bd->tie->svsi = LLDP_EVB_DEFAULT_SVSI;
+ bd->tie->rte = LLDP_EVB_DEFAULT_RTE;
+
+ return 0;
+}
+
+static int evb_bld_tlv(struct evb_data *bd)
+{
+ int rc = 0;
+
+ if (!port_find_by_name(bd->ifname)) {
+ rc = EEXIST;
+ goto out_err;
+ }
+
+ if (!init_cfg()) {
+ rc = ENOENT;
+ goto out_err;
+ }
+
+ if (evb_bld_cfg_tlv(bd)) {
+ fprintf(stderr, "### %s:%s:evb_bld_cfg_tlv() failed\n",
+ __func__, bd->ifname);
+ rc = EINVAL;
+ goto out_err_destroy;
+ }
+
+out_err_destroy:
+ destroy_cfg();
+
+out_err:
+ return rc;
+}
+
+static void evb_free_data(struct evb_user_data *ud)
+{
+ struct evb_data *bd;
+ if (ud) {
+ while (!LIST_EMPTY(&ud->head)) {
+ bd = LIST_FIRST(&ud->head);
+ LIST_REMOVE(bd, entry);
+ evb_free_tlv(bd);
+ free(bd);
+ }
+ }
+}
+
+struct packed_tlv *evb_gettlv(struct port *port)
+{
+ int size;
+ struct evb_data *bd;
+ struct packed_tlv *ptlv = NULL;
+
+ bd = evb_data(port->ifname);
+ if (!bd)
+ goto out_err;
+
+ evb_free_tlv(bd);
+
+ if (evb_bld_tlv(bd)) {
+ fprintf(stderr, "### %s:%s evb_bld_tlv failed\n",
+ __func__, port->ifname);
+ goto out_err;
+ }
+
+ size = TLVSIZE(bd->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(bd->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)
+{
+ if ((tie->smode & (LLDP_EVB_CAPABILITY_FORWARD_STANDARD |
+ LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY)) == 0)
+ return TLV_ERR;
+
+ if ((tie->scap & (LLDP_EVB_CAPABILITY_PROTOCOL_RTE |
+ LLDP_EVB_CAPABILITY_PROTOCOL_ECP |
+ LLDP_EVB_CAPABILITY_PROTOCOL_VDP |
+ LLDP_EVB_CAPABILITY_PROTOCOL_VDPL)) == 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;
+
+ /* If both sides support RR, set it */
+ if ((tie->smode & LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY) &&
+ (ed->tie->smode & LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY)) {
+ ed->tie->cmode = LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY;
+ } else {
+ ed->tie->cmode = LLDP_EVB_CAPABILITY_FORWARD_STANDARD;
+ }
+
+ /* If both sides support RTE, set it */
+ if ((tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) &&
+ (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE))
+ ed->tie->ccap |= LLDP_EVB_CAPABILITY_PROTOCOL_RTE;
+
+ /* If both sides support ECP, set it */
+ if ((tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) &&
+ (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP))
+ ed->tie->ccap |= LLDP_EVB_CAPABILITY_PROTOCOL_ECP;
+
+ /* If both sides support VDPL, set it */
+ if ((tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDPL) &&
+ (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDPL))
+ ed->tie->ccap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDPL;
+
+ /* If both sides support VDP, set it */
+ if ((tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) &&
+ (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP))
+ ed->tie->ccap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDP;
+
+ /* If supported caps include VDP take over min value of both */
+ if (tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP)
+ ed->tie->cvsi = MIN(ed->tie->svsi,tie->svsi);
+
+ /* If both sides support RTE and value offer is > 0, set it */
+ if ((tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) &&
+ (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) &&
+ (tie->rte > 0))
+ ed->tie->rte = MIN(ed->tie->svsi,tie->rte);
+
+ 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)
+{
+ if ((ed->tie->smode == tie->smode) &&
+ (ed->tie->scap == tie->scap) &&
+ (ed->tie->cmode == tie->cmode) &&
+ (ed->tie->ccap == tie->ccap) &&
+ (ed->tie->svsi == tie->svsi) &&
+ (ed->tie->cvsi == tie->cvsi))
+ 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)) {
+ 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, offset;
+ struct evb_data *ed;
+ struct tlv_info_evb *tie = (struct tlv_info_evb *) tlv->info;
+ u8 oui_subtype[OUI_SUB_SIZE] = LLDP_OUI_SUBTYPE;
+
+ ed = evb_data(port->ifname);
+
+ /* TODO: disable rx if tx has been disabled by administrator ?
+ if (!is_tlv_txenabled(ed->ifname, TLVID_8021(LLDP_EVB_SUBTYPE))) {
+ fprintf(stderr, "### %s:%s:EVB Config disabled\n",
+ __func__, ed->ifname);
+ return TLV_OK;
+ }
+ */
+
+ if (!ed)
+ return SUBTYPE_INVALID;
+
+ 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");
+
+ 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;
+ }
+
+ /* decode values */
+ fprintf(stderr, "### %s:now ready to decode values !\n", __func__);
+
+ offset = OUI_SUB_SIZE;
+
+ /* received valid values, save them */
+ fprintf(stderr,"### supported forwarding mode: %02x\n", tie->smode);
+ fprintf(stderr,"### configured forwarding mode: %02x\n", tie->cmode);
+ fprintf(stderr,"### supported capabilities: %02x\n", tie->scap);
+ fprintf(stderr,"### configured capabilities: %02x\n", tie->ccap);
+ fprintf(stderr,"### supported no. of vsis: %04i\n", tie->svsi);
+ fprintf(stderr,"### configured no. of vsis: %04i\n", tie->cvsi);
+ fprintf(stderr,"### rte: %02i\n", tie->rte);
+
+ /* change state */
+ evb_statemachine(ed, tie);
+ }
+
+ return TLV_OK;
+}
+
+void evb_ifdown(char *ifname)
+{
+ struct evb_data *bd;
+
+ bd = evb_data(ifname);
+ if (!bd)
+ goto out_err;
+
+ LIST_REMOVE(bd, entry);
+ evb_free_tlv(bd);
+ free(bd);
+ fprintf(stderr, "### %s:port %s removed\n", __func__, ifname);
+ return;
+out_err:
+ fprintf(stderr, "### %s:port %s adding failed\n", __func__, ifname);
+
+ return;
+}
+
+void evb_ifup(char *ifname)
+{
+ struct evb_data *bd;
+ struct evb_user_data *ud;
+
+ bd = evb_data(ifname);
+ if (bd) {
+ fprintf(stderr, "### %s:%s exists\n", __func__, ifname);
+ goto out_err;
+ }
+
+ /* not found, alloc/init per-port tlv data */
+ bd = (struct evb_data *) calloc(1, sizeof(struct evb_data));
+ if (!bd) {
+ fprintf(stderr, "### %s:%s malloc %ld failed\n",
+ __func__, ifname, sizeof(*bd));
+ goto out_err;
+ }
+ strncpy(bd->ifname, ifname, IFNAMSIZ);
+
+ if (evb_init_cfg_tlv(bd)) {
+ fprintf(stderr, "### %s:%s evb_init_cfg_tlv failed\n", __func__, ifname);
+ free(bd);
+ goto out_err;
+ }
+
+ bd->state = EVB_OFFER_CAPABILITIES;
+
+ if (evb_bld_tlv(bd)) {
+ fprintf(stderr, "### %s:%s evb_bld_tlv failed\n", __func__, ifname);
+ free(bd);
+ goto out_err;
+ }
+
+ ud = find_module_user_data_by_if(ifname, &lldp_head, LLDP_MOD_EVB);
+ LIST_INSERT_HEAD(&ud->head, bd, entry);
+ fprintf(stderr, "### %s:port %s added\n", __func__, ifname);
+ return;
+
+out_err:
+ fprintf(stderr, "### %s:port %s adding failed\n", __func__, ifname);
+ return;
+}
+
+static const struct lldp_mod_ops evb_ops = {
+ .lldp_mod_register = evb_register,
+ .lldp_mod_unregister = evb_unregister,
+ .lldp_mod_gettlv = evb_gettlv,
+ .lldp_mod_rchange = evb_rchange,
+ .lldp_mod_ifup = evb_ifup,
+ .lldp_mod_ifdown = evb_ifdown,
+ .get_arg_handler = evb_get_arg_handlers,
+};
+
+struct lldp_module *evb_register(void)
+{
+ struct lldp_module *mod;
+ struct evb_user_data *ud;
+
+ mod = malloc(sizeof(*mod));
+ if (!mod) {
+ fprintf(stderr, "failed to malloc module data\n");
+ log_message(MSG_ERR_SERVICE_START_FAILURE,
+ "%s", "failed to malloc module data");
+ goto out_err;
+ }
+ ud = malloc(sizeof(struct evb_user_data));
+ if (!ud) {
+ free(mod);
+ fprintf(stderr, "failed to malloc module user data\n");
+ log_message(MSG_ERR_SERVICE_START_FAILURE,
+ "%s", "failed to malloc module user data");
+ goto out_err;
+ }
+ LIST_INIT(&ud->head);
+ mod->id = LLDP_MOD_EVB;
+ mod->ops = &evb_ops;
+ mod->data = ud;
+ fprintf(stderr, "### %s:done\n", __func__);
+ return mod;
+
+out_err:
+ fprintf(stderr, "### %s:failed\n", __func__);
+ return NULL;
+}
+
+void evb_unregister(struct lldp_module *mod)
+{
+ if (mod->data) {
+ evb_free_data((struct evb_user_data *) mod->data);
+ free(mod->data);
+ }
+ free(mod);
+ fprintf(stderr, "### %s:done\n", __func__);
+}
diff --git a/lldp_evb_clif.c b/lldp_evb_clif.c
new file mode 100644
index 0000000..d1773fe
--- /dev/null
+++ b/lldp_evb_clif.c
@@ -0,0 +1,232 @@
+/*******************************************************************************
+
+ 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 "includes.h"
+#include "common.h"
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include "lldp_mod.h"
+#include "lldptool.h"
+#include "lldp.h"
+#include "lldp_evb.h"
+#include "lldp_evb_clif.h"
+
+void evb_print_cfg_tlv(u16, char *info);
+int evb_print_help();
+
+u32 evb_lookup_tlv_name(char *tlvid_str);
+
+static const struct lldp_mod_ops evb_ops_clif = {
+ .lldp_mod_register = evb_cli_register,
+ .lldp_mod_unregister = evb_cli_unregister,
+ .print_tlv = evb_print_tlv,
+ .lookup_tlv_name = evb_lookup_tlv_name,
+ .print_help = evb_print_help,
+};
+
+struct type_name_info evb_tlv_names[] = {
+ { (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE,
+ "EVB Configuration TLV",
+ "evbCfg", evb_print_cfg_tlv },
+ { INVALID_TLVID, NULL, NULL }
+};
+
+int evb_print_help()
+{
+ struct type_name_info *tn = &evb_tlv_names[0];
+
+ while (tn->type != INVALID_TLVID) {
+ if (tn->key && strlen(tn->key) && tn->name) {
+ printf(" %s", tn->key);
+ if (strlen(tn->key)+3 <= 8)
+ printf("\t");
+ printf("\t: %s\n", tn->name);
+ }
+ tn++;
+ }
+
+ return 0;
+}
+
+struct lldp_module *evb_cli_register(void)
+{
+ struct lldp_module *mod;
+
+ mod = malloc(sizeof(*mod));
+ if (!mod) {
+ fprintf(stderr, "failed to malloc module data\n");
+ return NULL;
+ }
+ mod->id = LLDP_MOD_EVB;
+ mod->ops = &evb_ops_clif;
+
+ return mod;
+}
+
+void evb_cli_unregister(struct lldp_module *mod)
+{
+ free(mod);
+}
+
+void evb_print_cfg_tlv(u16 len, char *info)
+{
+ u8 smode;
+ u8 scap;
+ u8 cmode;
+ u8 ccap;
+ u16 svsi;
+ u16 cvsi;
+ u8 rte;
+
+ if (len != 9) {
+ printf("Bad Cfg TLV: %s\n", info);
+ return;
+ }
+
+ if (!hexstr2bin(info, &smode, sizeof(smode))) {
+ printf("supported forwarding mode:");
+
+ if (smode & LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY)
+ printf(" reflective relay");
+
+ if (smode & LLDP_EVB_CAPABILITY_FORWARD_STANDARD)
+ printf(" standard 802.1Q");
+
+ printf("\n");
+ } else {
+ printf("Unable to decode smode !\n");
+ }
+
+ if (!hexstr2bin(info+2, &scap, sizeof(scap))) {
+ printf("\tsupported capabilities:");
+
+ if ( scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE)
+ printf(" RTE");
+
+ if ( scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP)
+ printf(" ECP");
+
+ if ( scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDPL)
+ printf(" VDPL");
+
+ if ( scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP)
+ printf(" VDP");
+
+ printf("\n");
+ } else {
+ printf("Unable to decode scap !\n");
+ }
+
+ if (!hexstr2bin(info, &cmode, sizeof(cmode))) {
+ printf("\tconfigured forwarding mode:");
+
+ if (cmode & LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY)
+ printf(" reflective relay");
+
+ if (cmode & LLDP_EVB_CAPABILITY_FORWARD_STANDARD)
+ printf(" standard 802.1Q");
+
+ printf("\n");
+ } else {
+ printf("Unable to decode cmode !\n");
+ }
+
+ if (!hexstr2bin(info+4, &ccap, sizeof(ccap))) {
+ printf("\tconfigured capabilities:");
+
+ if ( ccap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE)
+ printf(" RTE");
+
+ if ( ccap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP)
+ printf(" ECP");
+
+ if ( ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDPL)
+ printf(" VDPL");
+
+ if ( ccap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP)
+ printf(" VDP");
+
+ printf("\n");
+ } else {
+ printf("Unable to decode ccap !\n");
+ }
+
+ if (!hexstr2bin(info+8, (u16 *)&svsi, sizeof(svsi))) {
+ printf("\tno. of supported VSIs: %04i\n",svsi);
+ } else {
+ printf("Unable to decode svsi !\n");
+ }
+
+ if (!hexstr2bin(info+12, (u16 *)&cvsi, sizeof(cvsi))) {
+ printf("\tno. of configured VSIs: %04i\n",cvsi);
+ } else {
+ printf("Unable to decode cvsi !\n");
+ }
+
+ if (!hexstr2bin(info+16, &rte, sizeof(rte))) {
+ printf("\tRTE: %i\n",rte);
+ } else {
+ printf("Unable to decode cvsi !\n");
+ }
+
+ printf("\n");
+}
+
+/* return 1: if it printed the TLV
+ * 0: if it did not
+ */
+int evb_print_tlv(u32 tlvid, u16 len, u8 *info)
+{
+ struct type_name_info *tn = &evb_tlv_names[0];
+
+ while (tn->type != INVALID_TLVID) {
+ if (tlvid == tn->type) {
+ printf("%s\n", tn->name);
+ if (tn->print_info) {
+ printf("\t");
+ tn->print_info(len-4, info);
+ }
+ return 1;
+ }
+ tn++;
+ }
+
+ return 0;
+}
+
+u32 evb_lookup_tlv_name(char *tlvid_str)
+{
+ struct type_name_info *tn = &evb_tlv_names[0];
+
+ while (tn->type != INVALID_TLVID) {
+ if (!strcasecmp(tn->key, tlvid_str))
+ return tn->type;
+ tn++;
+ }
+ return INVALID_TLVID;
+}
+
diff --git a/lldp_evb_cmds.c b/lldp_evb_cmds.c
new file mode 100644
index 0000000..b6f6ad5
--- /dev/null
+++ b/lldp_evb_cmds.c
@@ -0,0 +1,127 @@
+/*******************************************************************************
+
+ 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 "includes.h"
+#include "common.h"
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include "lldpad.h"
+#include "ctrl_iface.h"
+#include "lldp.h"
+#include "lldp_evb.h"
+#include "lldp_mand_clif.h"
+#include "lldp_evb_clif.h"
+#include "lldp/ports.h"
+#include "libconfig.h"
+#include "config.h"
+#include "clif_msgs.h"
+#include "lldp/states.h"
+
+static int get_arg_tlvtxenable(struct cmd *, char *, char *, char *);
+static int set_arg_tlvtxenable(struct cmd *, char *, char *, char *);
+
+static struct arg_handlers arg_handlers[] = {
+ { ARG_TLVTXENABLE, get_arg_tlvtxenable, set_arg_tlvtxenable },
+ { NULL }
+};
+
+static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ int value;
+ char *s;
+ char arg_path[256];
+
+ if (cmd->cmd != cmd_gettlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s",
+ TLVID_PREFIX, cmd->tlvid, arg);
+
+ if (get_config_setting(cmd->ifname, arg_path, (void *)&value,
+ CONFIG_TYPE_BOOL))
+ value = false;
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ if (value)
+ s = VAL_YES;
+ else
+ s = VAL_NO;
+
+ sprintf(obuf, "%02x%s%04x%s", strlen(arg), arg, strlen(s), s);
+
+ return cmd_success;
+}
+
+static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ int value;
+ char arg_path[256];
+
+ if (cmd->cmd != cmd_settlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ if (!strcasecmp(argvalue, VAL_YES))
+ value = 1;
+ else if (!strcasecmp(argvalue, VAL_NO))
+ value = 0;
+ else
+ return cmd_invalid;
+
+ snprintf(arg_path, sizeof(arg_path), "%s%08x.%s", TLVID_PREFIX,
+ cmd->tlvid, arg);
+
+ if (set_cfg(cmd->ifname, arg_path, (void *)&value, CONFIG_TYPE_BOOL))
+ return cmd_failed;
+
+ somethingChangedLocal(cmd->ifname);
+
+ return cmd_success;
+}
+
+struct arg_handlers *evb_get_arg_handlers()
+{
+ return &arg_handlers[0];
+}
diff --git a/lldpad.c b/lldpad.c
index e89abcd..711a995 100644
--- a/lldpad.c
+++ b/lldpad.c
@@ -49,6 +49,7 @@
#include "lldp_dcbx.h"
#include "lldp_med.h"
#include "lldp_8023.h"
+#include "lldp_evb.h"
#include "config.h"
#include "lldpad_shm.h"
#include "clif.h"
@@ -63,6 +64,7 @@ struct lldp_module *(*register_tlv_table[])(void) = {
dcbx_register,
med_register,
ieee8023_register,
+ evb_register,
NULL,
};
diff --git a/lldptool.c b/lldptool.c
index a48df28..a06a279 100644
--- a/lldptool.c
+++ b/lldptool.c
@@ -39,6 +39,7 @@
#include "lldp_med_clif.h"
#include "lldp_8023_clif.h"
#include "lldp_dcbx_clif.h"
+#include "lldp_evb_clif.h"
#include "lldptool.h"
#include "lldptool_cli.h"
#include "lldp_mod.h"
@@ -156,6 +157,7 @@ struct lldp_module *(*register_tlv_table[])(void) = {
ieee8023_cli_register,
med_cli_register,
dcbx_cli_register,
+ evb_cli_register,
NULL,
};
--
1.7.0.1
^ permalink raw reply related
* [PATCH 3/3] support for getting and setting EVB TLV parameters
From: Jens Osterkamp @ 2010-05-04 11:47 UTC (permalink / raw)
To: e1000-eedc, virtualization, evb; +Cc: chrisw, Jens Osterkamp
In-Reply-To: <1272973669-6694-1-git-send-email-jens@linux.vnet.ibm.com>
This patch adds 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 and VDPL)
- no. of supported VSIs
- retransmission timer exponent (RTE)
To implement this, struct tlv_info_evb had to move to include/lldp_evb.h.
Besides that, the patch contains some minor bugfixes.
Signed-off-by: Jens Osterkamp <jens@linux.vnet.ibm.com>
---
include/lldp_evb.h | 20 +++
include/lldp_evb_clif.h | 18 +++
lldp_evb.c | 21 +---
lldp_evb_cmds.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 372 insertions(+), 22 deletions(-)
diff --git a/include/lldp_evb.h b/include/lldp_evb.h
index 3559dde..de39fd3 100644
--- a/include/lldp_evb.h
+++ b/include/lldp_evb.h
@@ -37,6 +37,25 @@ typedef enum {
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;
@@ -54,5 +73,6 @@ 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
index 56011d1..5306eca 100644
--- a/include/lldp_evb_clif.h
+++ b/include/lldp_evb_clif.h
@@ -30,4 +30,22 @@ struct lldp_module *evb_cli_register(void);
void evb_cli_unregister(struct lldp_module *);
int evb_print_tlv(u32, u16, u8 *);
+#define EVB_BUF_SIZE 256
+
+#define ARG_EVB_FORWARDING_MODE "fmode"
+
+#define VAL_EVB_FMODE_BRIDGE "bridge"
+#define VAL_EVB_FMODE_RELAXEDRELAY "relaxedrelay"
+
+#define ARG_EVB_CAPABILITIES "capabilities"
+
+#define VAL_EVB_CAPA_RTE "rte"
+#define VAL_EVB_CAPA_ECP "ecp"
+#define VAL_EVB_CAPA_VDPL "vdpl"
+#define VAL_EVB_CAPA_VDP "vdp"
+
+#define ARG_EVB_VSIS "vsis"
+
+#define ARG_EVB_RTE "rte"
+
#endif
diff --git a/lldp_evb.c b/lldp_evb.c
index 304a9f4..db5a11c 100644
--- a/lldp_evb.c
+++ b/lldp_evb.c
@@ -39,26 +39,7 @@
extern struct lldp_head lldp_head;
-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__));
-
-static struct evb_data *evb_data(const char *ifname)
+struct evb_data *evb_data(char *ifname)
{
struct evb_user_data *ud;
struct evb_data *bd = NULL;
diff --git a/lldp_evb_cmds.c b/lldp_evb_cmds.c
index b6f6ad5..7cef1bb 100644
--- a/lldp_evb_cmds.c
+++ b/lldp_evb_cmds.c
@@ -45,7 +45,23 @@
static int get_arg_tlvtxenable(struct cmd *, char *, char *, char *);
static int set_arg_tlvtxenable(struct cmd *, char *, char *, char *);
+static int get_arg_fmode(struct cmd *, char *, char *, char *);
+static int set_arg_fmode(struct cmd *, char *, char *, char *);
+
+static int get_arg_rte(struct cmd *, char *, char *, char *);
+static int set_arg_rte(struct cmd *, char *, char *, char *);
+
+static int get_arg_vsis(struct cmd *, char *, char *, char *);
+static int set_arg_vsis(struct cmd *, char *, char *, char *);
+
+static int get_arg_capabilities(struct cmd *, char *, char *, char *);
+static int set_arg_capabilities(struct cmd *, char *, char *, char *);
+
static struct arg_handlers arg_handlers[] = {
+ { ARG_EVB_FORWARDING_MODE, get_arg_fmode, set_arg_fmode },
+ { ARG_EVB_CAPABILITIES, get_arg_capabilities, set_arg_capabilities },
+ { ARG_EVB_VSIS, get_arg_vsis, set_arg_vsis },
+ { ARG_EVB_RTE, get_arg_rte, set_arg_rte },
{ ARG_TLVTXENABLE, get_arg_tlvtxenable, set_arg_tlvtxenable },
{ NULL }
};
@@ -55,7 +71,7 @@ static int get_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
{
int value;
char *s;
- char arg_path[256];
+ char arg_path[EVB_BUF_SIZE];
if (cmd->cmd != cmd_gettlv)
return cmd_invalid;
@@ -89,7 +105,7 @@ static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
char *obuf)
{
int value;
- char arg_path[256];
+ char arg_path[EVB_BUF_SIZE];
if (cmd->cmd != cmd_settlv)
return cmd_invalid;
@@ -121,6 +137,321 @@ static int set_arg_tlvtxenable(struct cmd *cmd, char *arg, char *argvalue,
return cmd_success;
}
+static int get_arg_fmode(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ u8 smode;
+ char *s;
+ char arg_path[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_gettlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+ if (!ed)
+ return cmd_invalid;
+ if (ed->tie->smode & LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY)
+ s = VAL_EVB_FMODE_BRIDGE;
+ else
+ s = VAL_EVB_FMODE_RELAXEDRELAY;
+
+ sprintf(obuf, "%02x%s%04x%s", strlen(arg), arg, strlen(s), s);
+
+ return cmd_success;
+}
+
+static int set_arg_fmode(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ char arg_path[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_settlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+
+ if (!ed)
+ return cmd_invalid;
+
+ if (!strcasecmp(argvalue, VAL_EVB_FMODE_BRIDGE))
+ ed->tie->smode = LLDP_EVB_CAPABILITY_FORWARD_STANDARD;
+ else if (!strcasecmp(argvalue, VAL_EVB_FMODE_RELAXEDRELAY))
+ ed->tie->smode = LLDP_EVB_CAPABILITY_FORWARD_RELAXEDRELAY;
+ else
+ return cmd_invalid;
+
+ somethingChangedLocal(cmd->ifname);
+
+ return cmd_success;
+}
+
+static int get_arg_capabilities(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ int c;
+ char *s, *t;
+ char arg_path[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ printf("%s(%i): arg %s, argvalue %s !\n", __func__, __LINE__, arg, argvalue);
+
+ s = t = malloc(EVB_BUF_SIZE);
+
+ if (!s)
+ return cmd_invalid;
+
+ memset(s, 0, EVB_BUF_SIZE);
+
+ if (cmd->cmd != cmd_gettlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+ if (!ed)
+ return cmd_invalid;
+
+ if (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_RTE) {
+ c = sprintf(s, VAL_EVB_CAPA_RTE " ");
+ if (c <= 0)
+ return cmd_invalid;
+ s += c;
+ }
+
+ if (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_ECP) {
+ c = sprintf(s, VAL_EVB_CAPA_ECP " ");
+ if (c <= 0)
+ return cmd_invalid;
+ s += c;
+ }
+
+ if (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDP) {
+ c = sprintf(s, VAL_EVB_CAPA_VDP " ");
+ if (c <= 0)
+ return cmd_invalid;
+ s += c;
+ }
+
+ if (ed->tie->scap & LLDP_EVB_CAPABILITY_PROTOCOL_VDPL) {
+ c = sprintf(s, VAL_EVB_CAPA_VDPL " ");
+ if (c <= 0)
+ return cmd_invalid;
+ s += c;
+ }
+
+
+ sprintf(obuf, "%02x%s%04x%s", strlen(arg), arg, strlen(t), t);
+
+ return cmd_success;
+}
+
+static int set_arg_capabilities(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ u8 scap;
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_settlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+
+ if (!ed)
+ return cmd_invalid;
+
+ if (strcasestr(argvalue, VAL_EVB_CAPA_RTE)) {
+ scap |= LLDP_EVB_CAPABILITY_PROTOCOL_RTE;
+ }
+
+ if (strcasestr(argvalue, VAL_EVB_CAPA_ECP)) {
+ scap |= LLDP_EVB_CAPABILITY_PROTOCOL_ECP;
+ }
+
+ if (strcasestr(argvalue, VAL_EVB_CAPA_VDP)) {
+ scap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDP;
+ }
+
+ if (strcasestr(argvalue, VAL_EVB_CAPA_VDPL)) {
+ scap |= LLDP_EVB_CAPABILITY_PROTOCOL_VDPL;
+ }
+
+ if (scap != ed->tie->scap) {
+ ed->tie->scap = scap;
+ somethingChangedLocal(cmd->ifname);
+ }
+
+ return cmd_success;
+}
+
+static int get_arg_rte(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ char s[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_gettlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+ if (!ed)
+ return cmd_invalid;
+
+ if (sprintf(s, "%i", ed->tie->rte) <= 0)
+ return cmd_invalid;
+
+ sprintf(obuf, "%02x%s%04x%s", strlen(arg), arg, strlen(s), s);
+
+ return cmd_success;
+}
+
+static int set_arg_rte(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ int value;
+ char arg_path[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_settlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+
+ if (!ed)
+ return cmd_invalid;
+
+ value = atoi(argvalue);
+
+ if ((value < 0))
+ return cmd_invalid;
+
+ ed->tie->rte = value;
+
+ somethingChangedLocal(cmd->ifname);
+
+ return cmd_success;
+}
+
+
+static int get_arg_vsis(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ char s[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_gettlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+ if (!ed)
+ return cmd_invalid;
+
+ if (sprintf(s, "%04i", ed->tie->svsi) <= 0)
+ return cmd_invalid;
+
+ sprintf(obuf, "%02x%s%04x%s", strlen(arg), arg, strlen(s), s);
+
+ return cmd_success;
+}
+
+static int set_arg_vsis(struct cmd *cmd, char *arg, char *argvalue,
+ char *obuf)
+{
+ int value;
+ char arg_path[EVB_BUF_SIZE];
+ struct evb_data *ed;
+
+ if (cmd->cmd != cmd_settlv)
+ return cmd_invalid;
+
+ switch (cmd->tlvid) {
+ case (LLDP_MOD_EVB << 8) | LLDP_EVB_SUBTYPE:
+ break;
+ case INVALID_TLVID:
+ return cmd_invalid;
+ default:
+ return cmd_not_applicable;
+ }
+
+ ed = evb_data((char *) &cmd->ifname);
+
+ if (!ed)
+ return cmd_invalid;
+
+ value = atoi(argvalue);
+
+ if ((value < 0) || (value > LLDP_EVB_DEFAULT_MAX_VSI))
+ return cmd_invalid;
+
+ ed->tie->svsi = value;
+
+ somethingChangedLocal(cmd->ifname);
+
+ return cmd_success;
+}
+
struct arg_handlers *evb_get_arg_handlers()
{
return &arg_handlers[0];
--
1.7.0.1
^ permalink raw reply related
* Re: [PATCH 1/1] hv: Added new hv_utils driver with shutdown as first functionality - NO OUTLOOK
From: Greg KH @ 2010-05-04 15:29 UTC (permalink / raw)
To: Hank Janssen
Cc: hjanssen, linux-kernel, devel, virtualization, gregkh, haiyangz
In-Reply-To: <4BE0A5C9.2020409@sailtheuniverse.com>
On Tue, May 04, 2010 at 03:55:05PM -0700, Hank Janssen wrote:
>
> Resending this patch from my personal Linux server. Exchange server and
> outlook at Microsoft seems to badly munge my patch. :(
>
> From: Hank Janssen <hjanssen@sailtheuniverse.com>
In the future, please put your microsoft email address here.
> Subject: [PATCH 1/1] hv: Added new hv_utils driver with shutdown as first functionality
>
> Addition of new driver for Hyper-V called hv_utils.
> This driver is intended to support things like KVP, Timesync, Heartbeat etc.
>
> This first release has support for Gracefull shutdown.
> e.g. Select shutdown from the Hyper-V main admin screen and the Linux VM
> will do a gracefull shutdown.
>
> Signed-off-by: Hank Janssen <microsoft.com>
That's not a valid email address.
> Signed-off-by: Hank Janssen <sailtheuniverse.com>
Neither is that.
Also, you "signed-off" on a patch twice, not good.
Other than that, which I fixed up by hand, it looks good, and I've
applied it and added some clean-up patches on top of it to resolve some
issues.
thanks,
greg k-h
^ permalink raw reply
* RE: [PATCH 1/1] hv: Added new hv_utils driver with shutdown as first functionality - NO OUTLOOK
From: Hank Janssen @ 2010-05-04 16:26 UTC (permalink / raw)
To: Greg KH, Hank Janssen
Cc: devel@driverdev.osuosl.org, virtualization@lists.osdl.org,
Haiyang Zhang, gregkh@suse.de, linux-kernel@vger.kernel.org
In-Reply-To: <20100504152949.GA22850@kroah.com>
>> Greg Wrote
>>
>> Signed-off-by: Hank Janssen <microsoft.com
>>
>>That's not a valid email address.
>>
>>> Signed-off-by: Hank Janssen <sailtheuniverse.com>
>>
>>Neither is that.
Sorry, by this time I was so frustrated arguing with lookout and Exchange that I did not properly
Add the emails when I send it from my own server. :(
Thanks,
Hank.
^ permalink raw reply
* Re: virtio: put last_used and last_avail index into ring itself.
From: Michael S. Tsirkin @ 2010-05-04 18:22 UTC (permalink / raw)
To: Rusty Russell
Cc: Eric Dumazet, kvm, netdev, linux-kernel, virtualization, linux-mm,
s.hetze, hpa, Daniel Walker, mingo, akpm
In-Reply-To: <200911091647.29655.rusty@rustcorp.com.au>
> virtio: put last_used and last_avail index into ring itself.
>
> Generally, the other end of the virtio ring doesn't need to see where
> you're up to in consuming the ring. However, to completely understand
> what's going on from the outside, this information must be exposed.
> For example, if you want to save and restore a virtio_ring, but you're
> not the consumer because the kernel is using it directly.
>
> Fortunately, we have room to expand: the ring is always a whole number
> of pages and there's hundreds of bytes of padding after the avail ring
> and the used ring, whatever the number of descriptors (which must be a
> power of 2).
>
> We add a feature bit so the guest can tell the host that it's writing
> out the current value there, if it wants to use that.
>
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
I've been looking at this patch some more (more on why
later), and I wonder: would it be better to add some
alignment to the last used index address, so that
if we later add more stuff at the tail, it all
fits in a single cache line?
We use a new feature bit anyway, so layout change should not be
a problem.
Since I raised the question of caches: for used ring,
the ring is not aligned to 64 bit, so on CPUs with 64 bit
or larger cache lines, used entries will often cross
cache line boundaries. Am I right and might it
have been better to align ring entries to cache line boundaries?
What do you think?
> ---
> drivers/virtio/virtio_ring.c | 23 +++++++++++++++--------
> include/linux/virtio_ring.h | 12 +++++++++++-
> 2 files changed, 26 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
> --- a/drivers/virtio/virtio_ring.c
> +++ b/drivers/virtio/virtio_ring.c
> @@ -71,9 +71,6 @@ struct vring_virtqueue
> /* Number we've added since last sync. */
> unsigned int num_added;
>
> - /* Last used index we've seen. */
> - u16 last_used_idx;
> -
> /* How to notify other side. FIXME: commonalize hcalls! */
> void (*notify)(struct virtqueue *vq);
>
> @@ -278,12 +275,13 @@ static void detach_buf(struct vring_virt
>
> static inline bool more_used(const struct vring_virtqueue *vq)
> {
> - return vq->last_used_idx != vq->vring.used->idx;
> + return vring_last_used(&vq->vring) != vq->vring.used->idx;
> }
>
> static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
> {
> struct vring_virtqueue *vq = to_vvq(_vq);
> + struct vring_used_elem *u;
> void *ret;
> unsigned int i;
>
> @@ -300,8 +298,11 @@ static void *vring_get_buf(struct virtqu
> return NULL;
> }
>
> - i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
> - *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
> + u = &vq->vring.used->ring[vring_last_used(&vq->vring) % vq->vring.num];
> + i = u->id;
> + *len = u->len;
> + /* Make sure we don't reload i after doing checks. */
> + rmb();
>
> if (unlikely(i >= vq->vring.num)) {
> BAD_RING(vq, "id %u out of range\n", i);
> @@ -315,7 +316,8 @@ static void *vring_get_buf(struct virtqu
> /* detach_buf clears data, so grab it now. */
> ret = vq->data[i];
> detach_buf(vq, i);
> - vq->last_used_idx++;
> + vring_last_used(&vq->vring)++;
> +
> END_USE(vq);
> return ret;
> }
> @@ -402,7 +404,6 @@ struct virtqueue *vring_new_virtqueue(un
> vq->vq.name = name;
> vq->notify = notify;
> vq->broken = false;
> - vq->last_used_idx = 0;
> vq->num_added = 0;
> list_add_tail(&vq->vq.list, &vdev->vqs);
> #ifdef DEBUG
> @@ -413,6 +414,10 @@ struct virtqueue *vring_new_virtqueue(un
>
> vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
>
> + /* We publish indices whether they offer it or not: if not, it's junk
> + * space anyway. But calling this acknowledges the feature. */
> + virtio_has_feature(vdev, VIRTIO_RING_F_PUBLISH_INDICES);
> +
> /* No callback? Tell other side not to bother us. */
> if (!callback)
> vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
> @@ -443,6 +448,8 @@ void vring_transport_features(struct vir
> switch (i) {
> case VIRTIO_RING_F_INDIRECT_DESC:
> break;
> + case VIRTIO_RING_F_PUBLISH_INDICES:
> + break;
> default:
> /* We don't understand this bit. */
> clear_bit(i, vdev->features);
> diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
> --- a/include/linux/virtio_ring.h
> +++ b/include/linux/virtio_ring.h
> @@ -29,6 +29,9 @@
> /* We support indirect buffer descriptors */
> #define VIRTIO_RING_F_INDIRECT_DESC 28
>
> +/* We publish our last-seen used index at the end of the avail ring. */
> +#define VIRTIO_RING_F_PUBLISH_INDICES 29
> +
> /* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
> struct vring_desc
> {
> @@ -87,6 +90,7 @@ struct vring {
> * __u16 avail_flags;
> * __u16 avail_idx;
> * __u16 available[num];
> + * __u16 last_used_idx;
> *
> * // Padding to the next align boundary.
> * char pad[];
> @@ -95,6 +99,7 @@ struct vring {
> * __u16 used_flags;
> * __u16 used_idx;
> * struct vring_used_elem used[num];
> + * __u16 last_avail_idx;
> * };
> */
> static inline void vring_init(struct vring *vr, unsigned int num, void *p,
> @@ -111,9 +116,14 @@ static inline unsigned vring_size(unsign
> {
> return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
> + align - 1) & ~(align - 1))
> - + sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num;
> + + sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num + 2;
> }
>
> +/* We publish the last-seen used index at the end of the available ring, and
> + * vice-versa. These are at the end for backwards compatibility. */
> +#define vring_last_used(vr) ((vr)->avail->ring[(vr)->num])
> +#define vring_last_avail(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
> +
> #ifdef __KERNEL__
> #include <linux/irqreturn.h>
> struct virtio_device;
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Christoph Hellwig @ 2010-05-04 18:54 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: kvm, qemu-devel, virtualization, Anthony Liguori, hch
In-Reply-To: <20100218222220.GA14847@redhat.com>
On Fri, Feb 19, 2010 at 12:22:20AM +0200, Michael S. Tsirkin wrote:
> I took a stub at documenting CMD and FLUSH request types in virtio
> block. Christoph, could you look over this please?
>
> I note that the interface seems full of warts to me,
> this might be a first step to cleaning them.
The whole virtio-blk interface is full of warts. It has been
extended rather ad-hoc, so that is rather expected.
> One issue I struggled with especially is how type
> field mixes bits and non-bit values. I ended up
> simply defining all legal values, so that we have
> CMD = 2, CMD_OUT = 3 and so on.
It's basically a complete mess without much logic behind it.
> +\change_unchanged
> +the high bit
> +\change_inserted 0 1266497301
> + (VIRTIO_BLK_T_BARRIER)
> +\change_unchanged
> + indicates that this request acts as a barrier and that all preceeding requests
> + must be complete before this one, and all following requests must not be
> + started until this is complete.
> +
> +\change_inserted 0 1266504385
> + Note that a barrier does not flush caches in the underlying backend device
> + in host, and thus does not serve as data consistency guarantee.
> + Driver must use FLUSH request to flush the host cache.
> +\change_unchanged
I'm not sure it's even worth documenting it. I can't see any way to
actually implement safe behaviour with the VIRTIO_BLK_T_BARRIER-style
barriers.
Btw, did I mention that .lyx is a a really horrible format to review
diffs for? Plain latex would be a lot better..
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] virtio-spec: document block CMD and FLUSH
From: Christoph Hellwig @ 2010-05-04 18:56 UTC (permalink / raw)
To: Jamie Lokier; +Cc: kvm, Michael S. Tsirkin, qemu-devel, virtualization, hch
In-Reply-To: <20100420014635.GE21899@shareable.org>
On Tue, Apr 20, 2010 at 02:46:35AM +0100, Jamie Lokier wrote:
> Does this mean that virtio-blk supports all three combinations?
>
> 1. FLUSH that isn't a barrier
> 2. FLUSH that is also a barrier
> 3. Barrier that is not a flush
>
> 1 is good for fsync-like operations;
> 2 is good for journalling-like ordered operations.
> 3 sounds like it doesn't mean a lot as the host cache provides no
> guarantees and has no ordering facility that can be used.
No. The Linux virtio_blk guest driver either supports data integrity
by using FLUSH or can send down BARRIER requests which aren't much
help at all. Qemu only implements FLUSH anyway.
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Michael S. Tsirkin @ 2010-05-04 18:56 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: kvm, qemu-devel, Anthony Liguori, virtualization
In-Reply-To: <20100504185459.GA24998@lst.de>
On Tue, May 04, 2010 at 08:54:59PM +0200, Christoph Hellwig wrote:
> On Fri, Feb 19, 2010 at 12:22:20AM +0200, Michael S. Tsirkin wrote:
> > I took a stub at documenting CMD and FLUSH request types in virtio
> > block. Christoph, could you look over this please?
> >
> > I note that the interface seems full of warts to me,
> > this might be a first step to cleaning them.
>
> The whole virtio-blk interface is full of warts. It has been
> extended rather ad-hoc, so that is rather expected.
>
> > One issue I struggled with especially is how type
> > field mixes bits and non-bit values. I ended up
> > simply defining all legal values, so that we have
> > CMD = 2, CMD_OUT = 3 and so on.
>
> It's basically a complete mess without much logic behind it.
>
> > +\change_unchanged
> > +the high bit
> > +\change_inserted 0 1266497301
> > + (VIRTIO_BLK_T_BARRIER)
> > +\change_unchanged
> > + indicates that this request acts as a barrier and that all preceeding requests
> > + must be complete before this one, and all following requests must not be
> > + started until this is complete.
> > +
> > +\change_inserted 0 1266504385
> > + Note that a barrier does not flush caches in the underlying backend device
> > + in host, and thus does not serve as data consistency guarantee.
> > + Driver must use FLUSH request to flush the host cache.
> > +\change_unchanged
>
> I'm not sure it's even worth documenting it. I can't see any way to
> actually implement safe behaviour with the VIRTIO_BLK_T_BARRIER-style
> barriers.
lguest seems to still use this.
I guess if you have a reliable host, VIRTIO_BLK_T_BARRIER is enough?
> Btw, did I mention that .lyx is a a really horrible format to review
> diffs for? Plain latex would be a lot better..
^ permalink raw reply
* Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Michael S. Tsirkin @ 2010-05-04 18:58 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: kvm, qemu-devel, Anthony Liguori, virtualization
In-Reply-To: <20100504185618.GA29725@redhat.com>
On Tue, May 04, 2010 at 09:56:18PM +0300, Michael S. Tsirkin wrote:
> On Tue, May 04, 2010 at 08:54:59PM +0200, Christoph Hellwig wrote:
> > On Fri, Feb 19, 2010 at 12:22:20AM +0200, Michael S. Tsirkin wrote:
> > > I took a stub at documenting CMD and FLUSH request types in virtio
> > > block. Christoph, could you look over this please?
> > >
> > > I note that the interface seems full of warts to me,
> > > this might be a first step to cleaning them.
> >
> > The whole virtio-blk interface is full of warts. It has been
> > extended rather ad-hoc, so that is rather expected.
> >
> > > One issue I struggled with especially is how type
> > > field mixes bits and non-bit values. I ended up
> > > simply defining all legal values, so that we have
> > > CMD = 2, CMD_OUT = 3 and so on.
> >
> > It's basically a complete mess without much logic behind it.
> >
> > > +\change_unchanged
> > > +the high bit
> > > +\change_inserted 0 1266497301
> > > + (VIRTIO_BLK_T_BARRIER)
> > > +\change_unchanged
> > > + indicates that this request acts as a barrier and that all preceeding requests
> > > + must be complete before this one, and all following requests must not be
> > > + started until this is complete.
> > > +
> > > +\change_inserted 0 1266504385
> > > + Note that a barrier does not flush caches in the underlying backend device
> > > + in host, and thus does not serve as data consistency guarantee.
> > > + Driver must use FLUSH request to flush the host cache.
> > > +\change_unchanged
> >
> > I'm not sure it's even worth documenting it. I can't see any way to
> > actually implement safe behaviour with the VIRTIO_BLK_T_BARRIER-style
> > barriers.
>
> lguest seems to still use this.
Sorry, it doesn't. No idea why I thought it does.
> I guess if you have a reliable host, VIRTIO_BLK_T_BARRIER is enough?
>
> > Btw, did I mention that .lyx is a a really horrible format to review
> > diffs for? Plain latex would be a lot better..
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] virtio-spec: document block CMD and FLUSH
From: Michael S. Tsirkin @ 2010-05-04 19:01 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: Jamie Lokier, qemu-devel, kvm, virtualization
In-Reply-To: <20100504185614.GB24998@lst.de>
On Tue, May 04, 2010 at 08:56:14PM +0200, Christoph Hellwig wrote:
> On Tue, Apr 20, 2010 at 02:46:35AM +0100, Jamie Lokier wrote:
> > Does this mean that virtio-blk supports all three combinations?
> >
> > 1. FLUSH that isn't a barrier
> > 2. FLUSH that is also a barrier
> > 3. Barrier that is not a flush
> >
> > 1 is good for fsync-like operations;
> > 2 is good for journalling-like ordered operations.
> > 3 sounds like it doesn't mean a lot as the host cache provides no
> > guarantees and has no ordering facility that can be used.
>
> No. The Linux virtio_blk guest driver either supports data integrity
> by using FLUSH or can send down BARRIER requests which aren't much
> help at all.
It seems we use BARRIER when we get REQ_HARDBARRIER, right?
What does the REQ_HARDBARRIER flag in request mean and when is it set?
> Qemu only implements FLUSH anyway.
^ permalink raw reply
* Re: [Qemu-devel] Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Jamie Lokier @ 2010-05-04 20:17 UTC (permalink / raw)
To: Jens Axboe
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, hch
In-Reply-To: <20100504084133.GH27497@kernel.dk>
Jens Axboe wrote:
> On Tue, May 04 2010, Rusty Russell wrote:
> > ISTR someone mentioning a desire for such an API years ago, so CC'ing the
> > usual I/O suspects...
>
> It would be nice to have a more fuller API for this, but the reality is
> that only the flush approach is really workable. Even just strict
> ordering of requests could only be supported on SCSI, and even there the
> kernel still lacks proper guarantees on error handling to prevent
> reordering there.
There's a few I/O scheduling differences that might be useful:
1. The I/O scheduler could freely move WRITEs before a FLUSH but not
before a BARRIER. That might be useful for time-critical WRITEs,
and those issued by high I/O priority.
2. The I/O scheduler could move WRITEs after a FLUSH if the FLUSH is
only for data belonging to a particular file (e.g. fdatasync with
no file size change, even on btrfs if O_DIRECT was used for the
writes being committed). That would entail tagging FLUSHes and
WRITEs with a fs-specific identifier (such as inode number), opaque
to the scheduler which only checks equality.
3. By delaying FLUSHes through reordering as above, the I/O scheduler
could merge multiple FLUSHes into a single command.
4. On MD/RAID, BARRIER requires every backing device to quiesce before
sending the low-level cache-flush, and all of those to finish
before resuming each backing device. FLUSH doesn't require as much
synchronising. (With per-file FLUSH; see 2; it could even avoid
FLUSH altogether to some backing devices for small files).
In other words, FLUSH can be more relaxed than BARRIER inside the
kernel. It's ironic that we think of fsync as stronger than
fbarrier outside the kernel :-)
-- Jamie
^ permalink raw reply
* Re: [Qemu-devel] Re: [PATCH] virtio-spec: document block CMD and FLUSH
From: Jamie Lokier @ 2010-05-04 20:32 UTC (permalink / raw)
To: Rusty Russell
Cc: tytso, kvm, Michael S. Tsirkin, Neil Brown, qemu-devel,
virtualization, Jens Axboe, hch
In-Reply-To: <201005041408.25069.rusty@rustcorp.com.au>
Rusty Russell wrote:
> On Fri, 19 Feb 2010 08:52:20 am Michael S. Tsirkin wrote:
> > I took a stub at documenting CMD and FLUSH request types in virtio
> > block. Christoph, could you look over this please?
> >
> > I note that the interface seems full of warts to me,
> > this might be a first step to cleaning them.
>
> ISTR Christoph had withdrawn some patches in this area, and was waiting
> for him to resubmit?
>
> I've given up on figuring out the block device. What seem to me to be sane
> semantics along the lines of memory barriers are foreign to disk people: they
> want (and depend on) flushing everywhere.
>
> For example, tdb transactions do not require a flush, they only require what
> I would call a barrier: that prior data be written out before any future data.
> Surely that would be more efficient in general than a flush! In fact, TDB
> wants only writes to *that file* (and metadata) written out first; it has no
> ordering issues with other I/O on the same device.
I've just posted elsewhere on this thread, that an I/O level flush can
be more efficient than an I/O level barrier (implemented using a
cache-flush really), because the barrier has stricter ordering
requirements at the I/O scheduling level.
By the time you work up to tdb, another way to think of it is
distinguishing "eager fsync" from "fsync but I'm not in a hurry -
delay as long as is convenient". The latter makes much more sense
with AIO.
> A generic I/O interface would allow you to specify "this request
> depends on these outstanding requests" and leave it at that. It
> might have some sync flush command for dumb applications and OSes.
For filesystems, it would probably be easy to label in-place
overwrites and fdatasync data flushes when there's no file extension
with an opqaue per-file identifier for certain operations. Typically
over-writing in place and fdatasync would match up and wouldn't need
ordering against anything else. Other operations would tend to get
labelled as ordered against everything including these.
-- Jamie
^ 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