diff mbox series

[PATCHv3,1/2] linux-generic: classification: implement ipv6 packet matching rule

Message ID 1486125945-8641-1-git-send-email-bala.manoharan@linaro.org
State Accepted
Commit aa3bbe4da1639ac4649c7d34ae75b0230ade70b2
Headers show
Series [PATCHv3,1/2] linux-generic: classification: implement ipv6 packet matching rule | expand

Commit Message

Balasubramanian Manoharan Feb. 3, 2017, 12:45 p.m. UTC
Adds test case for ipv6 source and destination address matching

Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>

---
v3: performance enhancement using bitwise AND for ip address mask

 .../include/odp_classification_datamodel.h         | 11 ++++-
 .../include/odp_classification_inlines.h           | 52 ++++++++++++++++++----
 .../linux-generic/include/odp_packet_internal.h    |  5 +++
 platform/linux-generic/include/protocols/ip.h      | 14 +++++-
 platform/linux-generic/odp_classification.c        | 27 +++++++++++
 platform/linux-generic/odp_packet.c                |  2 +-
 6 files changed, 99 insertions(+), 12 deletions(-)

-- 
1.9.1

Comments

Bill Fischofer Feb. 7, 2017, 12:23 a.m. UTC | #1
For this series:

Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org>

On Fri, Feb 3, 2017 at 6:45 AM, Balasubramanian Manoharan
<bala.manoharan@linaro.org> wrote:
> Adds test case for ipv6 source and destination address matching

>

> Signed-off-by: Balasubramanian Manoharan <bala.manoharan@linaro.org>

> ---

> v3: performance enhancement using bitwise AND for ip address mask

>

>  .../include/odp_classification_datamodel.h         | 11 ++++-

>  .../include/odp_classification_inlines.h           | 52 ++++++++++++++++++----

>  .../linux-generic/include/odp_packet_internal.h    |  5 +++

>  platform/linux-generic/include/protocols/ip.h      | 14 +++++-

>  platform/linux-generic/odp_classification.c        | 27 +++++++++++

>  platform/linux-generic/odp_packet.c                |  2 +-

>  6 files changed, 99 insertions(+), 12 deletions(-)

>

> diff --git a/platform/linux-generic/include/odp_classification_datamodel.h b/platform/linux-generic/include/odp_classification_datamodel.h

> index f6393ee..140f39e 100644

> --- a/platform/linux-generic/include/odp_classification_datamodel.h

> +++ b/platform/linux-generic/include/odp_classification_datamodel.h

> @@ -25,6 +25,7 @@ extern "C" {

>  #include <odp_packet_internal.h>

>  #include <odp_packet_io_internal.h>

>  #include <odp_queue_internal.h>

> +#include <protocols/ip.h>

>

>  /* Maximum Class Of Service Entry */

>  #define ODP_COS_MAX_ENTRY              64

> @@ -43,7 +44,7 @@ extern "C" {

>  /* Max L3 QoS Value */

>  #define ODP_COS_MAX_L3_QOS             (1 << ODP_COS_L3_QOS_BITS)

>  /* Max PMR Term bits */

> -#define ODP_PMR_TERM_BYTES_MAX         8

> +#define ODP_PMR_TERM_BYTES_MAX         16

>

>  /**

>  Packet Matching Rule Term Value

> @@ -67,6 +68,14 @@ typedef struct pmr_term_value {

>                         /** End value of the range */

>                         uint64_t        val_end;

>                 } range;

> +               struct {

> +                       _odp_ipv6_addr_t addr;

> +                       _odp_ipv6_addr_t mask;

> +               } match_ipv6;

> +               struct {

> +                       _odp_ipv6_addr_t addr_start;

> +                       _odp_ipv6_addr_t addr_end;

> +               } range_ipv6;

>         };

>         uint32_t        offset; /**< Offset if term == ODP_PMR_CUSTOM_FRAME */

>         uint32_t        val_sz; /**< Size of the value to be matched */

> diff --git a/platform/linux-generic/include/odp_classification_inlines.h b/platform/linux-generic/include/odp_classification_inlines.h

> index b839197..e6f9be9 100644

> --- a/platform/linux-generic/include/odp_classification_inlines.h

> +++ b/platform/linux-generic/include/odp_classification_inlines.h

> @@ -25,6 +25,8 @@ extern "C" {

>  #include <protocols/udp.h>

>  #include <protocols/tcp.h>

>  #include <odp_packet_internal.h>

> +#include <stdio.h>

> +#include <inttypes.h>

>

>  /* PMR term value verification function

>  These functions verify the given PMR term value with the value in the packet

> @@ -179,19 +181,53 @@ static inline int verify_pmr_dmac(const uint8_t *pkt_addr,

>         return 0;

>  }

>

> -static inline int verify_pmr_ipv6_saddr(const uint8_t *pkt_addr ODP_UNUSED,

> -                                       odp_packet_hdr_t *pkt_hdr ODP_UNUSED,

> -                                       pmr_term_value_t *term_value ODP_UNUSED)

> +static inline int verify_pmr_ipv6_saddr(const uint8_t *pkt_addr,

> +                                       odp_packet_hdr_t *pkt_hdr,

> +                                       pmr_term_value_t *term_value)

>  {

> -       ODP_UNIMPLEMENTED();

> +       const _odp_ipv6hdr_t *ipv6;

> +       uint64_t addr[2];

> +

> +       if (!packet_hdr_has_ipv6(pkt_hdr))

> +               return 0;

> +

> +       ipv6 = (const _odp_ipv6hdr_t *)(pkt_addr + pkt_hdr->p.l3_offset);

> +

> +       addr[0] = ipv6->src_addr.u64[0];

> +       addr[1] = ipv6->src_addr.u64[1];

> +

> +       /* 128 bit address is processed as two 64 bit value

> +       * for bitwise AND operation */

> +       addr[0] = addr[0] & term_value->match_ipv6.mask.u64[0];

> +       addr[1] = addr[1] & term_value->match_ipv6.mask.u64[1];

> +

> +       if (!memcmp(addr, term_value->match_ipv6.addr.u8, _ODP_IPV6ADDR_LEN))

> +               return 1;

> +

>         return 0;

>  }

>

> -static inline int verify_pmr_ipv6_daddr(const uint8_t *pkt_addr ODP_UNUSED,

> -                                       odp_packet_hdr_t *pkt_hdr ODP_UNUSED,

> -                                       pmr_term_value_t *term_value ODP_UNUSED)

> +static inline int verify_pmr_ipv6_daddr(const uint8_t *pkt_addr,

> +                                       odp_packet_hdr_t *pkt_hdr,

> +                                       pmr_term_value_t *term_value)

>  {

> -       ODP_UNIMPLEMENTED();

> +       const _odp_ipv6hdr_t *ipv6;

> +       uint64_t addr[2];

> +

> +       if (!packet_hdr_has_ipv6(pkt_hdr))

> +               return 0;

> +       ipv6 = (const _odp_ipv6hdr_t *)(pkt_addr + pkt_hdr->p.l3_offset);

> +       addr[0] = ipv6->dst_addr.u64[0];

> +       addr[1] = ipv6->dst_addr.u64[1];

> +

> +       /* 128 bit address is processed as two 64 bit value

> +       * for bitwise AND operation */

> +       addr[0] = addr[0] & term_value->match_ipv6.mask.u64[0];

> +       addr[1] = addr[1] & term_value->match_ipv6.mask.u64[1];

> +

> +       if (!memcmp(addr, term_value->match_ipv6.addr.u8, _ODP_IPV6ADDR_LEN))

> +               return 1;

> +

>         return 0;

>  }

>

> diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h

> index e6e9d74..e3ada5c 100644

> --- a/platform/linux-generic/include/odp_packet_internal.h

> +++ b/platform/linux-generic/include/odp_packet_internal.h

> @@ -294,6 +294,11 @@ static inline int packet_hdr_has_eth(odp_packet_hdr_t *pkt_hdr)

>         return pkt_hdr->p.input_flags.eth;

>  }

>

> +static inline int packet_hdr_has_ipv6(odp_packet_hdr_t *pkt_hdr)

> +{

> +       return pkt_hdr->p.input_flags.ipv6;

> +}

> +

>  static inline void packet_set_ts(odp_packet_hdr_t *pkt_hdr, odp_time_t *ts)

>  {

>         if (ts != NULL) {

> diff --git a/platform/linux-generic/include/protocols/ip.h b/platform/linux-generic/include/protocols/ip.h

> index 6c089e3..20041f1 100644

> --- a/platform/linux-generic/include/protocols/ip.h

> +++ b/platform/linux-generic/include/protocols/ip.h

> @@ -117,6 +117,16 @@ ODP_STATIC_ASSERT(sizeof(_odp_ipv4hdr_t) == _ODP_IPV4HDR_LEN,

>         (uint8_t)((((ver_tc_flow) & 0x0fc00000) >> 22) & 0xff)

>

>  /**

> + * Ipv6 address

> + */

> +typedef union ODP_PACKED {

> +       uint8_t         u8[16];

> +       odp_u16be_t     u16[8];

> +       odp_u32be_t     u32[4];

> +       odp_u64be_t     u64[2];

> +} _odp_ipv6_addr_t;

> +

> +/**

>   * IPv6 header

>   */

>  typedef struct ODP_PACKED {

> @@ -124,8 +134,8 @@ typedef struct ODP_PACKED {

>         odp_u16be_t payload_len; /**< Payload length */

>         uint8_t    next_hdr;     /**< Next header */

>         uint8_t    hop_limit;    /**< Hop limit */

> -       uint8_t    src_addr[16]; /**< Source address */

> -       uint8_t    dst_addr[16]; /**< Destination address */

> +       _odp_ipv6_addr_t src_addr; /**< Source address */

> +       _odp_ipv6_addr_t dst_addr; /**< Destination address */

>  } _odp_ipv6hdr_t;

>

>  /** @internal Compile time assert */

> diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c

> index 50a7e54..4882c5c 100644

> --- a/platform/linux-generic/odp_classification.c

> +++ b/platform/linux-generic/odp_classification.c

> @@ -447,6 +447,32 @@ static int odp_pmr_create_term(pmr_term_value_t *value,

>  {

>         value->term = param->term;

>         value->range_term = param->range_term;

> +       uint8_t i;

> +

> +       switch (value->term) {

> +       case ODP_PMR_SIP6_ADDR:

> +       case ODP_PMR_DIP6_ADDR:

> +       if (!value->range_term) {

> +               memset(value->match_ipv6.addr.u8, 0, 16);

> +               memset(value->match_ipv6.mask.u8, 0, 16);

> +               memcpy(&value->match_ipv6.addr.u8, param->match.value,

> +                      param->val_sz);

> +               memcpy(&value->match_ipv6.mask.u8, param->match.mask,

> +                      param->val_sz);

> +               for (i = 0; i < 2; i++)

> +                       value->match_ipv6.addr.u64[i] &=

> +                               value->match_ipv6.mask.u64[i];

> +       } else {

> +               memset(value->range_ipv6.addr_start.u8, 0, 16);

> +               memset(value->range_ipv6.addr_end.u8, 0, 16);

> +               memcpy(&value->range_ipv6.addr_start.u8, param->range.val_start,

> +                      param->val_sz);

> +               memcpy(&value->range_ipv6.addr_end.u8, param->range.val_end,

> +                      param->val_sz);

> +       }

> +

> +       break;

> +       default:

>         if (!value->range_term) {

>                 value->match.value = 0;

>                 value->match.mask = 0;

> @@ -461,6 +487,7 @@ static int odp_pmr_create_term(pmr_term_value_t *value,

>                 memcpy(&value->range.val_end, param->range.val_end,

>                        param->val_sz);

>         }

> +       }

>         value->offset = param->offset;

>         value->val_sz = param->val_sz;

>         return 0;

> diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c

> index 34d720c..a87b2d9 100644

> --- a/platform/linux-generic/odp_packet.c

> +++ b/platform/linux-generic/odp_packet.c

> @@ -1888,7 +1888,7 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,

>  {

>         const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr;

>         const _odp_ipv6hdr_ext_t *ipv6ext;

> -       uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr[0]);

> +       uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr.u8[0]);

>

>         prs->l3_len = odp_be_to_cpu_16(ipv6->payload_len) +

>                                 _ODP_IPV6HDR_LEN;

> --

> 1.9.1

>
diff mbox series

Patch

diff --git a/platform/linux-generic/include/odp_classification_datamodel.h b/platform/linux-generic/include/odp_classification_datamodel.h
index f6393ee..140f39e 100644
--- a/platform/linux-generic/include/odp_classification_datamodel.h
+++ b/platform/linux-generic/include/odp_classification_datamodel.h
@@ -25,6 +25,7 @@  extern "C" {
 #include <odp_packet_internal.h>
 #include <odp_packet_io_internal.h>
 #include <odp_queue_internal.h>
+#include <protocols/ip.h>
 
 /* Maximum Class Of Service Entry */
 #define ODP_COS_MAX_ENTRY		64
@@ -43,7 +44,7 @@  extern "C" {
 /* Max L3 QoS Value */
 #define ODP_COS_MAX_L3_QOS		(1 << ODP_COS_L3_QOS_BITS)
 /* Max PMR Term bits */
-#define ODP_PMR_TERM_BYTES_MAX		8
+#define ODP_PMR_TERM_BYTES_MAX		16
 
 /**
 Packet Matching Rule Term Value
@@ -67,6 +68,14 @@  typedef struct pmr_term_value {
 			/** End value of the range */
 			uint64_t	val_end;
 		} range;
+		struct {
+			_odp_ipv6_addr_t addr;
+			_odp_ipv6_addr_t mask;
+		} match_ipv6;
+		struct {
+			_odp_ipv6_addr_t addr_start;
+			_odp_ipv6_addr_t addr_end;
+		} range_ipv6;
 	};
 	uint32_t	offset;	/**< Offset if term == ODP_PMR_CUSTOM_FRAME */
 	uint32_t	val_sz;	/**< Size of the value to be matched */
diff --git a/platform/linux-generic/include/odp_classification_inlines.h b/platform/linux-generic/include/odp_classification_inlines.h
index b839197..e6f9be9 100644
--- a/platform/linux-generic/include/odp_classification_inlines.h
+++ b/platform/linux-generic/include/odp_classification_inlines.h
@@ -25,6 +25,8 @@  extern "C" {
 #include <protocols/udp.h>
 #include <protocols/tcp.h>
 #include <odp_packet_internal.h>
+#include <stdio.h>
+#include <inttypes.h>
 
 /* PMR term value verification function
 These functions verify the given PMR term value with the value in the packet
@@ -179,19 +181,53 @@  static inline int verify_pmr_dmac(const uint8_t *pkt_addr,
 	return 0;
 }
 
-static inline int verify_pmr_ipv6_saddr(const uint8_t *pkt_addr ODP_UNUSED,
-					odp_packet_hdr_t *pkt_hdr ODP_UNUSED,
-					pmr_term_value_t *term_value ODP_UNUSED)
+static inline int verify_pmr_ipv6_saddr(const uint8_t *pkt_addr,
+					odp_packet_hdr_t *pkt_hdr,
+					pmr_term_value_t *term_value)
 {
-	ODP_UNIMPLEMENTED();
+	const _odp_ipv6hdr_t *ipv6;
+	uint64_t addr[2];
+
+	if (!packet_hdr_has_ipv6(pkt_hdr))
+		return 0;
+
+	ipv6 = (const _odp_ipv6hdr_t *)(pkt_addr + pkt_hdr->p.l3_offset);
+
+	addr[0] = ipv6->src_addr.u64[0];
+	addr[1] = ipv6->src_addr.u64[1];
+
+	/* 128 bit address is processed as two 64 bit value
+	* for bitwise AND operation */
+	addr[0] = addr[0] & term_value->match_ipv6.mask.u64[0];
+	addr[1] = addr[1] & term_value->match_ipv6.mask.u64[1];
+
+	if (!memcmp(addr, term_value->match_ipv6.addr.u8, _ODP_IPV6ADDR_LEN))
+		return 1;
+
 	return 0;
 }
 
-static inline int verify_pmr_ipv6_daddr(const uint8_t *pkt_addr ODP_UNUSED,
-					odp_packet_hdr_t *pkt_hdr ODP_UNUSED,
-					pmr_term_value_t *term_value ODP_UNUSED)
+static inline int verify_pmr_ipv6_daddr(const uint8_t *pkt_addr,
+					odp_packet_hdr_t *pkt_hdr,
+					pmr_term_value_t *term_value)
 {
-	ODP_UNIMPLEMENTED();
+	const _odp_ipv6hdr_t *ipv6;
+	uint64_t addr[2];
+
+	if (!packet_hdr_has_ipv6(pkt_hdr))
+		return 0;
+	ipv6 = (const _odp_ipv6hdr_t *)(pkt_addr + pkt_hdr->p.l3_offset);
+	addr[0] = ipv6->dst_addr.u64[0];
+	addr[1] = ipv6->dst_addr.u64[1];
+
+	/* 128 bit address is processed as two 64 bit value
+	* for bitwise AND operation */
+	addr[0] = addr[0] & term_value->match_ipv6.mask.u64[0];
+	addr[1] = addr[1] & term_value->match_ipv6.mask.u64[1];
+
+	if (!memcmp(addr, term_value->match_ipv6.addr.u8, _ODP_IPV6ADDR_LEN))
+		return 1;
+
 	return 0;
 }
 
diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index e6e9d74..e3ada5c 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -294,6 +294,11 @@  static inline int packet_hdr_has_eth(odp_packet_hdr_t *pkt_hdr)
 	return pkt_hdr->p.input_flags.eth;
 }
 
+static inline int packet_hdr_has_ipv6(odp_packet_hdr_t *pkt_hdr)
+{
+	return pkt_hdr->p.input_flags.ipv6;
+}
+
 static inline void packet_set_ts(odp_packet_hdr_t *pkt_hdr, odp_time_t *ts)
 {
 	if (ts != NULL) {
diff --git a/platform/linux-generic/include/protocols/ip.h b/platform/linux-generic/include/protocols/ip.h
index 6c089e3..20041f1 100644
--- a/platform/linux-generic/include/protocols/ip.h
+++ b/platform/linux-generic/include/protocols/ip.h
@@ -117,6 +117,16 @@  ODP_STATIC_ASSERT(sizeof(_odp_ipv4hdr_t) == _ODP_IPV4HDR_LEN,
 	(uint8_t)((((ver_tc_flow) & 0x0fc00000) >> 22) & 0xff)
 
 /**
+ * Ipv6 address
+ */
+typedef union ODP_PACKED {
+	uint8_t		u8[16];
+	odp_u16be_t	u16[8];
+	odp_u32be_t	u32[4];
+	odp_u64be_t	u64[2];
+} _odp_ipv6_addr_t;
+
+/**
  * IPv6 header
  */
 typedef struct ODP_PACKED {
@@ -124,8 +134,8 @@  typedef struct ODP_PACKED {
 	odp_u16be_t payload_len; /**< Payload length */
 	uint8_t    next_hdr;     /**< Next header */
 	uint8_t    hop_limit;    /**< Hop limit */
-	uint8_t    src_addr[16]; /**< Source address */
-	uint8_t    dst_addr[16]; /**< Destination address */
+	_odp_ipv6_addr_t src_addr; /**< Source address */
+	_odp_ipv6_addr_t dst_addr; /**< Destination address */
 } _odp_ipv6hdr_t;
 
 /** @internal Compile time assert */
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index 50a7e54..4882c5c 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -447,6 +447,32 @@  static int odp_pmr_create_term(pmr_term_value_t *value,
 {
 	value->term = param->term;
 	value->range_term = param->range_term;
+	uint8_t i;
+
+	switch (value->term) {
+	case ODP_PMR_SIP6_ADDR:
+	case ODP_PMR_DIP6_ADDR:
+	if (!value->range_term) {
+		memset(value->match_ipv6.addr.u8, 0, 16);
+		memset(value->match_ipv6.mask.u8, 0, 16);
+		memcpy(&value->match_ipv6.addr.u8, param->match.value,
+		       param->val_sz);
+		memcpy(&value->match_ipv6.mask.u8, param->match.mask,
+		       param->val_sz);
+		for (i = 0; i < 2; i++)
+			value->match_ipv6.addr.u64[i] &=
+				value->match_ipv6.mask.u64[i];
+	} else {
+		memset(value->range_ipv6.addr_start.u8, 0, 16);
+		memset(value->range_ipv6.addr_end.u8, 0, 16);
+		memcpy(&value->range_ipv6.addr_start.u8, param->range.val_start,
+		       param->val_sz);
+		memcpy(&value->range_ipv6.addr_end.u8, param->range.val_end,
+		       param->val_sz);
+	}
+
+	break;
+	default:
 	if (!value->range_term) {
 		value->match.value = 0;
 		value->match.mask = 0;
@@ -461,6 +487,7 @@  static int odp_pmr_create_term(pmr_term_value_t *value,
 		memcpy(&value->range.val_end, param->range.val_end,
 		       param->val_sz);
 	}
+	}
 	value->offset = param->offset;
 	value->val_sz = param->val_sz;
 	return 0;
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 34d720c..a87b2d9 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -1888,7 +1888,7 @@  static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
 {
 	const _odp_ipv6hdr_t *ipv6 = (const _odp_ipv6hdr_t *)*parseptr;
 	const _odp_ipv6hdr_ext_t *ipv6ext;
-	uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr[0]);
+	uint32_t dstaddr0 = odp_be_to_cpu_32(ipv6->dst_addr.u8[0]);
 
 	prs->l3_len = odp_be_to_cpu_16(ipv6->payload_len) +
 				_ODP_IPV6HDR_LEN;