On Wed, Dec 10, 2014 at 2:03 PM, Bala Manoharan <bala.manoha...@linaro.org> wrote: > On Wed, Dec 10, 2014 at 12:54:38PM +0200, Ciprian Barbu wrote: >> On Tue, Dec 9, 2014 at 7:53 PM, Bill Fischofer >> <bill.fischo...@linaro.org> wrote: >> > If you've already received the packet there's not much point in classifying >> > it since the output of classification is the queue that the packet should >> > be >> > sent to (and the buffer pool it should be stored in for non-linux-generic >> > implementations). In my packet patch I include the odp_packet_parse() >> > function but it's an internal API for now since it isn't part of the v0.5 >> > external spec. Parsing would be useful independent of classification. >> >> I agree with always parsing packets received from the interface, but >> for real platforms it's not clear to me if it can be an independent >> process, like it can be for linux-generic. Looking at the >> Classification document I see parsing as in integral part of the >> classifier, if I'm reading it correctly. >> >> To be clear, I'm ok to give a go to the patch series as they are, just >> wanted to get an idea of the differences between linux-generic and >> other platforms in regards to classification. >> >> So please add my Reviewed-by to this patch also. >> > If the application wants to use the feature of classification for > user-generated packet > it will have to send the packet through a loop back interface and the > classification engine > can classify the packet and enqueue to correct queue. > The same will be the used in-case for Encrypted packet which gets de-crypted > by the application > and classification is applied by sending them over a virtual loopback > interface.
Ok, that sounds fair. But that's for user-generated packets, the question was for packets that the application receives with odp_pktio_recv. >> > >> > On Tue, Dec 9, 2014 at 10:47 AM, Ciprian Barbu <ciprian.ba...@linaro.org> >> > wrote: >> >> >> >> I have one question that just came to me. See below. >> >> >> >> On Tue, Dec 9, 2014 at 4:23 AM, Bill Fischofer >> >> <bill.fischo...@linaro.org> wrote: >> >> > >> >> > >> >> > On Mon, Dec 8, 2014 at 6:02 AM, Balasubramanian Manoharan >> >> > <bala.manoha...@linaro.org> wrote: >> >> >> >> >> >> The following features are implemented in this classification >> >> >> implementation: >> >> >> * Attaches PMR, PMR_SET to a Pktio entry >> >> >> * Adds classifier object to pktio entry >> >> >> * Attaches CoS values for L2 and L3 QoS to a Pktio entry >> >> >> * Selects ClassOfService for a packet based on PMR, L2 QoS and L3 QoS >> >> >> values >> >> >> * Selects a default CoS if packet does not match any of the assigned >> >> >> rules >> >> >> * Selects an Error CoS for an Error packet >> >> >> * Enqueues the packet to the queue associated with the selected CoS >> >> >> >> >> >> Signed-off-by: Balasubramanian Manoharan <bala.manoha...@linaro.org> >> >> > >> >> > >> >> > Reviewed-by: Bill Fischofer <bill.fischo...@linaro.org> >> >> > >> >> >> >> >> >> --- >> >> >> V6: Incorporates review comments from Bill >> >> >> helper/include/odph_ip.h | 6 + >> >> >> platform/linux-generic/include/api/odp.h | 1 + >> >> >> .../include/odp_buffer_pool_internal.h | 9 + >> >> >> .../include/odp_classification_datamodel.h | 201 +++++ >> >> >> .../include/odp_classification_inlines.h | 259 ++++++ >> >> >> .../include/odp_classification_internal.h | 173 ++++ >> >> >> platform/linux-generic/include/odp_internal.h | 2 + >> >> >> .../linux-generic/include/odp_packet_io_internal.h | 2 + >> >> >> platform/linux-generic/odp_buffer_pool.c | 10 - >> >> >> platform/linux-generic/odp_classification.c | 883 >> >> >> +++++++++++++++++++-- >> >> >> platform/linux-generic/odp_init.c | 4 + >> >> >> platform/linux-generic/odp_packet_io.c | 47 +- >> >> >> 12 files changed, 1498 insertions(+), 99 deletions(-) >> >> >> create mode 100644 >> >> >> platform/linux-generic/include/odp_classification_datamodel.h >> >> >> create mode 100644 >> >> >> platform/linux-generic/include/odp_classification_inlines.h >> >> >> create mode 100644 >> >> >> platform/linux-generic/include/odp_classification_internal.h >> >> >> >> >> >> diff --git a/helper/include/odph_ip.h b/helper/include/odph_ip.h >> >> >> index 2c83c0f..f78724e 100644 >> >> >> --- a/helper/include/odph_ip.h >> >> >> +++ b/helper/include/odph_ip.h >> >> >> @@ -35,6 +35,9 @@ extern "C" { >> >> >> /** @internal Returns IPv4 header length */ >> >> >> #define ODPH_IPV4HDR_IHL(ver_ihl) ((ver_ihl) & 0x0f) >> >> >> >> >> >> +/** @internal Returns IPv4 DSCP */ >> >> >> +#define ODPH_IPV4HDR_DSCP(tos) (((tos) & 0xfc) >> 2) >> >> >> + >> >> >> /** @internal Returns IPv4 Don't fragment */ >> >> >> #define ODPH_IPV4HDR_FLAGS_DONT_FRAG(frag_offset) ((frag_offset) & >> >> >> 0x4000) >> >> >> >> >> >> @@ -47,6 +50,9 @@ extern "C" { >> >> >> /** @internal Returns true if IPv4 packet is a fragment */ >> >> >> #define ODPH_IPV4HDR_IS_FRAGMENT(frag_offset) ((frag_offset) & 0x3fff) >> >> >> >> >> >> +/** @internal Returns IPv4 DSCP */ >> >> >> +#define ODPH_IPV6HDR_DSCP(ver_tc_flow) (uint8_t)((((ver_tc_flow) & >> >> >> 0x0fc00000) >> 22) & 0xff) >> >> >> + >> >> >> /** IPv4 header */ >> >> >> typedef struct ODP_PACKED { >> >> >> uint8_t ver_ihl; /**< Version / Header length */ >> >> >> diff --git a/platform/linux-generic/include/api/odp.h >> >> >> b/platform/linux-generic/include/api/odp.h >> >> >> index 6e4f69e..b7b1ca9 100644 >> >> >> --- a/platform/linux-generic/include/api/odp.h >> >> >> +++ b/platform/linux-generic/include/api/odp.h >> >> >> @@ -47,6 +47,7 @@ extern "C" { >> >> >> #include <odp_packet_flags.h> >> >> >> #include <odp_packet_io.h> >> >> >> #include <odp_crypto.h> >> >> >> +#include <odp_classification.h> >> >> >> #include <odp_rwlock.h> >> >> >> >> >> >> #ifdef __cplusplus >> >> >> diff --git a/platform/linux-generic/include/odp_buffer_pool_internal.h >> >> >> b/platform/linux-generic/include/odp_buffer_pool_internal.h >> >> >> index e0210bd..07602fe 100644 >> >> >> --- a/platform/linux-generic/include/odp_buffer_pool_internal.h >> >> >> +++ b/platform/linux-generic/include/odp_buffer_pool_internal.h >> >> >> @@ -22,6 +22,7 @@ extern "C" { >> >> >> #include <odp_buffer_pool.h> >> >> >> #include <odp_buffer_internal.h> >> >> >> #include <odp_align.h> >> >> >> +#include <odp_align_internal.h> >> >> >> #include <odp_hints.h> >> >> >> #include <odp_config.h> >> >> >> #include <odp_debug.h> >> >> >> @@ -64,6 +65,10 @@ struct pool_entry_s { >> >> >> size_t hdr_size; >> >> >> }; >> >> >> >> >> >> +typedef union pool_entry_u { >> >> >> + struct pool_entry_s s; >> >> >> + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct >> >> >> pool_entry_s))]; >> >> >> +} pool_entry_t; >> >> >> >> >> >> extern void *pool_entry_ptr[]; >> >> >> >> >> >> @@ -73,6 +78,10 @@ static inline void *get_pool_entry(uint32_t pool_id) >> >> >> return pool_entry_ptr[pool_id]; >> >> >> } >> >> >> >> >> >> +static inline uint32_t pool_handle_to_index(odp_buffer_pool_t >> >> >> pool_hdl) >> >> >> +{ >> >> >> + return pool_hdl - 1; >> >> >> +} >> >> >> >> >> >> static inline odp_buffer_hdr_t *odp_buf_to_hdr(odp_buffer_t buf) >> >> >> { >> >> >> diff --git >> >> >> a/platform/linux-generic/include/odp_classification_datamodel.h >> >> >> b/platform/linux-generic/include/odp_classification_datamodel.h >> >> >> new file mode 100644 >> >> >> index 0000000..18846bc >> >> >> --- /dev/null >> >> >> +++ b/platform/linux-generic/include/odp_classification_datamodel.h >> >> >> @@ -0,0 +1,201 @@ >> >> >> +/* Copyright (c) 2014, Linaro Limited >> >> >> + * All rights reserved. >> >> >> + * >> >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> >> + */ >> >> >> + >> >> >> + >> >> >> +/** >> >> >> + * @file >> >> >> + * >> >> >> + * ODP Classification Datamodel >> >> >> + * Describes the classification internal data model >> >> >> + */ >> >> >> + >> >> >> +#ifndef ODP_CLASSIFICATION_DATAMODEL_H_ >> >> >> +#define ODP_CLASSIFICATION_DATAMODEL_H_ >> >> >> + >> >> >> +#ifdef __cplusplus >> >> >> +extern "C" { >> >> >> +#endif >> >> >> + >> >> >> +#include <odp_spinlock.h> >> >> >> +#include <odp_classification.h> >> >> >> +#include <odp_buffer_pool_internal.h> >> >> >> +#include <odp_packet_internal.h> >> >> >> +#include <odp_packet_io_internal.h> >> >> >> +#include <odp_queue_internal.h> >> >> >> + >> >> >> +/* Maximum Class Of Service Entry */ >> >> >> +#define ODP_COS_MAX_ENTRY 64 >> >> >> +/* Maximum PMR Set Entry */ >> >> >> +#define ODP_PMRSET_MAX_ENTRY 64 >> >> >> +/* Maximum PMR Entry */ >> >> >> +#define ODP_PMR_MAX_ENTRY 64 >> >> >> +/* Maximum PMR Terms in a PMR Set */ >> >> >> +#define ODP_PMRTERM_MAX 8 >> >> >> +/* Maximum PMRs attached in PKTIO Level */ >> >> >> +#define ODP_PKTIO_MAX_PMR 8 >> >> >> +/* L2 Priority Bits */ >> >> >> +#define ODP_COS_L2_QOS_BITS 3 >> >> >> +/* Max L2 QoS value */ >> >> >> +#define ODP_COS_MAX_L2_QOS (1 << ODP_COS_L2_QOS_BITS) >> >> >> +/* L2 DSCP Bits */ >> >> >> +#define ODP_COS_L3_QOS_BITS 6 >> >> >> +/* 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 >> >> >> + >> >> >> +/* forward declaration */ >> >> >> +typedef union pmr_u pmr_t; >> >> >> + >> >> >> +/** >> >> >> +Packet Matching Rule Term Value >> >> >> + >> >> >> +Stores the Term and Value mapping for a PMR. >> >> >> +The maximum size of value currently supported in 64 bits >> >> >> +**/ >> >> >> +typedef struct pmr_term_value { >> >> >> + odp_pmr_match_type_e match_type; /**< Packet Match Type*/ >> >> >> + odp_pmr_term_e term; /* PMR Term */ >> >> >> + union { >> >> >> + struct { >> >> >> + uint64_t val; >> >> >> + uint64_t mask; >> >> >> + } mask; /**< Match a masked set of bits */ >> >> >> + struct { >> >> >> + uint64_t val1; >> >> >> + uint64_t val2; >> >> >> + } range; /**< Match an integer range */ >> >> >> + }; >> >> >> +} pmr_term_value_t; >> >> >> + >> >> >> +typedef union cos_u cos_t; >> >> >> +/* >> >> >> +Class Of Service >> >> >> +*/ >> >> >> +struct cos_s { >> >> >> + queue_entry_t *queue; /* Associated Queue */ >> >> >> + pool_entry_t *pool; /* Associated Buffer pool */ >> >> >> + pmr_t *pmr; /* Chained PMR */ >> >> >> + cos_t *linked_cos; /* CoS linked with the PMR */ >> >> >> + uint32_t valid; /* validity Flag */ >> >> >> + odp_drop_e drop_policy; /* Associated Drop Policy */ >> >> >> + odp_queue_group_t queue_group; /* Associated Queue Group */ >> >> >> + odp_cos_flow_set_t flow_set; /* Assigned Flow Set */ >> >> >> + char name[ODP_COS_NAME_LEN]; /* name */ >> >> >> + size_t headroom; /* Headroom for this CoS */ >> >> >> + odp_spinlock_t lock; /* cos lock */ >> >> >> +}; >> >> >> + >> >> >> +typedef union cos_u { >> >> >> + struct cos_s s; >> >> >> + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct cos_s))]; >> >> >> +} cos_t; >> >> >> + >> >> >> + >> >> >> +/** >> >> >> +Packet Matching Rule >> >> >> + >> >> >> +**/ >> >> >> +struct pmr_s { >> >> >> + uint32_t valid; /* Validity Flag */ >> >> >> + odp_atomic_u32_t count; /* num of packets matching this >> >> >> rule */ >> >> >> + uint32_t num_pmr; /* num of PMR Term Values*/ >> >> >> + odp_spinlock_t lock; /* pmr lock*/ >> >> >> + pmr_term_value_t pmr_term_value[1]; /* Associated PMR Term >> >> >> */ >> >> >> +}; >> >> >> + >> >> >> +typedef union pmr_u { >> >> >> + struct pmr_s s; >> >> >> + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct pmr_s))]; >> >> >> +} pmr_t; >> >> >> + >> >> >> +/** >> >> >> +Packet Matching Rule Set >> >> >> + >> >> >> +This structure is implemented as a extension over struct pmr_s >> >> >> +In order to use same pointer to access both pmr_s and pmr_set_s >> >> >> +'num_pmr' value is used to differentiate between pmr_s and pmr_set_s >> >> >> struct >> >> >> +**/ >> >> >> +struct pmr_set_s { >> >> >> + pmr_t pmr; >> >> >> + pmr_term_value_t pmr_term_value[ODP_PMRTERM_MAX - 1]; >> >> >> + /* List of associated PMR Terms */ >> >> >> +}; >> >> >> + >> >> >> +typedef union pmr_set_u { >> >> >> + struct pmr_set_s s; >> >> >> + uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct >> >> >> pmr_set_s))]; >> >> >> +} pmr_set_t; >> >> >> + >> >> >> +/** >> >> >> +L2 QoS and CoS Map >> >> >> + >> >> >> +This structure holds the mapping between L2 QoS value and >> >> >> +corresponding cos_t object >> >> >> +**/ >> >> >> +typedef struct pmr_l2_cos { >> >> >> + odp_spinlock_t lock; /* pmr_l2_cos lock */ >> >> >> + cos_t *cos[ODP_COS_MAX_L2_QOS]; /* Array of CoS objects */ >> >> >> +} pmr_l2_cos_t; >> >> >> + >> >> >> +/** >> >> >> +L3 QoS and CoS Map >> >> >> + >> >> >> +This structure holds the mapping between L3 QoS value and >> >> >> +corresponding cos_t object >> >> >> +**/ >> >> >> +typedef struct pmr_l3_cos { >> >> >> + odp_spinlock_t lock; /* pmr_l3_cos lock */ >> >> >> + cos_t *cos[ODP_COS_MAX_L3_QOS]; /* Array of CoS objects */ >> >> >> +} pmr_l3_cos_t; >> >> >> + >> >> >> +/** >> >> >> +Linux Generic Classifier >> >> >> + >> >> >> +This structure is stored in pktio_entry and holds all >> >> >> +the classifier configuration value. >> >> >> +**/ >> >> >> +typedef struct classifier { >> >> >> + odp_spinlock_t lock; /*pktio_cos lock */ >> >> >> + uint32_t num_pmr; /* num of PMRs linked to given >> >> >> PKTIO*/ >> >> >> + pmr_t *pmr[ODP_PKTIO_MAX_PMR]; /* PMRs linked with this PKTIO >> >> >> */ >> >> >> + cos_t *cos[ODP_PKTIO_MAX_PMR]; /* CoS linked with this PKTIO >> >> >> */ >> >> >> + cos_t *error_cos; /* Associated Error CoS */ >> >> >> + cos_t *default_cos; /* Associated Default CoS */ >> >> >> + uint32_t l3_precedence; /* L3 QoS precedence */ >> >> >> + pmr_l2_cos_t l2_cos_table; /* L2 QoS-CoS table map */ >> >> >> + pmr_l3_cos_t l3_cos_table; /* L3 Qos-CoS table map */ >> >> >> + odp_cos_flow_set_t flow_set; /* Flow Set to be calculated >> >> >> + for this pktio */ >> >> >> + size_t headroom; /* Pktio Headroom */ >> >> >> + size_t skip; /* Pktio Skip Offset */ >> >> >> +} classifier_t; >> >> >> + >> >> >> +/** >> >> >> +Class of Service Table >> >> >> +**/ >> >> >> +typedef struct odp_cos_table { >> >> >> + cos_t cos_entry[ODP_COS_MAX_ENTRY]; >> >> >> +} cos_tbl_t; >> >> >> + >> >> >> +/** >> >> >> +PMR set table >> >> >> +**/ >> >> >> +typedef struct pmr_set_tbl { >> >> >> + pmr_set_t pmr_set[ODP_PMRSET_MAX_ENTRY]; >> >> >> +} pmr_set_tbl_t; >> >> >> + >> >> >> +/** >> >> >> +PMR table >> >> >> +**/ >> >> >> +typedef struct pmr_tbl { >> >> >> + pmr_t pmr[ODP_PMR_MAX_ENTRY]; >> >> >> +} pmr_tbl_t; >> >> >> + >> >> >> +#ifdef __cplusplus >> >> >> +} >> >> >> +#endif >> >> >> +#endif >> >> >> diff --git >> >> >> a/platform/linux-generic/include/odp_classification_inlines.h >> >> >> b/platform/linux-generic/include/odp_classification_inlines.h >> >> >> new file mode 100644 >> >> >> index 0000000..6b20119 >> >> >> --- /dev/null >> >> >> +++ b/platform/linux-generic/include/odp_classification_inlines.h >> >> >> @@ -0,0 +1,259 @@ >> >> >> +/* Copyright (c) 2014, Linaro Limited >> >> >> + * All rights reserved. >> >> >> + * >> >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> >> + */ >> >> >> + >> >> >> + >> >> >> +/** >> >> >> + * @file >> >> >> + * >> >> >> + * ODP Classification Inlines >> >> >> + * Classification Inlines Functions >> >> >> + */ >> >> >> +#ifndef __ODP_CLASSIFICATION_INLINES_H_ >> >> >> +#define __ODP_CLASSIFICATION_INLINES_H_ >> >> >> + >> >> >> +#ifdef __cplusplus >> >> >> +extern "C" { >> >> >> +#endif >> >> >> + >> >> >> +#include <odp_debug.h> >> >> >> +#include <odph_eth.h> >> >> >> +#include <odph_ip.h> >> >> >> +#include <odph_udp.h> >> >> >> +#include <odph_tcp.h> >> >> >> + >> >> >> +/* PMR term value verification function >> >> >> +These functions verify the given PMR term value with the value in the >> >> >> packet >> >> >> +These following functions return 1 on success and 0 on failure >> >> >> +*/ >> >> >> + >> >> >> +static inline int verify_pmr_packet_len(odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (pkt_hdr->frame_len & >> >> >> + term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= pkt_hdr->frame_len) && >> >> >> + (pkt_hdr->frame_len <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_ip_proto(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + odph_ipv4hdr_t *ip; >> >> >> + uint8_t proto; >> >> >> + if (!pkt_hdr->input_flags.ipv4) >> >> >> + return 0; >> >> >> + ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset); >> >> >> + proto = ip->proto; >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (proto & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= proto) && >> >> >> + (proto <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_ipv4_saddr(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + odph_ipv4hdr_t *ip; >> >> >> + uint32_t ipaddr; >> >> >> + if (!pkt_hdr->input_flags.ipv4) >> >> >> + return 0; >> >> >> + ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset); >> >> >> + ipaddr = odp_be_to_cpu_32(ip->src_addr); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (ipaddr & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= ipaddr) && >> >> >> + (ipaddr <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_ipv4_daddr(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + odph_ipv4hdr_t *ip; >> >> >> + uint32_t ipaddr; >> >> >> + if (!pkt_hdr->input_flags.ipv4) >> >> >> + return 0; >> >> >> + ip = (odph_ipv4hdr_t *)(pkt_addr + pkt_hdr->l3_offset); >> >> >> + ipaddr = odp_be_to_cpu_32(ip->dst_addr); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (ipaddr & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= ipaddr) && >> >> >> + (ipaddr <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_tcp_sport(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + uint16_t sport; >> >> >> + odph_tcphdr_t *tcp; >> >> >> + if (!pkt_hdr->input_flags.tcp) >> >> >> + return 0; >> >> >> + tcp = (odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset); >> >> >> + sport = odp_be_to_cpu_16(tcp->src_port); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (sport & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= sport) && >> >> >> + (sport <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_tcp_dport(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + uint16_t dport; >> >> >> + odph_tcphdr_t *tcp; >> >> >> + if (!pkt_hdr->input_flags.tcp) >> >> >> + return 0; >> >> >> + tcp = (odph_tcphdr_t *)(pkt_addr + pkt_hdr->l4_offset); >> >> >> + dport = odp_be_to_cpu_16(tcp->dst_port); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (dport & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= dport) && >> >> >> + (dport <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_udp_dport(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + uint16_t dport; >> >> >> + odph_udphdr_t *udp; >> >> >> + if (!pkt_hdr->input_flags.udp) >> >> >> + return 0; >> >> >> + udp = (odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset); >> >> >> + dport = odp_be_to_cpu_16(udp->dst_port); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (dport & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= dport) && >> >> >> + (dport <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_udp_sport(uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr, >> >> >> + pmr_term_value_t *term_value) >> >> >> +{ >> >> >> + uint16_t sport; >> >> >> + odph_udphdr_t *udp; >> >> >> + if (!pkt_hdr->input_flags.udp) >> >> >> + return 0; >> >> >> + udp = (odph_udphdr_t *)(pkt_addr + pkt_hdr->l4_offset); >> >> >> + sport = odp_be_to_cpu_16(udp->src_port); >> >> >> + if (term_value->match_type == ODP_PMR_MASK) { >> >> >> + if (term_value->mask.val == (sport & >> >> >> term_value->mask.mask)) >> >> >> + return 1; >> >> >> + } else { >> >> >> + if ((term_value->range.val1 <= sport) && >> >> >> + (sport <= term_value->range.val2)) >> >> >> + return 1; >> >> >> + } >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_dmac(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +static inline int verify_pmr_ipv6_saddr(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_ipv6_daddr(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_vlan_id_0(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_vlan_id_x(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_ipsec_spi(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_ld_vni(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_eth_type_0(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +static inline int verify_pmr_eth_type_x(uint8_t *pkt_addr ODP_UNUSED, >> >> >> + odp_packet_hdr_t *pkt_hdr >> >> >> ODP_UNUSED, >> >> >> + pmr_term_value_t *term_value >> >> >> ODP_UNUSED) >> >> >> +{ >> >> >> + ODP_UNIMPLEMENTED(); >> >> >> + return 0; >> >> >> +} >> >> >> +#ifdef __cplusplus >> >> >> +} >> >> >> +#endif >> >> >> +#endif >> >> >> diff --git >> >> >> a/platform/linux-generic/include/odp_classification_internal.h >> >> >> b/platform/linux-generic/include/odp_classification_internal.h >> >> >> new file mode 100644 >> >> >> index 0000000..fd2c6af >> >> >> --- /dev/null >> >> >> +++ b/platform/linux-generic/include/odp_classification_internal.h >> >> >> @@ -0,0 +1,173 @@ >> >> >> +/* Copyright (c) 2014, Linaro Limited >> >> >> + * All rights reserved. >> >> >> + * >> >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> >> + */ >> >> >> + >> >> >> + >> >> >> +/** >> >> >> + * @file >> >> >> + * >> >> >> + * ODP Classification Internal >> >> >> + * Describes the classification internal Functions >> >> >> + */ >> >> >> + >> >> >> +#ifndef __ODP_CLASSIFICATION_INTERNAL_H_ >> >> >> +#define __ODP_CLASSIFICATION_INTERNAL_H_ >> >> >> + >> >> >> +#ifdef __cplusplus >> >> >> +extern "C" { >> >> >> +#endif >> >> >> + >> >> >> +#include <odp_classification.h> >> >> >> +#include <odp_queue.h> >> >> >> +#include <odp_packet_internal.h> >> >> >> +#include <odp_packet_io.h> >> >> >> +#include <odp_packet_io_internal.h> >> >> >> +#include <odp_classification_datamodel.h> >> >> >> + >> >> >> +/** Classification Internal function **/ >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Select a CoS for the given Packet based on pktio >> >> >> + >> >> >> +This function will call all the PMRs associated with a pktio for >> >> >> +a given packet and will return the matched COS object. >> >> >> +This function will check PMR, L2 and L3 QoS COS object associated >> >> >> +with the PKTIO interface. >> >> >> + >> >> >> +Returns the default cos if the packet does not match any PMR >> >> >> +Returns the error_cos if the packet has an error >> >> >> +**/ >> >> >> +cos_t *pktio_select_cos(pktio_entry_t *pktio, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +match_qos_cos >> >> >> + >> >> >> +Select a CoS for the given Packet based on QoS values >> >> >> +This function returns the COS object matching the L2 and L3 QoS >> >> >> +based on the l3_preference value of the pktio >> >> >> +**/ >> >> >> +cos_t *match_qos_cos(pktio_entry_t *entry, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr); >> >> >> +/** >> >> >> +Packet Classifier >> >> >> + >> >> >> +Start function for Packet Classifier >> >> >> +This function calls Classifier module internal functions for a given >> >> >> packet and >> >> >> +enqueues the packet to specific Queue based on PMR and CoS selected. >> >> >> +**/ >> >> >> +int packet_classifier(odp_pktio_t pktio, odp_packet_t pkt); >> >> >> +/** >> >> >> +Packet IO classifier init >> >> >> + >> >> >> +This function does initialization of classifier object associated with >> >> >> pktio. >> >> >> +This function should be called during pktio initialization. >> >> >> +**/ >> >> >> +int pktio_classifier_init(pktio_entry_t *pktio); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +match_pmr_cos >> >> >> + >> >> >> +Match a PMR chain with a Packet and return matching CoS >> >> >> +This function gets called recursively to check the chained PMR Term >> >> >> value >> >> >> +with the packet. >> >> >> + >> >> >> +**/ >> >> >> +cos_t *match_pmr_cos(cos_t *cos, uint8_t *pkt_addr, pmr_t *pmr, >> >> >> + odp_packet_hdr_t *hdr); >> >> >> +/** >> >> >> +@internal >> >> >> +CoS associated with L3 QoS value >> >> >> + >> >> >> +This function returns the CoS associated with L3 QoS value >> >> >> +**/ >> >> >> +cos_t *match_qos_l3_cos(pmr_l3_cos_t *l3_cos, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +CoS associated with L2 QoS value >> >> >> + >> >> >> +This function returns the CoS associated with L2 QoS value >> >> >> +**/ >> >> >> +cos_t *match_qos_l2_cos(pmr_l2_cos_t *l2_cos, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr); >> >> >> +/** >> >> >> +@internal >> >> >> +Flow Signature Calculation >> >> >> + >> >> >> +This function calculates the Flow Signature for a packet based on >> >> >> +CoS and updates in Packet Meta Data >> >> >> +**/ >> >> >> +int update_flow_signature(uint8_t *pkt_addr, cos_t *cos); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Allocate a odp_pmr_set_t Handle >> >> >> +*/ >> >> >> +odp_pmr_set_t alloc_pmr_set(pmr_t **pmr); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Allocate a odp_pmr_t Handle >> >> >> +*/ >> >> >> +odp_pmr_t alloc_pmr(pmr_t **pmr); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to pmr_set_t Handle >> >> >> +This function checks for validity of pmr_set_t Handle >> >> >> +*/ >> >> >> +pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to pmr_set_t Handle >> >> >> +*/ >> >> >> +pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to pmr_set_t Handle >> >> >> +This function checks for validity of pmr_set_t Handle >> >> >> +*/ >> >> >> +pmr_t *get_pmr_entry(odp_pmr_t pmr_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to pmr_set_t Handle >> >> >> +*/ >> >> >> +pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to odp_cos_t Handle >> >> >> +*/ >> >> >> +cos_t *get_cos_entry(odp_cos_t cos_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Pointer to odp_cos_t Handle >> >> >> +This function checks for validity of odp_cos_t Handle >> >> >> +*/ >> >> >> +cos_t *get_cos_entry_internal(odp_cos_t cos_id); >> >> >> + >> >> >> +/** >> >> >> +@internal >> >> >> +Verify PMR with a Packet >> >> >> + >> >> >> +This function goes through each PMR_TERM value in pmr_t structure and >> >> >> +calls verification function for each term.Returns 1 if PMR matches or >> >> >> 0 >> >> >> +Otherwise. >> >> >> +**/ >> >> >> +int verify_pmr(pmr_t *pmr, uint8_t *pkt_addr, odp_packet_hdr_t >> >> >> *pkt_hdr); >> >> >> + >> >> >> +#ifdef __cplusplus >> >> >> +} >> >> >> +#endif >> >> >> +#endif >> >> >> diff --git a/platform/linux-generic/include/odp_internal.h >> >> >> b/platform/linux-generic/include/odp_internal.h >> >> >> index f8c1596..04c1030 100644 >> >> >> --- a/platform/linux-generic/include/odp_internal.h >> >> >> +++ b/platform/linux-generic/include/odp_internal.h >> >> >> @@ -32,6 +32,8 @@ int odp_buffer_pool_init_global(void); >> >> >> int odp_pktio_init_global(void); >> >> >> int odp_pktio_init_local(void); >> >> >> >> >> >> +int odp_classification_init_global(void); >> >> >> + >> >> >> int odp_queue_init_global(void); >> >> >> >> >> >> int odp_crypto_init_global(void); >> >> >> diff --git a/platform/linux-generic/include/odp_packet_io_internal.h >> >> >> b/platform/linux-generic/include/odp_packet_io_internal.h >> >> >> index d129f22..465127b 100644 >> >> >> --- a/platform/linux-generic/include/odp_packet_io_internal.h >> >> >> +++ b/platform/linux-generic/include/odp_packet_io_internal.h >> >> >> @@ -20,6 +20,7 @@ extern "C" { >> >> >> >> >> >> #include <odp_spinlock.h> >> >> >> #include <odp_packet_socket.h> >> >> >> +#include <odp_classification_datamodel.h> >> >> >> #include <odp_align_internal.h> >> >> >> >> >> >> #include <odp_config.h> >> >> >> @@ -43,6 +44,7 @@ struct pktio_entry { >> >> >> odp_pktio_type_t type; /**< pktio type */ >> >> >> pkt_sock_t pkt_sock; /**< using socket API for IO */ >> >> >> pkt_sock_mmap_t pkt_sock_mmap; /**< using socket mmap API for >> >> >> IO >> >> >> */ >> >> >> + classifier_t cls; /**< classifier linked with >> >> >> this >> >> >> pktio*/ >> >> >> char name[IFNAMSIZ]; /**< name of pktio provided to >> >> >> pktio_open() */ >> >> >> }; >> >> >> diff --git a/platform/linux-generic/odp_buffer_pool.c >> >> >> b/platform/linux-generic/odp_buffer_pool.c >> >> >> index 83c51fa..d20999b 100644 >> >> >> --- a/platform/linux-generic/odp_buffer_pool.c >> >> >> +++ b/platform/linux-generic/odp_buffer_pool.c >> >> >> @@ -57,12 +57,6 @@ typedef struct { >> >> >> } odp_any_buffer_hdr_t; >> >> >> >> >> >> >> >> >> -typedef union pool_entry_u { >> >> >> - struct pool_entry_s s; >> >> >> - >> >> >> - uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(struct >> >> >> pool_entry_s))]; >> >> >> - >> >> >> -} pool_entry_t; >> >> >> >> >> >> >> >> >> typedef struct pool_table_t { >> >> >> @@ -87,10 +81,6 @@ static inline odp_buffer_pool_t >> >> >> pool_index_to_handle(uint32_t pool_id) >> >> >> } >> >> >> >> >> >> >> >> >> -static inline uint32_t pool_handle_to_index(odp_buffer_pool_t >> >> >> pool_hdl) >> >> >> -{ >> >> >> - return pool_hdl -1; >> >> >> -} >> >> >> >> >> >> >> >> >> static inline void set_handle(odp_buffer_hdr_t *hdr, >> >> >> diff --git a/platform/linux-generic/odp_classification.c >> >> >> b/platform/linux-generic/odp_classification.c >> >> >> index 190d71e..3cb1537 100644 >> >> >> --- a/platform/linux-generic/odp_classification.c >> >> >> +++ b/platform/linux-generic/odp_classification.c >> >> >> @@ -1,69 +1,321 @@ >> >> >> +/* Copyright (c) 2014, Linaro Limited >> >> >> + * All rights reserved. >> >> >> + * >> >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> >> + */ >> >> >> + >> >> >> #include <odp_classification.h> >> >> >> #include <odp_align.h> >> >> >> #include <odp_queue.h> >> >> >> #include <odp_debug.h> >> >> >> +#include <odp_internal.h> >> >> >> #include <odp_debug_internal.h> >> >> >> +#include <odp_packet_internal.h> >> >> >> #include <odp_packet_io.h> >> >> >> +#include <odp_packet_io_internal.h> >> >> >> +#include <odp_classification_datamodel.h> >> >> >> +#include <odp_classification_inlines.h> >> >> >> +#include <odp_classification_internal.h> >> >> >> +#include <odp_buffer_pool_internal.h> >> >> >> +#include <odp_shared_memory.h> >> >> >> +#include <odph_eth.h> >> >> >> +#include <string.h> >> >> >> +#include <odp_spinlock.h> >> >> >> >> >> >> -odp_cos_t odp_cos_create(const char *name) >> >> >> +#define LOCK(a) odp_spinlock_lock(a) >> >> >> +#define UNLOCK(a) odp_spinlock_unlock(a) >> >> >> +#define LOCK_INIT(a) odp_spinlock_init(a) >> >> >> + >> >> >> +static cos_tbl_t *cos_tbl; >> >> >> +static pmr_set_tbl_t *pmr_set_tbl; >> >> >> +static pmr_tbl_t *pmr_tbl; >> >> >> + >> >> >> +cos_t *get_cos_entry_internal(odp_cos_t cos_id) >> >> >> +{ >> >> >> + return &(cos_tbl->cos_entry[cos_id]); >> >> >> +} >> >> >> + >> >> >> +pmr_set_t *get_pmr_set_entry_internal(odp_pmr_set_t pmr_set_id) >> >> >> +{ >> >> >> + return &(pmr_set_tbl->pmr_set[pmr_set_id]); >> >> >> +} >> >> >> + >> >> >> +pmr_t *get_pmr_entry_internal(odp_pmr_t pmr_id) >> >> >> { >> >> >> - (void) name; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + return &(pmr_tbl->pmr[pmr_id]); >> >> >> +} >> >> >> + >> >> >> +int odp_classification_init_global(void) >> >> >> +{ >> >> >> + odp_shm_t cos_shm; >> >> >> + odp_shm_t pmr_shm; >> >> >> + odp_shm_t pmr_set_shm; >> >> >> + int i; >> >> >> + >> >> >> + cos_shm = odp_shm_reserve("shm_odp_cos_tbl", >> >> >> + sizeof(cos_tbl_t), >> >> >> + sizeof(cos_t), 0); >> >> >> + >> >> >> + if (cos_shm == ODP_SHM_INVALID) { >> >> >> + ODP_ERR("shm allocation failed for shm_odp_cos_tbl"); >> >> >> + goto error; >> >> >> + } >> >> >> + >> >> >> + cos_tbl = odp_shm_addr(cos_shm); >> >> >> + if (cos_tbl == NULL) >> >> >> + goto error_cos; >> >> >> + >> >> >> + memset(cos_tbl, 0, sizeof(cos_tbl_t)); >> >> >> + for (i = 0; i < ODP_COS_MAX_ENTRY; i++) { >> >> >> + /* init locks */ >> >> >> + cos_t *cos = get_cos_entry_internal(i); >> >> >> + LOCK_INIT(&cos->s.lock); >> >> >> + } >> >> >> + >> >> >> + pmr_shm = odp_shm_reserve("shm_odp_pmr_tbl", >> >> >> + sizeof(pmr_tbl_t), >> >> >> + sizeof(pmr_t), 0); >> >> >> + >> >> >> + if (pmr_shm == ODP_SHM_INVALID) { >> >> >> + ODP_ERR("shm allocation failed for shm_odp_pmr_tbl"); >> >> >> + goto error_cos; >> >> >> + } >> >> >> + >> >> >> + pmr_tbl = odp_shm_addr(pmr_shm); >> >> >> + if (pmr_tbl == NULL) >> >> >> + goto error_pmr; >> >> >> + >> >> >> + memset(pmr_tbl, 0, sizeof(pmr_tbl_t)); >> >> >> + for (i = 0; i < ODP_PMR_MAX_ENTRY; i++) { >> >> >> + /* init locks */ >> >> >> + pmr_t *pmr = get_pmr_entry_internal(i); >> >> >> + LOCK_INIT(&pmr->s.lock); >> >> >> + } >> >> >> + >> >> >> + pmr_set_shm = odp_shm_reserve("shm_odp_pmr_set_tbl", >> >> >> + sizeof(pmr_set_tbl_t), >> >> >> + sizeof(pmr_set_t), 0); >> >> >> + >> >> >> + if (pmr_set_shm == ODP_SHM_INVALID) { >> >> >> + ODP_ERR("shm allocation failed for >> >> >> shm_odp_pmr_set_tbl"); >> >> >> + goto error_pmr; >> >> >> + } >> >> >> + >> >> >> + pmr_set_tbl = odp_shm_addr(pmr_set_shm); >> >> >> + if (pmr_set_tbl == NULL) >> >> >> + goto error_pmrset; >> >> >> + >> >> >> + memset(pmr_set_tbl, 0, sizeof(pmr_set_tbl_t)); >> >> >> + for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) { >> >> >> + /* init locks */ >> >> >> + pmr_set_t *pmr = get_pmr_set_entry_internal(i); >> >> >> + LOCK_INIT(&pmr->s.pmr.s.lock); >> >> >> + } >> >> >> + >> >> >> return 0; >> >> >> + >> >> >> +error_pmrset: >> >> >> + odp_shm_free(pmr_set_shm); >> >> >> +error_pmr: >> >> >> + odp_shm_free(pmr_shm); >> >> >> +error_cos: >> >> >> + odp_shm_free(cos_shm); >> >> >> +error: >> >> >> + return -1; >> >> >> +} >> >> >> + >> >> >> +odp_cos_t odp_cos_create(const char *name) >> >> >> +{ >> >> >> + int i; >> >> >> + >> >> >> + for (i = 0; i < ODP_COS_MAX_ENTRY; i++) { >> >> >> + LOCK(&cos_tbl->cos_entry[i].s.lock); >> >> >> + if (0 == cos_tbl->cos_entry[i].s.valid) { >> >> >> + strncpy(cos_tbl->cos_entry[i].s.name, name, >> >> >> + ODP_COS_NAME_LEN - 1); >> >> >> + cos_tbl->cos_entry[i].s.name[ODP_COS_NAME_LEN - >> >> >> 1] >> >> >> = 0; >> >> >> + cos_tbl->cos_entry[i].s.pmr = NULL; >> >> >> + cos_tbl->cos_entry[i].s.linked_cos = NULL; >> >> >> + cos_tbl->cos_entry[i].s.queue = NULL; >> >> >> + cos_tbl->cos_entry[i].s.pool = NULL; >> >> >> + cos_tbl->cos_entry[i].s.flow_set = 0; >> >> >> + cos_tbl->cos_entry[i].s.headroom = 0; >> >> >> + cos_tbl->cos_entry[i].s.valid = 1; >> >> >> + UNLOCK(&cos_tbl->cos_entry[i].s.lock); >> >> >> + return (odp_cos_t)i; >> >> >> + } >> >> >> + UNLOCK(&cos_tbl->cos_entry[i].s.lock); >> >> >> + } >> >> >> + ODP_ERR("ODP_COS_MAX_ENTRY reached"); >> >> >> + return ODP_COS_INVALID; >> >> >> +} >> >> >> + >> >> >> +odp_pmr_set_t alloc_pmr_set(pmr_t **pmr) >> >> >> +{ >> >> >> + int i; >> >> >> + >> >> >> + for (i = 0; i < ODP_PMRSET_MAX_ENTRY; i++) { >> >> >> + LOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock); >> >> >> + if (0 == pmr_set_tbl->pmr_set[i].s.pmr.s.valid) { >> >> >> + pmr_set_tbl->pmr_set[i].s.pmr.s.valid = 1; >> >> >> + pmr_set_tbl->pmr_set[i].s.pmr.s.num_pmr = 0; >> >> >> + *pmr = (pmr_t *)&pmr_set_tbl->pmr_set[i]; >> >> >> + odp_atomic_init_u32(&pmr_set_tbl->pmr_set[i] >> >> >> + .s.pmr.s.count, 0); >> >> >> + return (odp_pmr_set_t)i; /* return as locked */ >> >> >> + } >> >> >> + UNLOCK(&pmr_set_tbl->pmr_set[i].s.pmr.s.lock); >> >> >> + } >> >> >> + ODP_ERR("ODP_PMRSET_MAX_ENTRY reached"); >> >> >> + return ODP_PMR_INVAL; >> >> >> +} >> >> >> + >> >> >> +odp_pmr_t alloc_pmr(pmr_t **pmr) >> >> >> +{ >> >> >> + int i; >> >> >> + >> >> >> + for (i = 0; i < ODP_PMR_MAX_ENTRY; i++) { >> >> >> + LOCK(&pmr_tbl->pmr[i].s.lock); >> >> >> + if (0 == pmr_tbl->pmr[i].s.valid) { >> >> >> + pmr_tbl->pmr[i].s.valid = 1; >> >> >> + odp_atomic_init_u32(&pmr_tbl->pmr[i].s.count, >> >> >> 0); >> >> >> + pmr_tbl->pmr[i].s.num_pmr = 0; >> >> >> + *pmr = &pmr_tbl->pmr[i]; >> >> >> + return (odp_pmr_t)i; /* return as locked */ >> >> >> + } >> >> >> + UNLOCK(&pmr_tbl->pmr[i].s.lock); >> >> >> + } >> >> >> + ODP_ERR("ODP_PMR_MAX_ENTRY reached"); >> >> >> + return ODP_PMR_INVAL; >> >> >> +} >> >> >> + >> >> >> + >> >> >> +cos_t *get_cos_entry(odp_cos_t cos_id) >> >> >> +{ >> >> >> + if (cos_id >= ODP_COS_MAX_ENTRY || cos_id == ODP_COS_INVALID) >> >> >> + return NULL; >> >> >> + if (cos_tbl->cos_entry[cos_id].s.valid == 0) >> >> >> + return NULL; >> >> >> + return &(cos_tbl->cos_entry[cos_id]); >> >> >> +} >> >> >> + >> >> >> + >> >> >> +pmr_set_t *get_pmr_set_entry(odp_pmr_set_t pmr_set_id) >> >> >> +{ >> >> >> + if (pmr_set_id >= ODP_PMRSET_MAX_ENTRY || pmr_set_id == >> >> >> ODP_PMR_INVAL) >> >> >> + return NULL; >> >> >> + if (pmr_set_tbl->pmr_set[pmr_set_id].s.pmr.s.valid == 0) >> >> >> + return NULL; >> >> >> + return &(pmr_set_tbl->pmr_set[pmr_set_id]); >> >> >> +} >> >> >> + >> >> >> +pmr_t *get_pmr_entry(odp_pmr_t pmr_id) >> >> >> +{ >> >> >> + if (pmr_id >= ODP_PMR_MAX_ENTRY || pmr_id == ODP_PMR_INVAL) >> >> >> + return NULL; >> >> >> + if (pmr_tbl->pmr[pmr_id].s.valid == 0) >> >> >> + return NULL; >> >> >> + return &(pmr_tbl->pmr[pmr_id]); >> >> >> } >> >> >> >> >> >> int odp_cos_destroy(odp_cos_t cos_id) >> >> >> { >> >> >> - (void)cos_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + cos_t *cos = get_cos_entry(cos_id); >> >> >> + if (NULL == cos) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + cos->s.valid = 0; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_cos_set_queue(odp_cos_t cos_id, odp_queue_t queue_id) >> >> >> { >> >> >> - (void)cos_id; >> >> >> - (void)queue_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + cos_t *cos = get_cos_entry(cos_id); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + /* Locking is not required as intermittent stale >> >> >> + data during CoS modification is acceptable*/ >> >> >> + cos->s.queue = queue_to_qentry(queue_id); >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_cos_set_drop(odp_cos_t cos_id, odp_drop_e drop_policy) >> >> >> { >> >> >> - (void)cos_id; >> >> >> - (void)drop_policy; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + cos_t *cos = get_cos_entry(cos_id); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + /*Drop policy is not supported in v1.0*/ >> >> >> + cos->s.drop_policy = drop_policy; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_pktio_set_default_cos(odp_pktio_t pktio_in, odp_cos_t >> >> >> default_cos) >> >> >> { >> >> >> - (void)pktio_in; >> >> >> - (void)default_cos; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pktio_entry_t *entry; >> >> >> + cos_t *cos; >> >> >> + entry = get_pktio_entry(pktio_in); >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + cos = get_cos_entry(default_cos); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + entry->s.cls.default_cos = cos; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_pktio_set_error_cos(odp_pktio_t pktio_in, odp_cos_t error_cos) >> >> >> { >> >> >> - (void)pktio_in; >> >> >> - (void)error_cos; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pktio_entry_t *entry; >> >> >> + cos_t *cos; >> >> >> + >> >> >> + entry = get_pktio_entry(pktio_in); >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + cos = get_cos_entry(error_cos); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + entry->s.cls.error_cos = cos; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_pktio_set_skip(odp_pktio_t pktio_in, size_t offset) >> >> >> { >> >> >> - (void)pktio_in; >> >> >> - (void)offset; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pktio_entry_t *entry = get_pktio_entry(pktio_in); >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + entry->s.cls.skip = offset; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> -int odp_pktio_set_headroom(odp_pktio_t port_id, size_t headroom) >> >> >> +int odp_pktio_set_headroom(odp_pktio_t pktio_in, size_t headroom) >> >> >> { >> >> >> - (void)port_id; >> >> >> - (void)headroom; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pktio_entry_t *entry = get_pktio_entry(pktio_in); >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + entry->s.cls.headroom = headroom; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> @@ -72,11 +324,26 @@ int odp_cos_with_l2_priority(odp_pktio_t pktio_in, >> >> >> uint8_t qos_table[], >> >> >> odp_cos_t cos_table[]) >> >> >> { >> >> >> - (void)pktio_in; >> >> >> - (void)num_qos; >> >> >> - (void)qos_table; >> >> >> - (void)cos_table; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pmr_l2_cos_t *l2_cos; >> >> >> + size_t i; >> >> >> + cos_t *cos; >> >> >> + pktio_entry_t *entry = get_pktio_entry(pktio_in); >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + l2_cos = &entry->s.cls.l2_cos_table; >> >> >> + >> >> >> + LOCK(&l2_cos->lock); >> >> >> + /* Update the L2 QoS table*/ >> >> >> + for (i = 0; i < num_qos; i++) { >> >> >> + cos = get_cos_entry(cos_table[i]); >> >> >> + if (cos != NULL) { >> >> >> + if (ODP_COS_MAX_L2_QOS > qos_table[i]) >> >> >> + l2_cos->cos[qos_table[i]] = cos; >> >> >> + } >> >> >> + } >> >> >> + UNLOCK(&l2_cos->lock); >> >> >> return 0; >> >> >> } >> >> >> >> >> >> @@ -86,12 +353,29 @@ int odp_cos_with_l3_qos(odp_pktio_t pktio_in, >> >> >> odp_cos_t cos_table[], >> >> >> bool l3_preference) >> >> >> { >> >> >> - (void)pktio_in; >> >> >> - (void)num_qos; >> >> >> - (void)qos_table; >> >> >> - (void)cos_table; >> >> >> - (void)l3_preference; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pmr_l3_cos_t *l3_cos; >> >> >> + size_t i; >> >> >> + pktio_entry_t *entry = get_pktio_entry(pktio_in); >> >> >> + cos_t *cos; >> >> >> + >> >> >> + if (entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + entry->s.cls.l3_precedence = l3_preference; >> >> >> + l3_cos = &entry->s.cls.l3_cos_table; >> >> >> + >> >> >> + LOCK(&l3_cos->lock); >> >> >> + /* Update the L3 QoS table*/ >> >> >> + for (i = 0; i < num_qos; i++) { >> >> >> + cos = get_cos_entry(cos_table[i]); >> >> >> + if (cos != NULL) { >> >> >> + if (ODP_COS_MAX_L3_QOS > qos_table[i]) >> >> >> + l3_cos->cos[qos_table[i]] = cos; >> >> >> + } >> >> >> + } >> >> >> + UNLOCK(&l3_cos->lock); >> >> >> return 0; >> >> >> } >> >> >> >> >> >> @@ -100,12 +384,27 @@ odp_pmr_t odp_pmr_create_match(odp_pmr_term_e >> >> >> term, >> >> >> const void *mask, >> >> >> size_t val_sz) >> >> >> { >> >> >> - (void)term; >> >> >> - (void)val; >> >> >> - (void)mask; >> >> >> - (void)val_sz; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + pmr_t *pmr; >> >> >> + odp_pmr_t id; >> >> >> + if (val_sz > ODP_PMR_TERM_BYTES_MAX) { >> >> >> + ODP_ERR("val_sz greater than max supported limit"); >> >> >> + return ODP_PMR_INVAL; >> >> >> + } >> >> >> + >> >> >> + id = alloc_pmr(&pmr); >> >> >> + /*if alloc_pmr() is successful it returns with lock acquired*/ >> >> >> + if (id == ODP_PMR_INVAL) >> >> >> + return ODP_PMR_INVAL; >> >> >> + >> >> >> + pmr->s.num_pmr = 1; >> >> >> + pmr->s.pmr_term_value[0].match_type = ODP_PMR_MASK; >> >> >> + pmr->s.pmr_term_value[0].term = term; >> >> >> + pmr->s.pmr_term_value[0].mask.val = 0; >> >> >> + pmr->s.pmr_term_value[0].mask.mask = 0; >> >> >> + memcpy(&pmr->s.pmr_term_value[0].mask.val, val, val_sz); >> >> >> + memcpy(&pmr->s.pmr_term_value[0].mask.mask, mask, val_sz); >> >> >> + UNLOCK(&pmr->s.lock); >> >> >> + return id; >> >> >> } >> >> >> >> >> >> odp_pmr_t odp_pmr_create_range(odp_pmr_term_e term, >> >> >> @@ -113,18 +412,36 @@ odp_pmr_t odp_pmr_create_range(odp_pmr_term_e >> >> >> term, >> >> >> const void *val2, >> >> >> size_t val_sz) >> >> >> { >> >> >> - (void)term; >> >> >> - (void)val1; >> >> >> - (void)val2; >> >> >> - (void)val_sz; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + pmr_t *pmr; >> >> >> + odp_pmr_t id; >> >> >> + >> >> >> + if (val_sz > ODP_PMR_TERM_BYTES_MAX) { >> >> >> + ODP_ERR("val_sz greater than max supported limit"); >> >> >> + return ODP_PMR_INVAL; >> >> >> + } >> >> >> + id = alloc_pmr(&pmr); >> >> >> + /*if alloc_pmr() is successful it returns with lock acquired*/ >> >> >> + if (id == ODP_PMR_INVAL) >> >> >> + return ODP_PMR_INVAL; >> >> >> + >> >> >> + pmr->s.num_pmr = 1; >> >> >> + pmr->s.pmr_term_value[0].match_type = ODP_PMR_MASK; >> >> >> + pmr->s.pmr_term_value[0].term = term; >> >> >> + pmr->s.pmr_term_value[0].range.val1 = 0; >> >> >> + pmr->s.pmr_term_value[0].range.val2 = 0; >> >> >> + memcpy(&pmr->s.pmr_term_value[0].range.val1, val1, val_sz); >> >> >> + memcpy(&pmr->s.pmr_term_value[0].range.val2, val2, val_sz); >> >> >> + UNLOCK(&pmr->s.lock); >> >> >> + return id; >> >> >> } >> >> >> >> >> >> int odp_pmr_destroy(odp_pmr_t pmr_id) >> >> >> { >> >> >> - (void)pmr_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pmr_t *pmr = get_pmr_entry(pmr_id); >> >> >> + >> >> >> + if (pmr == NULL) >> >> >> + return -1; >> >> >> + pmr->s.valid = 0; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> @@ -132,64 +449,478 @@ int odp_pktio_pmr_cos(odp_pmr_t pmr_id, >> >> >> odp_pktio_t src_pktio, >> >> >> odp_cos_t dst_cos) >> >> >> { >> >> >> - (void)pmr_id; >> >> >> - (void)src_pktio; >> >> >> - (void)dst_cos; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + uint8_t num_pmr; >> >> >> + pktio_entry_t *pktio_entry; >> >> >> + pmr_t *pmr; >> >> >> + cos_t *cos; >> >> >> + >> >> >> + pktio_entry = get_pktio_entry(src_pktio); >> >> >> + if (pktio_entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + pmr = get_pmr_entry(pmr_id); >> >> >> + if (pmr == NULL) { >> >> >> + ODP_ERR("Invalid odp_pmr_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + cos = get_cos_entry(dst_cos); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + LOCK(&pktio_entry->s.cls.lock); >> >> >> + num_pmr = pktio_entry->s.cls.num_pmr; >> >> >> + if (num_pmr >= ODP_PKTIO_MAX_PMR) { >> >> >> + ODP_ERR("ODP_PKTIO_MAX_PMR reached"); >> >> >> + UNLOCK(&pktio_entry->s.cls.lock); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + pktio_entry->s.cls.pmr[num_pmr] = pmr; >> >> >> + pktio_entry->s.cls.cos[num_pmr] = cos; >> >> >> + pktio_entry->s.cls.num_pmr++; >> >> >> + UNLOCK(&pktio_entry->s.cls.lock); >> >> >> + >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_cos_pmr_cos(odp_pmr_t pmr_id, odp_cos_t src_cos, odp_cos_t >> >> >> dst_cos) >> >> >> { >> >> >> - (void)pmr_id; >> >> >> - (void)src_cos; >> >> >> - (void)dst_cos; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + cos_t *cos_src = get_cos_entry(src_cos); >> >> >> + cos_t *cos_dst = get_cos_entry(dst_cos); >> >> >> + pmr_t *pmr = get_pmr_entry(pmr_id); >> >> >> + if (NULL == cos_src || NULL == cos_dst || NULL == pmr) { >> >> >> + ODP_ERR("Invalid input handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + /*Locking is not required as intermittent stale data is >> >> >> acceptable*/ >> >> >> + cos_src->s.pmr = pmr; >> >> >> + cos_src->s.linked_cos = cos_dst; >> >> >> + >> >> >> return 0; >> >> >> } >> >> >> >> >> >> signed long odp_pmr_match_count(odp_pmr_t pmr_id) >> >> >> { >> >> >> - (void)pmr_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + pmr_t *pmr = get_pmr_entry(pmr_id); >> >> >> + if (pmr == NULL) >> >> >> + return -1; >> >> >> + return (signed long)odp_atomic_load_u32(&pmr->s.count); >> >> >> } >> >> >> >> >> >> unsigned long long odp_pmr_terms_cap(void) >> >> >> { >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + unsigned long long term_cap = 0; >> >> >> + >> >> >> + term_cap |= (1 << ODP_PMR_LEN); >> >> >> + term_cap |= (1 << ODP_PMR_IPPROTO); >> >> >> + term_cap |= (1 << ODP_PMR_UDP_DPORT); >> >> >> + term_cap |= (1 << ODP_PMR_TCP_DPORT); >> >> >> + term_cap |= (1 << ODP_PMR_UDP_SPORT); >> >> >> + term_cap |= (1 << ODP_PMR_TCP_SPORT); >> >> >> + term_cap |= (1 << ODP_PMR_SIP_ADDR); >> >> >> + term_cap |= (1 << ODP_PMR_DIP_ADDR); >> >> >> + return term_cap; >> >> >> } >> >> >> >> >> >> unsigned odp_pmr_terms_avail(void) >> >> >> { >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + unsigned count = 0; >> >> >> + int i; >> >> >> + >> >> >> + for (i = 0; i < ODP_PMR_MAX_ENTRY; i++) >> >> >> + if (!pmr_tbl->pmr[i].s.valid) >> >> >> + count++; >> >> >> + return count; >> >> >> } >> >> >> >> >> >> int odp_pmr_match_set_create(int num_terms, odp_pmr_match_t *terms, >> >> >> odp_pmr_set_t *pmr_set_id) >> >> >> { >> >> >> - (void)num_terms; >> >> >> - (void)terms; >> >> >> - (void)pmr_set_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> - return 0; >> >> >> + pmr_t *pmr; >> >> >> + int i; >> >> >> + uint32_t id; >> >> >> + int val_sz; >> >> >> + int count = 0; >> >> >> + >> >> >> + if (num_terms > ODP_PMRTERM_MAX) { >> >> >> + ODP_ERR("no of terms greater than supported >> >> >> ODP_PMRTERM_MAX"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + id = alloc_pmr_set(&pmr); >> >> >> + /*if alloc_pmr_set is successful it returns with the acquired >> >> >> lock*/ >> >> >> + if (id == ODP_PMR_INVAL) { >> >> >> + *pmr_set_id = id; >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + pmr->s.num_pmr = num_terms; >> >> >> + for (i = 0; i < num_terms; i++) { >> >> >> + pmr->s.pmr_term_value[i].match_type = >> >> >> terms[i].match_type; >> >> >> + if (terms[i].match_type == ODP_PMR_MASK) { >> >> >> + val_sz = terms[i].mask.val_sz; >> >> >> + if (val_sz > ODP_PMR_TERM_BYTES_MAX) >> >> >> + continue; >> >> >> + pmr->s.pmr_term_value[i].term = >> >> >> terms[i].mask.term; >> >> >> + pmr->s.pmr_term_value[i].mask.val = 0; >> >> >> + pmr->s.pmr_term_value[i].mask.mask = 0; >> >> >> + memcpy(&pmr->s.pmr_term_value[i].mask.val, >> >> >> + terms[i].mask.val, val_sz); >> >> >> + memcpy(&pmr->s.pmr_term_value[i].mask.mask, >> >> >> + terms[i].mask.mask, val_sz); >> >> >> + } else { >> >> >> + val_sz = terms[i].range.val_sz; >> >> >> + if (val_sz > ODP_PMR_TERM_BYTES_MAX) >> >> >> + continue; >> >> >> + pmr->s.pmr_term_value[i].term = >> >> >> terms[i].range.term; >> >> >> + pmr->s.pmr_term_value[i].range.val1 = 0; >> >> >> + pmr->s.pmr_term_value[i].range.val2 = 0; >> >> >> + memcpy(&pmr->s.pmr_term_value[i].range.val1, >> >> >> + terms[i].range.val1, val_sz); >> >> >> + memcpy(&pmr->s.pmr_term_value[i].range.val2, >> >> >> + terms[i].range.val2, val_sz); >> >> >> + } >> >> >> + count++; >> >> >> + } >> >> >> + *pmr_set_id = id; >> >> >> + UNLOCK(&pmr->s.lock); >> >> >> + return count; >> >> >> } >> >> >> >> >> >> int odp_pmr_match_set_destroy(odp_pmr_set_t pmr_set_id) >> >> >> { >> >> >> - (void)pmr_set_id; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + pmr_set_t *pmr_set = get_pmr_set_entry(pmr_set_id); >> >> >> + if (pmr_set == NULL) >> >> >> + return -1; >> >> >> + >> >> >> + pmr_set->s.pmr.s.valid = 0; >> >> >> return 0; >> >> >> } >> >> >> >> >> >> int odp_pktio_pmr_match_set_cos(odp_pmr_set_t pmr_set_id, odp_pktio_t >> >> >> src_pktio, >> >> >> - odp_cos_t dst_cos) >> >> >> + odp_cos_t dst_cos) >> >> >> +{ >> >> >> + uint8_t num_pmr; >> >> >> + pktio_entry_t *pktio_entry; >> >> >> + pmr_t *pmr; >> >> >> + cos_t *cos; >> >> >> + >> >> >> + pktio_entry = get_pktio_entry(src_pktio); >> >> >> + if (pktio_entry == NULL) { >> >> >> + ODP_ERR("Invalid odp_pktio_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + pmr = (pmr_t *)get_pmr_set_entry(pmr_set_id); >> >> >> + if (pmr == NULL) { >> >> >> + ODP_ERR("Invalid odp_pmr_set_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + cos = get_cos_entry(dst_cos); >> >> >> + if (cos == NULL) { >> >> >> + ODP_ERR("Invalid odp_cos_t handle"); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + LOCK(&pktio_entry->s.cls.lock); >> >> >> + num_pmr = pktio_entry->s.cls.num_pmr; >> >> >> + if (num_pmr >= ODP_PKTIO_MAX_PMR) { >> >> >> + ODP_ERR("ODP_PKTIO_MAX_PMR reached"); >> >> >> + UNLOCK(&pktio_entry->s.cls.lock); >> >> >> + return -1; >> >> >> + } >> >> >> + >> >> >> + pktio_entry->s.cls.pmr[num_pmr] = pmr; >> >> >> + pktio_entry->s.cls.cos[num_pmr] = cos; >> >> >> + pktio_entry->s.cls.num_pmr++; >> >> >> + UNLOCK(&pktio_entry->s.cls.lock); >> >> >> + >> >> >> + return 0; >> >> >> +} >> >> >> + >> >> >> +int verify_pmr(pmr_t *pmr, uint8_t *pkt_addr, odp_packet_hdr_t >> >> >> *pkt_hdr) >> >> >> +{ >> >> >> + int pmr_failure = 0; >> >> >> + int num_pmr; >> >> >> + int i; >> >> >> + pmr_term_value_t *term_value; >> >> >> + >> >> >> + /* Locking is not required as PMR rules for in-flight packets >> >> >> + delivery during a PMR change is indeterminate*/ >> >> >> + >> >> >> + if (!pmr->s.valid) >> >> >> + return 0; >> >> >> + num_pmr = pmr->s.num_pmr; >> >> >> + >> >> >> + /* Iterate through list of PMR Term values in a pmr_t */ >> >> >> + for (i = 0; i < num_pmr; i++) { >> >> >> + term_value = &pmr->s.pmr_term_value[i]; >> >> >> + switch (term_value->term) { >> >> >> + case ODP_PMR_LEN: >> >> >> + if (!verify_pmr_packet_len(pkt_hdr, >> >> >> term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_ETHTYPE_0: >> >> >> + if (!verify_pmr_eth_type_0(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_ETHTYPE_X: >> >> >> + if (!verify_pmr_eth_type_x(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_VLAN_ID_0: >> >> >> + if (!verify_pmr_vlan_id_0(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_VLAN_ID_X: >> >> >> + if (!verify_pmr_vlan_id_x(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_DMAC: >> >> >> + if (!verify_pmr_dmac(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_IPPROTO: >> >> >> + if (!verify_pmr_ip_proto(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_UDP_DPORT: >> >> >> + if (!verify_pmr_udp_dport(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_TCP_DPORT: >> >> >> + if (!verify_pmr_tcp_dport(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_UDP_SPORT: >> >> >> + if (!verify_pmr_udp_sport(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_TCP_SPORT: >> >> >> + if (!verify_pmr_tcp_sport(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_SIP_ADDR: >> >> >> + if (!verify_pmr_ipv4_saddr(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_DIP_ADDR: >> >> >> + if (!verify_pmr_ipv4_daddr(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_SIP6_ADDR: >> >> >> + if (!verify_pmr_ipv6_saddr(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_DIP6_ADDR: >> >> >> + if (!verify_pmr_ipv6_daddr(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_IPSEC_SPI: >> >> >> + if (!verify_pmr_ipsec_spi(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_LD_VNI: >> >> >> + if (!verify_pmr_ld_vni(pkt_addr, pkt_hdr, >> >> >> + term_value)) >> >> >> + pmr_failure = 1; >> >> >> + break; >> >> >> + case ODP_PMR_INNER_HDR_OFF: >> >> >> + break; >> >> >> + } >> >> >> + >> >> >> + if (pmr_failure) >> >> >> + return false; >> >> >> + } >> >> >> + odp_atomic_inc_u32(&pmr->s.count); >> >> >> + return true; >> >> >> +} >> >> >> + >> >> >> +cos_t *match_pmr_cos(cos_t *cos, uint8_t *pkt_addr, pmr_t *pmr, >> >> >> + odp_packet_hdr_t *hdr) >> >> >> +{ >> >> >> + cos_t *retcos = NULL; >> >> >> + >> >> >> + if (cos == NULL || pmr == NULL) >> >> >> + return NULL; >> >> >> + >> >> >> + if (!cos->s.valid) >> >> >> + return NULL; >> >> >> + >> >> >> + if (verify_pmr(pmr, pkt_addr, hdr)) { >> >> >> + /** This gets called recursively to check all the PMRs >> >> >> in >> >> >> + * a PMR chain */ >> >> >> + retcos = match_pmr_cos(cos->s.linked_cos, pkt_addr, >> >> >> + cos->s.pmr, hdr); >> >> >> + if (!retcos) >> >> >> + return cos; >> >> >> + } >> >> >> + return retcos; >> >> >> +} >> >> >> + >> >> >> +int pktio_classifier_init(pktio_entry_t *entry) >> >> >> { >> >> >> - (void)pmr_set_id; >> >> >> - (void)src_pktio; >> >> >> - (void)dst_cos; >> >> >> - ODP_UNIMPLEMENTED(); >> >> >> + classifier_t *cls; >> >> >> + int i; >> >> >> + /* classifier lock should be acquired by the calling function >> >> >> */ >> >> >> + if (entry == NULL) >> >> >> + return -1; >> >> >> + cls = &entry->s.cls; >> >> >> + cls->num_pmr = 0; >> >> >> + cls->flow_set = 0; >> >> >> + cls->error_cos = NULL; >> >> >> + cls->default_cos = NULL; >> >> >> + cls->headroom = 0; >> >> >> + cls->skip = 0; >> >> >> + >> >> >> + for (i = 0; i < ODP_PKTIO_MAX_PMR; i++) { >> >> >> + cls->pmr[i] = NULL; >> >> >> + cls->cos[i] = NULL; >> >> >> + } >> >> >> + >> >> >> return 0; >> >> >> } >> >> >> + >> >> >> +int packet_classifier(odp_pktio_t pktio, odp_packet_t pkt) >> >> >> +{ >> >> >> + pktio_entry_t *entry; >> >> >> + queue_entry_t *queue; >> >> >> + cos_t *cos; >> >> >> + odp_packet_hdr_t *pkt_hdr; >> >> >> + uint8_t *pkt_addr; >> >> >> + >> >> >> + entry = get_pktio_entry(pktio); >> >> >> + if (entry == NULL) >> >> >> + return -1; >> >> >> + >> >> >> + pkt_hdr = odp_packet_hdr(pkt); >> >> >> + pkt_addr = odp_packet_addr(pkt); >> >> >> + >> >> >> + /* Matching PMR and selecting the CoS for the packet*/ >> >> >> + cos = pktio_select_cos(entry, pkt_addr, pkt_hdr); >> >> >> + if (cos == NULL) >> >> >> + return -1; >> >> >> + >> >> >> + /* Enqueuing the Packet based on the CoS */ >> >> >> + queue = cos->s.queue; >> >> >> + return queue_enq(queue, odp_buf_to_hdr((odp_buffer_t)pkt)); >> >> >> +} >> >> >> + >> >> >> +cos_t *pktio_select_cos(pktio_entry_t *entry, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *pkt_hdr) >> >> >> +{ >> >> >> + pmr_t *pmr; >> >> >> + cos_t *cos; >> >> >> + uint32_t i; >> >> >> + classifier_t *cls; >> >> >> + >> >> >> + cls = &entry->s.cls; >> >> >> + >> >> >> + /* Return error cos for error packet */ >> >> >> + if (pkt_hdr->error_flags.all) >> >> >> + return cls->error_cos; >> >> >> + /* Calls all the PMRs attached at the PKTIO level*/ >> >> >> + for (i = 0; i < cls->num_pmr; i++) { >> >> >> + pmr = entry->s.cls.pmr[i]; >> >> >> + cos = entry->s.cls.cos[i]; >> >> >> + cos = match_pmr_cos(cos, pkt_addr, pmr, pkt_hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + } >> >> >> + >> >> >> + cos = match_qos_cos(entry, pkt_addr, pkt_hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + >> >> >> + return cls->default_cos; >> >> >> +} >> >> >> + >> >> >> +cos_t *match_qos_l3_cos(pmr_l3_cos_t *l3_cos, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr) >> >> >> +{ >> >> >> + uint8_t dscp; >> >> >> + cos_t *cos = NULL; >> >> >> + odph_ipv4hdr_t *ipv4; >> >> >> + odph_ipv6hdr_t *ipv6; >> >> >> + >> >> >> + if (hdr->input_flags.l3 && hdr->input_flags.ipv4) { >> >> >> + ipv4 = (odph_ipv4hdr_t *)(pkt_addr + hdr->l3_offset); >> >> >> + dscp = ODPH_IPV4HDR_DSCP(ipv4->tos); >> >> >> + cos = l3_cos->cos[dscp]; >> >> >> + } else if (hdr->input_flags.l3 && hdr->input_flags.ipv6) { >> >> >> + ipv6 = (odph_ipv6hdr_t *)(pkt_addr + hdr->l3_offset); >> >> >> + dscp = ODPH_IPV6HDR_DSCP(ipv6->ver_tc_flow); >> >> >> + cos = l3_cos->cos[dscp]; >> >> >> + } >> >> >> + >> >> >> + return cos; >> >> >> +} >> >> >> + >> >> >> +cos_t *match_qos_l2_cos(pmr_l2_cos_t *l2_cos, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr) >> >> >> +{ >> >> >> + uint8_t qos; >> >> >> + cos_t *cos = NULL; >> >> >> + odph_ethhdr_t *eth; >> >> >> + odph_vlanhdr_t *vlan; >> >> >> + >> >> >> + if (hdr->input_flags.l2 && hdr->input_flags.vlan && >> >> >> + hdr->input_flags.eth) { >> >> >> + eth = (odph_ethhdr_t *)(pkt_addr + hdr->l2_offset); >> >> >> + vlan = (odph_vlanhdr_t *)(ð->type); >> >> >> + qos = ((vlan->tci >> 13) & 0xFF); >> >> >> + cos = l2_cos->cos[qos]; >> >> >> + } >> >> >> + return cos; >> >> >> +} >> >> >> + >> >> >> +cos_t *match_qos_cos(pktio_entry_t *entry, uint8_t *pkt_addr, >> >> >> + odp_packet_hdr_t *hdr) >> >> >> +{ >> >> >> + classifier_t *cls = &entry->s.cls; >> >> >> + pmr_l2_cos_t *l2_cos; >> >> >> + pmr_l3_cos_t *l3_cos; >> >> >> + cos_t *cos; >> >> >> + >> >> >> + l2_cos = &cls->l2_cos_table; >> >> >> + l3_cos = &cls->l3_cos_table; >> >> >> + >> >> >> + if (cls->l3_precedence) { >> >> >> + cos = match_qos_l3_cos(l3_cos, pkt_addr, hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + cos = match_qos_l2_cos(l2_cos, pkt_addr, hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + } else { >> >> >> + cos = match_qos_l2_cos(l2_cos, pkt_addr, hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + cos = match_qos_l3_cos(l3_cos, pkt_addr, hdr); >> >> >> + if (cos) >> >> >> + return cos; >> >> >> + } >> >> >> + return NULL; >> >> >> +} >> >> >> diff --git a/platform/linux-generic/odp_init.c >> >> >> b/platform/linux-generic/odp_init.c >> >> >> index 672b3d6..c661231 100644 >> >> >> --- a/platform/linux-generic/odp_init.c >> >> >> +++ b/platform/linux-generic/odp_init.c >> >> >> @@ -54,6 +54,10 @@ int odp_init_global(odp_init_t *params ODP_UNUSED, >> >> >> ODP_ERR("ODP crypto init failed.\n"); >> >> >> return -1; >> >> >> } >> >> >> + if (odp_classification_init_global()) { >> >> >> + ODP_ERR("ODP crypto init failed.\n"); >> >> >> + return -1; >> >> >> + } >> >> >> >> >> >> return 0; >> >> >> } >> >> >> diff --git a/platform/linux-generic/odp_packet_io.c >> >> >> b/platform/linux-generic/odp_packet_io.c >> >> >> index 19b9eea..6bda003 100644 >> >> >> --- a/platform/linux-generic/odp_packet_io.c >> >> >> +++ b/platform/linux-generic/odp_packet_io.c >> >> >> @@ -13,10 +13,10 @@ >> >> >> #include <odp_spinlock.h> >> >> >> #include <odp_shared_memory.h> >> >> >> #include <odp_packet_socket.h> >> >> >> -#include <odp_hints.h> >> >> >> #include <odp_config.h> >> >> >> #include <odp_queue_internal.h> >> >> >> #include <odp_schedule_internal.h> >> >> >> +#include <odp_classification_internal.h> >> >> >> #include <odp_debug_internal.h> >> >> >> >> >> >> #include <string.h> >> >> >> @@ -50,6 +50,7 @@ int odp_pktio_init_global(void) >> >> >> pktio_entry = &pktio_tbl->entries[id - 1]; >> >> >> >> >> >> odp_spinlock_init(&pktio_entry->s.lock); >> >> >> + odp_spinlock_init(&pktio_entry->s.cls.lock); >> >> >> >> >> >> pktio_entry_ptr[id - 1] = pktio_entry; >> >> >> /* Create a default output queue for each pktio >> >> >> resource >> >> >> */ >> >> >> @@ -98,12 +99,25 @@ static void unlock_entry(pktio_entry_t *entry) >> >> >> odp_spinlock_unlock(&entry->s.lock); >> >> >> } >> >> >> >> >> >> +static void lock_entry_classifier(pktio_entry_t *entry) >> >> >> +{ >> >> >> + odp_spinlock_lock(&entry->s.lock); >> >> >> + odp_spinlock_lock(&entry->s.cls.lock); >> >> >> +} >> >> >> + >> >> >> +static void unlock_entry_classifier(pktio_entry_t *entry) >> >> >> +{ >> >> >> + odp_spinlock_unlock(&entry->s.cls.lock); >> >> >> + odp_spinlock_unlock(&entry->s.lock); >> >> >> +} >> >> >> + >> >> >> static void init_pktio_entry(pktio_entry_t *entry) >> >> >> { >> >> >> set_taken(entry); >> >> >> entry->s.inq_default = ODP_QUEUE_INVALID; >> >> >> memset(&entry->s.pkt_sock, 0, sizeof(entry->s.pkt_sock)); >> >> >> memset(&entry->s.pkt_sock_mmap, 0, >> >> >> sizeof(entry->s.pkt_sock_mmap)); >> >> >> + pktio_classifier_init(entry); >> >> >> } >> >> >> >> >> >> static odp_pktio_t alloc_lock_pktio_entry(void) >> >> >> @@ -115,13 +129,13 @@ static odp_pktio_t alloc_lock_pktio_entry(void) >> >> >> for (i = 0; i < ODP_CONFIG_PKTIO_ENTRIES; ++i) { >> >> >> entry = &pktio_tbl->entries[i]; >> >> >> if (is_free(entry)) { >> >> >> - lock_entry(entry); >> >> >> + lock_entry_classifier(entry); >> >> >> if (is_free(entry)) { >> >> >> init_pktio_entry(entry); >> >> >> id = i + 1; >> >> >> return id; /* return with entry locked! >> >> >> */ >> >> >> } >> >> >> - unlock_entry(entry); >> >> >> + unlock_entry_classifier(entry); >> >> >> } >> >> >> } >> >> >> >> >> >> @@ -190,14 +204,14 @@ odp_pktio_t odp_pktio_open(const char *dev, >> >> >> odp_buffer_pool_t pool) >> >> >> close_pkt_sock(&pktio_entry->s.pkt_sock); >> >> >> } >> >> >> >> >> >> - unlock_entry(pktio_entry); >> >> >> + unlock_entry_classifier(pktio_entry); >> >> >> free_pktio_entry(id); >> >> >> ODP_ERR("Unable to init any I/O type.\n"); >> >> >> return ODP_PKTIO_INVALID; >> >> >> >> >> >> done: >> >> >> strncpy(pktio_entry->s.name, dev, IFNAMSIZ); >> >> >> - unlock_entry(pktio_entry); >> >> >> + unlock_entry_classifier(pktio_entry); >> >> >> return id; >> >> >> } >> >> >> >> >> >> @@ -415,7 +429,7 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t >> >> >> *qentry) >> >> >> odp_buffer_t buf; >> >> >> odp_packet_t pkt_tbl[QUEUE_MULTI_MAX]; >> >> >> odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX]; >> >> >> - int pkts, i; >> >> >> + int pkts, i, j; >> >> >> >> >> >> buf_hdr = queue_deq(qentry); >> >> >> if (buf_hdr != NULL) >> >> >> @@ -425,12 +439,15 @@ odp_buffer_hdr_t *pktin_dequeue(queue_entry_t >> >> >> *qentry) >> >> >> if (pkts <= 0) >> >> >> return NULL; >> >> >> >> >> >> - for (i = 0; i < pkts; ++i) { >> >> >> + for (i = 0, j = 0; i < pkts; ++i) { >> >> >> buf = odp_packet_to_buffer(pkt_tbl[i]); >> >> >> - tmp_hdr_tbl[i] = odp_buf_to_hdr(buf); >> >> >> + buf_hdr = odp_buf_to_hdr(buf); >> >> >> + if (0 > packet_classifier(qentry->s.pktin, pkt_tbl[i])) >> >> >> >> For linux-generic does it make sense to classify packets in poll-mode >> >> operation? I.e. odp_pktio_recv? >> >> >> >> >> + tmp_hdr_tbl[j++] = buf_hdr; >> >> >> } >> >> >> >> >> >> - queue_enq_multi(qentry, tmp_hdr_tbl, pkts); >> >> >> + if (j) >> >> >> + queue_enq_multi(qentry, tmp_hdr_tbl, j); >> >> >> buf_hdr = tmp_hdr_tbl[0]; >> >> >> return buf_hdr; >> >> >> } >> >> >> @@ -446,8 +463,9 @@ int pktin_deq_multi(queue_entry_t *qentry, >> >> >> odp_buffer_hdr_t *buf_hdr[], int num) >> >> >> int nbr; >> >> >> odp_packet_t pkt_tbl[QUEUE_MULTI_MAX]; >> >> >> odp_buffer_hdr_t *tmp_hdr_tbl[QUEUE_MULTI_MAX]; >> >> >> + odp_buffer_hdr_t *tmp_hdr; >> >> >> odp_buffer_t buf; >> >> >> - int pkts, i; >> >> >> + int pkts, i, j; >> >> >> >> >> >> nbr = queue_deq_multi(qentry, buf_hdr, num); >> >> >> if (odp_unlikely(nbr > num)) >> >> >> @@ -464,12 +482,15 @@ int pktin_deq_multi(queue_entry_t *qentry, >> >> >> odp_buffer_hdr_t *buf_hdr[], int num) >> >> >> if (pkts <= 0) >> >> >> return nbr; >> >> >> >> >> >> - for (i = 0; i < pkts; ++i) { >> >> >> + for (i = 0, j = 0; i < pkts; ++i) { >> >> >> buf = odp_packet_to_buffer(pkt_tbl[i]); >> >> >> - tmp_hdr_tbl[i] = odp_buf_to_hdr(buf); >> >> >> + tmp_hdr = odp_buf_to_hdr(buf); >> >> >> + if (0 > packet_classifier(qentry->s.pktin, pkt_tbl[i])) >> >> >> + tmp_hdr_tbl[j++] = tmp_hdr; >> >> >> } >> >> >> >> >> >> - queue_enq_multi(qentry, tmp_hdr_tbl, pkts); >> >> >> + if (j) >> >> >> + queue_enq_multi(qentry, tmp_hdr_tbl, j); >> >> >> return nbr; >> >> >> } >> >> >> >> >> >> -- >> >> >> 2.0.1.472.g6f92e5f >> >> >> >> >> >> >> >> >> _______________________________________________ >> >> >> lng-odp mailing list >> >> >> lng-odp@lists.linaro.org >> >> >> http://lists.linaro.org/mailman/listinfo/lng-odp >> >> > >> >> > >> >> > >> >> > _______________________________________________ >> >> > lng-odp mailing list >> >> > lng-odp@lists.linaro.org >> >> > http://lists.linaro.org/mailman/listinfo/lng-odp >> >> > >> > >> > _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org http://lists.linaro.org/mailman/listinfo/lng-odp