xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Ross Philipson <ross.philipson@citrix.com>
To: xen-devel@lists.xen.org
Cc: Tim Deegan <tim@xen.org>
Subject: Re: [PATCH (V9) 2/2] xen: Add V4V implementation
Date: Tue, 4 Jun 2013 14:01:39 -0400	[thread overview]
Message-ID: <51AE2B83.1070808@citrix.com> (raw)
In-Reply-To: <20130530162009.GB64390@ocelot.phlegethon.org>

On 05/30/2013 12:20 PM, Tim Deegan wrote:
> Hi,
>
> Nice to see this series again. :)  Thanks for your work cleaning it up.

Thanks, and thanks for your feedback.

>
> At 15:43 -0400 on 28 May (1369755811), Ross Philipson wrote:
>> Setup of v4v domains a domain gets created and cleanup
>> when a domain die. Wire up the v4v hypercall.
>>
>> Include v4v internal and public headers.
>>
>> Signed-off-by: Ross Philipson<ross.philipson@citrix.com>
>
> I'm a bit worried about resource exhaustion attacks in this interface.
> In particular:
>   - It looks like a malicious guest can register large numbers of rings
>     (like, 2^48 of them), each of which causes Xen to xmalloc bookkeeping
>     space (up to 2^22 bytes per ring).
>   - A malicious guest that has enough memory can send a very large vector
>     (2^31 1-byte entries), which would cause Xen to read and check 2^37
>     bytes of control structures before even starting the copy of the data.
>     At a rough guess that could be>10seconds without checking for preemption.
>     Maybe reduce the limits a bit (say, 32MB per hypercall, may 100 elements
>     per vector)?
>   - Something similar for V4VOP_notify, I guess, though that could perhaps
>     be handled by the usual pending-events check + hypercall continuations.

Yes we agree. I think the plan is to have some reasonable default limits 
and allow the values to be adjusted during domain creation if that is 
needed. This would be done through a new V4V op for the hypercall.

>
> And now, some detailed review:
>
>> +/*
>> + * Messages on the ring are padded to 128 bits
>> + * Len here refers to the exact length of the data not including the
>> + * 128 bit header. The message uses
>> + * ((len +0xf)&  ~0xf) + sizeof(v4v_ring_message_header) bytes
>> + */
>> +#define V4V_ROUNDUP(a) (((a) +0xf )&  ~0xf)
>
> Even though this is always used on values<2^32 and so is safe,
> it would be nice to have it as (((a) + 0xf)&  ~(typeof (a))0xf)
> so it's clear that it doesn't truncate any high-order bits.

Ack

>
> [...]
>> +/*
>> + * lock to protect the filtering rules list: v4vtable_rules
>> + *
>> + * The write lock is held for viptables_del and viptables_add
>> + * The read lock is held for viptable_list
>
> s/viptables/v4vtables/g/

For all the minor ones I don't address directly, just assume I will fix 
it per your suggestions.

>
> [...]
>> +static int
>> +v4v_ringbuf_get_rx_ptr(struct domain *d, struct v4v_ring_info *ring_info,
>> +                        uint32_t * rx_ptr)
>> +{
>> +    v4v_ring_t *ringp;
>> +
>> +    if ( ring_info->npage == 0 )
>> +        return -1;
>> +
>> +    ringp = map_domain_page(mfn_x(ring_info->mfns[0]));
>> +
>> +    v4v_dprintk("v4v_ringbuf_payload_space: mapped %p to %p\n",
>> +                (void *)mfn_x(ring_info->mfns[0]), ringp);
>
> The function name is wrong there, presumably after this code was
> refctored.  You might add %s/__func__ to the definition of v4v_dprintk()
> instead?
>
>> +    if ( !ringp )
>> +        return -1;
>> +
>> +    write_atomic(rx_ptr, ringp->rx_ptr);
>
> AIUI ringp->rx_ptr is the shared variable here, so this should be
>    *rx_ptr = read_atomic(ringp->rx_ptr);
>
> Also, maybe comment in the hypercall interface that the guest should
> also use atomic operations when accessing rx_ptr and tx_ptr.  (Though I
> should say the hypercall comments are already pretty good compared to
> some things we already have!)

What you say sounds right. I will address this.

>
>> +    mb();
>
> I'm not 100% convinced this barrier is needed (since we're not going to
> read the 'free' memory in the ring and I don't think that writes to it
> can possibly be hoisted past this read since they're gated on the
> result).  OTOH I'm happy to err on the side of caution. :)

This could be cargo. There have been quite a number of modifications to 
this code since its birth in our product 3+ years ago. But if I cannot 
be sure, I will probably leave it be.

>
>> +    unmap_domain_page(ringp);
>> +    return 0;
>> +}
>> +
>> +uint32_t
>> +v4v_ringbuf_payload_space(struct domain * d, struct v4v_ring_info * ring_info)
>> +{
>> +    v4v_ring_t ring;
>> +    int32_t ret;
>> +
>> +    ring.tx_ptr = ring_info->tx_ptr;
>> +    ring.len = ring_info->len;
>> +
>> +    if ( v4v_ringbuf_get_rx_ptr(d, ring_info,&ring.rx_ptr) )
>> +        return 0;
>> +
>> +    v4v_dprintk("v4v_ringbuf_payload_space:tx_ptr=%d rx_ptr=%d\n",
>> +                (int)ring.tx_ptr, (int)ring.rx_ptr);
>> +    if ( ring.rx_ptr == ring.tx_ptr )
>> +        return ring.len - sizeof(struct v4v_ring_message_header);
>> +
>> +    ret = ring.rx_ptr - ring.tx_ptr;
>> +    if ( ret<  0 )
>> +        ret += ring.len;
>> +
>> +    ret -= sizeof(struct v4v_ring_message_header);
>> +    ret -= V4V_ROUNDUP(1);
>> +
>> +    return (ret<  0) ? 0 : ret;
>
> Sanity check for ret>  ring.len as well?  I guess it's not clear what
> you'd do about that.
>
> [...]
>> +static long
>> +v4v_ringbuf_insertv(struct domain *d,
>> +                    struct v4v_ring_info *ring_info,
>> +                    v4v_ring_id_t *src_id, uint32_t message_type,
>> +                    XEN_GUEST_HANDLE_PARAM(v4v_iov_t) iovs,
>> +                    uint32_t niov, size_t len)
>> +{
>> +    v4v_ring_t ring;
>> +    struct v4v_ring_message_header mh = { 0 };
>> +    int32_t sp;
>> +    long happy_ret;
>> +    int32_t ret = 0;
>> +    XEN_GUEST_HANDLE(uint8_t) empty_hnd = { 0 };
>> +
>> +    ASSERT(spin_is_locked(&ring_info->lock));
>> +
>> +    happy_ret = len;
>> +
>> +    if ( (V4V_ROUNDUP(len) + sizeof(struct v4v_ring_message_header) )>=
>> +            ring_info->len)
>> +        return -EMSGSIZE;
>> +
>> +    do {
>> +        if ( (ret = v4v_memcpy_from_guest_ring(&ring, ring_info, 0,
>> +                                               sizeof(ring))) )
>> +            break;
>
> Should this be using an atomic operation to read ring.rx_ptr instead?
> That's the only field we actually use from the guest copy anyway.

Probably. I will look at this as well as other uses of the t/rx_ptr 
usage mentioned above.

>
>> +
>> +        ring.tx_ptr = ring_info->tx_ptr;
>> +        ring.len = ring_info->len;
>> +
>> +        v4v_dprintk("ring.tx_ptr=%d ring.rx_ptr=%d ring.len=%d ring_info->tx_ptr=%d\n",
>> +                    ring.tx_ptr, ring.rx_ptr, ring.len, ring_info->tx_ptr);
>> +
>> +        if ( ring.rx_ptr == ring.tx_ptr )
>> +            sp = ring_info->len;
>> +        else
>> +        {
>> +            sp = ring.rx_ptr - ring.tx_ptr;
>> +            if ( sp<  0 )
>> +                sp += ring.len;
>> +        }
>> +
>> +        if ( (V4V_ROUNDUP(len) + sizeof(struct v4v_ring_message_header))>= sp )
>> +        {
>> +            v4v_dprintk("EAGAIN\n");
>> +            ret = -EAGAIN;
>> +            break;
>> +        }
>> +
>> +        mh.len = len + sizeof (struct v4v_ring_message_header);
>> +        mh.source.port = src_id->addr.port;
>> +        mh.source.domain = src_id->addr.domain;
>> +        mh.message_type = message_type;
>> +
>> +        if ( (ret = v4v_memcpy_to_guest_ring(ring_info,
>> +                                             ring.tx_ptr + sizeof(v4v_ring_t),
>> +&mh, empty_hnd,
>> +                                             sizeof(mh))) )
>> +            break;
>
> OK, I think this is correct, because the tx_ptr is always 16-byte
> aligned and the message header is 16 bytes long, but it's not
> obvious. :) Maybe add a comment here, and a BUILD_BUG_ON() to assert
> that sizeof (struct v4v_ring_message_header)<= V4V_ROUNDUP(1)?

Ack

>
>> +        ring.tx_ptr += sizeof(mh);
>> +        if ( ring.tx_ptr == ring_info->len )
>> +            ring.tx_ptr = 0;
>> +
>> +        while ( niov-- )
>> +        {
>> +            XEN_GUEST_HANDLE_PARAM(uint8_t) bufp_hnd;
>> +            XEN_GUEST_HANDLE(uint8_t) buf_hnd;
>> +            v4v_iov_t iov;
>> +
>> +            if ( copy_from_guest(&iov, iovs, 1) )
>
> Hrmn.  So here we re-copy the iov from the guest, but the guest might
> have changed it since we looked at it last (when we calculated the total
> length).  That means we need to keep a running count of how much we copy,
> to be sure the guest doesn't swap short iovs for long ones and make
> us overrun the ring's rx_ptr.

Yea I was starting to have concerns about just this right after I posted 
patch set 9. I really don't like that we read it twice. Your suggestion 
sounds reasonable.

>
>> +            {
>> +                ret = -EFAULT;
>> +                break;
>> +            }
>> +
>> +            bufp_hnd = guest_handle_from_ptr(iov.iov_base, uint8_t);
>> +            buf_hnd = guest_handle_from_param(bufp_hnd, uint8_t);
>> +            len = iov.iov_len;
>> +
>> +            if ( unlikely(!guest_handle_okay(buf_hnd, len)) )
>> +            {
>> +                ret = -EFAULT;
>> +                break;
>> +            }
>> +
>> +            sp = ring.len - ring.tx_ptr;
>> +
>> +            if ( len>  sp )
>> +            {
>> +                ret = v4v_memcpy_to_guest_ring(ring_info,
>> +                        ring.tx_ptr + sizeof(v4v_ring_t),
>> +                        NULL, buf_hnd, sp);
>> +                if ( ret )
>> +                    break;
>> +
>> +                ring.tx_ptr = 0;
>> +                len -= sp;
>> +                guest_handle_add_offset(buf_hnd, sp);
>> +            }
>> +
>> +            ret = v4v_memcpy_to_guest_ring(ring_info,
>> +                    ring.tx_ptr + sizeof(v4v_ring_t),
>> +                    NULL, buf_hnd, len);
>> +            if ( ret )
>> +                break;
>> +
>> +            ring.tx_ptr += len;
>> +
>> +            if ( ring.tx_ptr == ring_info->len )
>> +                ring.tx_ptr = 0;
>> +
>> +            guest_handle_add_offset(iovs, 1);
>> +        }
>> +        if ( ret )
>> +            break;
>> +
>> +        ring.tx_ptr = V4V_ROUNDUP(ring.tx_ptr);
>> +
>> +        if ( ring.tx_ptr>= ring_info->len )
>> +            ring.tx_ptr -= ring_info->len;
>> +
>> +        mb();
>> +        ring_info->tx_ptr = ring.tx_ptr;
>> +        if ( (ret = v4v_update_tx_ptr(ring_info, ring.tx_ptr)) )
>> +            break;
>> +    } while ( 0 );
>> +
>> +    v4v_ring_unmap(ring_info);
>> +
>> +    return ret ? ret : happy_ret;
>> +}
> [...]
>> +static int
>> +v4v_pending_requeue(struct v4v_ring_info *ring_info, domid_t src_id, int len)
>> +{
>> +    struct hlist_node *node;
>> +    struct v4v_pending_ent *ent;
>> +
>> +    hlist_for_each_entry(ent, node,&ring_info->pending, node)
>> +    {
>> +        if ( ent->id == src_id )
>> +        {
>> +            if ( ent->len<  len )
>> +                ent->len = len;
>
> Does this mean that if I call V4VOP_notify with some large space
> requirement, and then again with a smaller one, I won't get a
> notification until the original large amount is free?  Seems like this
> should always overwrite the old length instead, and notify on the most
> recently requested amount.

It has been a while since I have looked closely at the queuing code so I 
will have to study this some. I believe it does the right thing but I 
will check.

>
>> +static int
>> +v4v_fill_ring_data(struct domain *src_d,
>> +                   XEN_GUEST_HANDLE(v4v_ring_data_ent_t) data_ent_hnd)
>> +{
>> +    v4v_ring_data_ent_t ent;
>> +    struct domain *dst_d;
>> +    struct v4v_ring_info *ring_info;
>> +
>> +    if ( copy_from_guest(&ent, data_ent_hnd, 1) )
>> +    {
>> +        v4v_dprintk("EFAULT\n");
>> +        return -EFAULT;
>> +    }
>> +
>> +    v4v_dprintk("v4v_fill_ring_data: ent.ring.domain=%d,ent.ring.port=%u\n",
>> +                (int)ent.ring.domain, (int)ent.ring.port);
>> +
>> +    ent.flags = 0;
>> +
>> +    dst_d = get_domain_by_id(ent.ring.domain);
>> +
>> +    if ( dst_d&&  dst_d->v4v )
>> +    {
>> +        read_lock(&dst_d->v4v->lock);
>> +        ring_info = v4v_ring_find_info_by_addr(dst_d,&ent.ring,
>> +                                               src_d->domain_id);
>> +
>
> Should there be a call to v4vtables_check() here?  Otherwise we leak a
> little bit of information to a guest who's not supposed to see the ring,
> (and also it's a bit odd to say 'yes, you may send' and then bounce the
> sendv call).

Yea I think so. Concerning all the v4vtables issues, we are now looking 
at reworking a lot of this. We just started discussing options so I 
don't have a lot to reply with yet.

>
> [...]
>> +static void v4v_ring_remove_mfns(struct domain *d, struct v4v_ring_info *ring_info)
>> +{
>> +    int i;
>> +
>> +    ASSERT(rw_is_write_locked(&d->v4v->lock));
>> +
>> +    if ( ring_info->mfns )
>> +    {
>> +        for ( i = 0; i<  ring_info->npage; ++i )
>> +            if ( mfn_x(ring_info->mfns[i]) != 0 )
>
> Here, and where the array is populated, it would be better to use
> INVALID_MFN in any empty slots.  On x86, MFN 0 is never allocated to a
> guest, but that may not always be true on all architectures.

Ack.

>
> [...]
>> +static long
>> +v4v_ring_add(struct domain *d, XEN_GUEST_HANDLE_PARAM(v4v_ring_t) ring_hnd,
>> +             uint32_t npage, XEN_GUEST_HANDLE_PARAM(v4v_pfn_t) pfn_hnd)
>> +{
> [...]
>> +        /*
>> +         * no need for a lock yet, because only we know about this
>> +         * set the tx pointer if it looks bogus (we don't reset it
>> +         * because this might be a re-register after S4)
>> +         */
>> +        if ( (ring.tx_ptr>= ring.len)
>> +                || (V4V_ROUNDUP(ring.tx_ptr) != ring.tx_ptr) )
>> +        {
>> +            ring.tx_ptr = ring.rx_ptr;
>> +        }
>
> Maybe check here that the guest-supplied rx_ptr is correctly aligned?
> I don't think an unaligned one would be a security risk, but it might
> cause entertaining breakage on the first sendv().

Ack.

>
>> +        copy_field_to_guest(ring_hnd,&ring, tx_ptr);
>> +
>> +        read_lock(&d->v4v->lock);
>> +        ring_info = v4v_ring_find_info(d,&ring.id);
>> +
>> +        if ( !ring_info )
>> +        {
>> +            read_unlock(&d->v4v->lock);
>> +            ring_info = xmalloc(struct v4v_ring_info);
>> +            if ( !ring_info )
>> +            {
>> +                v4v_dprintk("ENOMEM\n");
>> +                ret = -ENOMEM;
>> +                break;
>> +            }
>> +            need_to_insert++;
>> +            spin_lock_init(&ring_info->lock);
>> +            INIT_HLIST_HEAD(&ring_info->pending);
>> +            ring_info->mfns = NULL;
>> +        }
>> +        else
>> +        {
>> +            /*
>> +             * Ring info already existed.
>> +             */
>> +            printk(KERN_INFO "v4v: dom%d ring already registered\n",
>> +                    current->domain->domain_id);
>> +            ret = -EEXIST;
>> +            break;
>> +        }
>
> If you reshuffle these so that the already-exists case is first, then
> the not-already-exists case doesn't need to be indented, i.e.
>
>      if ( ring_info )
>      {
>          printk();
>          ret = -EEXIST;
>          break;
>      }
>      /* Normal case goes here */
>
> Then I think it becomes clear that you don't need a 'need_to_insert'
> flag -- and that the read_unlock() below is dead code, so the error path
> doesn't unlock at all!
>
>> +
>> +        spin_lock(&ring_info->lock);
>> +        ring_info->id = ring.id;
>> +        ring_info->len = ring.len;
>> +        ring_info->tx_ptr = ring.tx_ptr;
>> +        ring_info->ring = ring_hnd;
>
> I can't see where this field is used, but AFAICT the ring_hnd isn't
> guaranteed to be valid after this hypercall finishes (and certainly not
> after, say, the next context switch), so storing it doesn't seem useful.

Yes I don't understand that one either. It will go away.

>
>> +        if ( ring_info->mfns )
>> +            xfree(ring_info->mfns);
>> +        ret = v4v_find_ring_mfns(d, ring_info, npage, pfn_hnd);
>> +        spin_unlock(&ring_info->lock);
>> +        if ( ret )
>> +            break;
>> +
>> +        if ( !need_to_insert )
>> +        {
>> +            read_unlock(&d->v4v->lock);
>> +        }
>> +        else
>> +        {
>> +            uint16_t hash = v4v_hash_fn(&ring.id);
>> +
>> +            write_lock(&d->v4v->lock);
>> +            hlist_add_head(&ring_info->node,&d->v4v->ring_hash[hash]);
>> +            write_unlock(&d->v4v->lock);
>> +        }
>> +    } while ( 0 );
>> +
>> +    read_unlock(&v4v_lock);
>> +    return ret;
>> +}
> [...]
>> +void
>> +v4vtables_print_rule(struct v4vtables_rule_node *node)
>> +{
> [...]
>> +    if ( rule->accept == 1 )
>> +        printk("ACCEPT");
>
> The logic in the actual ACL is (effectively) 'if ( rule->accept != 0 )';
> so this probably ought to follow suit. :)

Ack

>
> [...]
>> +int
>> +v4vtables_del(struct domain *src_d,
>> +              XEN_GUEST_HANDLE_PARAM(v4vtables_rule_t) rule_hnd,
>> +              int32_t position)
>> +{
>> +    struct list_head *tmp = NULL;
>> +    struct list_head *to_delete = NULL;
>> +    struct list_head *next = NULL;
>> +    struct v4vtables_rule_node *node;
>> +
>> +    ASSERT(rw_is_write_locked(&v4vtables_rules_lock));
>> +
>> +    v4v_dprintk("v4vtables_del position:%d\n", position);
>> +
>> +    if ( position != -1 )
>> +    {
>> +        /* We want to delete the rule number<position>  */
>> +        list_for_each(tmp,&v4vtables_rules)
>> +        {
>> +            to_delete = tmp;
>> +            if (position == 0)
>> +                break;
>> +            position--;
>> +        }
>
> Hmmm.  If this is called with position = 1 with a multi-element list, it
> selects the second element (which conflicts with the semantics of the
> add operation, where '1' is the first element).  And if it's called with
> '1' on a single-element list, it selects the first (and only) element.

Needs fixing along with other problems in the v4vtables.

>
>> +        /* Can't find the position */
>> +        if (position != 0)
>> +            to_delete = NULL;
>> +    }
>> +    else if ( !guest_handle_is_null(rule_hnd) )
>> +    {
>> +        struct v4vtables_rule r;
>> +
>> +        if ( copy_from_guest(&r, rule_hnd, 1) )
>> +            return -EFAULT;
>> +
>> +        list_for_each(tmp,&v4vtables_rules)
>> +        {
>> +            node = list_entry(tmp, struct v4vtables_rule_node, list);
>> +
>> +            if ( (node->rule.src.domain == r.src.domain)&&
>> +                 (node->rule.src.port   == r.src.port)&&
>> +                 (node->rule.dst.domain == r.dst.domain)&&
>> +                 (node->rule.dst.port   == r.dst.port))
>
> Not matching by 'accept' too?  That should be mentioned in the hypercall
> interface, I think.
>
>> +            {
>> +                to_delete = tmp;
>> +                break;
>> +            }
>> +        }
>> +    }
>> +    else
>> +    {
>> +        /* We want to flush the rules! */
>> +        printk(KERN_ERR "VIPTables: flushing rules\n");
>> +        list_for_each_safe(tmp, next,&v4vtables_rules)
>> +        {
>> +            node = list_entry(tmp, struct v4vtables_rule_node, list);
>> +            list_del(tmp);
>> +            xfree(node);
>> +        }
>> +    }
>> +
>> +    if ( to_delete )
>> +    {
>> +        node = list_entry(to_delete, struct v4vtables_rule_node, list);
>> +#ifdef V4V_DEBUG
>> +        printk(KERN_ERR "VIPTables: deleting rule: ");
>> +        v4vtables_print_rule(node);
>> +#endif /* V4V_DEBUG */
>> +        list_del(to_delete);
>> +        xfree(node);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static size_t
>> +v4vtables_list(struct domain *src_d,
>> +               XEN_GUEST_HANDLE_PARAM(v4vtables_list_t) list_hnd)
>> +{
>> +    struct list_head *ptr;
>> +    struct v4vtables_rule_node *node;
>> +    struct v4vtables_list rules_list;
>> +    uint32_t nbrules;
>> +    XEN_GUEST_HANDLE(v4vtables_rule_t) guest_rules;
>> +
>> +    ASSERT(rw_is_locked(&v4vtables_rules_lock));
>> +
>> +    memset(&rules_list, 0, sizeof (rules_list));
>> +    if ( copy_from_guest(&rules_list, list_hnd, 1) )
>> +        return -EFAULT;
>> +
>> +    ptr = v4vtables_rules.next;
>> +    while ( rules_list.start_rule != 0&&  ptr->next !=&v4vtables_rules )
>> +    {
>> +        ptr = ptr->next;
>> +        rules_list.start_rule--;
>> +    }
>
> Again, that seems to conflict with the 'add' semantics that the first
> rule is rule 1.
>
> And what if the supplied start_rule was too large?  As it stands I think
> this will return the last rule in the list rather than returning no
> rules (or an error).
>
>> +
>> +    if ( rules_list.nb_rules == 0 )
>> +        return -EINVAL;
>> +
>> +    guest_rules = guest_handle_for_field(list_hnd, v4vtables_rule_t, rules[0]);
>> +
>> +    nbrules = 0;
>> +    while ( nbrules<  rules_list.nb_rules&&  ptr !=&v4vtables_rules )
>> +    {
>> +        node = list_entry(ptr, struct v4vtables_rule_node, list);
>> +
>> +        if ( copy_to_guest(guest_rules,&node->rule, 1) )
>> +            break;
>
> Maybe also arrange to return -EFAULT?
>
>> +
>> +        guest_handle_add_offset(guest_rules, 1);
>> +
>> +        nbrules++;
>> +        ptr = ptr->next;
>> +    }
>> +
>> +    rules_list.nb_rules = nbrules;
>> +    if ( copy_field_to_guest(list_hnd,&rules_list, nb_rules) )
>> +        return -EFAULT;
>> +
>> +    return 0;
>> +}
>> +
>> +static size_t
>> +v4vtables_check(v4v_addr_t *src, v4v_addr_t *dst)
>> +{
>> +    struct list_head *ptr;
>> +    struct v4vtables_rule_node *node;
>> +    size_t ret = 0; /* Defaulting to ACCEPT */
>
> size_t?  bool_t would be better.  Also, having this function return the
> inverse of the rule encoding is just perverse.
>
> [...]
>> +    case V4VOP_tables_add:
>> +    {
>> +        uint32_t position = arg3;
>> +
>> +        XEN_GUEST_HANDLE_PARAM(v4vtables_rule_t) rule_hnd =
>> +               guest_handle_cast(arg1, v4vtables_rule_t);
>> +        rc = -EPERM;
>> +        if ( !is_hardware_domain(d) )
>> +            goto out;
>
> I think this ought to be an XSM check now, with XSM_PRIV to indicate
> that the default policy is to check IS_PRIV().  (Likewise for the
> other table ops.)

Ok. Again, we have v4vtables high on our list of needs overhauling.

>
> [...]
>> +struct keyhandler v4v_info_keyhandler =
>> +{
>> +    .diagnostic = 1,
>> +    .u.fn = dump_state,
>> +    .desc = "dump v4v states and interupt"
>
> s/interupt/interrupt/
>
> [...]
>> +/*
>> + * V4VOP_register_ring
>> + *
>> + * Registers a ring with Xen. If a ring with the same v4v_ring_id exists,
>> + * the hypercall will return -EEXIST.
>> + *
>> + * do_v4v_op(V4VOP_register_ring,
>> + *           XEN_GUEST_HANDLE(v4v_ring_t), XEN_GUEST_HANDLE(v4v_pfn_t),
>> + *           npage, 0)
>
> Maybe add a 'uint32_t ' before npage, to match the same style below?
>
> [...]
>> +/*
>> + * V4VOP_sendv
>> + *
>> + * Sends of list of buffer contained in iov.
>> + *
>> + * For each iov entry send iov_len bytes of iov_base to addr.dst, giving
>> + * src as the source address (xen will ignore src->domain and put your
>> + * domain in the actually message), xen first looks for a ring with id.addr==dst
>> + * and id.partner==sending_domain if that fails it looks for id.addr==dst and
>
> These lines are longer than 80 chars - can you wrap a little narrower please?
> Also s/actually/actual/.
>
>> + * id.partner==DOMID_ANY.
>> + * message_type is the 32 bit number used from the message
>> + * most likely V4V_MESSAGE_DGRAM or V4V_MESSAGE_STREAM. If insufficient space exists
>> + * it will return -EAGAIN and xen will twing the V4V_INTERRUPT when
>
> 'twing'? :)

Not my "verb" :)

>
> [...]
>> +/*
>> + * V4VOP_tables_add
>> + *
>> + * Insert a filtering rules after a given position.
>> + *
>
> Can you add a description of the semantics of the rules?
> E.g. does the first match or the last match or the tightest match dominate?
>
>> + * do_v4v_op(V4VOP_tables_add,
>> + *           XEN_GUEST_HANDLE(v4vtables_rule_t) rule,
>> + *           NULL,
>> + *           uint32_t position, 0)
>> + */
>> +#define V4VOP_tables_add        7
>> +
>> +/*
>> + * V4VOP_tables_del
>> + *
>> + * Delete a filtering rules at a position or the rule
>> + * that matches "rule".
>> + *
>> + * do_v4v_op(V4VOP_tables_del,
>> + *           XEN_GUEST_HANDLE(v4vtables_rule_t) rule,
>> + *           NULL,
>> + *           uint32_t position, 0)
>> + */
>> +#define V4VOP_tables_del       8
>
> Can you describe the calling convention a bit more fully?  In particular
> that position should == -1 if you want to match by rule (though I think
> == 0 would make more sense), and that position == -1&&  rule == NULL
> means to flush everything.

Yes, I will take all your v4vtables concerns into account when we work 
on it.

Again, thanks a bunch.
Ross

>
> Cheers,
>
> Tim.

  reply	other threads:[~2013-06-04 18:01 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-05-28 19:43 [PATCH (V9) 0/2] Add V4V to Xen Ross Philipson
2013-05-28 19:43 ` [PATCH (V9) 1/2] xen: events, exposes evtchn_alloc_unbound_domain Ross Philipson
2013-05-28 19:43 ` [PATCH (V9) 2/2] xen: Add V4V implementation Ross Philipson
2013-05-29  0:43   ` Matt Wilson
2013-05-29 19:28     ` Ross Philipson
2013-05-29  8:34   ` Jan Beulich
2013-05-29 19:26     ` Ross Philipson
2013-05-30  5:16       ` Jan Beulich
2013-05-29  9:56   ` Vincent Hanquez
2013-05-30 16:20   ` Tim Deegan
2013-06-04 18:01     ` Ross Philipson [this message]
2013-06-10 15:06   ` David Vrabel
2013-05-30 11:57 ` [PATCH (V9) 0/2] Add V4V to Xen Ian Campbell
2013-05-31  7:36   ` Vincent Hanquez
2013-05-31  7:50     ` Ian Campbell
2013-05-31  8:56       ` Vincent Hanquez
2013-05-31  9:01         ` Ian Campbell
2013-05-31  9:26           ` Vincent Hanquez
2013-05-31 16:29             ` Ross Philipson
2013-05-31 16:38               ` Ian Campbell
2013-05-30 12:07 ` Ian Campbell
2013-05-30 16:08   ` David Vrabel
2013-05-31  7:25     ` Vincent Hanquez
2013-05-31 10:21       ` David Vrabel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=51AE2B83.1070808@citrix.com \
    --to=ross.philipson@citrix.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).