Commit 31264f95 authored by Alexander Aring's avatar Alexander Aring Committed by Stefan Schmidt
Browse files

net: 6lowpan: use array for find nhc id



This patch will remove the complete overengineered and overthinking rb data
structure for looking up the nhc by nhcid. Instead we using the existing
nhc next header array and iterate over it. It works now for 1 byte values
only. However there are only 1 byte nhc id values currently
supported and IANA also does not specify large than 1 byte values yet.
If there are 2 byte values for nhc ids specified we can revisit this
data structure and add support for it.

Signed-off-by: default avatarAlexander Aring <aahringo@redhat.com>
Reviewed-by: default avatarStefan Schmidt <stefan@datenfreihafen.org>
Acked-by: default avatarJukka Rissanen <jukka.rissanen@linux.intel.com>
Link: https://lore.kernel.org/r/20220428030534.3220410-3-aahringo@redhat.com


Signed-off-by: default avatarStefan Schmidt <stefan@datenfreihafen.org>
parent eb9edf43
Loading
Loading
Loading
Loading
+13 −78
Original line number Diff line number Diff line
@@ -12,77 +12,26 @@

#include "nhc.h"

static struct rb_root rb_root = RB_ROOT;
static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1];
static DEFINE_SPINLOCK(lowpan_nhc_lock);

static int lowpan_nhc_insert(struct lowpan_nhc *nhc)
static struct lowpan_nhc *lowpan_nhc_by_nhcid(struct sk_buff *skb)
{
	struct rb_node **new = &rb_root.rb_node, *parent = NULL;

	/* Figure out where to put new node */
	while (*new) {
		struct lowpan_nhc *this = rb_entry(*new, struct lowpan_nhc,
						   node);
		int result, len_dif, len;

		len_dif = nhc->idlen - this->idlen;

		if (nhc->idlen < this->idlen)
			len = nhc->idlen;
		else
			len = this->idlen;

		result = memcmp(nhc->id, this->id, len);
		if (!result)
			result = len_dif;

		parent = *new;
		if (result < 0)
			new = &((*new)->rb_left);
		else if (result > 0)
			new = &((*new)->rb_right);
		else
			return -EEXIST;
	}

	/* Add new node and rebalance tree. */
	rb_link_node(&nhc->node, parent, new);
	rb_insert_color(&nhc->node, &rb_root);

	return 0;
}

static void lowpan_nhc_remove(struct lowpan_nhc *nhc)
{
	rb_erase(&nhc->node, &rb_root);
}
	struct lowpan_nhc *nhc;
	int i;
	u8 id;

static struct lowpan_nhc *lowpan_nhc_by_nhcid(const struct sk_buff *skb)
{
	struct rb_node *node = rb_root.rb_node;
	const u8 *nhcid_skb_ptr = skb->data;
	if (!pskb_may_pull(skb, 1))
		return NULL;

	while (node) {
		struct lowpan_nhc *nhc = rb_entry(node, struct lowpan_nhc,
						  node);
		u8 nhcid_skb_ptr_masked[LOWPAN_NHC_MAX_ID_LEN];
		int result, i;
	id = *skb->data;

		if (nhcid_skb_ptr + nhc->idlen > skb->data + skb->len)
			return NULL;
	for (i = 0; i < NEXTHDR_MAX + 1; i++) {
		nhc = lowpan_nexthdr_nhcs[i];
		if (!nhc)
			continue;

		/* copy and mask afterwards the nhid value from skb */
		memcpy(nhcid_skb_ptr_masked, nhcid_skb_ptr, nhc->idlen);
		for (i = 0; i < nhc->idlen; i++)
			nhcid_skb_ptr_masked[i] &= nhc->idmask[i];

		result = memcmp(nhcid_skb_ptr_masked, nhc->id, nhc->idlen);
		if (result < 0)
			node = node->rb_left;
		else if (result > 0)
			node = node->rb_right;
		else
		if ((id & nhc->idmask) == nhc->id)
			return nhc;
	}

@@ -191,16 +140,7 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,

int lowpan_nhc_add(struct lowpan_nhc *nhc)
{
	int ret;

	if (!nhc->idlen || !nhc->idsetup)
		return -EINVAL;

	WARN_ONCE(nhc->idlen > LOWPAN_NHC_MAX_ID_LEN,
		  "LOWPAN_NHC_MAX_ID_LEN should be updated to %zd.\n",
		  nhc->idlen);

	nhc->idsetup(nhc);
	int ret = 0;

	spin_lock_bh(&lowpan_nhc_lock);

@@ -209,10 +149,6 @@ int lowpan_nhc_add(struct lowpan_nhc *nhc)
		goto out;
	}

	ret = lowpan_nhc_insert(nhc);
	if (ret < 0)
		goto out;

	lowpan_nexthdr_nhcs[nhc->nexthdr] = nhc;
out:
	spin_unlock_bh(&lowpan_nhc_lock);
@@ -224,7 +160,6 @@ void lowpan_nhc_del(struct lowpan_nhc *nhc)
{
	spin_lock_bh(&lowpan_nhc_lock);

	lowpan_nhc_remove(nhc);
	lowpan_nexthdr_nhcs[nhc->nexthdr] = NULL;

	spin_unlock_bh(&lowpan_nhc_lock);
+9 −19
Original line number Diff line number Diff line
@@ -16,24 +16,20 @@
 * @_name: const char * of common header compression name.
 * @_nexthdr: ipv6 nexthdr field for the header compression.
 * @_nexthdrlen: ipv6 nexthdr len for the reserved space.
 * @_idsetup: callback to setup id and mask values.
 * @_idlen: len for the next header id and mask, should be always the same.
 * @_id: one byte nhc id value.
 * @_idmask: one byte nhc id mask value.
 * @_uncompress: callback for uncompression call.
 * @_compress: callback for compression call.
 */
#define LOWPAN_NHC(__nhc, _name, _nexthdr,	\
		   _hdrlen, _idsetup, _idlen,	\
		   _hdrlen, _id, _idmask,	\
		   _uncompress, _compress)	\
static u8 __nhc##_val[_idlen];			\
static u8 __nhc##_mask[_idlen];			\
static struct lowpan_nhc __nhc = {		\
	.name		= _name,		\
	.nexthdr	= _nexthdr,		\
	.nexthdrlen	= _hdrlen,		\
	.id		= __nhc##_val,		\
	.idmask		= __nhc##_mask,		\
	.idlen		= _idlen,		\
	.idsetup	= _idsetup,		\
	.id		= _id,			\
	.idmask		= _idmask,		\
	.uncompress	= _uncompress,		\
	.compress	= _compress,		\
}
@@ -53,27 +49,21 @@ module_exit(__nhc##_exit);
/**
 * struct lowpan_nhc - hold 6lowpan next hdr compression ifnformation
 *
 * @node: holder for the rbtree.
 * @name: name of the specific next header compression
 * @nexthdr: next header value of the protocol which should be compressed.
 * @nexthdrlen: ipv6 nexthdr len for the reserved space.
 * @id: array for nhc id. Note this need to be in network byteorder.
 * @mask: array for nhc id mask. Note this need to be in network byteorder.
 * @len: the length of the next header id and mask.
 * @setup: callback to setup fill the next header id value and mask.
 * @id: one byte nhc id value.
 * @idmask: one byte nhc id mask value.
 * @compress: callback to do the header compression.
 * @uncompress: callback to do the header uncompression.
 */
struct lowpan_nhc {
	struct rb_node	node;
	const char	*name;
	u8		nexthdr;
	size_t		nexthdrlen;
	u8		*id;
	u8		*idmask;
	size_t		idlen;
	u8		id;
	u8		idmask;

	void		(*idsetup)(struct lowpan_nhc *nhc);
	int		(*uncompress)(struct sk_buff *skb, size_t needed);
	int		(*compress)(struct sk_buff *skb, u8 **hc_ptr);
};
+1 −8
Original line number Diff line number Diff line
@@ -6,18 +6,11 @@

#include "nhc.h"

#define LOWPAN_NHC_DEST_IDLEN	1
#define LOWPAN_NHC_DEST_ID_0	0xe6
#define LOWPAN_NHC_DEST_MASK_0	0xfe

static void dest_nhid_setup(struct lowpan_nhc *nhc)
{
	nhc->id[0] = LOWPAN_NHC_DEST_ID_0;
	nhc->idmask[0] = LOWPAN_NHC_DEST_MASK_0;
}

LOWPAN_NHC(nhc_dest, "RFC6282 Destination Options", NEXTHDR_DEST, 0,
	   dest_nhid_setup, LOWPAN_NHC_DEST_IDLEN, NULL, NULL);
	   LOWPAN_NHC_DEST_ID_0, LOWPAN_NHC_DEST_MASK_0,  NULL, NULL);

module_lowpan_nhc(nhc_dest);
MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Destination Options compression");
+1 −8
Original line number Diff line number Diff line
@@ -5,18 +5,11 @@

#include "nhc.h"

#define LOWPAN_NHC_FRAGMENT_IDLEN	1
#define LOWPAN_NHC_FRAGMENT_ID_0	0xe4
#define LOWPAN_NHC_FRAGMENT_MASK_0	0xfe

static void fragment_nhid_setup(struct lowpan_nhc *nhc)
{
	nhc->id[0] = LOWPAN_NHC_FRAGMENT_ID_0;
	nhc->idmask[0] = LOWPAN_NHC_FRAGMENT_MASK_0;
}

LOWPAN_NHC(nhc_fragment, "RFC6282 Fragment", NEXTHDR_FRAGMENT, 0,
	   fragment_nhid_setup, LOWPAN_NHC_FRAGMENT_IDLEN, NULL, NULL);
	   LOWPAN_NHC_FRAGMENT_ID_0, LOWPAN_NHC_FRAGMENT_MASK_0, NULL, NULL);

module_lowpan_nhc(nhc_fragment);
MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Fragment compression");
+1 −8
Original line number Diff line number Diff line
@@ -5,18 +5,11 @@

#include "nhc.h"

#define LOWPAN_GHC_EXT_DEST_IDLEN	1
#define LOWPAN_GHC_EXT_DEST_ID_0	0xb6
#define LOWPAN_GHC_EXT_DEST_MASK_0	0xfe

static void dest_ghid_setup(struct lowpan_nhc *nhc)
{
	nhc->id[0] = LOWPAN_GHC_EXT_DEST_ID_0;
	nhc->idmask[0] = LOWPAN_GHC_EXT_DEST_MASK_0;
}

LOWPAN_NHC(ghc_ext_dest, "RFC7400 Destination Extension Header", NEXTHDR_DEST,
	   0, dest_ghid_setup, LOWPAN_GHC_EXT_DEST_IDLEN, NULL, NULL);
	   0, LOWPAN_GHC_EXT_DEST_ID_0, LOWPAN_GHC_EXT_DEST_MASK_0, NULL, NULL);

module_lowpan_nhc(ghc_ext_dest);
MODULE_DESCRIPTION("6LoWPAN generic header destination extension compression");
Loading