Reusing an npkt structure with tx_down()

I have one type of packet (a time sync message) that is being sent
repeatedly. I set up the packet once, and send it periodically with
tx_down(). I alter nothing in the npkt_t structure except my time stamp in
the body of the packet.

Are there any fields in the npkt that must be reset every time? In
particular, are there any fields that are set by alloc_down_npkt() that
might not be correct now that the packet has been tx_down()ed already.

I set up the packet like this:
npkt = ion->alloc_down_pkt( hRegister, sizeof( net_buf_t) +
izeof( net_iov_t), (void **)&nb);
pBody = ion->alloc( sizeof( VORNET_PACKET), 0);

TAILQ_INSERT_HEAD( &npkt->buffers, nb, ptrs);
iov = (net_iov_t*)(nb + 1);

nb->niov = 1;
nb->net_iov = iov;
iov->iov_base = pBody;
iov->iov_len = sizeof( *pBody);
iov->iov_phys = ion->mphys( pBody);

npkt->org_data = pBody;
npkt->framelen = sizeof( *pBody);
npkt->tot_iov = 1;
npkt->cell = nCell;
npkt->endpoint = nEndPoint;
npkt->iface = nIface;

// set up packet data payload here [clip]

I send the packet like this: (this is repeated many times)
ion->reg_tx_done( hRegister, npkt, NULL);
ion->tx_down( hRegister, npkt);

I found I had to set iov_phys in the iov, otherwise the ethernet would send
garbage instead of my data. Is this typical? Can QNX potentially move the
memory to a different physical location? If so, do I have to set iov_phys
every time I send the packet?

Thanks,
Shaun

You can’t reuse the packet until your tx_done()
has been called.

Shaun Jackman <sjackman@nospam.vortek.com> wrote:
: I have one type of packet (a time sync message) that is being sent
: repeatedly. I set up the packet once, and send it periodically with
: tx_down(). I alter nothing in the npkt_t structure except my time stamp in
: the body of the packet.

: Are there any fields in the npkt that must be reset every time? In
: particular, are there any fields that are set by alloc_down_npkt() that
: might not be correct now that the packet has been tx_down()ed already.

: I set up the packet like this:
: npkt = ion->alloc_down_pkt( hRegister, sizeof( net_buf_t) +
: izeof( net_iov_t), (void **)&nb);
: pBody = ion->alloc( sizeof( VORNET_PACKET), 0);

: TAILQ_INSERT_HEAD( &npkt->buffers, nb, ptrs);
: iov = (net_iov_t*)(nb + 1);

: nb->niov = 1;
: nb->net_iov = iov;
: iov->iov_base = pBody;
: iov->iov_len = sizeof( *pBody);
: iov->iov_phys = ion->mphys( pBody);

: npkt->org_data = pBody;
: npkt->framelen = sizeof( *pBody);
: npkt->tot_iov = 1;
: npkt->cell = nCell;
: npkt->endpoint = nEndPoint;
: npkt->iface = nIface;

: // set up packet data payload here [clip]

: I send the packet like this: (this is repeated many times)
: ion->reg_tx_done( hRegister, npkt, NULL);
: ion->tx_down( hRegister, npkt);

: I found I had to set iov_phys in the iov, otherwise the ethernet would send
: garbage instead of my data. Is this typical? Can QNX potentially move the
: memory to a different physical location? If so, do I have to set iov_phys
: every time I send the packet?

You need to set it (once). If you use the same packet, you shouldn’t
have to reset it.

-seanb

You can’t reuse the packet until your tx_done()
has been called.
Right.



You need to set it (once). If you use the same packet, you shouldn’t
have to reset it.
Good, I’m just grasping at straws here.

I’ve done some empirical testing, and found that if I never call
reg_tx_done() my filter proceeds happily sending a sync packet every 100ms.
If however I call reg_tx_done() immediately before I tx_down() the packet,
I’m able to send off only three packets before the TCP/IP module dies
SIGSEGV. My arguments to reg_tx_done() look good and are identical to the
arguments I pass immediately thereafter to tx_down(). In my tx_done()
callback I do very little: with an internal flag I mark the packet as
recycled, and quickly return.

So, my testing shows that either my registration to reg_tx_done() is in err,
or my callback is. To further debugging I replaced the callback with a
totally empty declaration. The crashes continued.

Here’s the reg line: (called once per tx)
ion->reg_tx_done( hRegister, npkt, NULL);
Here’s the callback:
static int my_tx_done( npkt_t* pPacket, void* pTxDataHandle, void*
hFunc)
{ return 0; }

When tracing (using printf) I see
callback timer_callback()
calling reg_tx_done()
calling tx_down()
callback tx_done()
SIGSEGV

Occasionally I still get a ‘ex_tx_done BAD3’ message. Am I somehow using
reg_tx_done() incorrectly?

Thanks for all your help. I really appreciate it.
Shaun

I’ve found the root-source of my problem. Each additional reg_tx_done()
increments npkt->req_complete.

From the DDK docs:
req_complete
The required number of npkt_done_t elements this downward-headed packet
required before it reached its final destination. This member is for
information purposes only (read-only) in the originator’s tx_done() function
if the originator isn’t using io-net’s alloc_down_pkt() function.

It seems each call tacks on an additional npkt_done_t, whereas I only need
one total. If I set req_complete = 0 before I reg_tx_done() tx_down() (or in
the tx_done() callback) everything works! However, the docs say req_complete
is r/o, so what’s the clean solution? I’m allowed to recycle a npkt, but I
have no way to return the npkt to the clean state.

If the solution is to manually clear req_complete, is the clean place to do
this in the tx_done() callback? Can req_complete be used as a flag to
indicate whether that npkt is in use or not? That sort of flag would be
handy.

The second sentance of the DDK definition suggests that I (the originator of
a tx_down() packet) should inspect the req_complete member since I’m not
using alloc_down_pkt() every time to allocate the packet (although it was
used the first time). What am I inspecting it for? What information does it
convey? The doc says it’s r/o. Why is that? When my tx_done() callback is
called, isn’t the npkt finished with?

Thanks,
Shaun

Shaun Jackman <sjackman@nospam.vortek.com> wrote:
: I’ve found the root-source of my problem. Each additional reg_tx_done()
: increments npkt->req_complete.

: From the DDK docs:
: req_complete
: The required number of npkt_done_t elements this downward-headed packet
: required before it reached its final destination. This member is for
: information purposes only (read-only) in the originator’s tx_done() function
: if the originator isn’t using io-net’s alloc_down_pkt() function.

: It seems each call tacks on an additional npkt_done_t, whereas I only need
: one total. If I set req_complete = 0 before I reg_tx_done() tx_down() (or in
: the tx_done() callback) everything works! However, the docs say req_complete
: is r/o, so what’s the clean solution? I’m allowed to recycle a npkt, but I
: have no way to return the npkt to the clean state.

Setting req_complete = 0 after the packet has been tx’d
is the correct thing to do. It doesn’t matter whether
it’s done in your tx_done() callback or just prior to
re-sending it.

: If the solution is to manually clear req_complete, is the clean place to do
: this in the tx_done() callback? Can req_complete be used as a flag to
: indicate whether that npkt is in use or not? That sort of flag would be
: handy.

In 6.2, the top 12 bits in npkt->flags are set aside for the use of the
originator.

: The second sentance of the DDK definition suggests that I (the originator of
: a tx_down() packet) should inspect the req_complete member since I’m not
: using alloc_down_pkt() every time to allocate the packet (although it was
: used the first time). What am I inspecting it for? What information does it
: convey? The doc says it’s r/o. Why is that? When my tx_done() callback is
: called, isn’t the npkt finished with?

If req_complete > num_complete in your tx_done() callback, it is “nice”
performance wise if you free the packet and allocate a new one next
time around, rather than recycling it.

-seanb