Signed-off-by: David S. Miller <davem@davemloft.net>
---
Basically I want to get the whole tree to consistently use
the convention that the frag list is built as packets arrive
by using "skb->prev" of the head skb to track the tail member
of the frag list.
This will allow me to do something like:
struct sk_buff {
union {
struct {
struct sk_buff *next;
struct sk_buff *prev;
};
struct {
struct sk_buff *frag_next;
struct sk_buff *frag_tail_tracker;
};
}
...
}
And have all frag_list code use these members consistently.
While doing this patch I noticed that there are some left-over bits in
the IXGBEVF driver that builds these IXGBE style (before my patch)
skb->prev RSC chains.
But nothing other than the RX ring shutdown code processes them, so
likely if they are created they will leak or cause some other kind of
problem.
Please take a look, thanks.
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 5cebc37..434c9fa 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -181,6 +181,7 @@ struct ixgbe_ring {
struct ixgbe_queue_stats stats;
unsigned long reinit_state;
int numa_node;
+ struct sk_buff *rsc_skb; /* RSC packet being built */
u64 rsc_count; /* stat for coalesced packets */
u64 rsc_flush; /* stats for flushed packets */
u32 restart_queue; /* track tx queue restarts */
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index c35e13c..43987a4 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1130,36 +1130,6 @@ static inline u32 ixgbe_get_rsc_count(union ixgbe_adv_rx_desc *rx_desc)
IXGBE_RXDADV_RSCCNT_SHIFT;
}
-/**
- * ixgbe_transform_rsc_queue - change rsc queue into a full packet
- * @skb: pointer to the last skb in the rsc queue
- * @count: pointer to number of packets coalesced in this context
- *
- * This function changes a queue full of hw rsc buffers into a completed
- * packet. ...RSC isn't actually supported in virtual functions or even when SR-IOV mode is enabled. Any left over bits are just cruft from when the vf driver was ported from the pf driver. I'll have a look at it. --
This will not work for RSC due to the fact that it assumes only one RSC
context is active per ring and that is not the case. There can be
multiple RSC combined flows interlaced on the ring.
It occurs to me that RSC needs the inverse of what you need for frag
list handling. You state that you need the next and tail pointers,
while RSC really needs the prev and head pointers. One possible
solution for all this would be to just reverse the logic a bit.
What you are setting up right now is essentially a head based layout
based on the idea that th head it the component you will have access to.
RSC on the other hand is a tail based layout. If we were to overload
skb->next so that it pointed at head from tail in ixgbe then we could
make RSC function, and probably even improve the performance a bit by
getting rid of the extra RSC transform at the end of creating RSC packets.
Below I have made suggestions based on a tail based approach if we
This bit of code is based on the flawed assumption that RSC doesn't have
So this bit of code could be changed to something like:
if (skb->next) {
skb = skb->next;
skb->frag_tail_tracker->next == NULL;
This piece is a bit trickier, the len/data_len/truesize addition needs
to be done on all packets and it looks like it was only done on the
non-EOP packets which may be an issue. My guess would be that it would
probably work if we added something along of the lines of the following
before the EOP check:
if (skb->next) {
skb->next->len += skb->len;
skb->next->data_len += skb->data_len;
skb->next->truesize += skb->truesize;
rx_ring->rsc_count++;
}
My thoughts for the rest of the code for the non-EOP case would be
something more along the lines of:
if (skb->next) {
next_buffer->skb->next = skb->next;
skb->next->frag_tail_tracker = next_buffer->skb;
skb->next = next_buffer->skb;
--
From: Alexander Duyck <alexander.h.duyck@intel.com> Thanks for looking at this Alexander. I must have mis-understood what the current code is doing. It looked like RSC packets always show up in-order in the RX ring. And that they are scanned for by simply combining any sequence of non-EOP packets up to and including the final EOP one into a frag list. Are the RSC packets are identified via something else entirely? --
They show up in order, but they are not necessarily linear. You can have other packets show up in the middle of the flow and RSC just jumps over them. The determination for the jump is handled via nextp in ixgbe_clean_rx_irq. I'll look into this and see if I can come up with a counter-proposal patch based on the suggestions I was making. The key item though is that the tail would need some means of referencing head which I think can probably be accomplished via skb->next. Thanks, Alex --
Dave,
The patch below is kind of what I had in mind for a way to do RSC and maintain
the pointer scheme you are looking for. Consider this patch an RFC for now
since I based this off of Jeff's internal testing tree and so it would need
some modification to apply cleanly to net-next.
The only deviation from a standard frag list is that we are appending the tail
before it actually has any data in it so we have to break things into three
steps. One to add the tail to the end of the frag list, one to merge the
length from the tail into the head, and finally one to clean-up the head->prev
pointer.
If this works for you I will send it to Jeff to add to his tree for testing.
Thanks,
Alex
---
ixgbe: change RSC to use a normalize frag_list usage
From: Alexander Duyck <alexander.h.duyck@intel.com>
This change drops the RSC queue approach and instead creates a normalized
frag_list skb but the tail is kept active and regularly merged into the
host SKB every time it is completed. In order to identify the tail skb
as a tail we set the next pointer to the head skb, and the head skb prev
pointer to the tail.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
drivers/net/ixgbe/ixgbe.h | 2 -
drivers/net/ixgbe/ixgbe_main.c | 96 +++++++++++++++++++++++-----------------
2 files changed, 56 insertions(+), 42 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index b9a1e70..2c7a296 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -470,7 +470,7 @@ enum ixbge_state_t {
struct ixgbe_rsc_cb {
dma_addr_t dma;
- u16 skb_cnt;
+ u16 append_cnt;
bool delay_unmap;
};
#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 221d5ef..c3774b9 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1251,34 +1251,46 @@ static inline u16 ixgbe_get_hlen(union ...From: "Duyck, Alexander H" <alexander.h.duyck@intel.com> Thanks a lot for doing this work Alex. I'll take a look and give you some feedback soon. --
From: "Duyck, Alexander H" <alexander.h.duyck@intel.com>
Can you really not remember the head somewhere?
What I wanted is for everyone to build their frag list SKBs from head to tail,
always. So that I could, as I mentioned in my original posting, do something
like:
struct sk_buff {
union {
struct list_head list;
struct {
struct sk_buff *frag_next;
struct sk_buff *frag_tail_tracker;
};
};
};
The ->frag_tail_tracker is only used in the head SKB to maintain where the
last SKB in the frag list is.
You're tracking the head from the inner SKBs, such that my intended
conventions are not being followed.
--
I can track it in the RSC_CB if that works for you. Right now though I guess I am not seeing the difference between tracking this in skb->frag_next vs IXGBE_RSC_CB(skb)->frag_head. I think it might help if you were to provide some functions that demonstrate exactly what you had in mind for frag list handling. Specifically if you were to add a function for merging a frag into the frag list, and for how you want to approach cleaning up the skb->prev/frag_tail_tracker pointer when you My change is doing just that. It is building from head to tail. The only difference is that tail is tracking head since it has to be updated What I am doing is tracking the head from the tail skb. The reason for this is that I need some way to update the len, data_len, and truesize after I have placed data in the tail via skb_put. All of the other SKBs in the frag list are just tracking the next like any other SKB in the frag_list. Now that I think about it I guess the issue is that I am adding the SKB to the frag_list before it is complete. I will send another patch out in the next couple of hours that should address most of the issues. Thanks, Alex --
From: Alexander Duyck <alexander.h.duyck@intel.com>
Basically the one helper function will look like this.
static inline void skb_frag_list_add(struct sk_buff *head,
struct sk_buff *new)
{
if (!skb_shinfo(skb)->frag_list) {
skb_shinfo(skb)->frag_list = new;
skb->frag_list_tail = new;
} else {
skb->frag_list_tail->frag_list_next = new;
skb->frag_list_tail = new;
}
}
If you have to track the head from the tail packets, please do
so in a private control block.
--
Dave,
Below is the new and improved version of the RSC chaining approach. Basically
I am holding off on merging the SKB into the frame until the SKB has data in
order to make it take a more standard approach.
Let me know if this will work with the new pointer structure.
Thanks,
Alex
---
This change drops the RSC queue approach and instead creates a normalized
frag_list skb but the tail is kept active and regularly merged into the
host SKB every time it is completed. In order to identify the tail skb
as a tail we set the head pointer in the RSC CB block of the skb. To locate
the head we just need to check to see if skb->prev is set and make sure to
clean up the pointer before we pass it up to the stack.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
drivers/net/ixgbe/ixgbe.h | 3 +
drivers/net/ixgbe/ixgbe_main.c | 96 +++++++++++++++++++++++-----------------
2 files changed, 58 insertions(+), 41 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index a62d19c..397f9e1 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -469,8 +469,9 @@ enum ixbge_state_t {
};
struct ixgbe_rsc_cb {
+ struct sk_buff *head;
dma_addr_t dma;
- u16 skb_cnt;
+ u16 append_cnt;
bool delay_unmap;
};
#define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 8edce66..104a833 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1251,34 +1251,51 @@ static inline u16 ixgbe_get_hlen(union ixgbe_adv_rx_desc *rx_desc)
}
/**
- * ixgbe_transform_rsc_queue - change rsc queue into a full packet
- * @skb: pointer to the last skb in the rsc queue
+ * ixgbe_merge_active_tail - merge active tail into frag_list skb
+ * @tail: pointer to active tail in frag_list
*
- * This function changes a queue full of hw rsc buffers into a completed
- * packet. It uses the ->prev ...From: "Duyck, Alexander H" <alexander.h.duyck@intel.com> This variant looks great, thanks Alexander! --
