[v2,2/2] ip_frag: use key length for key comparision
Checks
Commit Message
Right now reassembly code relies on src_dst[] being all zeroes to
determine is it free/occupied entry in the fragments table.
This is suboptimal and error prone - user can crash DPDK ip_reassembly
app by something like the following scapy script:
x=Ether(src=...,dst=...)/IP(dst='0.0.0.0',src='0.0.0.0',id=0)/('X'*1000)
frags=fragment(x, fragsize=500)
sendp(frags, iface=...)
To overcome that issue and reduce overhead of
'key invalidate' and 'key is empty' operations -
add key_len into keys comparision procedure.
Fixes: 4f1a8f633862 ("ip_frag: add IPv6 reassembly")
Cc: stable@dpdk.org
Reported-by: Ryan E Hall <ryan.e.hall@intel.com>
Reported-by: Alexander V Gutkin <alexander.v.gutkin@intel.com>
Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
---
lib/librte_ip_frag/ip_frag_common.h | 14 ++++----------
lib/librte_ip_frag/rte_ip_frag.h | 14 +++++++++++---
2 files changed, 15 insertions(+), 13 deletions(-)
Comments
On 05-Nov-18 12:18 PM, Konstantin Ananyev wrote:
> Right now reassembly code relies on src_dst[] being all zeroes to
> determine is it free/occupied entry in the fragments table.
> This is suboptimal and error prone - user can crash DPDK ip_reassembly
> app by something like the following scapy script:
> x=Ether(src=...,dst=...)/IP(dst='0.0.0.0',src='0.0.0.0',id=0)/('X'*1000)
> frags=fragment(x, fragsize=500)
> sendp(frags, iface=...)
> To overcome that issue and reduce overhead of
> 'key invalidate' and 'key is empty' operations -
> add key_len into keys comparision procedure.
>
> Fixes: 4f1a8f633862 ("ip_frag: add IPv6 reassembly")
> Cc: stable@dpdk.org
>
> Reported-by: Ryan E Hall <ryan.e.hall@intel.com>
> Reported-by: Alexander V Gutkin <alexander.v.gutkin@intel.com>
> Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> ---
> @@ -44,9 +44,17 @@ struct ip_frag {
>
> /** @internal <src addr, dst_addr, id> to uniquely identify fragmented datagram. */
> struct ip_frag_key {
> - uint64_t src_dst[4]; /**< src address, first 8 bytes used for IPv4 */
> - uint32_t id; /**< dst address */
> - uint32_t key_len; /**< src/dst key length */
> + uint64_t src_dst[4];
> + /**< src and dst address, only first 8 bytes used for IPv4 */
> + RTE_STD_C11
> + union {
> + uint64_t id_key_len; /**< combined for easy fetch */
> + __extension__
> + struct {
> + uint32_t id; /**< packet id */
> + uint32_t key_len; /**< src/dst key length */
> + };
> + };
> };
Would that break ABI?
>
> /**
>
> -----Original Message-----
> From: Burakov, Anatoly
> Sent: Tuesday, November 6, 2018 10:54 AM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>; dev@dpdk.org
> Cc: stable@dpdk.org; Hall, Ryan E <ryan.e.hall@intel.com>; Gutkin, Alexander V <alexander.v.gutkin@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v2 2/2] ip_frag: use key length for key comparision
>
> On 05-Nov-18 12:18 PM, Konstantin Ananyev wrote:
> > Right now reassembly code relies on src_dst[] being all zeroes to
> > determine is it free/occupied entry in the fragments table.
> > This is suboptimal and error prone - user can crash DPDK ip_reassembly
> > app by something like the following scapy script:
> > x=Ether(src=...,dst=...)/IP(dst='0.0.0.0',src='0.0.0.0',id=0)/('X'*1000)
> > frags=fragment(x, fragsize=500)
> > sendp(frags, iface=...)
> > To overcome that issue and reduce overhead of
> > 'key invalidate' and 'key is empty' operations -
> > add key_len into keys comparision procedure.
> >
> > Fixes: 4f1a8f633862 ("ip_frag: add IPv6 reassembly")
> > Cc: stable@dpdk.org
> >
> > Reported-by: Ryan E Hall <ryan.e.hall@intel.com>
> > Reported-by: Alexander V Gutkin <alexander.v.gutkin@intel.com>
> > Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> > ---
>
>
>
> > @@ -44,9 +44,17 @@ struct ip_frag {
> >
> > /** @internal <src addr, dst_addr, id> to uniquely identify fragmented datagram. */
> > struct ip_frag_key {
> > - uint64_t src_dst[4]; /**< src address, first 8 bytes used for IPv4 */
> > - uint32_t id; /**< dst address */
> > - uint32_t key_len; /**< src/dst key length */
> > + uint64_t src_dst[4];
> > + /**< src and dst address, only first 8 bytes used for IPv4 */
> > + RTE_STD_C11
> > + union {
> > + uint64_t id_key_len; /**< combined for easy fetch */
> > + __extension__
> > + struct {
> > + uint32_t id; /**< packet id */
> > + uint32_t key_len; /**< src/dst key length */
> > + };
> > + };
> > };
>
> Would that break ABI?
No, size and layout of the structure remains the same.
Konstantin
@@ -58,20 +58,14 @@ struct rte_mbuf *ipv6_frag_reassemble(struct ip_frag_pkt *fp);
static inline int
ip_frag_key_is_empty(const struct ip_frag_key * key)
{
- uint32_t i;
- for (i = 0; i < RTE_MIN(key->key_len, RTE_DIM(key->src_dst)); i++)
- if (key->src_dst[i] != 0)
- return 0;
- return 1;
+ return (key->key_len == 0);
}
-/* empty the key */
+/* invalidate the key */
static inline void
ip_frag_key_invalidate(struct ip_frag_key * key)
{
- uint32_t i;
- for (i = 0; i < key->key_len; i++)
- key->src_dst[i] = 0;
+ key->key_len = 0;
}
/* compare two keys */
@@ -80,7 +74,7 @@ ip_frag_key_cmp(const struct ip_frag_key * k1, const struct ip_frag_key * k2)
{
uint32_t i;
uint64_t val;
- val = k1->id ^ k2->id;
+ val = k1->id_key_len ^ k2->id_key_len;
for (i = 0; i < k1->key_len; i++)
val |= k1->src_dst[i] ^ k2->src_dst[i];
return val;
@@ -44,9 +44,17 @@ struct ip_frag {
/** @internal <src addr, dst_addr, id> to uniquely identify fragmented datagram. */
struct ip_frag_key {
- uint64_t src_dst[4]; /**< src address, first 8 bytes used for IPv4 */
- uint32_t id; /**< dst address */
- uint32_t key_len; /**< src/dst key length */
+ uint64_t src_dst[4];
+ /**< src and dst address, only first 8 bytes used for IPv4 */
+ RTE_STD_C11
+ union {
+ uint64_t id_key_len; /**< combined for easy fetch */
+ __extension__
+ struct {
+ uint32_t id; /**< packet id */
+ uint32_t key_len; /**< src/dst key length */
+ };
+ };
};
/**