Message ID | 1417838383-3215-3-git-send-email-bala.manoharan@linaro.org |
---|---|
State | New |
Headers | show |
These patches are available in the following public repo http://git.linaro.org/people/bala.manoharan/classification.git Regards, Bala On 6 December 2014 at 09:29, Balasubramanian Manoharan < bala.manoharan@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.manoharan@linaro.org> > --- > 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 | 878 > +++++++++++++++++++-- > platform/linux-generic/odp_init.c | 4 + > platform/linux-generic/odp_packet_io.c | 47 +- > 12 files changed, 1493 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..e3c4bf7 100644 > --- a/platform/linux-generic/odp_classification.c > +++ b/platform/linux-generic/odp_classification.c > @@ -1,69 +1,318 @@ > +/* 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"); > + return -1; > + } > + > + cos_tbl = odp_shm_addr(cos_shm); > + if (cos_tbl == NULL) { > + odp_shm_free(cos_shm); > + return -1; > + } > + > + 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"); > + return -1; > + } > + > + pmr_tbl = odp_shm_addr(pmr_shm); > + if (pmr_tbl == NULL) { > + odp_shm_free(pmr_shm); > + return -1; > + } > + > + 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"); > + return -1; > + } > + > + pmr_set_tbl = odp_shm_addr(pmr_set_shm); > + if (pmr_set_tbl == NULL) { > + odp_shm_free(pmr_set_shm); > + return -1; > + } > + > + 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; > } > > +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 intermitted 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 +321,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 +350,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 +381,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_DBG(); > + 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 +409,34 @@ 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) > + 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 +444,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 intermitted 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) > { > - (void)pmr_set_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 = (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) > +{ > + 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])) > + 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 > >
General comments: This patch will conflict with the buffer pool patch I posted this evening, because we're both moving the same things from odp_buffer_pool.c to odp_buffer_pool_internal.h. Whichever gets merged first the other can do the very trivial fixup to resolve the conflict. Aside from a few minor comments (see below). This looks good. Bill On Fri, Dec 5, 2014 at 9:59 PM, Balasubramanian Manoharan < bala.manoharan@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.manoharan@linaro.org> > --- > 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 | 878 > +++++++++++++++++++-- > platform/linux-generic/odp_init.c | 4 + > platform/linux-generic/odp_packet_io.c | 47 +- > 12 files changed, 1493 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..e3c4bf7 100644 > --- a/platform/linux-generic/odp_classification.c > +++ b/platform/linux-generic/odp_classification.c > @@ -1,69 +1,318 @@ > +/* 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"); > + return -1; > + } > + > + cos_tbl = odp_shm_addr(cos_shm); > + if (cos_tbl == NULL) { > + odp_shm_free(cos_shm); > + return -1; > + } > + > + 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"); > + return -1; > + } > + > Good you're doing the step-by-step checks here, but if the first odp_shm_reserve() call succeeds and the second one fails, you exit without doing an odp_shm_free() for the first one, so it's now lost. Similar problem with chaining the reserves/frees as you step through this routine. For robustness, you need to back out all of the prior successful reservations when you detect a later error. > + pmr_tbl = odp_shm_addr(pmr_shm); > + if (pmr_tbl == NULL) { > + odp_shm_free(pmr_shm); > + return -1; > + } > + > + 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"); > + return -1; > + } > + > + pmr_set_tbl = odp_shm_addr(pmr_set_shm); > + if (pmr_set_tbl == NULL) { > + odp_shm_free(pmr_set_shm); > + return -1; > + } > + > + 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; > } > > +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 intermitted stale > + data during CoS modification is acceptable*/ > Typo: intermitted. I assume either intermediate or intermittent? > + 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 +321,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 +350,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 +381,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_DBG(); > Is the null ODP_DBG() intentional here? Looks odd. Vestigial from some debugging, perhaps? > + 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 +409,34 @@ 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) > + 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 +444,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 intermitted 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) > { > - (void)pmr_set_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 = (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) > +{ > + 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])) > + 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 >
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..e3c4bf7 100644 --- a/platform/linux-generic/odp_classification.c +++ b/platform/linux-generic/odp_classification.c @@ -1,69 +1,318 @@ +/* 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"); + return -1; + } + + cos_tbl = odp_shm_addr(cos_shm); + if (cos_tbl == NULL) { + odp_shm_free(cos_shm); + return -1; + } + + 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"); + return -1; + } + + pmr_tbl = odp_shm_addr(pmr_shm); + if (pmr_tbl == NULL) { + odp_shm_free(pmr_shm); + return -1; + } + + 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"); + return -1; + } + + pmr_set_tbl = odp_shm_addr(pmr_set_shm); + if (pmr_set_tbl == NULL) { + odp_shm_free(pmr_set_shm); + return -1; + } + + 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; } +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 intermitted 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 +321,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 +350,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 +381,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_DBG(); + 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 +409,34 @@ 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) + 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 +444,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 intermitted 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) { - (void)pmr_set_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 = (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) +{ + 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])) + 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; }
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.manoharan@linaro.org> --- 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 | 878 +++++++++++++++++++-- platform/linux-generic/odp_init.c | 4 + platform/linux-generic/odp_packet_io.c | 47 +- 12 files changed, 1493 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