[dpdk-dev] [PATCH] KNI: use a memzone pool for KNI alloc/release

Zhang, Helin helin.zhang at intel.com
Thu Oct 9 10:33:29 CEST 2014


Hi Marc

Thanks for your clarification! I added more comments.

> -----Original Message-----
> From: Marc Sune [mailto:marc.sune at bisdn.de]
> Sent: Thursday, October 9, 2014 3:53 PM
> To: Zhang, Helin
> Cc: dev at dpdk.org
> Subject: Re: [dpdk-dev] [PATCH] KNI: use a memzone pool for KNI alloc/release
> 
> Hi Helin,
> 
> Thanks for the comments. Inline and  snipped
> 
> On 09/10/14 09:32, Zhang, Helin wrote:
> > Hi Marc
> >
> > Good explanation! Thank you very much! I add more comments for your code
> changes.
> > One common comment for annotation, in DPDK, we do not use "//" to start
> annotation.
> 
> OK, "//" => "/* */"
> 
> > [snip]
> >>>> It adds a new API call, rte_kni_init(max_kni_ifaces) that shall be
> >>>> called before any call to rte_kni_alloc() if KNI is used.
> > To avoid the additional interface, this initialization works can be
> > done during the first time of calling rte_kni_alloc(), please refer to how it
> opens kni_fd ("/dev/kni").
> > Also I think there should be some de-initialization works should be done in
> rte_kni_close().
> How is rte_kni_alloc() supposed to know the size of the pool that has to be
> pre-allocated (max_kni_ifaces)?
Add it into 'struct rte_kni_conf', also a default one might be needed if 0 is
configured by the user app.

> 
> I don't think the approach of pre-allocating on the first
> rte_kni_alloc() would work (I already discarded this approach before
> implementing the patch), because this would imply we need a define of #define
> MAX_KNI_IFACES during compilation time of DPDK, and the pre-allocation is
> highly dependent on the amount of hugepages memory you have and the usage
> of the KNI interfaces the applications wants to do.
> We can easily end up with DPDK users having to tweak the default
> MAX_KNI_IFACES before compiling DPDK every time, which is definetely not
> desirable IMHO.
Your idea is good! My point is it possible to avoid adding new interface, then no
changes are needed in user app.

> 
> For rte_kni_close(), the pool is static (incl. the slot struct), and the memzones
> cannot be unreserved, hence there is nothing AFAIU to de-initialize; what do
> you mean specifically?
You can see that rte_kni_close() will be called in XEN (#ifdef RTE_LIBRTE_XEN_DOM0),
XEN support is different from standard Linux support.

> >
> >>>> Signed-off-by: Marc Sune <marc.sune at bisdn.de>
> >>>> ---
> >>>>    lib/librte_kni/rte_kni.c |  302
> >>>> ++++++++++++++++++++++++++++++++++++++--------
> >>>>    lib/librte_kni/rte_kni.h |   18 +++
> >>>>    2 files changed, 269 insertions(+), 51 deletions(-)
> >>>>
> >>>> diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c
> >>>> index
> >>>> 76feef4..df55789 100644
> >>>> --- a/lib/librte_kni/rte_kni.c
> >>>> +++ b/lib/librte_kni/rte_kni.c
> >>>> @@ -40,6 +40,7 @@
> >>>>    #include <unistd.h>
> >>>>    #include <sys/ioctl.h>
> >>>>
> >>>> +#include <rte_spinlock.h>
> >>>>    #include <rte_string_fns.h>
> >>>>    #include <rte_ethdev.h>
> >>>>    #include <rte_malloc.h>
> >>>> @@ -58,7 +59,7 @@
> >>>>
> >>>>    #define KNI_REQUEST_MBUF_NUM_MAX      32
> >>>>
> >>>> -#define KNI_MZ_CHECK(mz) do { if (mz) goto fail; } while (0)
> >>>> +#define KNI_MEM_CHECK(cond) do { if (cond) goto kni_fail; } while
> >>>> +(0)
> >>>>
> >>>>    /**
> >>>>     * KNI context
> >>>> @@ -66,6 +67,7 @@
> >>>>    struct rte_kni {
> >>>>    	char name[RTE_KNI_NAMESIZE];        /**< KNI interface
> name
> >> */
> >>>>    	uint16_t group_id;                  /**< Group ID of KNI
> devices
> >> */
> >>>> +	unsigned slot_id;                   /**< KNI pool slot ID */
> > It would be better to use uint16_t or similar, as that's DPDK style.
> I usually use uint16_t (or unsigned int, not unsinged) but the original source
> code (rte_kni.c I think, but I could have looked up something
> else) was using already unsigned, so I tried to mimic that. Please clarify which
> is the standard!!
I can see most of code lines are using uint16_t/uint32_t or similar, but some may
use others which is possibly required by kernel space. KNI will transfer a struct
from user space to kernel space.
My observation is that DPDK tries to use uint16_t like types as most as possible,
though no rule for that I guess.

> >
> >>>>    	struct rte_mempool *pktmbuf_pool;   /**< pkt mbuf mempool
> */
> >>>>    	unsigned mbuf_size;                 /**< mbuf size */
> >>>>
> >>>> @@ -88,10 +90,48 @@ enum kni_ops_status {
> >>>>    	KNI_REQ_REGISTERED,
> >>>>    };
> >>>>
> >>>> +/**
> >>>> +* KNI memzone pool slot
> >>>> +*/
> >>>> +struct rte_kni_memzone_slot{
> >>>> +	unsigned id;
> >>>> +	uint8_t in_use : 1;                    /**< slot in use */
> >>>> +
> >>>> +	//Memzones
> > The comments style is not DPDK style, please try to use DPDK style as others.
> 
> I will use in v2:
> 
> /*
> *
> */
> 
>   and /* */ for inline.
> >
> >>>> +	const struct rte_memzone *m_ctx;       /**< KNI ctx */
> >>>> +	const struct rte_memzone *m_tx_q;      /**< TX queue */
> >>>> +	const struct rte_memzone *m_rx_q;      /**< RX queue */
> >>>> +	const struct rte_memzone *m_alloc_q;   /**< Allocated mbufs
> queue */
> >>>> +	const struct rte_memzone *m_free_q;    /**< To be freed mbufs
> queue
> >>>> */
> >>>> +	const struct rte_memzone *m_req_q;     /**< Request queue */
> >>>> +	const struct rte_memzone *m_resp_q;    /**< Response queue */
> >>>> +	const struct rte_memzone *m_sync_addr;
> >>>> +
> >>>> +	/* Free linked list */
> >>>> +	struct rte_kni_memzone_slot *next;     /**< Next slot link.list */
> > For the linked list management, "TAILQ_" might be a better choice.
> > Please check if it can be usable here.
> 
> I will check it for patch v2
> 
> >
> >>>> +};
> >>>> +
> >>>> +/**
> >>>> +* KNI memzone pool
> >>>> +*/
> >>>> +struct rte_kni_memzone_pool{
> >>>> +	uint8_t initialized : 1;            /**< Global KNI pool init flag */
> >>>> +
> >>>> +	unsigned max_ifaces;                /**< Max. num of KNI ifaces
> */
> >>>> +	struct rte_kni_memzone_slot *slots;        /**< Pool slots */
> >>>> +	rte_spinlock_t mutex;               /**< alloc/relase mutex */
> >>>> +
> >>>> +	//Free memzone slots linked-list
> >>>> +	struct rte_kni_memzone_slot *free;         /**< First empty slot
> */
> >>>> +	struct rte_kni_memzone_slot *free_tail;    /**< Last empty slot */
> >>>> +};
> >>>> +
> >>>> +
> >>>>    static void kni_free_mbufs(struct rte_kni *kni);  static void
> >>>> kni_allocate_mbufs(struct rte_kni *kni);
> >>>>
> >>>>    static volatile int kni_fd = -1;
> >>>> +static struct rte_kni_memzone_pool kni_memzone_pool = {0};
> >>>>
> >>>>    static const struct rte_memzone *
> >>>>    kni_memzone_reserve(const char *name, size_t len, int socket_id,
> >>>> @@
> >>>> -105,6 +145,154 @@ kni_memzone_reserve(const char *name, size_t
> >>>> len, int socket_id,
> >>>>    	return mz;
> >>>>    }
> >>>>
> >>>> +/* Pool mgmt */
> >>>> +static struct rte_kni_memzone_slot*
> >>>> +kni_memzone_pool_alloc(void)
> >>>> +{
> >>>> +	struct rte_kni_memzone_slot* slot;
> >>>> +
> >>>> +	rte_spinlock_lock(&kni_memzone_pool.mutex);
> >>>> +
> >>>> +	if(!kni_memzone_pool.free) {
> >>>> +		rte_spinlock_unlock(&kni_memzone_pool.mutex);
> >>>> +		return NULL;
> >>>> +	}
> >>>> +
> >>>> +	slot = kni_memzone_pool.free;
> >>>> +	kni_memzone_pool.free = slot->next;
> >>>> +
> >>>> +	if(!kni_memzone_pool.free)
> >>>> +		kni_memzone_pool.free_tail = NULL;
> >>>> +
> >>>> +	rte_spinlock_unlock(&kni_memzone_pool.mutex);
> >>>> +
> >>>> +	return slot;
> >>>> +}
> >>>> +
> >>>> +static void
> >>>> +kni_memzone_pool_dealloc(struct rte_kni_memzone_slot* slot) {
> > Generally we don't use "dealloc" like, how about "release"? Just want
> > to get it be similar to the existing code.
> 
> I have no problem on changing that. v2
> 
> 
> Thanks and regards
> 
> > [snip]
> >

Regards,
Helin


More information about the dev mailing list