From: Barry Spinney <[email protected]>

This patch adds a new marking_colors_supported and marking_colors_needed
arrays.  Also splits the TOS marking function - which previously could
specify ECN or DSCP marking into two separate calls.  Also improved the
documentation.

This patch also updates the TM implementation to match the latest
changes to the header file.  In addition a few bugs were fixed
in the marking implementations.

Signed-off-by: Barry Spinney <[email protected]>
Signed-off-by: Bill Fischofer <[email protected]>
---
 include/odp/api/spec/traffic_mngr.h                | 135 ++++++++++++++++-----
 .../include/odp_traffic_mngr_internal.h            |  11 +-
 platform/linux-generic/odp_traffic_mngr.c          | 127 +++++++++++++------
 3 files changed, 206 insertions(+), 67 deletions(-)

diff --git a/include/odp/api/spec/traffic_mngr.h 
b/include/odp/api/spec/traffic_mngr.h
index c5b9d24..83b89e7 100644
--- a/include/odp/api/spec/traffic_mngr.h
+++ b/include/odp/api/spec/traffic_mngr.h
@@ -293,19 +293,35 @@ typedef struct {
         * form of VLAN egress marking using the odp_tm_vlan_marking()
         * function.  This being true does not imply that all colors and
         * subfield values and changes are supported.  Unsupported features
-        * can be detected by the marking function returning an error code.*/
+        * can be detected by the marking function returning an error code. */
        odp_bool_t vlan_marking_supported;
 
-       /** ip_tos_marking_supported indicates that this TM system supports
+       /** ecn_marking_supported indicates that this TM system supports
+        * Explicit Congestion Notification egress marking by using the
+        * odp_tm_ip_ecn_marking() function.  Note that the ECN is the bottom
+        * two bits of the IPv4 TOS field or the analogous IPv6 Traffic Class
+        * (TC) field.  Note that the ecn_marking_supported boolean being
+        * true does not imply that all colors are supported. */
+       odp_bool_t ecn_marking_supported;
+
+       /** drop_prec_marking_supported indicates that this TM system supports
         * SOME form of IPv4/IPv6 egress marking by using the
-        * odp_tm_ip_tos_marking() function.  Note that the actually field
+        * odp_tm_drop_prec_marking() function.  Note that the actually field
         * modified for IPv4 pkts is called TOS, whereas the field modified
         * for IPv6 pkts is called Traffic Class (TC) - but they are analogous
-        * fields.  Note that the ip_tos_marking_supported boolean being true
+        * fields.  Note that the drop_prec_marking_supported boolean being true
         * does not imply that all colors and subfield values and changes are
         * supported.  Unsupported features can be detected by the marking
         * function returning an error code.*/
-       odp_bool_t ip_tos_marking_supported;
+       odp_bool_t drop_prec_marking_supported;
+
+       /** The marking_colors_supported array is used to indicate which colors
+        * can be used for marking.  A value of FALSE means that this color
+        * should not be enabled for either vlan marking, ecn marking or
+        * drop precedence marking.  A value of TRUE means that this color is
+        * supported for at least one of (and ideally all of) vlan marking,
+        * ecn marking or drop precedence marking. */
+       odp_bool_t marking_colors_supported[ODP_NUM_PACKET_COLORS];
 
        /** The per_level array specifies the TM system capabilities that
         * can vary based upon the tm_node level. */
@@ -379,7 +395,7 @@ typedef struct {
        uint32_t max_tm_queues;
 
        /** num_levels specifies that number of levels of hierarchical
-        * scheduling that will b used.  This is a count of the tm_node
+        * scheduling that will be used.  This is a count of the tm_node
         * stages and does not include tm_queues or tm_egress objects. */
        uint8_t num_levels;
 
@@ -402,11 +418,25 @@ typedef struct {
         * vlan_marking_supported. */
        odp_bool_t vlan_marking_needed;
 
-       /** ip_tos_marking_needed indicates that the ODP application expects
+       /** ecn_marking_needed indicates that the ODP application expects
+        * to use some form of IPv4 TOS or IPv6 TC field egress marking by
+        * using the odp_tm_ecn_marking() function.  See also comments for
+        * ecn_marking_supported. */
+       odp_bool_t ecn_marking_needed;
+
+       /** drop_prec_marking_needed indicates that the ODP application expects
         * to use some form of IPv4 TOS or IPv6 TC field egress marking by
-        * using the odp_tm_ip_tos_marking() function.  See also comments for
-        * ip_tos_marking_supported. */
-       odp_bool_t ip_tos_marking_needed;
+        * using the odp_tm_drop_prec_marking() function.  See also comments for
+        * drop_prec_marking_supported. */
+       odp_bool_t drop_prec_marking_needed;
+
+       /** The marking_colors_needed array is used to indicate which colors
+        * are expected to be used for marking.  A value of FALSE means that
+        * the application will not enable this color for vlan marking,
+        * ecn marking nor drop precedence marking.  A value of TRUE means that
+        * the application expects to use this color in conjunction with one or
+        * more of the marking API's. */
+       odp_bool_t marking_colors_needed[ODP_NUM_PACKET_COLORS];
 
        /** The per_level array specifies the TM system requirements that
         * can vary based upon the tm_node level. */
@@ -598,7 +628,11 @@ int odp_tm_destroy(odp_tm_t odp_tm);
  * field (but only for pkts that already carry a VLAN tag) of a pkt based upon
  * the final pkt (or shaper?) color assigned to the pkt when it reaches the
  * egress node.  When drop_eligible_enabled is false, then the given color has
- * no effect on the VLAN fields.
+ * no effect on the VLAN fields.  See IEEE 802.1q for more details.
+ *
+ * Note that ALL ODP implementations are required to SUCCESSFULLY handle all
+ * calls to this function with drop_eligible_enabled == FALSE - i.e. must
+ * always return 0 when disabling this feature.
  *
  * @param[in] odp_tm                 Odp_tm is used to identify the TM system
  *                                   whose egress behavior is being changed.
@@ -612,39 +646,76 @@ int odp_tm_vlan_marking(odp_tm_t           odp_tm,
                        odp_packet_color_t color,
                        odp_bool_t         drop_eligible_enabled);
 
-/** IP Tos Marking.
+/** Explicit Congestion Notification Marking.
+ *
+ * The odp_tm_ecn_marking() function allows one to configure the TM
+ * egress so that the two bit ECN subfield of the eight bit TOS field of an
+ * IPv4 pkt OR the eight bit Traffic Class (TC) field of an IPv6 pkt can be
+ * selectively modified based upon the final color assigned to the pkt when it
+ * reaches the egress.  Note that the IPv4 header checksum will be updated -
+ * but only if the IPv4 TOS field actually changes as a result of this
+ * setting or the odp_tm_drop_prec_marking setting.  For IPv6, since there is
+ * no header checksum, nothing needs to be done.  Note that this marking API
+ * will only ever cause both ECN bits to be set to 1 - but only for TCP pkts
+ * whose incoming ECN bits are not both 0.  See RFC 3168 for more details.
  *
- * The odp_tm_ip_tos_marking() function allows one to configure the TM
- * egress so that the eight bit TOS field of an IPv4 pkt OR the analogous
- * eight bit Traffic Class (TC) field of an IPv6 pkt can be selectively
- * modified based upon the final color assigned to the pkt when it reaches the
- * egress.  Note that both the TOS/TC field and the VLAN header of a VLAN 
tagged
- * IP pkt could be independently modified.  Also note that this function
- * will update the IPv4 header checksum - but only if the TOS field actually
- * changes.  For IPv6, since there is no header checksum, nothing needs to
- * be done.
+ * Note that ALL ODP implementations are required to SUCCESSFULLY handle all
+ * calls to this function with ecn_ce_enabled == FALSE - i.e. must always
+ * return 0 when disabling this feature.
  *
  * @param[in] odp_tm          Odp_tm is used to identify the TM system whose
  *                            egress behavior is being changed.
  * @param[in] color           The packet color whose egress marking is
  *                            being changed.
- * @param[in] dscp_enabled    If true then egressed IPv4/IPv6 pkts with this
- *                            color will have the pkt's DSCP subfield set to 
the
- *                            new_dscp parameter (see below).
- * @param[in] new_dscp        The Differentiated Services Code Point value.
- *                            Must be in the range 0..63.
  * @param[in] ecn_ce_enabled  If true then egressed IPv4/IPv6 pkts whose
  *                            protocol field is TCP AND whose ECN subfield has
- *                            one of the two values 1 or 2, will set this
+ *                            either one of the two values 1 or 2, will set 
this
  *                            subfield to the value ECN_CE - i.e. Congestion
  *                            Experienced (whose value is 3).
  * @return                    0 upon success, < 0 upon failure.
  */
-int odp_tm_ip_tos_marking(odp_tm_t           odp_tm,
-                         odp_packet_color_t color,
-                         odp_bool_t         dscp_enabled,
-                         uint8_t            new_dscp,
-                         odp_bool_t         ecn_ce_enabled);
+int odp_tm_ecn_marking(odp_tm_t           odp_tm,
+                      odp_packet_color_t color,
+                      odp_bool_t         ecn_ce_enabled);
+
+/** Drop Precedence Marking.
+ *
+ * The odp_tm_drop_prec_marking() function allows one to configure the TM
+ * egress so that the two RFC 2597 Drop Precedence bits can be modified
+ * based upon the final color assigned to the pkt when it reaches the egress.
+ * The Drop Precedence bits are contained within the six bit Differentiated
+ * Services Code Point subfield of the IPv4 TOS field or the IPv6 Traffic
+ * Class (TC) field.  Specifically the Drop Precedence sub-subfield can be
+ * accessed with a DSCP bit mask of 0x06.  When enabled for a given color,
+ * these two bits will be set to Medium Drop Precedence (value 0x4) if the
+ * color is ODP_PACKET_YELLOW, set to High Drop Precedence (value 0x6) if
+ * the color is ODP_PACKET_RED, otherwise set to Low Drop Precedence for any
+ * other color.  Of course an implementation can restrict the set of colors
+ * which can be enabled via the marking_colors_supported array in the
+ * odp_tm_capabilities_t record.
+ *
+ * Note that the IPv4 header checksum will be updated - but only if the
+ * IPv4 TOS field actually changes as a result of this setting or the
+ * odp_tm_ecn_marking setting.  For IPv6, since there is no header checksum,
+ * nothing else needs to be done.
+ *
+ * Note that ALL ODP implementations are required to SUCCESSFULLY handle all
+ * calls to this function with drop_prec_enabled == FALSE - i.e. must always
+ * return 0 when disabling this feature.
+ *
+ * @param[in] odp_tm            Odp_tm is used to identify the TM system whose
+ *                              egress behavior is being changed.
+ * @param[in] color             The packet color whose egress marking is
+ *                              being changed.
+ * @param[in] drop_prec_enabled If true then egressed IPv4/IPv6 pkts with this
+ *                              color will have the pkt's Drop Precedence
+ *                              sub-subfield of the DSCP subfield set to
+ *                              LOW, MEDIUM or HIGH drop precedence.
+ * @return                      0 upon success, < 0 upon failure.
+ */
+int odp_tm_drop_prec_marking(odp_tm_t           odp_tm,
+                            odp_packet_color_t color,
+                            odp_bool_t         drop_prec_enabled);
 
 /** Shaper profile types and functions */
 
diff --git a/platform/linux-generic/include/odp_traffic_mngr_internal.h 
b/platform/linux-generic/include/odp_traffic_mngr_internal.h
index a0853eb..90036de 100644
--- a/platform/linux-generic/include/odp_traffic_mngr_internal.h
+++ b/platform/linux-generic/include/odp_traffic_mngr_internal.h
@@ -67,6 +67,15 @@ typedef struct stat  file_stat_t;
 
 typedef uint64_t tm_handle_t;
 
+#define LOW_DROP_PRECEDENCE      0x02
+#define MEDIUM_DROP_PRECEDENCE   0x04
+#define HIGH_DROP_PRECEDENCE     0x06
+#define DROP_PRECEDENCE_MASK     0x06
+#define DSCP_CLASS1              0x08
+#define DSCP_CLASS2              0x10
+#define DSCP_CLASS3              0x18
+#define DSCP_CLASS4              0x20
+
 #define PF_RM_CURRENT_BEST  0x01
 #define PF_NEW_PKT_IN       0x02
 #define PF_SHAPER_DELAYED   0x10
@@ -327,7 +336,7 @@ typedef struct {
 
 typedef struct {
        odp_bool_t marking_enabled;
-       odp_bool_t dscp_enabled;
+       odp_bool_t drop_prec_enabled;
        uint8_t    shifted_dscp;
        uint8_t    inverted_dscp_mask;
        odp_bool_t ecn_ce_enabled;
diff --git a/platform/linux-generic/odp_traffic_mngr.c 
b/platform/linux-generic/odp_traffic_mngr.c
index 27530ff..1cc5e9b 100644
--- a/platform/linux-generic/odp_traffic_mngr.c
+++ b/platform/linux-generic/odp_traffic_mngr.c
@@ -1924,7 +1924,7 @@ static void egress_ipv4_tos_marking(tm_tos_marking_t 
*tos_marking,
 
        old_tos = ipv4_hdr_ptr->tos;
        new_tos = old_tos;
-       if (tos_marking->dscp_enabled)
+       if (tos_marking->drop_prec_enabled)
                new_tos = (new_tos & tos_marking->inverted_dscp_mask) |
                                tos_marking->shifted_dscp;
 
@@ -1989,10 +1989,11 @@ static void egress_ipv6_tc_marking(tm_tos_marking_t 
*tos_marking,
        }
 
        old_ver_tc_flow = odp_be_to_cpu_32(ipv6_hdr_ptr->ver_tc_flow);
-       old_tc          = old_ver_tc_flow >> ODPH_IPV6HDR_TC_SHIFT;
+       old_tc          = (old_ver_tc_flow & ODPH_IPV6HDR_TC_MASK)
+                               >> ODPH_IPV6HDR_TC_SHIFT;
        new_tc          = old_tc;
 
-       if (tos_marking->dscp_enabled)
+       if (tos_marking->drop_prec_enabled)
                new_tc = (new_tc & tos_marking->inverted_dscp_mask) |
                               tos_marking->shifted_dscp;
 
@@ -2006,7 +2007,7 @@ static void egress_ipv6_tc_marking(tm_tos_marking_t 
*tos_marking,
        if (new_tc == old_tc)
                return;
 
-       new_ver_tc_flow = (old_ver_tc_flow & ODPH_IPV6HDR_TC_MASK) |
+       new_ver_tc_flow = (old_ver_tc_flow & ~ODPH_IPV6HDR_TC_MASK) |
                          (new_tc << ODPH_IPV6HDR_TC_SHIFT);
        ipv6_hdr_ptr->ver_tc_flow = odp_cpu_to_be_32(new_ver_tc_flow);
 
@@ -2345,12 +2346,12 @@ int odp_tm_capabilities(odp_tm_capabilities_t 
capabilities[] ODP_UNUSED,
 {
        odp_tm_level_capabilities_t *per_level_cap;
        odp_tm_capabilities_t       *cap_ptr;
+       odp_packet_color_t           color;
        uint32_t                     level_idx;
 
        if (capabilities_size == 0)
                return -1;
 
-       /* TBD */
        cap_ptr = &capabilities[0];
        memset(cap_ptr, 0, sizeof(odp_tm_capabilities_t));
 
@@ -2360,7 +2361,11 @@ int odp_tm_capabilities(odp_tm_capabilities_t 
capabilities[] ODP_UNUSED,
        cap_ptr->tm_queue_wred_supported       = true;
        cap_ptr->tm_queue_dual_slope_supported = true;
        cap_ptr->vlan_marking_supported        = true;
-       cap_ptr->ip_tos_marking_supported      = true;
+       cap_ptr->ecn_marking_supported         = true;
+       cap_ptr->drop_prec_marking_supported   = true;
+
+       for (color = 0; color < ODP_NUM_PACKET_COLORS; color++)
+               cap_ptr->marking_colors_supported[color] = true;
 
        for (level_idx = 0; level_idx < cap_ptr->max_levels; level_idx++) {
                per_level_cap = &cap_ptr->per_level[level_idx];
@@ -2378,7 +2383,7 @@ int odp_tm_capabilities(odp_tm_capabilities_t 
capabilities[] ODP_UNUSED,
                per_level_cap->weights_supported            = true;
        }
 
-       return 0;
+       return 1;
 }
 
 static void tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr,
@@ -2386,6 +2391,7 @@ static void 
tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr,
 {
        odp_tm_level_requirements_t *per_level_req;
        odp_tm_level_capabilities_t *per_level_cap;
+       odp_packet_color_t           color;
        odp_bool_t                   shaper_supported, wred_supported;
        odp_bool_t                   dual_slope;
        uint32_t                     num_levels, level_idx, max_nodes;
@@ -2407,7 +2413,13 @@ static void 
tm_system_capabilities_set(odp_tm_capabilities_t *cap_ptr,
        cap_ptr->tm_queue_wred_supported       = wred_supported;
        cap_ptr->tm_queue_dual_slope_supported = dual_slope;
        cap_ptr->vlan_marking_supported        = req_ptr->vlan_marking_needed;
-       cap_ptr->ip_tos_marking_supported      = req_ptr->ip_tos_marking_needed;
+       cap_ptr->ecn_marking_supported         = req_ptr->ecn_marking_needed;
+       cap_ptr->drop_prec_marking_supported   =
+                                       req_ptr->drop_prec_marking_needed;
+
+       for (color = 0; color < ODP_NUM_PACKET_COLORS; color++)
+               cap_ptr->marking_colors_supported[color] =
+                       req_ptr->marking_colors_needed[color];
 
        for (level_idx = 0; level_idx < num_levels; level_idx++) {
                per_level_cap = &cap_ptr->per_level[level_idx];
@@ -2635,6 +2647,11 @@ int odp_tm_vlan_marking(odp_tm_t           odp_tm,
        if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS < color))
                return -1;
 
+       if (drop_eligible_enabled)
+               if ((!tm_system->requirements.vlan_marking_needed) ||
+                   (!tm_system->requirements.marking_colors_needed[color]))
+                       return -2;
+
        vlan_marking = &tm_system->marking.vlan_marking[color];
        vlan_marking->marking_enabled       = drop_eligible_enabled;
        vlan_marking->drop_eligible_enabled = drop_eligible_enabled;
@@ -2646,37 +2663,79 @@ int odp_tm_vlan_marking(odp_tm_t           odp_tm,
        return 0;
 }
 
-static void tm_tos_marking(tm_tos_marking_t *tos_marking,
-                          odp_bool_t        dscp_enabled,
-                          uint8_t           new_dscp,
-                          odp_bool_t        ecn_ce_enabled)
-
+int odp_tm_ecn_marking(odp_tm_t           odp_tm,
+                      odp_packet_color_t color,
+                      odp_bool_t         ecn_ce_enabled)
 {
-       tos_marking->marking_enabled    = dscp_enabled | ecn_ce_enabled;
-       tos_marking->dscp_enabled       = dscp_enabled;
-       tos_marking->shifted_dscp       = (new_dscp & ~ODPH_IP_TOS_DSCP_MASK)
-                                               << ODPH_IP_TOS_DSCP_SHIFT;
-       tos_marking->inverted_dscp_mask = (uint8_t)~ODPH_IP_TOS_DSCP_MASK;
-       tos_marking->ecn_ce_enabled     = ecn_ce_enabled;
+       tm_tos_marking_t *tos_marking;
+       tm_system_t      *tm_system;
+
+       tm_system = GET_TM_SYSTEM(odp_tm);
+       if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color))
+               return -1;
+
+       if (ecn_ce_enabled)
+               if ((!tm_system->requirements.ecn_marking_needed) ||
+                   (!tm_system->requirements.marking_colors_needed[color]))
+                       return -2;
+
+       tos_marking = &tm_system->marking.ip_tos_marking[color];
+       tos_marking->marking_enabled = tos_marking->drop_prec_enabled |
+                                             ecn_ce_enabled;
+       tos_marking->ecn_ce_enabled  = ecn_ce_enabled;
+
+       if (ecn_ce_enabled)
+               tm_system->marking_enabled = true;
+       else
+               tm_system->marking_enabled = tm_marking_enabled(tm_system);
+
+       return 0;
 }
 
-int odp_tm_ip_tos_marking(odp_tm_t           odp_tm,
-                         odp_packet_color_t color,
-                         odp_bool_t         dscp_enabled,
-                         uint8_t            new_dscp,
-                         odp_bool_t         ecn_ce_enabled)
+int odp_tm_drop_prec_marking(odp_tm_t           odp_tm,
+                            odp_packet_color_t color,
+                            odp_bool_t         drop_prec_enabled)
 {
-       tm_tos_marking_t *ip_marking;
+       tm_tos_marking_t *tos_marking;
        tm_system_t      *tm_system;
+       uint8_t           dscp_mask, new_dscp, inverted_mask, tos_mask;
+       uint8_t           shifted_dscp;
 
        tm_system = GET_TM_SYSTEM(odp_tm);
-       if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color) ||
-           (ODPH_IP_TOS_MAX_DSCP < new_dscp))
+       if ((tm_system == NULL) || (ODP_NUM_PACKET_COLORS <= color))
                return -1;
 
-       ip_marking = &tm_system->marking.ip_tos_marking[color];
-       tm_tos_marking(ip_marking, dscp_enabled, new_dscp, ecn_ce_enabled);
-       if (dscp_enabled | ecn_ce_enabled)
+       if (drop_prec_enabled)
+               if ((!tm_system->requirements.drop_prec_marking_needed) ||
+                   (!tm_system->requirements.marking_colors_needed[color]))
+                       return -2;
+
+       dscp_mask = DROP_PRECEDENCE_MASK;
+       if (color == ODP_PACKET_YELLOW)
+               new_dscp = MEDIUM_DROP_PRECEDENCE;
+       else if (color == ODP_PACKET_RED)
+               new_dscp = HIGH_DROP_PRECEDENCE;
+       else
+               new_dscp = LOW_DROP_PRECEDENCE;
+
+       if (drop_prec_enabled) {
+               new_dscp      = new_dscp & dscp_mask;
+               inverted_mask = (uint8_t)~dscp_mask;
+               tos_mask      = (inverted_mask << ODPH_IP_TOS_DSCP_SHIFT) |
+                                       ODPH_IP_TOS_ECN_MASK;
+               shifted_dscp  = new_dscp << ODPH_IP_TOS_DSCP_SHIFT;
+       } else {
+               tos_mask     = 0xFF;  /* Note that this is an inverted mask */
+               shifted_dscp = 0;
+       }
+
+       tos_marking = &tm_system->marking.ip_tos_marking[color];
+       tos_marking->marking_enabled    = drop_prec_enabled |
+                                         tos_marking->ecn_ce_enabled;
+       tos_marking->drop_prec_enabled  = drop_prec_enabled;
+       tos_marking->shifted_dscp       = shifted_dscp;
+       tos_marking->inverted_dscp_mask = tos_mask;
+       if (drop_prec_enabled)
                tm_system->marking_enabled = true;
        else
                tm_system->marking_enabled = tm_marking_enabled(tm_system);
@@ -4012,18 +4071,18 @@ int odp_tm_node_fanin_info(odp_tm_node_t             
tm_node,
                return -5;
 
        info->is_last = next_shaper_obj->fanin_list_next == NULL;
-       if (shaper_obj->in_tm_node_obj) {
-               fanin_tm_node_obj = shaper_obj->enclosing_entity;
+       if (next_shaper_obj->in_tm_node_obj) {
+               fanin_tm_node_obj = next_shaper_obj->enclosing_entity;
                info->tm_node     = MAKE_ODP_TM_NODE(fanin_tm_node_obj);
                info->tm_queue    = ODP_TM_INVALID;
        } else {
-               fanin_tm_queue_obj = shaper_obj->enclosing_entity;
+               fanin_tm_queue_obj = next_shaper_obj->enclosing_entity;
                info->tm_queue     = MAKE_ODP_TM_QUEUE(fanin_tm_queue_obj);
                info->tm_node      = ODP_TM_INVALID;
        }
 
        info->sched_profile = ODP_TM_INVALID;
-       sched_params        = shaper_obj->sched_params;
+       sched_params        = next_shaper_obj->sched_params;
        if (sched_params != NULL)
                info->sched_profile = sched_params->sched_profile;
 
-- 
2.5.0

_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to