WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [PATCH 3/4] Support accelerated network plugin modules

To: Kieran Mansley <kmansley@xxxxxxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH 3/4] Support accelerated network plugin modules
From: Muli Ben-Yehuda <muli@xxxxxxxxxx>
Date: Wed, 9 May 2007 14:25:10 +0300
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Wed, 09 May 2007 04:23:40 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <1178618109.4147.35.camel@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1178618109.4147.35.camel@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.11
On Tue, May 08, 2007 at 10:55:09AM +0100, Kieran Mansley wrote:
> Add hooks in the netfront driver to allow an accelerated plugin module
> to attach and provide a fast path for network traffic in the presence of
> a virtualisable NIC.
> 
> Signed-off-by: Kieran Mansley <kmansley@xxxxxxxxxxxxxx>

> Frontend net driver acceleration
> 
> diff -r 325afaed01ff linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
> --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c    Tue Apr 17 
> 09:07:31 2007 +0100
> +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c    Tue Apr 17 
> 09:13:05 2007 +0100
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (c) 2002-2005, K A Fraser
>   * Copyright (c) 2005, XenSource Ltd
> + * Copyright (C) 2007 Solarflare Communications, Inc.
>   *
>   * This program is free software; you can redistribute it and/or
>   * modify it under the terms of the GNU General Public License version 2
> @@ -67,6 +68,8 @@
>  #include <xen/platform-compat.h>
>  #endif
>  
> +#include "netfront.h"
> +
>  /*
>   * Mutually-exclusive module options to select receive data path:
>   *  rx_copy : Packets are copied by network backend into local memory
> @@ -137,57 +140,6 @@ static inline int netif_needs_gso(struct
>  
>  #define GRANT_INVALID_REF    0
>  
> -#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
> -#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
> -
> -struct netfront_info {
> -     struct list_head list;
> -     struct net_device *netdev;
> -
> -     struct net_device_stats stats;
> -
> -     struct netif_tx_front_ring tx;
> -     struct netif_rx_front_ring rx;
> -
> -     spinlock_t   tx_lock;
> -     spinlock_t   rx_lock;
> -
> -     unsigned int irq;
> -     unsigned int copying_receiver;
> -     unsigned int carrier;
> -
> -     /* Receive-ring batched refills. */
> -#define RX_MIN_TARGET 8
> -#define RX_DFL_MIN_TARGET 64
> -#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
> -     unsigned rx_min_target, rx_max_target, rx_target;
> -     struct sk_buff_head rx_batch;
> -
> -     struct timer_list rx_refill_timer;
> -
> -     /*
> -      * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs
> -      * is an index into a chain of free entries.
> -      */
> -     struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1];
> -     struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
> -
> -#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
> -     grant_ref_t gref_tx_head;
> -     grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
> -     grant_ref_t gref_rx_head;
> -     grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
> -
> -     struct xenbus_device *xbdev;
> -     int tx_ring_ref;
> -     int rx_ring_ref;
> -     u8 mac[ETH_ALEN];
> -
> -     unsigned long rx_pfn_array[NET_RX_RING_SIZE];
> -     struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
> -     struct mmu_update rx_mmu[NET_RX_RING_SIZE];
> -};
> -
>  struct netfront_rx_info {
>       struct netif_rx_response rx;
>       struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
> @@ -271,6 +223,275 @@ static void xennet_sysfs_delif(struct ne
>  #define xennet_sysfs_delif(dev) do { } while(0)
>  #endif
>  
> +static struct netfront_accelerator *accelerators = NULL;
> +static spinlock_t accelerators_lock;
> +
> +static int match_accelerator(const char *frontend, 
> +                             struct netfront_accelerator *accelerator)
> +{
> +        return strcmp(frontend, accelerator->frontend) == 0;
> +}
> +
> +
> +static void add_accelerator_vif(struct netfront_accelerator *accelerator,
> +                                struct netfront_info *np,
> +                                struct xenbus_device *dev)
> +{
> +        unsigned flags;
> +        spin_lock_irqsave(&np->accelerator_lock, flags);
> +        np->accelerator = accelerator;
> +        np->accel_vif_state.np = np;
> +        np->accel_vif_state.dev = dev;
> +        np->accel_vif_state.hooks = accelerator->hooks;
> +        np->accel_vif_state.next = accelerator->vif_states;
> +        accelerator->vif_states = &np->accel_vif_state;
> +        spin_unlock_irqrestore(&np->accelerator_lock, flags);
> +}

Is there a reason not to use standard Linux list.h here rather than
implementinng your own linked list?

> +static int init_accelerator(struct netfront_info *np, struct xenbus_device 
> *dev, 
> +                            const char *frontend)
> +{
> +        struct netfront_accelerator *accelerator = 
> +                kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL);
> +
> +        if(!accelerator){
> +                DPRINTK("%s: no memory for accelerator", __FUNCTION__);
> +                return -ENOMEM;
> +        }
> +
> +        accelerator->frontend = kmalloc(strlen(frontend), GFP_KERNEL);
> +        if(!accelerator->frontend){
> +                DPRINTK("%s: no memory for accelerator", __FUNCTION__);
> +                kfree(accelerator);
> +                return -ENOMEM;
> +        }
> +        strcpy(accelerator->frontend, frontend);

You're not mallocing enough space for the final NULL. Use strlcpy?

> +
> +        accelerator->vif_states = NULL;
> +        accelerator->hooks = NULL;
> +
> +        accelerator->next = accelerators;
> +        
> +        accelerators = accelerator;

Shouldn't the list be protected here? also, better naming would be
appreciated - it's hard to differentate between 'accelerator' and
'accelerators' in first glance.

> +
> +        if(np){
> +                add_accelerator_vif(accelerator, np, dev);
> +        }

Coding style - no braces for a single line

> +        return 0;
> +}                                        
> +
> +
> +static int netfront_load_accelerator(struct netfront_info *np, 
> +                                     struct xenbus_device *dev, 
> +                                     const char *frontend)
> +{
> +        struct netfront_accelerator *accelerator = accelerators;
> +        int rc;
> +        unsigned flags;
> +
> +        spin_lock_irqsave(&accelerators_lock, flags);
> +
> +        /* Look at list of loaded accelerators to see if the requested
> +           one is already there */
> +        while(accelerator != NULL){
> +                if(match_accelerator(frontend, accelerator)){
> +                        /* Already know about it, already loaded, but
> +                           these details weren't known at the time */
> +                        if(accelerator->hooks == NULL)
> +                                DPRINTK("%s: no hooks set", __FUNCTION__);
> +                        else
> +
>                                  
> accelerator->hooks->new_device(np->accelerator->hooks->new_device(np->netdev, 
> dev);

It would be better to call the hoook without holding the lock.

> +                        /* Tell accelerator about this frontend device */
> +                        add_accelerator_vif(accelerator, np, dev);
> +                        spin_unlock_irqrestore(&accelerators_lock, flags);
> +                        return 0;
> +                }
> +
> +                accelerator = accelerator->next;
> +        }
> +
> +        /* Couldn't find it, so create a new one and load the module */
> +        if((rc = init_accelerator(np, dev, frontend)) < 0) {
> +                spin_unlock_irqrestore(&accelerators_lock, flags);
> +                return rc;
> +        }

coding style - 'if ((', seperate assignment and test.
> +
> +        spin_unlock_irqrestore(&accelerators_lock, flags);
> +
> +        DPRINTK("%s: loading module %s\n", __FUNCTION__, frontend);
> +
> +        /* load acceleration module */
> +        request_module("%s", frontend);
> +
> +        /* Module should now call netfront_accelerator_loaded() once
> +           it's up and running, and we can continue from there */
> +
> +        return 0;
> +}
> +
> +
> +static void accelerator_set_hooks(struct netfront_accelerator *accelerator,
> +                                  struct netfront_accel_hooks *hooks)
> +{
> +        struct netfront_accel_vif_state *accel_vif_state;
> +        unsigned flags;
> +
> +        DPRINTK("%s: %p %p\n", __FUNCTION__, accelerator, hooks);
> +
> +        accelerator->hooks = hooks;
> +
> +        accel_vif_state = accelerator->vif_states;
> +        while(accel_vif_state != NULL) {
> +                struct netfront_info *np = accel_vif_state->np;
> +                hooks->new_device(np->netdev, accel_vif_state->dev);
> +                spin_lock_irqsave(&np->accelerator_lock, flags);

This is called with the accelerators_lock held (from
netfront_accelerator_loaded) - is the lock ordering guaranteed?

> +                accel_vif_state->hooks = hooks;
> +                spin_unlock_irqrestore(&np->accelerator_lock, flags);
> +
> +                accel_vif_state = accel_vif_state->next;
> +        }
> +}
> +
> +
> +/* Called by the accelerator once it's ready for action */
> +int netfront_accelerator_loaded(const char *frontend, 
> +                                struct netfront_accel_hooks *hooks)
> +{
> +        /* Tell accelerator about the frontend device */
> +        struct netfront_accelerator *accelerator = accelerators;
> +        unsigned flags;
> +
> +        spin_lock_irqsave(&accelerators_lock, flags);
> +
> +        /* Look through list of accelerators to see if it has already
> +           been requested */
> +        while(accelerator != NULL){
> +                if(match_accelerator(frontend, accelerator)){
> +                        accelerator_set_hooks(accelerator, hooks);
> +                        spin_unlock_irqrestore(&accelerators_lock, flags);
> +                        return 0;
> +                }
> +
> +                accelerator = accelerator->next;
> +        }
> +
> +        /* If it wasn't in the list, add it now so that when it is
> +           requested the caller will find it */
> +        if(accelerator == NULL){
> +                DPRINTK("%s: Couldn't find matching accelerator (%s)\n",
> +                        __FUNCTION__, frontend);
> +                init_accelerator(NULL, NULL, frontend);
> +        }
> +
> +        spin_unlock_irqrestore(&accelerators_lock, flags);
> +
> +        return 0;
> +}
> +EXPORT_SYMBOL_GPL(netfront_accelerator_loaded);
> +
> +
> +void accelerator_disconnect_vif(struct netfront_accel_vif_state *vif_state)
> +{
> +        struct netfront_info *np = vif_state->np;
> +        unsigned flags;
> +
> +        if(np) {
> +                /* Spin lock doesn't protect poll, so
> +                   make sure there's none of those
> +                   going on */
> +                netif_poll_disable(np->netdev);
> +                /* Likewise for xmit */
> +                netif_tx_disable(np->netdev);
> +                
> +                spin_lock_irqsave(&np->accelerator_lock, flags);
> +                np->accel_vif_state.hooks = NULL;
> +                spin_unlock_irqrestore(&np->accelerator_lock, flags);
> +                
> +                netif_wake_queue(np->netdev);
> +                netif_poll_enable(np->netdev);
> +        }
> +       
> +}
> +
> +
> +void netfront_accelerator_unloaded(const char *frontend)
> +{
> +        /* Tell accelerator about the frontend device */
> +        struct netfront_accelerator *accelerator = accelerators;
> +        struct netfront_accelerator *prev = NULL;
> +        unsigned flags;
> +
> +        spin_lock_irqsave(&accelerators_lock, flags);
> +
> +        while(accelerator != NULL){
> +                if(match_accelerator(frontend, accelerator)){
> +                        struct netfront_accel_vif_state *vif_state 
> +                                = accelerator->vif_states;
> +
> +                        accelerator->hooks = NULL;
> +
> +                        spin_unlock_irqrestore(&accelerators_lock, flags);
> +                                
> +                        while(vif_state != NULL){
> +                                accelerator_disconnect_vif(vif_state);
> +                                vif_state = vif_state->next;
> +                        }
> +                        return;
> +                }
> +
> +                prev = accelerator;

accelerator is never incremented here??? if accelerator is not NULL
and match_accelerator fails, we'll go into an infinite loop. I
strongly recommend you use the standard list macros
(list_for_each...).

> +        }
> +        spin_unlock_irqrestore(&accelerators_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(netfront_accelerator_unloaded);
> +
> +
> +#define NETFRONT_CALL_ACCELERATOR_HOOK(_np, _hook, _args...)            \
> +        do {                                                            \
> +                if((_np)->accelerator && (_np)->accel_vif_state.hooks)  \
> +                        (_np)->accel_vif_state.hooks->_hook(_args);     \
> +        } while(0)
> +
> +
> +#define NETFRONT_LOCK_AND_CALL_ACCELERATOR_HOOK(_np, _hook, _args...)   \
> +        do {                                                            \
> +                unsigned _flags;                                        \
> +                spin_lock_irqsave(&(_np)->accelerator_lock, _flags);    \
> +                if((_np)->accelerator && (_np)->accel_vif_state.hooks)  \
> +                        (_np)->accel_vif_state.hooks->_hook(_args);     \
> +                spin_unlock_irqrestore(&(_np)->accelerator_lock, _flags); \
> +        } while(0)

Please get rid of these macros - it's not exactly a lot of code to
duplicate and it makes it obvious what's going on.

> +
> +
> +int netfront_schedule_poll(struct net_device *dev)
> +{
> +        /* TODO do we need to protect this with any netfront locks? */
> +        netif_rx_schedule(dev);
> +        return 0;
> +}
> +EXPORT_SYMBOL_GPL(netfront_schedule_poll);
> +
> +
> +int netfront_stop_queue(struct net_device *dev)
> +{
> +        netif_stop_queue(dev);
> +        return 0;
> +}
> +EXPORT_SYMBOL_GPL(netfront_stop_queue);
> +
> +
> +int netfront_wake_queue(struct net_device *dev)
> +{
> +        netif_wake_queue(dev);
> +        return 0;
> +}
> +EXPORT_SYMBOL_GPL(netfront_wake_queue);

These look like pointless wrapper *if* we don't need to do antyhing
netfront specific in them.

I'll review the rest once you repost the patches.

Cheers,
Muli


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel